From 87310b979857ab29c91499212eaa3bd24e9d0700 Mon Sep 17 00:00:00 2001 From: Helmut Merz Date: Wed, 23 Apr 2025 09:10:43 +0200 Subject: [PATCH] auth: improve loading of oidc provider data, provide and check in test --- scopes/tests/config.py | 2 +- scopes/tests/data_auth.py | 32 +++++++++++++++++++++++++++++ scopes/tests/dummy_requests.py | 26 +----------------------- scopes/tests/test_standard.py | 1 + scopes/tests/tlib_web.py | 7 +++++-- scopes/web/auth/oidc.py | 37 ++++++++++++++++++---------------- 6 files changed, 60 insertions(+), 45 deletions(-) create mode 100644 scopes/tests/data_auth.py diff --git a/scopes/tests/config.py b/scopes/tests/config.py index 8ffdcc4..475536a 100644 --- a/scopes/tests/config.py +++ b/scopes/tests/config.py @@ -34,7 +34,7 @@ dbpassword = None dbschema = None # special testing stuff -#from scopes.tests import oidc_data # add oidc URIs and keys to dummy_requests data +from scopes.tests import data_auth # add oidc URIs and keys to dummy_requests data from scopes.tests import dummy_requests sys.modules['requests'] = dummy_requests diff --git a/scopes/tests/data_auth.py b/scopes/tests/data_auth.py new file mode 100644 index 0000000..f629e5e --- /dev/null +++ b/scopes/tests/data_auth.py @@ -0,0 +1,32 @@ +# scopes.tests.data_auth + +"""provide response data for testing (via dummy_requests)""" + +oidc_data = { + 'test://oidc/.well-known/openid-configuration': { + "issuer": "test://oidc", + "authorization_endpoint": "test://oidc/oauth/v2/authorize", + "token_endpoint": "test://oidc/oauth/v2/token", + "introspection_endpoint": "test://oidc/oauth/v2/introspect", + "userinfo_endpoint": "test://oidc/oidc/v1/userinfo", + "revocation_endpoint": "test://oidc/oauth/v2/revoke", + "end_session_endpoint": "test://oidc/oidc/v1/end_session", + "device_authorization_endpoint": "test://oidc/oauth/v2/device_authorization", + "jwks_uri": "test://oidc/oauth/v2/keys"}, + 'test://oidc/oauth/v2/keys': { "keys": [ + {"use": "sig", + "kty": "RSA", + "kid": "316638486247563085", + "alg": "RS256", + "n": "167qFCfRa0tRR0MZv-PQVwdiVFf0NtfN-zFAogRASm6437sbXfsfxkpbh1F77TwQdl4qlR5Na_Ecs8VTxOuyHmuhIJ4FyZV4M0h71KRw7LCTVuNw7mWLpbjKPBzidyhctbkJrkcKtJymnHELsct0CdT16Lb27phd_0cBJexGbwhVNQBs10VbkvUJHHOJe6A_JVS9Q3_3MEWyCyFoHPeMchlk_Gd6yMiH4aJ1ql3GZD6c2JB9crloTH_oPWWFQObGoXTKcFonEBdkrwuCQfRVOfGh8UIhIcTM0JNgqtQOCcIkf0emfI30SoWSc6Qz8lU70Vpmb3qQgsqATFICgzgABw", + "e": "AQAB"}, + {"use": "sig", + "kty": "RSA", + "kid": "316766976250797901", + "alg": "RS256", + "n": "yZKIsrUWT2fEj4OtUUFYQbEe_Clodz464tn5vMAQ0q8zV07bqFaA7WKuBflowYctDNxoxdbiFNISpKEOx6yFnx7_g6Zd46DWsj5ggGZvNkgOa9SqTIsA7ho9nk7LDLQRpV0k5N1HkiG66GUqUCV2llJhstpTDQQLDvhI3qussG2HyylpTQSu-9b6gry0rb397yjAnXQu6tFOubEDteTN0fLNMblcdd2AvZKpGA2o_-M5U6AckezfmBCBdHWmrwxpjGGf7KWqGg8j6bJkV3sMg4XfD2x0KNog_3D-0pSx6k8dSWZGkNlDxB5AdWvNDYg1stkvjeNEbIJAhv0-awLs9Q", + "e": "AQAB"}]} +} + +from scopes.tests.dummy_requests import response_data +response_data.update(oidc_data) diff --git a/scopes/tests/dummy_requests.py b/scopes/tests/dummy_requests.py index d586094..787d724 100644 --- a/scopes/tests/dummy_requests.py +++ b/scopes/tests/dummy_requests.py @@ -19,28 +19,4 @@ class FakeResponse: return self.data -response_data = { - 'test://oidc/.well-known/openid-configuration': { - "issuer": "test://oidc", - "authorization_endpoint": "test://oidc/oauth/v2/authorize", - "token_endpoint": "test://oidc/oauth/v2/token", - "introspection_endpoint": "test://oidc/oauth/v2/introspect", - "userinfo_endpoint": "test://oidc/oidc/v1/userinfo", - "revocation_endpoint": "test://oidc/oauth/v2/revoke", - "end_session_endpoint": "test://oidc/oidc/v1/end_session", - "device_authorization_endpoint": "test://oidc/oauth/v2/device_authorization", - "jwks_uri": "test://oidc/oauth/v2/keys"}, - 'test://oidc/oauth/v2/keys': { "keys": [ - {"use": "sig", - "kty": "RSA", - "kid": "316638486247563085", - "alg": "RS256", - "n": "167qFCfRa0tRR0MZv-PQVwdiVFf0NtfN-zFAogRASm6437sbXfsfxkpbh1F77TwQdl4qlR5Na_Ecs8VTxOuyHmuhIJ4FyZV4M0h71KRw7LCTVuNw7mWLpbjKPBzidyhctbkJrkcKtJymnHELsct0CdT16Lb27phd_0cBJexGbwhVNQBs10VbkvUJHHOJe6A_JVS9Q3_3MEWyCyFoHPeMchlk_Gd6yMiH4aJ1ql3GZD6c2JB9crloTH_oPWWFQObGoXTKcFonEBdkrwuCQfRVOfGh8UIhIcTM0JNgqtQOCcIkf0emfI30SoWSc6Qz8lU70Vpmb3qQgsqATFICgzgABw", - "e": "AQAB"}, - {"use": "sig", - "kty": "RSA", - "kid": "316766976250797901", - "alg": "RS256", - "n": "yZKIsrUWT2fEj4OtUUFYQbEe_Clodz464tn5vMAQ0q8zV07bqFaA7WKuBflowYctDNxoxdbiFNISpKEOx6yFnx7_g6Zd46DWsj5ggGZvNkgOa9SqTIsA7ho9nk7LDLQRpV0k5N1HkiG66GUqUCV2llJhstpTDQQLDvhI3qussG2HyylpTQSu-9b6gry0rb397yjAnXQu6tFOubEDteTN0fLNMblcdd2AvZKpGA2o_-M5U6AckezfmBCBdHWmrwxpjGGf7KWqGg8j6bJkV3sMg4XfD2x0KNog_3D-0pSx6k8dSWZGkNlDxB5AdWvNDYg1stkvjeNEbIJAhv0-awLs9Q", - "e": "AQAB"}]} -} +response_data = {} diff --git a/scopes/tests/test_standard.py b/scopes/tests/test_standard.py index fe007b1..6b05915 100644 --- a/scopes/tests/test_standard.py +++ b/scopes/tests/test_standard.py @@ -32,6 +32,7 @@ class Test(unittest.TestCase): def test_013_web(self): tlib_web.test_app(self, config) + tlib_web.test_auth(self, config) def suite(): diff --git a/scopes/tests/tlib_web.py b/scopes/tests/tlib_web.py index c9efdcf..2e095cd 100644 --- a/scopes/tests/tlib_web.py +++ b/scopes/tests/tlib_web.py @@ -21,10 +21,13 @@ def publishRequest(config, storage, path): def test_app(self, config): logger = logging.getLogger('tlib_web') - logger.info('test_app') storage = config.storageFactory(config.dbschema) response = publishRequest(config, storage, '/top') - print('***', response.getStatus(), response.getHeaders()) + logger.info('test_app: response %s %s', response.getStatus(), response.getHeaders()) result = json.loads(response.consumeBody()) self.assertEqual(result['items'][0]['head']['name'], 'level2-item1') +def test_auth(self, config): + from scopes.web.auth import oidc + oidc.loadOidcProviderData() + self.assertEqual(len(config.oidc_params['op_uris']), 8) diff --git a/scopes/web/auth/oidc.py b/scopes/web/auth/oidc.py index 690f68b..384df4f 100644 --- a/scopes/web/auth/oidc.py +++ b/scopes/web/auth/oidc.py @@ -81,17 +81,11 @@ class Authenticator(DummyFolder): prefix = 'auth.oidc' - oidcProviderUris = ['authorization_endpoint', 'token_endpoint', - 'introspection_endpoint', 'userinfo_endpoint', - 'revocation_endpoint', 'end_session_endpoint', - 'device_authorization_endpoint', 'jwks_uri'] - def __init__(self, request): self.request = request self.params = config.oidc_params self.reqUrl = config.base_url self.setCrypt(self.params.get('cookie_crypt')) - self.loadOidcProviderData() def setReqUrl(self, base, path): self.reqUrl = '/'.join((base, path)) @@ -109,6 +103,7 @@ class Authenticator(DummyFolder): return None def login(self): + loadOidcProviderData() req = self.request #print('***', dir(req)) state = util.rndstr() @@ -202,17 +197,6 @@ class Authenticator(DummyFolder): data = json.loads(cookie) return data - def loadOidcProviderData(self, force=False): - if config.oidc_provider.startswith('test'): - pass - if force or self.params.get('op_uris') is None: - uris = self.params['op_uris'] = {} - opData = requests.get(self.params['op_config_url']).json() - for key in self.oidcProviderUris: - uris[key] = opData[key] - if force or self.params.get('op_keys') is None: - self.params['op_keys'] = requests.get(uris['jwks_uri']).json()['keys'] - @register('auth', Root) def authView(context, request): @@ -232,3 +216,22 @@ def callback(context, request): def logout(context, request): context.logout() return DefaultView(context, request) + + +oidcProviderUris = ['authorization_endpoint', 'token_endpoint', + 'introspection_endpoint', 'userinfo_endpoint', + 'revocation_endpoint', 'end_session_endpoint', + 'device_authorization_endpoint', 'jwks_uri'] + +def loadOidcProviderData(force=False): + params = config.oidc_params + if force or params.get('op_uris') is None: + uris = params['op_uris'] = {} + opData = requests.get(params['op_config_url']).json() + for key in oidcProviderUris: + uris[key] = opData[key] + if force or params.get('op_keys') is None: + params['op_keys'] = requests.get(uris['jwks_uri']).json()['keys'] + + +