FazBrowse GitHub Viewer | Trending |
URL:
| Home
Tools: [Download Repo ZIP]   [Original HTTPS Page]

Unavailable scopes - behaviour expected · Issue #73 · IdentityPython/oidcendpoint · GitHub

This repository was archived by the owner on Jun 12, 2021. It is now read-only.

Repository navigation

This repository was archived by the owner on Jun 12, 2021. It is now read-only.

Unavailable scopes - behaviour expected  #73

Description

I succesfully tested allowed_scopes and I found a default behaviour in oidcendpoint and oidcRP that I'd like to discuss.
When OidcRP have in its configuration some scopes not supported by OP (as found in Provider discovery) it simply omit them and send a authn request with which found available in provider discovery.

oidcendpoint when get a authz request with unavailable scopes, it simply ignore these and release its defaults (openid profile email address phone). The resulting access token could be used by a Client/RP (or a faulty RS) to give access to a resource for which the OP doesn't release the token for (simply ignoring the authz response and the auth code, no token introspection and the worst things ...).

The same behaviour if it have some allowed_scopes defined for a client_id that ask for a scope not configured for it.

In oidc.authorization we put a filter that increase this check:

oidcendpoint/oidc/authorization.py(682)process_request()
-> _cid = request_info["client_id"]
(Pdb) ll
672  	    def process_request(self, request_info=None, **kwargs):
673  	        """ The AuthorizationRequest endpoint
674  	
675  	        :param request_info: The authorization request as a dictionary
676  	        :return: dictionary
677  	        """
678  	
679  	        if isinstance(request_info, AuthorizationErrorResponse):
680  	            return request_info
681  	
682  ->	        _cid = request_info["client_id"]
683  	        cinfo = self.endpoint_context.cdb[_cid]

we have request_info e cinfo as follow

(Pdb) request_info
<oidcmsg.oidc.AuthorizationRequest object at 0x7feeb9e2a3d0>
(Pdb) request_info.__dict__
{'_dict': {'redirect_uri': 'https://127.0.0.1:8099/authz_cb/django_oidc_op', 'scope': ['openid', 'that_scope', 'profile', 'email', 'address', 'phone'], 'response_type': ['code'], 'nonce': '1mWXHQc7WEpe4HCOimA3s6Ko', 'state': 'P1y9a0KTqm1znr4ALOu31sNN6t8yXhRg', 'code_challenge': 'hz3Nx5jHHPdgaDUN6zuI8v9e4JOwHxo34FUFsCAtp3k', 'code_challenge_method': 'S256', 'client_id': '1UUl6cwNigmj'}, 'lax': False, 'jwt': None, 'jws_header': None, 'jwe_header': None, 'verify_ssl': True}

and

(Pdb) cinfo
{'id': 1, 'client_id': '1UUl6cwNigmj', 'client_salt': 'vWRsHApW', 'registration_access_token': 'dyIinaJe3gWFwJPqL2dVUHKKGcZhJdrv', 'registration_client_uri': 'https://127.0.0.1:8000/registration_api?client_id=1UUl6cwNigmj', 'client_id_issued_at': 1595799959, 'client_secret': '78be88872d5877c4ddb209335f4eb2fc5118a481a195a454c8b2ebcb', 'client_secret_expires_at': 1598391959, 'application_type': 'web', 'token_endpoint_auth_method': 'client_secret_basic', 'jwks_uri': 'https://127.0.0.1:8099/static/jwks.json', 'contacts': ['ops@example.com'], 'grant_types': ['authorization_code'], 'response_types': ['code'], 'post_logout_redirect_uris': [], 'redirect_uris': [('https://127.0.0.1:8099/authz_cb/django_oidc_op', {})], 'allowed_scopes': ['that_custom_scope', 'openid']}

@rohe I suggest to put a simple filter here, somethings like:

        # this prevents that authz would be released for unavailable scopes
        for scope in request_info['scope']:
            if scope not in client_allowed_scopes:
                _msg = '{} requested an unauthorized scope ({})'
                logger.warning(_msg.format(cinfo['client_id'],
                                           scope))
                raise UnAuthorizedClientScope()

Activity

  1. peppelinux commented on Aug 6, 2020

    MemberAuthor

    Regarding default behaviour, I digged in oidrp and got this:

    in oidcrp/__init__.py(490)init_authorization() scopes are here:
    client.service_context.config['client_preferences']['scope']

    they are, for example: ['openid', 'that_scope', 'profile', 'email', 'address', 'phone']

    but in the authz request they are taken from here:
    service_context.get('behaviour')['scope'] -> ['openid', 'profile', 'email', 'address', 'phone']

    500 -> _req_args = service_context.config.get("request_args")

    is None, service_context.config have instead these:

    (Pdb) service_context.config
    {'client_preferences': {'application_name': 'rp_test', 'application_type': 'web', 'contacts': ['ops@example.com'], 'response_types': ['code'], 'scope': ['openid', 'that_scope', 'profile', 'email', 'address', 'phone'], 'token_endpoint_auth_method': ['client_secret_basic', 'client_secret_post']}, 'client_id': '1UUl6cwNigmj', 'client_secret': '78be88872d5877c4ddb209335f4eb2fc5118a481a195a454c8b2ebcb', 'redirect_uris': ['https://127.0.0.1:8099/authz_cb/django_oidc_op'], 'issuer': 'https://127.0.0.1:8000/', 'jwks_uri': 'https://127.0.0.1:8099/static/jwks.json', 'services': {'discovery': {'class': 'oidcservice.oidc.provider_info_discovery.ProviderInfoDiscovery', 'kwargs': {'service_context': <oidcservice.service_context.ServiceContext object at 0x7fba3dce4510>, 'client_authn_factory': <function factory at 0x7fba3dec5200>}}, 'registration': {'class': 'oidcservice.oidc.registration.Registration', 'kwargs': {'service_context': <oidcservice.service_context.ServiceContext object at 0x7fba3dce4510>, 'client_authn_factory': <function factory at 0x7fba3dec5200>}}, 'authorization': {'class': 'oidcservice.oidc.authorization.Authorization', 'kwargs': {'service_context': <oidcservice.service_context.ServiceContext object at 0x7fba3dce4510>, 'client_authn_factory': <function factory at 0x7fba3dec5200>}}, 'accesstoken': {'class': 'oidcservice.oidc.access_token.AccessToken', 'kwargs': {'service_context': <oidcservice.service_context.ServiceContext object at 0x7fba3dce4510>, 'client_authn_factory': <function factory at 0x7fba3dec5200>}}, 'userinfo': {'class': 'oidcservice.oidc.userinfo.UserInfo', 'kwargs': {'service_context': <oidcservice.service_context.ServiceContext object at 0x7fba3dce4510>, 'client_authn_factory': <function factory at 0x7fba3dec5200>}}, 'end_session': {'class': 'oidcservice.oidc.end_session.EndSession', 'kwargs': {'service_context': <oidcservice.service_context.ServiceContext object at 0x7fba3dce4510>, 'client_authn_factory': <function factory at 0x7fba3dec5200>}}}, 'add_ons': {'pkce': {'function': 'oidcservice.oidc.add_on.pkce.add_pkce_support', 'kwargs': {'code_challenge_length': 64, 'code_challenge_method': 'S256'}}}}
    
  2. peppelinux commented on Aug 6, 2020

    MemberAuthor

    Looking at oidcservice.oidc.provider_info_discovery.ProviderInfoDiscovery -> match_preferences

    Because infoProvider clean up the scopes that the RP request but not supported by OP.

    This is a policy/behaviour decision to do.
    I would like that RP/Client that asks for some scopes that are not available to the OP should be Denied.

  3. peppelinux commented on Aug 6, 2020

    MemberAuthor

    As exposed here

        def match_preferences(self, pcr=None, issuer=None):
            """
            Match the clients preferences against what the provider can do.
            This is to prepare for later client registration and or what
            functionality the client actually will use.
            In the client configuration the client preferences are expressed.
            These are then compared with the Provider Configuration information.
            If the Provider has left some claims out, defaults specified in the
            standard will be used.
    
            :param pcr: Provider configuration response if available
            :param issuer: The issuer identifier
            """
    

    that's the default behaviour.
    I'd like to change this in a less adaptive way.
    If a RP requests for some unavailables scopes to the OP, the authz COULD be rejected (with motivation)

    We would create a global parameters that configures this policy as well if you agree.

  4. peppelinux commented on Aug 6, 2020

    MemberAuthor

    That's the default RP behaviour, in

    oidcservice/oidc/provider_info_discovery.py:141 discovery_provider_info. Commenting out the check on _pvals, here
    _behaviour[_pref] = [v for v in vals] # if v in _pvals]

    solved this problem.
    I think that this could began a configuration parameter in oidc-rp config.

    Then in oidcendpoint I think that this is important:
    5a854a1

    I put it in the branch userinfo_unallowed_scope, it came with another commit regarding a filter on userinfo endpoint.

  5. c00kiemon5ter commented on Sep 1, 2020

    Member

    looking at the oauth2 specification, the spec says that

    https://tools.ietf.org/html/rfc6749#section-3.3
    The authorization server MAY fully or partially ignore the scope
    requested by the client, based on the authorization server policy or
    the resource owner's instructions. If the issued access token scope
    is different from the one requested by the client, the authorization
    server MUST include the "scope" response parameter to inform the
    client of the actual scope granted.

    The client SHOULD request access tokens with the minimal scope
    necessary. The authorization server SHOULD take the client identity
    into account when choosing how to honor the requested scope and MAY
    issue an access token with less rights than requested.

    at the same time a relevant error code is defined, but it's not clear when such an error should be raised

    invalid_scope
    The requested scope is invalid, unknown, or malformed.


    with the above in mind

    I think that a Client that ask for an unavailable scope shouldn't be authorized to proceed.

    this seems like a reasonable behaviour, but not mandatory.

    oidcendpoint when get a authz request with unavailable scopes, it simply ignore these and release its defaults (openid profile email address phone)

    We should make a distinction: a requested scope will either be recognized or unknown.

    • If a requested scope is not recognized, I would say that an error should be raised.
    • If a requested scope is recognized, then it may be ignored. If a requested scope is ignored then the response must include the scope query param with a value that indicates which scopes were granted.

    Returning all those scopes as the defaults (openid profile email address phone) does not seem right. We want to do the opposite - we want to minimize the rights (scopes) and user-data (claims) that we give out. If we are ignoring a scope we should not be adding any others. If there are no other scopes left because we ignored all of the requested, then either return an error, or make this default set that will be used and be returned configurable, so that users can set this to the minimum for their use cases.

  6. peppelinux commented on Sep 1, 2020

    MemberAuthor

    Completely agree. I'm also Wondering that token introspection Is used Just because a RP/Client/RS Need to check for which scopes a token has been released, and other additional informations as well, because token are opaque. That's needed because the OP tries to answer even if some scopes mismatch, the RP later have to check for what the token was intended for.

    An example to explain this cuty paradox:
    I Ask for a pizza (Margherita, scope openid) with additional ingredients (scopes) like potatoes and pancetta. The guy that handle my request knows that pancetta and potatoes are unavailable, but he give me a Margherita anyway... Hey... I asked for something else, why he didn't told me asap that those ingredients was undeliverables?

    The correct answer would have been instead <<Sorry but this pizza (access token) was unavailable with the requested ingredients (scopes), please choose another one. We only have margherita (scope openid), can't handle this request>>.

    I faced this need because I would like, in addition, to have a oidc provider that could also used as OAuth2 AS. An organization would prefer a single component instead of two. In the client registration web backend form I can specify (addon: additional scopes) which scopes would be released for each SP. That's a very good features in the authorization field!

  7. rohe commented on Sep 2, 2020

    Contributor

    All over the OIDC specification hovers the notion that what you don't understand you should ignore.
    (you can actually see the same thinking in the JW* RFCs).

    If you use that thinking: if someone asks you for a scope you don't know you should just ignore it.
    And I would argue that that is the correct way of dealing with this.

    The only way (to my knowledge) that you can get to know what scopes was actually accepted is by using token introspection.

  8. peppelinux commented on Sep 2, 2020

    MemberAuthor

    All over the OIDC specification hovers the notion that what you don't understand you should ignore.
    (you can actually see the same thinking in the JW* RFCs).

    If you use that thinking: if someone asks you for a scope you don't know you should just ignore it.
    And I would argue that that is the correct way of dealing with this.

    The only way (to my knowledge) that you can get to know what scopes was actually accepted is by using token introspection.

    Yes, I'm afraid that token introspection is something abused because of this "lack of certainty".

    Actually oidcendpoint if misses some scopes it simply returns all the available, it should return only the necessary, the less possibile. And more, we could find a lever on https://tools.ietf.org/html/rfc6749#section-4.1.2.1 returning a code 4xx with invalid_scope message. That's not explicit in oidc core 1.0 but in oauth2, and it sounds good to me.

    For me we could deal with the default behaviour of the missing scopes (implicit ignore/decline).
    Then, in addition to this, we could also create an option the configure the default behaviour of oidcendpoint: ignore/decline implicitly OR raise invalid_scope (rfc6749#section-4.1.2.1)

    I think that's the most polite approach to this, that prevent also that token introspection beign indispensabile (like a patch!).

    however oidcendpoint already offers the possibility for a RP to understand what a CODE has been issued for:

    This currently happen in oidcendpoint, because the RP have this information when it get the Access Code, before the Access Token. Example:

     {
      "state": "rLlkrbHGqieo1fQ1vxoeu6oxyR9SWKXk",
      "scope": "openid profile email address phone",
      "code": "Z0FBQUFBQmZUMmY3cHJRdFlJeG5rOG83VTZMaHZiT2JYdlZlUXRiWVJuQ3BCem9sdkdyZWNXNUowc1ozUm9Vd3lDcWJkazFyR09ic04ycl96RG1xcExQaEt4Z2d2RzRIWHlyMWdackhKVWFDNzdjWk8wVElHU3pmWnNxSU80MFFYUzMwU2lsdjFsMkNQaFNqdW9UQWo3Mi0xU2tQMVZzc0U4NHNROTByQm5FUWZxSGxMNXQ2ejlwNWJYUWhoejdfeEJPcU1tU0R1aVg2bnJUekhwV2VwaXd1aXVRQjFpQXU1MWJfdnZES0pKVnIyUFhjQzdCdGFJTT0=",
      "session_state": "50ee943de580c66770f0abb381fdb31b3e1a003694c7d495e3899106ea2a3c65.e1QIziVvnyUAnYZr",
      "iss": "https://127.0.0.1:8000",
      "client_id": "1UUl6cwNigmj"
    }
    
  9. peppelinux commented on Sep 2, 2020

    MemberAuthor

    Davide (a fairly well-known boy) suggests we strive to stay in oidc spec as well, rather than hybridizing with some oauth2 rfc specs. This is however a middle ground, already having in the current implementation things like introspection token endpoint, pkce ...

    Anyway the suggestion could be the reuse of invalid_request
    https://openid.net/specs/openid-connect-core-1_0.html#AuthError

    although invalid_scope may be semantically more understandable but I know how heavy would sound this choice.

  10. changed the title [-] Authorization check over unavailable scopes [/-] [+]Unavailable scopes - behaviour expected [/+] on Sep 2, 2020
  11. rohe commented on Sep 7, 2020

    Contributor

    Oidcendpoint should:

    1. not return all available if it encounters one it doesn't know about. It MUST just return the ones there is coverage for.
    2. abide by a configuration flag ignore_unknown_scopes (default True). If ignore_unknown_scopes is True and the authentication request contains a scope value that the OP is unfamiliar with it will return a 400 with error code invalid_scope.

    Regarding PKCE I think its usage in OIDC environments is fairly common. Introspektion endpoint on the other hand is not in major usage to my knowledge. But since it doesn't affect other endpoints so I don't see its usage as a problem.

  12. 9 remaining items

  13. c00kiemon5ter commented on Sep 8, 2020

    Member

    one more thing:

    quoting rohe

    The only way (to my knowledge) that you can get to know what scopes was actually accepted is by using token introspection.

    The token introspection endpoint is only required to return whether the given token is active. Anything beyond that is optional and defined per deployment. Even if other information is returned, scopes may not be returned. However, I do feel that the introspection should return the scopes. The problem is that one cannot rely on that happening.

  14. peppelinux commented on Sep 8, 2020

    MemberAuthor

    Now as we talked about earlier, there is no way the app will know this unless it tries to use the token for bar or it uses introspection.

    the RP have the related scopes when it get the Access Code http response from op, before the Access Token. Once authentication has been performed, the OP produces a redirect of the user agent with these parameters in url

    Example:

     {
      "state": "rLlkrbHGqieo1fQ1vxoeu6oxyR9SWKXk",
      "scope": "openid profile email address phone",
      "code": "Z0FBQUFBQmZUMmY3cHJRdFlJeG5rOG83VTZMaHZiT2JYdlZlUXRiWVJuQ3BCem9sdkdyZWNXNUowc1ozUm9Vd3lDcWJkazFyR09ic04ycl96RG1xcExQaEt4Z2d2RzRIWHlyMWdackhKVWFDNzdjWk8wVElHU3pmWnNxSU80MFFYUzMwU2lsdjFsMkNQaFNqdW9UQWo3Mi0xU2tQMVZzc0U4NHNROTByQm5FUWZxSGxMNXQ2ejlwNWJYUWhoejdfeEJPcU1tU0R1aVg2bnJUekhwV2VwaXd1aXVRQjFpQXU1MWJfdnZES0pKVnIyUFhjQzdCdGFJTT0=",
      "session_state": "50ee943de580c66770f0abb381fdb31b3e1a003694c7d495e3899106ea2a3c65.e1QIziVvnyUAnYZr",
      "iss": "https://127.0.0.1:8000",
      "client_id": "1UUl6cwNigmj"
    }
    

    Thats the only change to know which scopes was released from op, without token introspection.

  15. peppelinux commented on Sep 8, 2020

    MemberAuthor

    I think we should separated the different cases that exist:

    • an app may request multiple scopes, some of which may be unknown to the OP.
      For example, an app requests the scopes profile foo bar. If the OP does not know foo and bar then it should:

      • ignore them and continue as if the request was only about openid profile, or
      • return an error (invalid_request, invalid_scope).

      A configuration option for this would be nice.

    • an app may request multiple scopes, all of which are unknown to the OP.
      For example, an app requests the scopes foo bar If the OP does not know foo and bar then (even if it ignores them) it has no other scopes to work with. The OP should return an error (invalid_request, invalid_scope).

    • an app may request multiple scopes, some of which it may not be authorized (by the OP) to use.
      For example, an app requests the scopes foo bar. If the OP knows about (recognizes) all those scopes, but it has not authorized the app to use bar then the OP should not ignore the scope and should return an error (invalid_scope).

    Do we have other cases like these?

    Do these agree with the proposed changes? Do you agree with such handling of requested scopes?

    I can deny scopes using allowed_scopes, only those are defined there would be released. If deny_unknown_scopes Is True the http response Will be 400 with that error message.

    Today I Hope to dig more in oidcendpoint/service to check how and when oidcendpoint automatically add openid as default scope, even if It was not requested from a RP. I'd add changes in the current branch regarding deny_unknown_scopes

  16. rohe commented on Sep 8, 2020

    Contributor

    @c00kiemon5ter correct! So the only sure way of finding out what an access token can be used for is to try to use it.

  17. rohe commented on Sep 8, 2020

    Contributor

    @peppelinux So would we have a flag in the configuration stating that the server is an OP or an AS ? Can it be both ? Should it be able to be both ?

  18. peppelinux commented on Sep 8, 2020

    MemberAuthor

    @c00kiemon5ter correct! So the only sure way of finding out what an access token can be used for is to try to use it.

    What about the returning URL args in the op's authz code response? That's a good Moment to get It. Am I wrong?

  19. rohe commented on Sep 8, 2020

    Contributor

    Sure, we can do that. No one else does, which might be a problem.
    Which means an RP can never assume that it will get the applied scopes in the authz code response.

  20. peppelinux commented on Sep 8, 2020

    MemberAuthor

    @peppelinux So would we have a flag in the configuration stating that the server is an OP or an AS ? Can it be both ? Should it be able to be both ?

    Didn't try to have them both but afaik oidcendpoint have the powers to be both

  21. rohe commented on Sep 8, 2020

    Contributor

    It can definitely be both and at the same time too. The question is whether we want this to be possible or if it's too confusing to users of the library.

  22. peppelinux commented on Sep 8, 2020

    MemberAuthor

    It can definitely be both and at the same time too. The question is whether we want this to be possible or if it's too confusing to users of the library.

    sure, it's something that we will be able to consider when we complete the documentation for the end users, being able to make it both is a great potential that we may not be able to manage now for other priorities but it sounds difficult to abandon completely. The ❤️ told me 😄

  23. c00kiemon5ter commented on Sep 8, 2020

    Member

    quoting rohe

    @c00kiemon5ter correct! So the only sure way of finding out what an access token can be used for is to try to use it.

    it seems so, but I find it super ugly and inefficient. I would have really liked the spec to be stricter on these things.

  24. peppelinux commented on Sep 8, 2020

    MemberAuthor

    quoting rohe

    @c00kiemon5ter correct! So the only sure way of finding out what an access token can be used for is to try to use it.

    it seems so, but I find it super ugly and inefficient. I would have really liked the spec to be stricter on these things.

    Completely Agree, pizza delivery problem (with missing ingredient).
    Let's keep the "custom" option deny_unknown_scopes and go ahead, asking for a revision of oidc core 1.0 will probably take a lot longer!

  25. rohe commented on Sep 8, 2020

    Contributor

    Agree! I know there is a revision of OIDC core in the making. Probably not more than a couple of month away.
    Given that it's taken quite a number of years since the last revision if the "scopes used" problem isn't handled now then we can just forget about it for the foreseeable future.

  26. peppelinux commented on Sep 18, 2020

    MemberAuthor

    Happy to see it merged here:
    #85

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or requestquestionFurther information is requested

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions


      Back | FazBrowse Home | New Git URL