From ecd70d8dd9ceeca4e8d429f931a0ec4fd837e69a Mon Sep 17 00:00:00 2001 From: Aurélien Bompard Date: Jun 17 2022 19:33:45 +0000 Subject: Don't expire refreshable OIDC tokens Fixes: #372 Signed-off-by: Aurélien Bompard --- diff --git a/ipsilon/providers/openidc/store.py b/ipsilon/providers/openidc/store.py index 44cfa4a..8cbf77f 100644 --- a/ipsilon/providers/openidc/store.py +++ b/ipsilon/providers/openidc/store.py @@ -385,7 +385,14 @@ class OpenIDCStore(Store): tokens = self.get_unique_data('token') cleaned = 0 for iden in tokens: - if int(tokens[iden]['expires_at']) <= int(time.time()): + token_props = tokens[iden] + # Values are stored as a JSON string + refreshable = json.loads(token_props.get("refreshable", "null")) + if refreshable: + expires_at = token_props.get('refreshable_until') + else: + expires_at = token_props['expires_at'] + if expires_at is not None and int(expires_at) <= int(time.time()): cleaned += 1 self.invalidateToken(iden) return cleaned diff --git a/tests/openidc.py b/tests/openidc.py index 80c52cb..558f713 100755 --- a/tests/openidc.py +++ b/tests/openidc.py @@ -295,7 +295,7 @@ if __name__ == '__main__': 'providers/openidc/admin/client/%s' % reg_resp['client_id'], {'Client Name': 'Test suite client updated'}) - with TC.case('Retrieving toke info'): + with TC.case('Retrieving token info'): # Testing token without client auth r = requests.post('https://127.0.0.10:45080/idp1/openidc/TokenInfo', data={'token': new_token['access_token']}) diff --git a/tests/testcleanup.py b/tests/testcleanup.py index bfa0289..a728624 100755 --- a/tests/testcleanup.py +++ b/tests/testcleanup.py @@ -11,6 +11,8 @@ import sqlite3 from string import Template import time +from ipsilon.providers.openidc.store import OpenIDCStore, OpenIDCStaticStore + idp_g = {'TEMPLATES': '${TESTDIR}/templates/install', 'CONFDIR': '${TESTDIR}/etc', 'DATADIR': '${TESTDIR}/lib', @@ -156,3 +158,53 @@ if __name__ == '__main__': cur.execute('SELECT * FROM saml2_sessions;') if len(cur.fetchall()) != 0: raise ValueError('SAML2 sessions left behind: %s' % cur.fetchall()) + + + with TC.case('Checking that refreshable OpenIDC tokens are not expired'): + static_db_path = os.path.join(os.environ['TESTDIR'], 'lib/idp1/openidc.static.sqlite') + db_path = os.path.join(os.environ['TESTDIR'], 'lib/idp1/openidc.sqlite') + static_store = OpenIDCStaticStore(database_url=f"sqlite:///{static_db_path}") + store = OpenIDCStore( + database_url=f"sqlite:///{db_path}", static_store=static_store + ) + + token_refreshable = store.issueToken( + client_id="client-id", username="username", scope=["openid"], + issue_refresh=True, userinfocode="userinfocode" + ) + + token_non_refreshable = store.issueToken( + client_id="client-id", username="username", scope=["openid"], + issue_refresh=False, userinfocode="userinfocode" + ) + + assert len(store.get_unique_data("token")) == 2 + + conn = sqlite3.connect(db_path) + cur = conn.cursor() + + expired_ts = int(time.time()) - 1 + + # Setting tokens to expire + cur.execute( + "UPDATE token SET value = ? WHERE name = 'expires_at'", + (expired_ts,) + ) + conn.commit() + conn.close() + + try: + cleanup_count = store._cleanupExpiredTokens() + except Exception as e: + print(e) + raise + + if cleanup_count != 1: + raise Exception( + f"Should only have cleaned up 1 token, cleaned {cleanup_count}" + ) + + tokens = store.get_unique_data("token") + assert len(tokens) == 1 + if list(tokens.keys())[0] != token_refreshable["token_id"]: + raise Exception("The refreshable token has been cleaned up")