Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
95 commits
Select commit Hold shift + click to select a range
015a89a
Fix SessionManager constructor call
ctriant Jan 18, 2023
e79b459
Fix bug related to the control of claims in tokens
ctriant Jan 19, 2023
22b3bb5
Make token.JWTToken use RFC9068 as model for payload.
rohe Jan 20, 2023
117b784
Merge pull request #44 from ctriant/control-claims-tokens
rohe Jan 20, 2023
90b0405
fix: default extended configuration, removed warning
peppelinux Jan 20, 2023
37e711f
Various client authentication related fixes
ctriant Jan 23, 2023
f9d2ab8
Introduce various token exchange enhancements
ctriant Jan 23, 2023
6e4a701
Properly handle expired tokens on introspection
ctriant Jan 23, 2023
d8d1c13
The parameter 'lev' in serialization/deserialization functions/method…
rohe Jan 23, 2023
a1779c4
Merge pull request #50 from IdentityPython/nolev
rohe Jan 27, 2023
079d3d9
Made choice of message class for JWTToken configurable.
rohe Jan 27, 2023
1c29dfc
Merge pull request #47 from ctriant/fix-introspection-expired
rohe Jan 27, 2023
e905239
Merge pull request #46 from IdentityPython/conffix
rohe Jan 27, 2023
021e36b
Merge pull request #45 from IdentityPython/jwttoken
rohe Jan 30, 2023
cd02bc7
Merge pull request #49 from ctriant/client_authn_fixes
rohe Jan 30, 2023
71f30cd
Merge pull request #48 from ctriant/token_exchange_enhancements
rohe Jan 30, 2023
6623da6
Merge pull request #42 from ctriant/fix-manager
rohe Jan 30, 2023
f095dc3
Enforce aud restrictions
ctriant Feb 2, 2023
3710cf2
Spring(?)/Autumn cleaning.
rohe Nov 11, 2022
7bf470c
Merged
rohe Nov 12, 2022
2afaee0
Reworking the work condition system.
rohe Nov 14, 2022
17b9eb3
Refactoring and putting better names on things.
rohe Nov 17, 2022
7ce4752
Fixed tests up to client_28
rohe Nov 18, 2022
65f98dc
working on tests.
rohe Nov 18, 2022
44e3743
Fixed tests up to client_28. Back and forth.
rohe Nov 20, 2022
aaa964a
working on tests...
rohe Nov 22, 2022
b1f5dcd
Fixed tests up to client_28. Back and forth...
rohe Nov 22, 2022
9864eff
All tests green
rohe Nov 26, 2022
5062006
Cleaned up code and removed keyjar from work_condition.
rohe Nov 27, 2022
2a60d20
Replaced StateInterface with Current a much simpler state manager.
rohe Nov 29, 2022
e11d014
Make server side also use WorkEnvironment
rohe Dec 1, 2022
afdb39d
Partly done with harmonizing work environment usage.
rohe Dec 1, 2022
17691c7
All tests green.
rohe Dec 3, 2022
abc35c5
Spring(?)/Autumn cleaning.
rohe Nov 11, 2022
290fb46
Merged
rohe Nov 12, 2022
04cd0f1
Reworking the work condition system.
rohe Nov 14, 2022
d8fb841
Refactoring and putting better names on things.
rohe Nov 17, 2022
4b4e2aa
Fixed tests up to client_28
rohe Nov 18, 2022
eb0c896
working on tests.
rohe Nov 18, 2022
235b9b3
working on tests...
rohe Nov 22, 2022
f906c85
Fixed tests up to client_28. Back and forth...
rohe Nov 22, 2022
f5c2eb6
All tests green
rohe Nov 26, 2022
8879ac9
Cleaned up code and removed keyjar from work_condition.
rohe Nov 27, 2022
bf7d3ee
Replaced StateInterface with Current a much simpler state manager.
rohe Nov 29, 2022
cfbeed2
Make server side also use WorkEnvironment
rohe Dec 1, 2022
a6383ba
Partly done with harmonizing work environment usage.
rohe Dec 1, 2022
27613ff
All tests green.
rohe Dec 3, 2022
c904389
Fedservice support
rohe Oct 8, 2022
9749b22
Fedservice support
rohe Oct 15, 2022
c1f0f2f
Rebased onto improved
rohe Dec 4, 2022
b52c820
Rebased onto improved
rohe Dec 4, 2022
4400915
Rebased onto improved
rohe Dec 4, 2022
ffbf880
Rebased onto improved
rohe Dec 4, 2022
4c47308
Rebased onto improved
rohe Dec 4, 2022
1821247
Rebased onto improved
rohe Dec 4, 2022
dea10b2
Deal with the fact that some responses may be signed and some clear t…
rohe Nov 1, 2022
32532bc
Rebased onto improved - partly done
rohe Dec 8, 2022
64f482a
Rebased onto improved - tests working
rohe Dec 11, 2022
f2edbfe
Rebased onto improved - tests working
rohe Dec 12, 2022
3d36762
Replaced work_environment/metadata with claims. Improved readability.
rohe Dec 12, 2022
d18e3d5
Fixed Flake8 complains
rohe Feb 9, 2023
916c0c5
Fixed Flake8 complains
rohe Feb 9, 2023
efb63cc
Fixed tests
rohe Feb 9, 2023
d45ab4f
Fixed some remaining flake8 complains.
rohe Feb 10, 2023
58852fb
Added Kristos's Token Revocation.
rohe Feb 10, 2023
6cf0d45
Added Kristos's Token Revocation.
rohe Feb 10, 2023
4ae2762
Bug discovered while attempting to use the package by another package.
rohe Feb 13, 2023
3c5dabd
Merge branch 'fedservice' of https://github.com/IdentityPython/idpy-o…
rohe Feb 13, 2023
3c322c4
Bug discovered when attempting to use this package by another package.
rohe Feb 13, 2023
3269e08
Encrypting request parameter turned off by default but if turned on s…
rohe Feb 13, 2023
04ff81e
Oops, this should work.
rohe Feb 13, 2023
d2487f6
Being more explicit on what type of client it is.
rohe Feb 23, 2023
55859f6
Fixed tests ! Missed changing claim names. In configuration *_support…
rohe Feb 23, 2023
949ebd2
One more claim name change.
rohe Feb 23, 2023
7c8409d
Merge pull request #54 from IdentityPython/fedservice
rohe Feb 23, 2023
4adc0a4
Fix registration after fedservice refactor
ctriant Mar 6, 2023
f7fd768
Refactored token endpoint helpers and added support for the two remai…
rohe Mar 14, 2023
1098be4
Refactored token endpoint helpers and added support for the two remai…
rohe Mar 16, 2023
a678cf0
Removed the old client_credentials implementationen.
rohe Mar 17, 2023
58b7f22
Merge pull request #58 from IdentityPython/ropc
rohe Mar 23, 2023
b9fb7ba
Fix scopes_handler after fedservice refactor
ctriant Mar 20, 2023
6ce2cc0
Merge pull request #52 from ctriant/enforce-aud-restrictions
rohe Mar 30, 2023
060c4f2
Merge pull request #57 from ctriant/fix_registration
rohe Mar 30, 2023
66ee608
Merge pull request #59 from ctriant/fix_scopes_handler
rohe Mar 30, 2023
26ae4fe
Fix refresh grant on access token helper after fedservice
ctriant Apr 2, 2023
b809758
Fix typo on introspection endpoint
ctriant Apr 3, 2023
24519cc
Merge pull request #60 from ctriant/fix-refresh-grant
rohe Apr 4, 2023
bd9c9b9
Support code_challenge_methods_supported
ctriant Feb 9, 2023
bfbb452
Merge pull request #55 from ctriant/oauth-discovery
rohe Apr 9, 2023
48ecfc9
Replace the name callable with function.
rohe Apr 21, 2023
4eb8214
Merge pull request #61 from IdentityPython/callable2function
rohe Apr 21, 2023
981dc40
Introduce userinfo policy
ctriant Jan 30, 2023
24ca0a4
Ignore PKCE for client credentials grant
ctriant May 2, 2023
2aba2aa
Merge pull request #51 from ctriant/userinfo-policy
rohe May 4, 2023
ca7e310
Merge pull request #62 from ctriant/client-credentials-pkce
rohe May 4, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 59 additions & 0 deletions archdoc/docs/client/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
# The IdpyOIDC client

A client can send requests to an endpoint and deal with the response.

IdpyOIDC assumes that there is one Relying Party(RP)/Client instance per
OpenID Connect Provider(OP)/Authorization Server (AS).

If you have a service that expects to talk to several OPs/ASs
then you must use **idpyoidc.client.rp_handler.RPHandler** to manage the RPs.

RPHandler has methods like:
- begin()
- finalize()
- refresh_access_token()
- logout()

More about RPHandler at the end of this section.

## Client

A client is configured to talk to a set of services each of them represented by
a Service Instance.

# Context

# Service

A Service instance is expected to be able to:

1. Collect all the request arguments
2. If necessary collect and add authentication information to the request attributes or HTTP header
3. Formats the message
4. chooses HTTP method
5. Add HTTP headers

and then after having received the response:

1. Parses the response
2. Gather verification information and verify the response
3. Do any special post-processing.
3. Store information from the response

Doesn't matter which service is considered they all have to be able to do this.

## Request

## Response

# AddOn

# Endpoints

## OAuth2

- Access Token
- Authorization
- Refresh Access Token
- Server Metadata
- Token Exchange
1 change: 1 addition & 0 deletions archdoc/docs/combo/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# An entity that can act both as a server and a client
10 changes: 10 additions & 0 deletions archdoc/docs/server/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@

# Service

## Request

## Response

# Context

# AddOn
132 changes: 132 additions & 0 deletions doc/server/contents/conf.rst
Original file line number Diff line number Diff line change
Expand Up @@ -408,6 +408,23 @@ An example::
"normal",
"aggregated",
"distributed"
],
"policy": {
"function": "/path/to/callable",
"kwargs": {}
}
}
},
"revocation": {
"path": "revoke",
"class": "idpyoidc.server.oauth2.revocation.Revocation",
"kwargs": {
"client_authn_method": [
"client_secret_post",
"client_secret_basic",
"client_secret_jwt",
"private_key_jwt",
"bearer_header"
]
}
},
Expand Down Expand Up @@ -734,6 +751,10 @@ the following::
"userinfo": {
"class": "oidc_provider.users.UserInfo",
"kwargs": {
"policy": {
"function": "/path/to/callable",
"kwargs": {}
},
"claims_map": {
"phone_number": "telephone",
"family_name": "last_name",
Expand All @@ -747,6 +768,17 @@ the following::
}
}

The policy for userinfo endpoint is optional and can also be configured in a client's metadata, for example::

"userinfo": {
"kwargs": {
"policy": {
"function": "/path/to/callable",
"kwargs": {}
}
}
}

================================
Special Configuration directives
================================
Expand Down Expand Up @@ -875,6 +907,106 @@ For example::
return request


==============
Token revocation
==============

In order to enable the token revocation endpoint a dictionary with key `token_revocation` should be placed
under the `endpoint` key of the configuration.

If present, the token revocation configuration should contain a `policy` dictionary
that defines the behaviour for each token type. Each token type
is mapped to a dictionary with the keys `callable` (mandatory), which must be a
python callable or a string that represents the path to a python callable, and
`kwargs` (optional), which must be a dict of key-value arguments that will be
passed to the callable.

The key `""` represents a fallback policy that will be used if the token
type can't be found. If a token type is defined in the `policy` but is
not in the `token_types_supported` list then it is ignored.

"token_revocation": {
"path": "revoke",
"class": "idpyoidc.server.oauth2.token_revocation.TokenRevocation",
"kwargs": {
"token_types_supported": ["access_token"],
"client_authn_method": [
"client_secret_post",
"client_secret_basic",
"client_secret_jwt",
"private_key_jwt",
"bearer_header"
],
"policy": {
"urn:ietf:params:oauth:token-type:access_token": {
"callable": "/path/to/callable",
"kwargs": {
"audience": ["https://example.com"],
"scopes": ["openid"]
}
},
"urn:ietf:params:oauth:token-type:refresh_token": {
"callable": "/path/to/callable",
"kwargs": {
"resource": ["https://example.com"],
"scopes": ["openid"]
}
},
"": {
"callable": "/path/to/callable",
"kwargs": {
"scopes": ["openid"]
}
}
}
}
}

For the per-client configuration a similar configuration scheme should be present in the client's
metadata under the `token_revocation` key.

For example::

"token_revocation":{
"token_types_supported": ["access_token"],
"policy": {
"urn:ietf:params:oauth:token-type:access_token": {
"callable": "/path/to/callable",
"kwargs": {
"audience": ["https://example.com"],
"scopes": ["openid"]
}
},
"urn:ietf:params:oauth:token-type:refresh_token": {
"callable": "/path/to/callable",
"kwargs": {
"resource": ["https://example.com"],
"scopes": ["openid"]
}
},
"": {
"callable": "/path/to/callable",
"kwargs": {
"scopes": ["openid"]
}
}
}
}
}

The policy callable accepts a specific argument list and handles the revocation appropriately and returns
an :py:class:`idpyoidc.message.oauth2..TokenRevocationResponse` or raises an exception.

For example::

def custom_token_revocation_policy(token, session_info, **kwargs):
if some_condition:
return TokenErrorResponse(
error="invalid_request", error_description="Some error occured"
)
response_args = {"response_args": {}}
return oauth2.TokenRevocationResponse(**response_args)

==================================
idpyoidc\.server\.configure module
==================================
Expand Down
34 changes: 16 additions & 18 deletions example/flask_op/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ def verify(authn_method):
auth_args = authn_method.unpack_token(kwargs['token'])
authz_request = AuthorizationRequest().from_urlencoded(auth_args['query'])

endpoint = current_app.server.server_get("endpoint", 'authorization')
endpoint = current_app.server.get_endpoint('authorization')
_session_id = endpoint.create_session(authz_request, username, auth_args['authn_class_ref'],
auth_args['iat'], authn_method)

Expand All @@ -133,8 +133,7 @@ def verify(authn_method):

@oidc_op_views.route('/verify/user', methods=['GET', 'POST'])
def verify_user():
authn_method = current_app.server.server_get(
"endpoint_context").authn_broker.get_method_by_id('user')
authn_method = current_app.server.get_context().authn_broker.get_method_by_id('user')
try:
return verify(authn_method)
except FailedAuthentication as exc:
Expand All @@ -143,8 +142,7 @@ def verify_user():

@oidc_op_views.route('/verify/user_pass_jinja', methods=['GET', 'POST'])
def verify_user_pass_jinja():
authn_method = current_app.server.server_get(
"endpoint_context").authn_broker.get_method_by_id('user')
authn_method = current_app.server.get_context().authn_broker.get_method_by_id('user')
try:
return verify(authn_method)
except FailedAuthentication as exc:
Expand All @@ -154,9 +152,9 @@ def verify_user_pass_jinja():
@oidc_op_views.route('/.well-known/<service>')
def well_known(service):
if service == 'openid-configuration':
_endpoint = current_app.server.server_get("endpoint", 'provider_config')
_endpoint = current_app.server.get_endpoint('provider_config')
elif service == 'webfinger':
_endpoint = current_app.server.server_get("endpoint", 'discovery')
_endpoint = current_app.server.get_endpoint('discovery')
else:
return make_response('Not supported', 400)

Expand All @@ -166,45 +164,45 @@ def well_known(service):
@oidc_op_views.route('/registration', methods=['GET', 'POST'])
def registration():
return service_endpoint(
current_app.server.server_get("endpoint", 'registration'))
current_app.server.get_endpoint('registration'))


@oidc_op_views.route('/registration_api', methods=['GET', 'DELETE'])
def registration_api():
if request.method == "DELETE":
return service_endpoint(
current_app.server.server_get("endpoint", 'registration_delete'))
current_app.server.get_endpoint('registration_delete'))
else:
return service_endpoint(
current_app.server.server_get("endpoint", 'registration_read'))
current_app.server.get_endpoint('registration_read'))


@oidc_op_views.route('/authorization')
def authorization():
return service_endpoint(
current_app.server.server_get("endpoint", 'authorization'))
current_app.server.get_endpoint('authorization'))


@oidc_op_views.route('/token', methods=['GET', 'POST'])
def token():
return service_endpoint(
current_app.server.server_get("endpoint", 'token'))
current_app.server.get_endpoint('token'))

@oidc_op_views.route('/introspection', methods=['POST'])
def introspection_endpoint():
return service_endpoint(
current_app.server.server_get("endpoint", 'introspection'))
current_app.server.get_endpoint('introspection'))

@oidc_op_views.route('/userinfo', methods=['GET', 'POST'])
def userinfo():
return service_endpoint(
current_app.server.server_get("endpoint", 'userinfo'))
current_app.server.get_endpoint('userinfo'))


@oidc_op_views.route('/session', methods=['GET'])
def session_endpoint():
return service_endpoint(
current_app.server.server_get("endpoint", 'session'))
current_app.server.get_endpoint('session'))


IGNORE = ["cookie", "user-agent"]
Expand Down Expand Up @@ -298,7 +296,7 @@ def check_session_iframe():
req_args = dict([(k, v) for k, v in request.form.items()])

if req_args:
_context = current_app.server.server_get("endpoint_context")
_context = current_app.server.get_context()
# will contain client_id and origin
if req_args['origin'] != _context.issuer:
return 'error'
Expand All @@ -314,15 +312,15 @@ def check_session_iframe():

@oidc_op_views.route('/verify_logout', methods=['GET', 'POST'])
def verify_logout():
part = urlparse(current_app.server.server_get("endpoint_context").issuer)
part = urlparse(current_app.server.get_context().issuer)
page = render_template('logout.html', op=part.hostname,
do_logout='rp_logout', sjwt=request.args['sjwt'])
return page


@oidc_op_views.route('/rp_logout', methods=['GET', 'POST'])
def rp_logout():
_endp = current_app.server.server_get("endpoint", 'session')
_endp = current_app.server.get_endpoint('session')
_info = _endp.unpack_signed_jwt(request.form['sjwt'])
try:
request.form['logout']
Expand Down
11 changes: 8 additions & 3 deletions example/flask_rp/application.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,14 @@ def init_oidc_rp_handler(app):
_path = ''
_kj.httpc_params = _rp_conf.httpc_params

rph = RPHandler(_rp_conf.base_url, _rp_conf.clients, services=_rp_conf.services,
hash_seed=_rp_conf.hash_seed, keyjar=_kj, jwks_path=_path,
httpc_params=_rp_conf.httpc_params)
rph = RPHandler(base_url=_rp_conf.base_url,
client_configs=_rp_conf.clients,
services=_rp_conf.services,
keyjar=_kj,
hash_seed=_rp_conf.hash_seed,
httpc_params=_rp_conf.httpc_params,
jwks_path=_path,
)

return rph

Expand Down
Loading