| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
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'}}}}
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.
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.
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.
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.
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.
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!
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.
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"
}
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.
Oidcendpoint should:
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.
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.
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.
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
@c00kiemon5ter correct! So the only sure way of finding out what an access token can be used for is to try to use it.
@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 ?
@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?
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.
@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
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.
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 😄
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.
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!
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.
Happy to see it merged here:
#85
| Back | FazBrowse Home | New Git URL |
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:
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()