diff --git a/src/oidcendpoint/exception.py b/src/oidcendpoint/exception.py index dfe0114..8ab680d 100755 --- a/src/oidcendpoint/exception.py +++ b/src/oidcendpoint/exception.py @@ -66,6 +66,10 @@ class UnAuthorizedClient(OidcEndpointError): pass +class UnAuthorizedClientScope(OidcEndpointError): + pass + + class InvalidCookieSign(Exception): pass diff --git a/src/oidcendpoint/oauth2/authorization.py b/src/oidcendpoint/oauth2/authorization.py index fd662e3..000d881 100755 --- a/src/oidcendpoint/oauth2/authorization.py +++ b/src/oidcendpoint/oauth2/authorization.py @@ -31,6 +31,7 @@ from oidcendpoint.exception import ServiceError from oidcendpoint.exception import TamperAllert from oidcendpoint.exception import ToOld +from oidcendpoint.exception import UnAuthorizedClientScope from oidcendpoint.exception import UnknownClient from oidcendpoint.session import setup_session from oidcendpoint.user_authn.authn_context import pick_auth @@ -59,6 +60,21 @@ def re_authenticate(request, authn): return False +def check_unknown_scopes_policy(request_info, cinfo, endpoint_context): + op_capabilities = endpoint_context.conf['capabilities'] + client_allowed_scopes = cinfo.get('allowed_scopes') or \ + op_capabilities['scopes_supported'] + + # this prevents that authz would be released for unavailable scopes + for scope in request_info['scope']: + if op_capabilities.get('deny_unknown_scopes') and \ + scope not in client_allowed_scopes: + _msg = '{} requested an unauthorized scope ({})' + logger.warning(_msg.format(cinfo['client_id'], + scope)) + raise UnAuthorizedClientScope() + + class Authorization(Endpoint): request_cls = oauth2.AuthorizationRequest response_cls = oauth2.AuthorizationResponse @@ -588,6 +604,11 @@ def process_request(self, request_info=None, **kwargs): _cid = request_info["client_id"] cinfo = self.endpoint_context.cdb[_cid] + logger.debug("client {}: {}".format(_cid, cinfo)) + + # this apply the default optionally deny_unknown_scopes policy + check_unknown_scopes_policy(request_info, cinfo, self.endpoint_context) + cookie = kwargs.get("cookie", "") if cookie: del kwargs["cookie"] diff --git a/src/oidcendpoint/oidc/authorization.py b/src/oidcendpoint/oidc/authorization.py index 7a89963..69141f4 100755 --- a/src/oidcendpoint/oidc/authorization.py +++ b/src/oidcendpoint/oidc/authorization.py @@ -34,6 +34,7 @@ from oidcendpoint.exception import TamperAllert from oidcendpoint.exception import ToOld from oidcendpoint.exception import UnknownClient +from oidcendpoint.oauth2.authorization import check_unknown_scopes_policy from oidcendpoint.session import setup_session from oidcendpoint.user_authn.authn_context import pick_auth @@ -680,6 +681,9 @@ def process_request(self, request_info=None, **kwargs): cinfo = self.endpoint_context.cdb[_cid] logger.debug("client {}: {}".format(_cid, cinfo)) + # this apply the default optionally deny_unknown_scopes policy + check_unknown_scopes_policy(request_info, cinfo, self.endpoint_context) + cookie = kwargs.get("cookie", "") if cookie: del kwargs["cookie"] diff --git a/tests/test_24_oauth2_authorization_endpoint.py b/tests/test_24_oauth2_authorization_endpoint.py index 8c35337..599269d 100755 --- a/tests/test_24_oauth2_authorization_endpoint.py +++ b/tests/test_24_oauth2_authorization_endpoint.py @@ -30,6 +30,7 @@ from oidcendpoint.exception import RedirectURIError from oidcendpoint.exception import ToOld from oidcendpoint.exception import UnknownClient +from oidcendpoint.exception import UnAuthorizedClientScope from oidcendpoint.exception import UnAuthorizedClient from oidcendpoint.id_token import IDToken from oidcendpoint.oauth2.authorization import Authorization @@ -464,6 +465,38 @@ def test_setup_auth_error(self): item["method"].file = "" + def test_setup_auth_invalid_scope(self): + request = AuthorizationRequest( + client_id="client_id", + redirect_uri="https://rp.example.com/cb", + response_type=["id_token"], + state="state", + nonce="nonce", + scope="openid THAT-BLOODY_SCOPE", + ) + redirect_uri = request["redirect_uri"] + cinfo = { + "client_id": "client_id", + "redirect_uris": [("https://rp.example.com/cb", {})], + "id_token_signed_response_alg": "RS256", + } + + _ec = self.endpoint.endpoint_context + _ec.cdb["client_id"] = cinfo + + kaka = self.endpoint.endpoint_context.cookie_dealer.create_cookie( + "value", "sso") + + # force to 400 Http Error message if the release scope policy is heavy! + self.endpoint.endpoint_context.conf['capabilities']['deny_unknown_scopes'] = True + excp = None + try: + res = self.endpoint.process_request(request) + except UnAuthorizedClientScope as e: + excp = e + assert excp + assert isinstance(excp, UnAuthorizedClientScope) + def test_setup_auth_user(self): request = AuthorizationRequest( client_id="client_id",