diff --git a/README.md b/README.md
index 3141898c..c140e8cf 100644
--- a/README.md
+++ b/README.md
@@ -6,7 +6,7 @@ Examples of a OIDC OPs with CherryPy, Flask and Django.
### Introduction
This project are here to show you how to 'build' an OP using the
-classes and functions provided by oidcendpoint.
+classes and functions provided by oidc-op.
If you are just going to build a standard OP you only have to write the
configuration file. If you want to add or replace functionality this document
diff --git a/chpy/private/jwks.json b/chpy/private/jwks.json
deleted file mode 100644
index 4d90bca4..00000000
--- a/chpy/private/jwks.json
+++ /dev/null
@@ -1,32 +0,0 @@
-{
- "keys": [
- {
- "kty": "RSA",
- "use": "sig",
- "kid": "S3ZNcGdDUnBPRGVjNXJISzg3N2RxMXdZVUJDekU2WTZ5NGRPdVJ4VlpEcw",
- "n": "xIja_Ne7PPmDpvSYJWp_-GSG3PCmhwNO98QctjwsBVOmyEOcJ7gGj8kC9wsC7_l0VuIsnQLzDp8ZaoPoow5_dnOR9mi_zuuPa-6v3qaIed7kD5LSlXWkJf-SNWtFPqZPM1eIbRAkpX8oB097x_mFtt-Hag2IR0FPGFmwo03NPwVjci0PMOQbgAUt1iTfuXTbssNQcT8iHu-B_BhAgsfFBQjZvU06EuQx9XqDmm8W-MtVVazjQ9_jyHVgIoxo13h_aIgbnJGTeYWVQgVaQTWRiJGuoRtR4FVffDh7Ntax7iNl3YtmVwHaAA_I2S77G_FE_yUfEdQU0smhLfgSMIFs1w",
- "e": "AQAB",
- "d": "K5_BFAyCuCceTOnP98Yq_6S4tsQIAsH-PkreoKi8kLYfuCYhvENB2ZqhuNpN3Zx-cWakxnlIID-6cYU0FzV5n35JsOtRYAmzfR6vFPncI0kRUE-jxJ8nP3P6LTdRWHWr8NaGJsdFiyKtbOn8rMe7IXt-YFD-pepeNyZ5adY0L7-LivJ-7P3DDfF2976PySBk388YJEnWNSYkJDs1mr_5C54tyQO1y-d5x4EkuIuqcK-e_8vunm8HghgAEofH2FW5IDDlfje_y666oL4qqHoPDQPb02pzRzYm3PtC4KgFYavgHcD1XPfw9z9ywecKFc94-9LRs-JDjYpjz7QQLZfpWQ",
- "p": "8zXgwSePXgV62ClQqE1twDkyIYI7vUWZk6F2PkrbipdaPqW6pkQDbfkWwQVNx6Wv6onmDcjt5Y5QQAycTlxoSaOsFzEw73iBBw-iNsvVuWwvMfLOJrxwm75ROruBooygukq0TUcigM3l2d5LA3Uzs9Mc_WqDjoByonEc_F5egls",
- "q": "zt6fXsgDIwZrNIQ9BYlp2bUDn_Wu7ol4Hn73gNZ0Q_BKmy06JmzH_jNrn1tHO-zg5C44ysYu-Lv-H_0Fg4WcuRZ2KjNbv4UVIJ9gR9KPvKyRWokhG7HrqWmkK5gf5T0hbTrdqPISzndwuw8zyu_nWUHtZAD1w3GB0p4YssjcUDU"
- },
- {
- "kty": "EC",
- "use": "sig",
- "kid": "WnNVcjd0NEJzYWJXN3dDZ1JpclZkWHMyU3Q5eGs0SG9qZFlsbENPUjkydw",
- "crv": "P-256",
- "x": "XqBi5FEAx3485Kw28qgy5vWuFE4OPfmq2eht6iuuo-Q",
- "y": "2MrrzBhkwOe4Q2Bzxmm_eyppE8Y7r2JFqQjAyK5C0w8",
- "d": "5xOhuurIpPXbYdD81QqI5BobOXKJ9IK0fD31koQUtwc"
- },
- {
- "kty": "EC",
- "use": "sig",
- "kid": "RWVYM1R2Y0RQRl9aWHhGSDYtVUdIQlNVTmZLWmNJTXY2N3NaZWlkOVRxTQ",
- "crv": "P-384",
- "x": "n2qe-DM4-dtN6M_lZR5rmgczHUoUgtttxv6T-mgUsqNa-Sd4Zr_vWp7v2pC1FO5f",
- "y": "kMHo2OVLF2TNXZRbJEjHfFFUiIaMyysXaC62PGd3Aw6Mkq1LdudLhVIJo00osn4h",
- "d": "NOydgMRJ5ofyI5sqJiCKN8kTKAKEIkPrFRrYF1FPpJ-36VECttQJxAMUdPkNPjJm"
- }
- ]
-}
\ No newline at end of file
diff --git a/chpy/static/jwks.json b/chpy/static/jwks.json
deleted file mode 100644
index 978b14cc..00000000
--- a/chpy/static/jwks.json
+++ /dev/null
@@ -1 +0,0 @@
-{"keys": [{"kty": "RSA", "use": "sig", "kid": "S3ZNcGdDUnBPRGVjNXJISzg3N2RxMXdZVUJDekU2WTZ5NGRPdVJ4VlpEcw", "e": "AQAB", "n": "xIja_Ne7PPmDpvSYJWp_-GSG3PCmhwNO98QctjwsBVOmyEOcJ7gGj8kC9wsC7_l0VuIsnQLzDp8ZaoPoow5_dnOR9mi_zuuPa-6v3qaIed7kD5LSlXWkJf-SNWtFPqZPM1eIbRAkpX8oB097x_mFtt-Hag2IR0FPGFmwo03NPwVjci0PMOQbgAUt1iTfuXTbssNQcT8iHu-B_BhAgsfFBQjZvU06EuQx9XqDmm8W-MtVVazjQ9_jyHVgIoxo13h_aIgbnJGTeYWVQgVaQTWRiJGuoRtR4FVffDh7Ntax7iNl3YtmVwHaAA_I2S77G_FE_yUfEdQU0smhLfgSMIFs1w"}, {"kty": "EC", "use": "sig", "kid": "WnNVcjd0NEJzYWJXN3dDZ1JpclZkWHMyU3Q5eGs0SG9qZFlsbENPUjkydw", "crv": "P-256", "x": "XqBi5FEAx3485Kw28qgy5vWuFE4OPfmq2eht6iuuo-Q", "y": "2MrrzBhkwOe4Q2Bzxmm_eyppE8Y7r2JFqQjAyK5C0w8"}, {"kty": "EC", "use": "sig", "kid": "RWVYM1R2Y0RQRl9aWHhGSDYtVUdIQlNVTmZLWmNJTXY2N3NaZWlkOVRxTQ", "crv": "P-384", "x": "n2qe-DM4-dtN6M_lZR5rmgczHUoUgtttxv6T-mgUsqNa-Sd4Zr_vWp7v2pC1FO5f", "y": "kMHo2OVLF2TNXZRbJEjHfFFUiIaMyysXaC62PGd3Aw6Mkq1LdudLhVIJo00osn4h"}]}
\ No newline at end of file
diff --git a/chpy/templates/user_pass.jinja2 b/chpy/templates/user_pass.jinja2
deleted file mode 100644
index 9add475c..00000000
--- a/chpy/templates/user_pass.jinja2
+++ /dev/null
@@ -1,39 +0,0 @@
-
-
-
-
-
- Please login
-
-
-
-{{ page_header }}
-
-
-
-
diff --git a/doc/source/conf.rst b/doc/source/conf.rst
new file mode 100644
index 00000000..5381a57b
--- /dev/null
+++ b/doc/source/conf.rst
@@ -0,0 +1,434 @@
+.. _oidcop_conf:
+
+========================
+Configuration directives
+========================
+
+------
+add_on
+------
+
+An example::
+
+ "add_on": {
+ "pkce": {
+ "function": "oidcop.oidc.add_on.pkce.add_pkce_support",
+ "kwargs": {
+ "essential": false,
+ "code_challenge_method": "S256 S384 S512"
+ }
+ },
+ "claims": {
+ "function": "oidcop.oidc.add_on.custom_scopes.add_custom_scopes",
+ "kwargs": {
+ "research_and_scholarship": [
+ "name",
+ "given_name",
+ "family_name",
+ "email",
+ "email_verified",
+ "sub",
+ "iss",
+ "eduperson_scoped_affiliation"
+ ]
+ }
+ }
+ }
+
+--------------
+authentication
+--------------
+
+An example::
+
+ "authentication": {
+ "user": {
+ "acr": "oidcop.user_authn.authn_context.INTERNETPROTOCOLPASSWORD",
+ "class": "oidcop.user_authn.user.UserPassJinja2",
+ "kwargs": {
+ "verify_endpoint": "verify/user",
+ "template": "user_pass.jinja2",
+ "db": {
+ "class": "oidcop.util.JSONDictDB",
+ "kwargs": {
+ "json_path": "passwd.json"
+ }
+ },
+ "page_header": "Testing log in",
+ "submit_btn": "Get me in!",
+ "user_label": "Nickname",
+ "passwd_label": "Secret sauce"
+ }
+ }
+ },
+
+------------
+capabilities
+------------
+
+This covers most of the basic functionality of the OP. The key words are the
+same as defined in
+https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderMetadata .
+A couple of things are defined else where. Like the endpoints, issuer id,
+jwks_uri and the authentication methods at the token endpoint.
+
+An example::
+
+ response_types_supported:
+ - code
+ - token
+ - id_token
+ - "code token"
+ - "code id_token"
+ - "id_token token"
+ - "code id_token token"
+ - none
+ response_modes_supported:
+ - query
+ - fragment
+ - form_post
+ subject_types_supported:
+ - public
+ - pairwise
+ grant_types_supported:
+ - authorization_code
+ - implicit
+ - urn:ietf:params:oauth:grant-type:jwt-bearer
+ - refresh_token
+ claim_types_supported:
+ - normal
+ - aggregated
+ - distributed
+ claims_parameter_supported: True
+ request_parameter_supported: True
+ request_uri_parameter_supported: True
+ frontchannel_logout_supported: True
+ frontchannel_logout_session_supported: True
+ backchannel_logout_supported: True
+ backchannel_logout_session_supported: True
+ check_session_iframe: https://127.0.0.1:5000/check_session_iframe
+
+
+-----------
+cookie_name
+-----------
+
+An example::
+
+ "cookie_name": {
+ "session": "oidc_op",
+ "register": "oidc_op_rp",
+ "session_management": "sman"
+ },
+
+-------------
+cookie_dealer
+-------------
+
+An example::
+
+ "cookie_dealer": {
+ "class": "oidcop.cookie.CookieDealer",
+ "kwargs": {
+ "sign_jwk": {
+ "filename": "private/cookie_sign_jwk.json",
+ "type": "OCT",
+ "kid": "cookie_sign_key_id"
+ },
+ "enc_jwk": {
+ "filename": "private/cookie_enc_jwk.json",
+ "type": "OCT",
+ "kid": "cookie_enc_key_id"
+ },
+ "default_values": {
+ "name": "oidc_op",
+ "domain": "127.0.0.1",
+ "path": "/",
+ "max_age": 3600
+ }
+ }
+ },
+
+--------
+endpoint
+--------
+
+An example::
+
+ "endpoint": {
+ "webfinger": {
+ "path": ".well-known/webfinger",
+ "class": "oidcop.oidc.discovery.Discovery",
+ "kwargs": {
+ "client_authn_method": null
+ }
+ },
+ "provider_info": {
+ "path": ".well-known/openid-configuration",
+ "class": "oidcop.oidc.provider_config.ProviderConfiguration",
+ "kwargs": {
+ "client_authn_method": null
+ }
+ },
+ "registration": {
+ "path": "registration",
+ "class": "oidcop.oidc.registration.Registration",
+ "kwargs": {
+ "client_authn_method": null,
+ "client_secret_expiration_time": 432000
+ }
+ },
+ "registration_api": {
+ "path": "registration_api",
+ "class": "oidcop.oidc.read_registration.RegistrationRead",
+ "kwargs": {
+ "client_authn_method": [
+ "bearer_header"
+ ]
+ }
+ },
+ "introspection": {
+ "path": "introspection",
+ "class": "oidcop.oauth2.introspection.Introspection",
+ "kwargs": {
+ "client_authn_method": [
+ "client_secret_post"
+ ],
+ "release": [
+ "username"
+ ]
+ }
+ },
+ "authorization": {
+ "path": "authorization",
+ "class": "oidcop.oidc.authorization.Authorization",
+ "kwargs": {
+ "client_authn_method": null,
+ "claims_parameter_supported": true,
+ "request_parameter_supported": true,
+ "request_uri_parameter_supported": true,
+ "response_types_supported": [
+ "code",
+ "token",
+ "id_token",
+ "code token",
+ "code id_token",
+ "id_token token",
+ "code id_token token",
+ "none"
+ ],
+ "response_modes_supported": [
+ "query",
+ "fragment",
+ "form_post"
+ ]
+ }
+ },
+ "token": {
+ "path": "token",
+ "class": "oidcop.oidc.token.Token",
+ "kwargs": {
+ "client_authn_method": [
+ "client_secret_post",
+ "client_secret_basic",
+ "client_secret_jwt",
+ "private_key_jwt"
+ ]
+ }
+ },
+ "userinfo": {
+ "path": "userinfo",
+ "class": "oidcop.oidc.userinfo.UserInfo",
+ "kwargs": {
+ "claim_types_supported": [
+ "normal",
+ "aggregated",
+ "distributed"
+ ]
+ }
+ },
+ "end_session": {
+ "path": "session",
+ "class": "oidcop.oidc.session.Session",
+ "kwargs": {
+ "logout_verify_url": "verify_logout",
+ "post_logout_uri_path": "post_logout",
+ "signing_alg": "ES256",
+ "frontchannel_logout_supported": true,
+ "frontchannel_logout_session_supported": true,
+ "backchannel_logout_supported": true,
+ "backchannel_logout_session_supported": true,
+ "check_session_iframe": "check_session_iframe"
+ }
+ }
+ }
+
+------------
+httpc_params
+------------
+
+Example ::
+
+ "httpc_params": {
+ "verify": false
+ },
+
+--------
+id_token
+--------
+
+Defines which class that handles creating an ID Token and possibly also
+arguments used when initiating that class.
+An example::
+
+ "id_token": {
+ "class": "oidcop.id_token.IDToken",
+ "kwargs": {
+ "default_claims": {
+ "email": {
+ "essential": true
+ },
+ "email_verified": {
+ "essential": true
+ }}}},
+
+
+------
+issuer
+------
+
+The issuer ID of the OP.
+
+----
+keys
+----
+
+An example::
+
+ "keys": {
+ "private_path": "private/jwks.json",
+ "key_defs": [
+ {
+ "type": "RSA",
+ "use": [
+ "sig"
+ ]
+ },
+ {
+ "type": "EC",
+ "crv": "P-256",
+ "use": [
+ "sig"
+ ]
+ }
+ ],
+ "public_path": "static/jwks.json",
+ "read_only": false,
+ "uri_path": "static/jwks.json"
+ },
+
+---------------
+login_hint2acrs
+---------------
+
+An example::
+
+ "login_hint2acrs": {
+ "class": "oidcop.login_hint.LoginHint2Acrs",
+ "kwargs": {
+ "scheme_map": {
+ "email": [
+ "oidcop.user_authn.authn_context.INTERNETPROTOCOLPASSWORD"
+ ]
+ }
+ }
+ },
+
+-----------
+session_key
+-----------
+
+An example::
+
+ "session_key": {
+ "filename": "private/session_jwk.json",
+ "type": "OCT",
+ "use": "sig"
+ },
+
+------------
+template_dir
+------------
+
+An example::
+
+ "template_dir": "templates"
+
+------------------
+token_handler_args
+------------------
+
+An example::
+
+ "token_handler_args": {
+ "jwks_def": {
+ "private_path": "private/token_jwks.json",
+ "read_only": false,
+ "key_defs": [
+ {
+ "type": "oct",
+ "bytes": 24,
+ "use": [
+ "enc"
+ ],
+ "kid": "code"
+ },
+ {
+ "type": "oct",
+ "bytes": 24,
+ "use": [
+ "enc"
+ ],
+ "kid": "refresh"
+ }
+ ]
+ },
+ "code": {
+ "kwargs": {
+ "lifetime": 600
+ }
+ },
+ "token": {
+ "class": "oidcop.token.jwt_token.JWTToken",
+ "kwargs": {
+ "lifetime": 3600,
+ "add_claims": [
+ "email",
+ "email_verified",
+ "phone_number",
+ "phone_number_verified"
+ ],
+ "add_claim_by_scope": true,
+ "aud": ["https://example.org/appl"]
+ }
+ },
+ "refresh": {
+ "kwargs": {
+ "lifetime": 86400
+ }
+ }
+ }
+
+--------
+userinfo
+--------
+
+An example::
+
+ "userinfo": {
+ "class": "oidcop.user_info.UserInfo",
+ "kwargs": {
+ "db_file": "users.json"
+ }
+ }
+
diff --git a/doc/source/howto.rst b/doc/source/howto.rst
deleted file mode 100644
index 2cd7cf92..00000000
--- a/doc/source/howto.rst
+++ /dev/null
@@ -1,110 +0,0 @@
-.. _oidcop:
-
-***************************
-The OpenID Connect Provider
-***************************
-
-============
-Introduction
-============
-
-This documentation are here to show you how to 'build' an OP using the
-classes and functions provided by oidcendpoint.
-
-If you are just going to build a standard OP you only have to write the
-configuration file. If you want to add or replace functionality this document
-should be able to tell you how.
-
-Setting up an OP means making a number if decisions. Like, should the OP support
-Web Finger (https://openid.net/specs/openid-connect-discovery-1_0.html#IssuerDiscovery),
-dynamic discovery (https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderConfig)
-and dynamic client registration (https://openid.net/specs/openid-connect-registration-1_0.html).
-
-All these are services you can access at endpoints. The total set of endpoints
-that this package supports are
-
-- webfinger
-- provider_info
-- registration
-- authorization
-- token
-- refresh_token
-- userinfo
-- end_session
-
-
-========================
-Configuration directives
-========================
-
-------
-issuer
-------
-
-The issuer ID of the OP.
-
-------------
-capabilities
-------------
-
-This covers most of the basic functionality of the OP. The key words are the
-same as defined in
-https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderMetadata .
-A couple of things are defined else where. Like the endpoints, issuer id,
-jwks_uri and the authentication methods at the token endpoint.
-
-An example::
-
- response_types_supported:
- - code
- - token
- - id_token
- - "code token"
- - "code id_token"
- - "id_token token"
- - "code id_token token"
- - none
- response_modes_supported:
- - query
- - fragment
- - form_post
- subject_types_supported:
- - public
- - pairwise
- grant_types_supported:
- - authorization_code
- - implicit
- - urn:ietf:params:oauth:grant-type:jwt-bearer
- - refresh_token
- claim_types_supported:
- - normal
- - aggregated
- - distributed
- claims_parameter_supported: True
- request_parameter_supported: True
- request_uri_parameter_supported: True
- frontchannel_logout_supported: True
- frontchannel_logout_session_supported: True
- backchannel_logout_supported: True
- backchannel_logout_session_supported: True
- check_session_iframe: https://127.0.0.1:5000/check_session_iframe
-
-
---------
-id_token
---------
-
-Defines which class that handles creating an ID Token and possibly also
-arguments used when initiating that class.
-An example::
-
- id_token:
- class: oidcendpoint.id_token.IDToken
- kwargs:
- default_claims:
- email:
- essential: True
- email_verified:
- essential: True
-
-
diff --git a/doc/source/intro.rst b/doc/source/intro.rst
new file mode 100644
index 00000000..c0e1e740
--- /dev/null
+++ b/doc/source/intro.rst
@@ -0,0 +1,118 @@
+.. _oidcop:
+
+***************************
+The OpenID Connect Provider
+***************************
+
+============
+Introduction
+============
+
+This documentation are here to show you how to 'build' an OP using the
+classes and functions provided by oidcop.
+
+OAuth2 and thereby OpenID Connect (OIDC) are built on a request-response paradigm.
+The RP issues a request and the OP returns a response.
+
+The OIDC core standard defines a set of such request-responses.
+This is a basic list of request-responses and the normal sequence in which they
+occur:
+
+1. Provider discovery (WebFinger)
+2. Provider Info Discovery
+3. Client registration
+4. Authorization/Authentication
+5. Access token
+6. User info
+
+If you are just going to build a standard OP you only have to write the
+configuration file and of course add authentication and user consent services.
+If you want to add or replace functionality this document should be able to
+tell you how.
+
+Setting up an OP means making a number if decisions. Like, should the OP support
+WebFinger_ , `dynamic discovery`_ and/or `dynamic client registration`_ .
+
+All these are services you can access at endpoints. The total set of endpoints
+that this package supports are
+
+- webfinger
+- provider_info
+- registration
+- authorization
+- token
+- refresh_token
+- userinfo
+- end_session
+
+.. _WebFinger: https://openid.net/specs/openid-connect-discovery-1_0.html#IssuerDiscovery
+.. _dynamic discovery: https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderConfig
+.. _dynamic client registration: https://openid.net/specs/openid-connect-registration-1_0.html
+
+===============
+Endpoint layout
+===============
+
+When an endpoint receives a request it has to do a number of things:
+
+- Verify that the client can issue the request (client authentication/authorization)
+- Verify that the request is correct and that it contains the necessary information.
+- Process the request, which includes applying server policies and gathering information.
+- Construct the response
+
+I should note at this point that this package is expected to work within the
+confines of a web server framework such that the actual receiving and sending
+of the HTTP messages are dealt with by the framework.
+
+Based on the actions an endpoint has to perform a method call structure
+has been constructed. It looks like this:
+
+1. parse_request
+
+ - client_authentication (*)
+ - post_parse_request (*)
+
+2. process_request
+
+3. do_response
+
+ - response_info
+ - construct
+ - pre_construct (*)
+ - _parse_args
+ - post_construct (*)
+ - update_http_args
+
+Steps marked with '*' are places where extensions can be applied.
+
+*parse_request* expects as input the request itself in a number of formats and
+also, if available, information about client authentication. The later is
+normally the authorization element of the HTTP header.
+
+*do_response* returns a dictionary that can look like this::
+
+ {
+ 'response':
+ _response as a string or as a Message instance_
+ 'http_headers': [
+ ('Content-type', 'application/json'),
+ ('Pragma', 'no-cache'),
+ ('Cache-Control', 'no-store')
+ ],
+ 'cookie': _list of cookies_,
+ 'response_placement': 'body'
+ }
+
+cookie
+ MAY be present
+http_headers
+ MAY be present
+http_response
+ Already clear and formatted HTTP response
+response
+ MUST be present
+response_placement
+ If absent defaults to the endpoints response_placement parameter value or
+ if that is also missing 'url'
+redirect_location
+ Where to send a redirect
diff --git a/django_op/.gitignore b/example/django_op/.gitignore
similarity index 100%
rename from django_op/.gitignore
rename to example/django_op/.gitignore
diff --git a/django_op/AUTHORS b/example/django_op/AUTHORS
similarity index 100%
rename from django_op/AUTHORS
rename to example/django_op/AUTHORS
diff --git a/django_op/LICENSE b/example/django_op/LICENSE
similarity index 100%
rename from django_op/LICENSE
rename to example/django_op/LICENSE
diff --git a/django_op/README.md b/example/django_op/README.md
similarity index 100%
rename from django_op/README.md
rename to example/django_op/README.md
diff --git a/chpy/certs/cert.pem b/example/django_op/example/data/oidc_op/certs/cert.pem
similarity index 100%
rename from chpy/certs/cert.pem
rename to example/django_op/example/data/oidc_op/certs/cert.pem
diff --git a/chpy/certs/key.pem b/example/django_op/example/data/oidc_op/certs/key.pem
similarity index 100%
rename from chpy/certs/key.pem
rename to example/django_op/example/data/oidc_op/certs/key.pem
diff --git a/django_op/example/data/oidc_rp/conf.django.yaml b/example/django_op/example/data/oidc_rp/conf.django.yaml
similarity index 100%
rename from django_op/example/data/oidc_rp/conf.django.yaml
rename to example/django_op/example/data/oidc_rp/conf.django.yaml
diff --git a/django_op/example/example/__init__.py b/example/django_op/example/example/__init__.py
similarity index 100%
rename from django_op/example/example/__init__.py
rename to example/django_op/example/example/__init__.py
diff --git a/django_op/example/example/oidc_op.conf.yaml b/example/django_op/example/example/oidc_op.conf.yaml
similarity index 85%
rename from django_op/example/example/oidc_op.conf.yaml
rename to example/django_op/example/example/oidc_op.conf.yaml
index 24f8efaa..2a88e64e 100644
--- a/django_op/example/example/oidc_op.conf.yaml
+++ b/example/django_op/example/example/oidc_op.conf.yaml
@@ -71,7 +71,7 @@ op:
backchannel_logout_session_supported: True
check_session_iframe: https://127.0.0.1:5000/check_session_iframe
id_token:
- class: oidcendpoint.id_token.IDToken
+ class: oidcop.id_token.IDToken
kwargs:
default_claims:
email:
@@ -98,7 +98,7 @@ op:
code:
lifetime: 600
token:
- class: oidcendpoint.jwt_token.JWTToken
+ class: oidcop.jwt_token.JWTToken
lifetime: 3600
add_claims:
- email
@@ -119,32 +119,32 @@ op:
endpoint:
webfinger:
path: '.well-known/webfinger'
- class: oidcendpoint.oidc.discovery.Discovery
+ class: oidcop.oidc.discovery.Discovery
kwargs:
# TODO: optionally manage discovery service authn
client_authn_method: null
provider_info:
path: ".well-known/openid-configuration"
- class: oidcendpoint.oidc.provider_config.ProviderConfiguration
+ class: oidcop.oidc.provider_config.ProviderConfiguration
kwargs:
# TODO: optionally manage openid-configuration authn
client_authn_method: null
registration:
path: registration
- class: oidcendpoint.oidc.registration.Registration
+ class: oidcop.oidc.registration.Registration
kwargs:
# TODO: make a authn method for 'client_authn_method'
client_authn_method: null
client_secret_expiration_time: 432000
registration_api:
path: registration_api
- class: oidcendpoint.oidc.read_registration.RegistrationRead
+ class: oidcop.oidc.read_registration.RegistrationRead
kwargs:
client_authn_method:
- bearer_header
introspection:
path: introspection
- class: oidcendpoint.oauth2.introspection.Introspection
+ class: oidcop.oauth2.introspection.Introspection
kwargs:
client_authn_method:
client_secret_post: ClientSecretPost
@@ -152,13 +152,13 @@ op:
- username
authorization:
path: authorization
- class: oidcendpoint.oidc.authorization.Authorization
+ class: oidcop.oidc.authorization.Authorization
kwargs:
# TODO: make a authn method for 'client_authn_method'
client_authn_method: null
token:
path: token
- class: oidcendpoint.oidc.token.AccessToken
+ class: oidcop.oidc.token.AccessToken
kwargs:
client_authn_method:
- client_secret_post
@@ -167,10 +167,10 @@ op:
- private_key_jwt
userinfo:
path: userinfo
- class: oidcendpoint.oidc.userinfo.UserInfo
+ class: oidcop.oidc.userinfo.UserInfo
end_session:
path: session
- class: oidcendpoint.oidc.session.Session
+ class: oidcop.oidc.session.Session
kwargs:
logout_verify_url: verify_logout
post_logout_uri_path: post_logout
@@ -190,7 +190,7 @@ op:
updated_at: get_oidc_lastlogin
authentication:
user:
- acr: oidcendpoint.user_authn.authn_context.INTERNETPROTOCOLPASSWORD
+ acr: oidcop.user_authn.authn_context.INTERNETPROTOCOLPASSWORD
class: oidc_op.users.UserPassDjango
kwargs:
# this would override web resource where credentials will be POSTed
@@ -199,7 +199,7 @@ op:
template: oidc_login.html
# args1:
- # class: oidcendpoint.util.JSONDictDB
+ # class: oidcop.util.JSONDictDB
# kwargs:
# args1_1: data/oidc_op/things.json
@@ -208,12 +208,12 @@ op:
user_label: "Nickname"
passwd_label: "Secret sauce"
#anon:
- #acr: oidcendpoint.user_authn.authn_context.UNSPECIFIED
- #class: oidcendpoint.user_authn.user.NoAuthn
+ #acr: oidcop.user_authn.authn_context.UNSPECIFIED
+ #class: oidcop.user_authn.user.NoAuthn
#kwargs:
#user: thatusername
cookie_dealer:
- class: oidcendpoint.cookie.CookieDealer
+ class: oidcop.cookie.CookieDealer
kwargs:
sign_jwk: data/oidc_op/private/cookie_sign_jwk.json
sign_alg: 'SHA256'
@@ -227,16 +227,16 @@ op:
path: /
max_age: 3600
login_hint2acrs:
- class: oidcendpoint.login_hint.LoginHint2Acrs
+ class: oidcop.login_hint.LoginHint2Acrs
kwargs:
scheme_map:
email:
- - oidcendpoint.user_authn.authn_context.INTERNETPROTOCOLPASSWORD
+ - oidcop.user_authn.authn_context.INTERNETPROTOCOLPASSWORD
# this adds PKCE support as mandatory - disable if needed
add_on:
pkce:
- function: oidcendpoint.oidc.add_on.pkce.add_pkce_support
+ function: oidcop.oidc.add_on.pkce.add_pkce_support
kwargs:
essential: True
code_challenge_method:
diff --git a/django_op/example/example/settings.py b/example/django_op/example/example/settings.py
similarity index 100%
rename from django_op/example/example/settings.py
rename to example/django_op/example/example/settings.py
diff --git a/django_op/example/example/urls.py b/example/django_op/example/example/urls.py
similarity index 100%
rename from django_op/example/example/urls.py
rename to example/django_op/example/example/urls.py
diff --git a/django_op/example/example/wsgi.py b/example/django_op/example/example/wsgi.py
similarity index 100%
rename from django_op/example/example/wsgi.py
rename to example/django_op/example/example/wsgi.py
diff --git a/django_op/example/manage.py b/example/django_op/example/manage.py
similarity index 100%
rename from django_op/example/manage.py
rename to example/django_op/example/manage.py
diff --git a/django_op/example/oidc_op b/example/django_op/example/oidc_op
similarity index 100%
rename from django_op/example/oidc_op
rename to example/django_op/example/oidc_op
diff --git a/django_op/example/requirements.txt b/example/django_op/example/requirements.txt
similarity index 100%
rename from django_op/example/requirements.txt
rename to example/django_op/example/requirements.txt
diff --git a/django_op/example/unical_accounts/__init__.py b/example/django_op/example/unical_accounts/__init__.py
similarity index 100%
rename from django_op/example/unical_accounts/__init__.py
rename to example/django_op/example/unical_accounts/__init__.py
diff --git a/django_op/example/unical_accounts/admin.py b/example/django_op/example/unical_accounts/admin.py
similarity index 100%
rename from django_op/example/unical_accounts/admin.py
rename to example/django_op/example/unical_accounts/admin.py
diff --git a/django_op/example/unical_accounts/admin_inlines.py b/example/django_op/example/unical_accounts/admin_inlines.py
similarity index 100%
rename from django_op/example/unical_accounts/admin_inlines.py
rename to example/django_op/example/unical_accounts/admin_inlines.py
diff --git a/django_op/example/unical_accounts/apps.py b/example/django_op/example/unical_accounts/apps.py
similarity index 100%
rename from django_op/example/unical_accounts/apps.py
rename to example/django_op/example/unical_accounts/apps.py
diff --git a/django_op/example/unical_accounts/forms.py b/example/django_op/example/unical_accounts/forms.py
similarity index 100%
rename from django_op/example/unical_accounts/forms.py
rename to example/django_op/example/unical_accounts/forms.py
diff --git a/django_op/example/unical_accounts/migrations/0001_initial.py b/example/django_op/example/unical_accounts/migrations/0001_initial.py
similarity index 100%
rename from django_op/example/unical_accounts/migrations/0001_initial.py
rename to example/django_op/example/unical_accounts/migrations/0001_initial.py
diff --git a/django_op/example/unical_accounts/migrations/__init__.py b/example/django_op/example/unical_accounts/migrations/__init__.py
similarity index 100%
rename from django_op/example/unical_accounts/migrations/__init__.py
rename to example/django_op/example/unical_accounts/migrations/__init__.py
diff --git a/django_op/example/unical_accounts/models.py b/example/django_op/example/unical_accounts/models.py
similarity index 100%
rename from django_op/example/unical_accounts/models.py
rename to example/django_op/example/unical_accounts/models.py
diff --git a/django_op/example/unical_accounts/templatetags/__init__.py b/example/django_op/example/unical_accounts/templatetags/__init__.py
similarity index 100%
rename from django_op/example/unical_accounts/templatetags/__init__.py
rename to example/django_op/example/unical_accounts/templatetags/__init__.py
diff --git a/django_op/example/unical_accounts/templatetags/has_group.py b/example/django_op/example/unical_accounts/templatetags/has_group.py
similarity index 100%
rename from django_op/example/unical_accounts/templatetags/has_group.py
rename to example/django_op/example/unical_accounts/templatetags/has_group.py
diff --git a/django_op/example/unical_accounts/tests.py b/example/django_op/example/unical_accounts/tests.py
similarity index 100%
rename from django_op/example/unical_accounts/tests.py
rename to example/django_op/example/unical_accounts/tests.py
diff --git a/django_op/example/unical_accounts/urls.py b/example/django_op/example/unical_accounts/urls.py
similarity index 100%
rename from django_op/example/unical_accounts/urls.py
rename to example/django_op/example/unical_accounts/urls.py
diff --git a/django_op/example/unical_accounts/views.py b/example/django_op/example/unical_accounts/views.py
similarity index 100%
rename from django_op/example/unical_accounts/views.py
rename to example/django_op/example/unical_accounts/views.py
diff --git a/django_op/oidc_op/__init__.py b/example/django_op/oidc_op/__init__.py
similarity index 100%
rename from django_op/oidc_op/__init__.py
rename to example/django_op/oidc_op/__init__.py
diff --git a/django_op/oidc_op/admin.py b/example/django_op/oidc_op/admin.py
similarity index 100%
rename from django_op/oidc_op/admin.py
rename to example/django_op/oidc_op/admin.py
diff --git a/django_op/oidc_op/application.py b/example/django_op/oidc_op/application.py
similarity index 100%
rename from django_op/oidc_op/application.py
rename to example/django_op/oidc_op/application.py
diff --git a/django_op/oidc_op/apps.py b/example/django_op/oidc_op/apps.py
similarity index 100%
rename from django_op/oidc_op/apps.py
rename to example/django_op/oidc_op/apps.py
diff --git a/django_op/oidc_op/configure.py b/example/django_op/oidc_op/configure.py
similarity index 97%
rename from django_op/oidc_op/configure.py
rename to example/django_op/oidc_op/configure.py
index 2b5236fe..1b78fdd4 100644
--- a/django_op/oidc_op/configure.py
+++ b/example/django_op/oidc_op/configure.py
@@ -16,7 +16,7 @@
try:
from secrets import token_urlsafe as rnd_token
except ImportError:
- from oidcendpoint import rndstr as rnd_token
+ from oidcop import rndstr as rnd_token
class Configuration:
diff --git a/django_op/oidc_op/migrations/__init__.py b/example/django_op/oidc_op/migrations/__init__.py
similarity index 100%
rename from django_op/oidc_op/migrations/__init__.py
rename to example/django_op/oidc_op/migrations/__init__.py
diff --git a/django_op/oidc_op/models.py b/example/django_op/oidc_op/models.py
similarity index 100%
rename from django_op/oidc_op/models.py
rename to example/django_op/oidc_op/models.py
diff --git a/django_op/oidc_op/tests.py b/example/django_op/oidc_op/tests.py
similarity index 100%
rename from django_op/oidc_op/tests.py
rename to example/django_op/oidc_op/tests.py
diff --git a/django_op/oidc_op/urls.py b/example/django_op/oidc_op/urls.py
similarity index 100%
rename from django_op/oidc_op/urls.py
rename to example/django_op/oidc_op/urls.py
diff --git a/django_op/oidc_op/users.py b/example/django_op/oidc_op/users.py
similarity index 100%
rename from django_op/oidc_op/users.py
rename to example/django_op/oidc_op/users.py
diff --git a/django_op/oidc_op/views.py b/example/django_op/oidc_op/views.py
similarity index 100%
rename from django_op/oidc_op/views.py
rename to example/django_op/oidc_op/views.py
diff --git a/django_op/requirements.txt b/example/django_op/requirements.txt
similarity index 100%
rename from django_op/requirements.txt
rename to example/django_op/requirements.txt
diff --git a/flask_op/Dockerfile b/example/flask_op/Dockerfile
similarity index 100%
rename from flask_op/Dockerfile
rename to example/flask_op/Dockerfile
diff --git a/flask_op/README.md b/example/flask_op/README.md
similarity index 100%
rename from flask_op/README.md
rename to example/flask_op/README.md
diff --git a/flask_op/__init__.py b/example/flask_op/__init__.py
similarity index 100%
rename from flask_op/__init__.py
rename to example/flask_op/__init__.py
diff --git a/flask_op/application.py b/example/flask_op/application.py
similarity index 75%
rename from flask_op/application.py
rename to example/flask_op/application.py
index b8f17fca..984e8b5a 100644
--- a/flask_op/application.py
+++ b/example/flask_op/application.py
@@ -1,14 +1,14 @@
import os
from urllib.parse import urlparse
-from cryptojwt.key_jar import init_key_jar
from flask.app import Flask
-from oidcendpoint.endpoint_context import EndpointContext
+
+from oidcop.server import Server
folder = os.path.dirname(os.path.realpath(__file__))
-def init_oidc_op_endpoints(app):
+def init_oidc_op(app):
_config = app.srv_config.op
_server_info_config = _config['server_info']
@@ -18,9 +18,9 @@ def init_oidc_op_endpoints(app):
port=app.srv_config.port)
_server_info_config['issuer'] = iss
- endpoint_context = EndpointContext(_server_info_config, cwd=folder)
+ server = Server(_server_info_config, cwd=folder)
- for endp in endpoint_context.endpoint.values():
+ for endp in server.endpoint.values():
p = urlparse(endp.endpoint_path)
_vpath = p.path.split('/')
if _vpath[0] == '':
@@ -28,7 +28,7 @@ def init_oidc_op_endpoints(app):
else:
endp.vpath = _vpath
- return endpoint_context
+ return server
def oidc_provider_init_app(config, name=None, **kwargs):
@@ -44,6 +44,6 @@ def oidc_provider_init_app(config, name=None, **kwargs):
app.register_blueprint(oidc_op_views)
# Initialize the oidc_provider after views to be able to set correct urls
- app.endpoint_context = init_oidc_op_endpoints(app)
+ app.server = init_oidc_op(app)
return app
diff --git a/django_op/example/data/oidc_op/certs/cert.pem b/example/flask_op/certs/cert.pem
similarity index 100%
rename from django_op/example/data/oidc_op/certs/cert.pem
rename to example/flask_op/certs/cert.pem
diff --git a/flask_op/certs/client.crt b/example/flask_op/certs/client.crt
similarity index 100%
rename from flask_op/certs/client.crt
rename to example/flask_op/certs/client.crt
diff --git a/flask_op/certs/client.key b/example/flask_op/certs/client.key
similarity index 100%
rename from flask_op/certs/client.key
rename to example/flask_op/certs/client.key
diff --git a/django_op/example/data/oidc_op/certs/key.pem b/example/flask_op/certs/key.pem
similarity index 100%
rename from django_op/example/data/oidc_op/certs/key.pem
rename to example/flask_op/certs/key.pem
diff --git a/flask_op/conf_192.yaml b/example/flask_op/conf_192.yaml
similarity index 76%
rename from flask_op/conf_192.yaml
rename to example/flask_op/conf_192.yaml
index 64c8b0ac..85576b2d 100644
--- a/flask_op/conf_192.yaml
+++ b/example/flask_op/conf_192.yaml
@@ -65,7 +65,7 @@ op:
- refresh_token
template_dir: templates
id_token:
- class: oidcendpoint.id_token.IDToken
+ class: oidcop.id_token.IDToken
kwargs:
default_claims:
email:
@@ -92,7 +92,7 @@ op:
code:
lifetime: 600
token:
- class: oidcendpoint.jwt_token.JWTToken
+ class: oidcop.jwt_token.JWTToken
lifetime: 3600
add_claims:
- email
@@ -109,29 +109,29 @@ op:
endpoint:
webfinger:
path: '.well-known/webfinger'
- class: oidcendpoint.oidc.discovery.Discovery
+ class: oidcop.oidc.discovery.Discovery
kwargs:
client_authn_method: null
provider_info:
path: ".well-known/openid-configuration"
- class: oidcendpoint.oidc.provider_config.ProviderConfiguration
+ class: oidcop.oidc.provider_config.ProviderConfiguration
kwargs:
client_authn_method: null
registration:
path: registration
- class: oidcendpoint.oidc.registration.Registration
+ class: oidcop.oidc.registration.Registration
kwargs:
client_authn_method: null
client_secret_expiration_time: 432000
registration_api:
path: registration_api
- class: oidcendpoint.oidc.read_registration.RegistrationRead
+ class: oidcop.oidc.read_registration.RegistrationRead
kwargs:
client_authn_method:
- bearer_header
introspection:
path: introspection
- class: oidcendpoint.oauth2.introspection.Introspection
+ class: oidcop.oauth2.introspection.Introspection
kwargs:
client_authn_method:
client_secret_post: ClientSecretPost
@@ -139,7 +139,7 @@ op:
- username
authorization:
path: authorization
- class: oidcendpoint.oidc.authorization.Authorization
+ class: oidcop.oidc.authorization.Authorization
kwargs:
client_authn_method: null
claims_parameter_supported: True
@@ -160,7 +160,7 @@ op:
- form_post
token:
path: token
- class: oidcendpoint.oidc.token.AccessToken
+ class: oidcop.oidc.token.AccessToken
kwargs:
client_authn_method:
- client_secret_post
@@ -169,7 +169,7 @@ op:
- private_key_jwt
userinfo:
path: userinfo
- class: oidcendpoint.oidc.userinfo.UserInfo
+ class: oidcop.oidc.userinfo.UserInfo
kwargs:
claim_types_supported:
- normal
@@ -177,7 +177,7 @@ op:
- distributed
end_session:
path: session
- class: oidcendpoint.oidc.session.Session
+ class: oidcop.oidc.session.Session
kwargs:
logout_verify_url: verify_logout
post_logout_uri_path: post_logout
@@ -188,18 +188,18 @@ op:
backchannel_logout_session_supported: True
check_session_iframe: 'check_session_iframe'
userinfo:
- class: oidcendpoint.user_info.UserInfo
+ class: oidcop.user_info.UserInfo
kwargs:
db_file: users.json
authentication:
user:
- acr: oidcendpoint.user_authn.authn_context.INTERNETPROTOCOLPASSWORD
- class: oidcendpoint.user_authn.user.UserPassJinja2
+ acr: oidcop.user_authn.authn_context.INTERNETPROTOCOLPASSWORD
+ class: oidcop.user_authn.user.UserPassJinja2
kwargs:
verify_endpoint: 'verify/user'
template: user_pass.jinja2
db:
- class: oidcendpoint.util.JSONDictDB
+ class: oidcop.util.JSONDictDB
kwargs:
json_path: passwd.json
page_header: "Testing log in"
@@ -207,38 +207,43 @@ op:
user_label: "Nickname"
passwd_label: "Secret sauce"
#anon:
- #acr: oidcendpoint.user_authn.authn_context.UNSPECIFIED
- #class: oidcendpoint.user_authn.user.NoAuthn
+ #acr: oidcop.user_authn.authn_context.UNSPECIFIED
+ #class: oidcop.user_authn.user.NoAuthn
#kwargs:
#user: diana
cookie_dealer:
- class: oidcendpoint.cookie.CookieDealer
- kwargs:
- sign_jwk:
- filename: 'private/cookie_sign_jwk.json'
- type: OCT
- kid: cookie_sign_key_id
- enc_jwk:
- filename: 'private/cookie_enc_jwk.json'
- type: OCT
- kid: cookie_enc_key_id
- # enc_jwk: 'private/cookie_enc_jwk.json'
- default_values:
- name: oidc_op
- domain: *domain
- path: /
- max_age: 3600
+ cookie_handler:
+ class: oidcop.cookie_handler.CookieHandler
+ kwargs":
+ keys:
+ private_path: "private/cookie_jwks.json"
+ key_defs:
+ -
+ type: OCT
+ kid: enc
+ use:
+ - enc
+ -
+ type: OCT
+ kid: sig
+ use:
+ - sig
+ read_only: false
+ name:
+ session: "oidc_op"
+ register: "oidc_op_rp"
+ session_management: "sman"
login_hint2acrs:
- class: oidcendpoint.login_hint.LoginHint2Acrs
+ class: oidcop.login_hint.LoginHint2Acrs
kwargs:
scheme_map:
email:
- - oidcendpoint.user_authn.authn_context.INTERNETPROTOCOLPASSWORD
+ - oidcop.user_authn.authn_context.INTERNETPROTOCOLPASSWORD
# this adds PKCE support as mandatory - disable it if needed (essential: False)
add_on:
pkce:
- function: oidcendpoint.oidc.add_on.pkce.add_pkce_support
+ function: oidcop.oidc.add_on.pkce.add_pkce_support
kwargs:
essential: False
code_challenge_method:
@@ -248,7 +253,7 @@ op:
S512
claims:
- function: oidcendpoint.oidc.add_on.custom_scopes.add_custom_scopes
+ function: oidcop.oidc.add_on.custom_scopes.add_custom_scopes
kwargs:
research_and_scholarship:
- name
diff --git a/example/flask_op/config.json b/example/flask_op/config.json
new file mode 100644
index 00000000..d6535afa
--- /dev/null
+++ b/example/flask_op/config.json
@@ -0,0 +1,396 @@
+{
+ "logging": {
+ "version": 1,
+ "root": {
+ "handlers": [
+ "default",
+ "console"
+ ],
+ "level": "DEBUG"
+ },
+ "loggers": {
+ "bobcat_idp": {
+ "level": "DEBUG"
+ }
+ },
+ "handlers": {
+ "default": {
+ "class": "logging.FileHandler",
+ "filename": "debug.log",
+ "formatter": "default"
+ },
+ "console": {
+ "class": "logging.StreamHandler",
+ "stream": "ext://sys.stdout",
+ "formatter": "default"
+ }
+ },
+ "formatters": {
+ "default": {
+ "format": "%(asctime)s %(name)s %(levelname)s %(message)s"
+ }
+ }
+ },
+ "port": 5000,
+ "domain": "127.0.0.1",
+ "server_name": "{domain}:{port}",
+ "base_url": "https://{domain}:{port}",
+ "key_def": [
+ {
+ "type": "RSA",
+ "use": [
+ "sig"
+ ]
+ },
+ {
+ "type": "EC",
+ "crv": "P-256",
+ "use": [
+ "sig"
+ ]
+ }
+ ],
+ "OIDC_KEYS": {
+ "private_path": "private/jwks.json",
+ "key_defs": [
+ {
+ "type": "RSA",
+ "use": [
+ "sig"
+ ]
+ },
+ {
+ "type": "EC",
+ "crv": "P-256",
+ "use": [
+ "sig"
+ ]
+ }
+ ],
+ "public_path": "static/jwks.json",
+ "read_only": false,
+ "uri_path": "static/jwks.json"
+ },
+ "op": {
+ "server_info": {
+ "add_on": {
+ "pkce": {
+ "function": "oidcop.oidc.add_on.pkce.add_pkce_support",
+ "kwargs": {
+ "essential": false,
+ "code_challenge_method": "S256 S384 S512"
+ }
+ },
+ "claims": {
+ "function": "oidcop.oidc.add_on.custom_scopes.add_custom_scopes",
+ "kwargs": {
+ "research_and_scholarship": [
+ "name",
+ "given_name",
+ "family_name",
+ "email",
+ "email_verified",
+ "sub",
+ "iss",
+ "eduperson_scoped_affiliation"
+ ]
+ }
+ }
+ },
+ "authz": {
+ "class": "oidcop.authz.AuthzHandling",
+ "kwargs": {
+ "grant_config": {
+ "usage_rules": {
+ "authorization_code": {
+ "supports_minting": ["access_token", "refresh_token", "id_token"],
+ "max_usage": 1
+ },
+ "access_token": {},
+ "refresh_token": {
+ "supports_minting": ["access_token", "refresh_token"]
+ }
+ },
+ "expires_in": 43200
+ }
+ }
+ },
+ "authentication": {
+ "user": {
+ "acr": "oidcop.user_authn.authn_context.INTERNETPROTOCOLPASSWORD",
+ "class": "oidcop.user_authn.user.UserPassJinja2",
+ "kwargs": {
+ "verify_endpoint": "verify/user",
+ "template": "user_pass.jinja2",
+ "db": {
+ "class": "oidcop.util.JSONDictDB",
+ "kwargs": {
+ "json_path": "passwd.json"
+ }
+ },
+ "page_header": "Testing log in",
+ "submit_btn": "Get me in!",
+ "user_label": "Nickname",
+ "passwd_label": "Secret sauce"
+ }
+ }
+ },
+ "capabilities": {
+ "subject_types_supported": [
+ "public",
+ "pairwise"
+ ],
+ "grant_types_supported": [
+ "authorization_code",
+ "implicit",
+ "urn:ietf:params:oauth:grant-type:jwt-bearer",
+ "refresh_token"
+ ]
+ },
+ "cookie_handler": {
+ "class": "oidcop.cookie_handler.CookieHandler",
+ "kwargs": {
+ "keys": {
+ "private_path": "private/cookie_jwks.json",
+ "key_defs": [
+ {"type": "OCT", "use": ["enc"], "kid": "enc"},
+ {"type": "OCT", "use": ["sig"], "kid": "sig"}
+ ],
+ "read_only": false
+ },
+ "name": {
+ "session": "oidc_op",
+ "register": "oidc_op_rp",
+ "session_management": "sman"
+ }
+ }
+ },
+ "endpoint": {
+ "webfinger": {
+ "path": ".well-known/webfinger",
+ "class": "oidcop.oidc.discovery.Discovery",
+ "kwargs": {
+ "client_authn_method": null
+ }
+ },
+ "provider_info": {
+ "path": ".well-known/openid-configuration",
+ "class": "oidcop.oidc.provider_config.ProviderConfiguration",
+ "kwargs": {
+ "client_authn_method": null
+ }
+ },
+ "registration": {
+ "path": "registration",
+ "class": "oidcop.oidc.registration.Registration",
+ "kwargs": {
+ "client_authn_method": null,
+ "client_secret_expiration_time": 432000
+ }
+ },
+ "registration_api": {
+ "path": "registration_api",
+ "class": "oidcop.oidc.read_registration.RegistrationRead",
+ "kwargs": {
+ "client_authn_method": [
+ "bearer_header"
+ ]
+ }
+ },
+ "introspection": {
+ "path": "introspection",
+ "class": "oidcop.oauth2.introspection.Introspection",
+ "kwargs": {
+ "client_authn_method": [
+ "client_secret_post"
+ ],
+ "release": [
+ "username"
+ ]
+ }
+ },
+ "authorization": {
+ "path": "authorization",
+ "class": "oidcop.oidc.authorization.Authorization",
+ "kwargs": {
+ "client_authn_method": null,
+ "claims_parameter_supported": true,
+ "request_parameter_supported": true,
+ "request_uri_parameter_supported": true,
+ "response_types_supported": [
+ "code",
+ "token",
+ "id_token",
+ "code token",
+ "code id_token",
+ "id_token token",
+ "code id_token token",
+ "none"
+ ],
+ "response_modes_supported": [
+ "query",
+ "fragment",
+ "form_post"
+ ]
+ }
+ },
+ "token": {
+ "path": "token",
+ "class": "oidcop.oidc.token.Token",
+ "kwargs": {
+ "client_authn_method": [
+ "client_secret_post",
+ "client_secret_basic",
+ "client_secret_jwt",
+ "private_key_jwt"
+ ]
+ }
+ },
+ "userinfo": {
+ "path": "userinfo",
+ "class": "oidcop.oidc.userinfo.UserInfo",
+ "kwargs": {
+ "claim_types_supported": [
+ "normal",
+ "aggregated",
+ "distributed"
+ ]
+ }
+ },
+ "end_session": {
+ "path": "session",
+ "class": "oidcop.oidc.session.Session",
+ "kwargs": {
+ "logout_verify_url": "verify_logout",
+ "post_logout_uri_path": "post_logout",
+ "signing_alg": "ES256",
+ "frontchannel_logout_supported": true,
+ "frontchannel_logout_session_supported": true,
+ "backchannel_logout_supported": true,
+ "backchannel_logout_session_supported": true,
+ "check_session_iframe": "check_session_iframe"
+ }
+ }
+ },
+ "httpc_params": {
+ "verify": false
+ },
+ "id_token": {
+ "class": "oidcop.id_token.IDToken",
+ "kwargs": {
+ "default_claims": {
+ "email": {
+ "essential": true
+ },
+ "email_verified": {
+ "essential": true
+ }
+ }
+ }
+ },
+ "issuer": "https://{domain}:{port}",
+ "keys": {
+ "private_path": "private/jwks.json",
+ "key_defs": [
+ {
+ "type": "RSA",
+ "use": [
+ "sig"
+ ]
+ },
+ {
+ "type": "EC",
+ "crv": "P-256",
+ "use": [
+ "sig"
+ ]
+ }
+ ],
+ "public_path": "static/jwks.json",
+ "read_only": false,
+ "uri_path": "static/jwks.json"
+ },
+ "login_hint2acrs": {
+ "class": "oidcop.login_hint.LoginHint2Acrs",
+ "kwargs": {
+ "scheme_map": {
+ "email": [
+ "oidcop.user_authn.authn_context.INTERNETPROTOCOLPASSWORD"
+ ]
+ }
+ }
+ },
+ "session_key": {
+ "filename": "private/session_jwk.json",
+ "type": "OCT",
+ "use": "sig"
+ },
+ "template_dir": "templates",
+ "token_handler_args": {
+ "jwks_def": {
+ "private_path": "private/token_jwks.json",
+ "read_only": false,
+ "key_defs": [
+ {
+ "type": "oct",
+ "bytes": 24,
+ "use": [
+ "enc"
+ ],
+ "kid": "code"
+ },
+ {
+ "type": "oct",
+ "bytes": 24,
+ "use": [
+ "enc"
+ ],
+ "kid": "refresh"
+ }
+ ]
+ },
+ "code": {
+ "kwargs": {
+ "lifetime": 600
+ }
+ },
+ "token": {
+ "class": "oidcop.token.jwt_token.JWTToken",
+ "kwargs": {
+ "lifetime": 3600,
+ "add_claims": [
+ "email",
+ "email_verified",
+ "phone_number",
+ "phone_number_verified"
+ ],
+ "add_claim_by_scope": true,
+ "aud": [
+ "https://example.org/appl"
+ ]
+ }
+ },
+ "refresh": {
+ "kwargs": {
+ "lifetime": 86400
+ }
+ }
+ },
+ "userinfo": {
+ "class": "oidcop.user_info.UserInfo",
+ "kwargs": {
+ "db_file": "users.json"
+ }
+ }
+ }
+ },
+ "webserver": {
+ "server_cert": "certs/client.crt",
+ "server_key": "certs/client.key",
+ "ca_bundle": null,
+ "verify_user": false,
+ "port": 5000,
+ "domain": "127.0.0.1",
+ "debug": true
+ }
+}
diff --git a/flask_op/config.yaml b/example/flask_op/config.yaml
similarity index 75%
rename from flask_op/config.yaml
rename to example/flask_op/config.yaml
index 99844adf..29f16fac 100644
--- a/flask_op/config.yaml
+++ b/example/flask_op/config.yaml
@@ -22,7 +22,7 @@ logging:
format: '%(asctime)s %(name)s %(levelname)s %(message)s'
port: &port 5000
-domain: &domain localhost
+domain: &domain 192.168.1.158
server_name: '{domain}:{port}'
base_url: &base_url 'https://{domain}:{port}'
@@ -66,7 +66,7 @@ op:
- refresh_token
template_dir: templates
id_token:
- class: oidcendpoint.id_token.IDToken
+ class: oidcop.id_token.IDToken
kwargs:
default_claims:
email:
@@ -93,7 +93,7 @@ op:
code:
lifetime: 600
token:
- class: oidcendpoint.jwt_token.JWTToken
+ class: oidcop.token.jwt_token.JWTToken
lifetime: 3600
add_claims:
- email
@@ -110,29 +110,29 @@ op:
endpoint:
webfinger:
path: '.well-known/webfinger'
- class: oidcendpoint.oidc.discovery.Discovery
+ class: oidcop.oidc.discovery.Discovery
kwargs:
client_authn_method: null
provider_info:
path: ".well-known/openid-configuration"
- class: oidcendpoint.oidc.provider_config.ProviderConfiguration
+ class: oidcop.oidc.provider_config.ProviderConfiguration
kwargs:
client_authn_method: null
registration:
path: registration
- class: oidcendpoint.oidc.registration.Registration
+ class: oidcop.oidc.registration.Registration
kwargs:
client_authn_method: null
client_secret_expiration_time: 432000
registration_api:
path: registration_api
- class: oidcendpoint.oidc.read_registration.RegistrationRead
+ class: oidcop.oidc.read_registration.RegistrationRead
kwargs:
client_authn_method:
- bearer_header
introspection:
path: introspection
- class: oidcendpoint.oauth2.introspection.Introspection
+ class: oidcop.oauth2.introspection.Introspection
kwargs:
client_authn_method:
- client_secret_post
@@ -140,7 +140,7 @@ op:
- username
authorization:
path: authorization
- class: oidcendpoint.oidc.authorization.Authorization
+ class: oidcop.oidc.authorization.Authorization
kwargs:
client_authn_method: null
claims_parameter_supported: True
@@ -161,7 +161,7 @@ op:
- form_post
token:
path: token
- class: oidcendpoint.oidc.token.AccessToken
+ class: oidcop.oidc.token.Token
kwargs:
client_authn_method:
- client_secret_post
@@ -170,7 +170,7 @@ op:
- private_key_jwt
userinfo:
path: userinfo
- class: oidcendpoint.oidc.userinfo.UserInfo
+ class: oidcop.oidc.userinfo.UserInfo
kwargs:
claim_types_supported:
- normal
@@ -178,7 +178,7 @@ op:
- distributed
end_session:
path: session
- class: oidcendpoint.oidc.session.Session
+ class: oidcop.oidc.session.Session
kwargs:
logout_verify_url: verify_logout
post_logout_uri_path: post_logout
@@ -189,18 +189,18 @@ op:
backchannel_logout_session_supported: True
check_session_iframe: 'check_session_iframe'
userinfo:
- class: oidcendpoint.user_info.UserInfo
+ class: oidcop.user_info.UserInfo
kwargs:
db_file: users.json
authentication:
user:
- acr: oidcendpoint.user_authn.authn_context.INTERNETPROTOCOLPASSWORD
- class: oidcendpoint.user_authn.user.UserPassJinja2
+ acr: oidcop.user_authn.authn_context.INTERNETPROTOCOLPASSWORD
+ class: oidcop.user_authn.user.UserPassJinja2
kwargs:
verify_endpoint: 'verify/user'
template: user_pass.jinja2
db:
- class: oidcendpoint.util.JSONDictDB
+ class: oidcop.util.JSONDictDB
kwargs:
json_path: passwd.json
page_header: "Testing log in"
@@ -208,42 +208,42 @@ op:
user_label: "Nickname"
passwd_label: "Secret sauce"
#anon:
- #acr: oidcendpoint.user_authn.authn_context.UNSPECIFIED
- #class: oidcendpoint.user_authn.user.NoAuthn
+ #acr: oidcop.user_authn.authn_context.UNSPECIFIED
+ #class: oidcop.user_authn.user.NoAuthn
#kwargs:
#user: diana
- cookie_name:
- session: oidc_op
- register: oidc_op_rp
- session_management: sman
- cookie_dealer:
- class: oidcendpoint.cookie.CookieDealer
- kwargs:
- sign_jwk:
- filename: 'private/cookie_sign_jwk.json'
- type: OCT
- kid: cookie_sign_key_id
- enc_jwk:
- filename: 'private/cookie_enc_jwk.json'
- type: OCT
- kid: cookie_enc_key_id
- # enc_jwk: 'private/cookie_enc_jwk.json'
- default_values:
- name: oidc_op
- domain: *domain
- path: /
- max_age: 3600
+ cookie_handler:
+ class: oidcop.cookie_handler.CookieHandler
+ kwargs":
+ keys:
+ private_path: "private/cookie_jwks.json"
+ key_defs:
+ -
+ type: OCT
+ kid: enc
+ use:
+ - enc
+ -
+ type: OCT
+ kid: sig
+ use:
+ - sig
+ read_only: false
+ name:
+ session: "oidc_op"
+ register: "oidc_op_rp"
+ session_management: "sman"
login_hint2acrs:
- class: oidcendpoint.login_hint.LoginHint2Acrs
+ class: oidcop.login_hint.LoginHint2Acrs
kwargs:
scheme_map:
email:
- - oidcendpoint.user_authn.authn_context.INTERNETPROTOCOLPASSWORD
+ - oidcop.user_authn.authn_context.INTERNETPROTOCOLPASSWORD
# this adds PKCE support as mandatory - disable it if needed (essential: False)
add_on:
pkce:
- function: oidcendpoint.oidc.add_on.pkce.add_pkce_support
+ function: oidcop.oidc.add_on.pkce.add_pkce_support
kwargs:
essential: false
code_challenge_method:
@@ -253,7 +253,7 @@ op:
S512
claims:
- function: oidcendpoint.oidc.add_on.custom_scopes.add_custom_scopes
+ function: oidcop.oidc.add_on.custom_scopes.add_custom_scopes
kwargs:
research_and_scholarship:
- name
diff --git a/chpy/passwd.json b/example/flask_op/passwd.json
similarity index 100%
rename from chpy/passwd.json
rename to example/flask_op/passwd.json
diff --git a/flask_op/requirements.txt b/example/flask_op/requirements.txt
similarity index 100%
rename from flask_op/requirements.txt
rename to example/flask_op/requirements.txt
diff --git a/flask_op/seed.txt b/example/flask_op/seed.txt
similarity index 100%
rename from flask_op/seed.txt
rename to example/flask_op/seed.txt
diff --git a/flask_op/server.py b/example/flask_op/server.py
similarity index 100%
rename from flask_op/server.py
rename to example/flask_op/server.py
diff --git a/chpy/users.json b/example/flask_op/users.json
similarity index 100%
rename from chpy/users.json
rename to example/flask_op/users.json
diff --git a/flask_op/views.py b/example/flask_op/views.py
similarity index 74%
rename from flask_op/views.py
rename to example/flask_op/views.py
index fdc19bf2..78b0686a 100644
--- a/flask_op/views.py
+++ b/example/flask_op/views.py
@@ -1,11 +1,9 @@
-import base64
import json
import os
import sys
import traceback
from urllib.parse import urlparse
-import werkzeug
from cryptojwt import as_unicode
from flask import Blueprint
from flask import current_app
@@ -14,14 +12,15 @@
from flask import request
from flask.helpers import make_response
from flask.helpers import send_from_directory
-from oidcendpoint.authn_event import create_authn_event
-from oidcendpoint.exception import FailedAuthentication
-from oidcendpoint.exception import InvalidClient
-from oidcendpoint.exception import UnknownClient
-from oidcendpoint.oidc.token import AccessToken
from oidcmsg.oauth2 import ResponseMessage
from oidcmsg.oidc import AccessTokenRequest
from oidcmsg.oidc import AuthorizationRequest
+import werkzeug
+
+from oidcop.exception import FailedAuthentication
+from oidcop.exception import InvalidClient
+from oidcop.exception import UnknownClient
+from oidcop.oidc.token import Token
# logger = logging.getLogger(__name__)
@@ -29,21 +28,20 @@
def _add_cookie(resp, cookie_spec):
- for key, _morsel in cookie_spec.items():
- kwargs = {'value': _morsel.value}
- for param in ['expires', 'path', 'comment', 'domain', 'max-age',
- 'secure',
- 'version']:
- if _morsel[param]:
- kwargs[param] = _morsel[param]
- resp.set_cookie(key, **kwargs)
+ kwargs = {'value': cookie_spec["value"]}
+ for param in ['expires', 'max-age']:
+ if param in cookie_spec:
+ kwargs[param] = cookie_spec[param]
+ kwargs["path"] = "/"
+ resp.set_cookie(cookie_spec["name"], **kwargs)
def add_cookie(resp, cookie_spec):
if isinstance(cookie_spec, list):
for _spec in cookie_spec:
_add_cookie(resp, _spec)
-
+ elif isinstance(cookie_spec, dict):
+ _add_cookie(resp, cookie_spec)
@oidc_op_views.route('/static/')
def send_js(path):
@@ -118,15 +116,11 @@ def verify(authn_method):
auth_args = authn_method.unpack_token(kwargs['token'])
authz_request = AuthorizationRequest().from_urlencoded(auth_args['query'])
- authn_event = create_authn_event(
- uid=username,
- salt=base64.b64encode(os.urandom(16)).decode(),
- authn_info=auth_args['authn_class_ref'],
- authn_time=auth_args['iat'])
+ endpoint = current_app.server.server_get("endpoint", 'authorization')
+ _session_id = endpoint.create_session(authz_request, username, auth_args['authn_class_ref'],
+ auth_args['iat'], authn_method)
- endpoint = current_app.endpoint_context.endpoint['authorization']
- args = endpoint.authz_part2(user=username, request=authz_request,
- authn_event=authn_event)
+ args = endpoint.authz_part2(request=authz_request, session_id=_session_id)
if isinstance(args, ResponseMessage) and 'error' in args:
return make_response(args.to_json(), 400)
@@ -136,8 +130,8 @@ def verify(authn_method):
@oidc_op_views.route('/verify/user', methods=['GET', 'POST'])
def verify_user():
- authn_method = current_app.endpoint_context.authn_broker.get_method_by_id(
- 'user')
+ authn_method = current_app.server.server_get(
+ "endpoint_context").authn_broker.get_method_by_id('user')
try:
return verify(authn_method)
except FailedAuthentication as exc:
@@ -146,8 +140,8 @@ def verify_user():
@oidc_op_views.route('/verify/user_pass_jinja', methods=['GET', 'POST'])
def verify_user_pass_jinja():
- authn_method = current_app.endpoint_context.authn_broker.get_method_by_id(
- 'user')
+ authn_method = current_app.server.server_get(
+ "endpoint_context").authn_broker.get_method_by_id('user')
try:
return verify(authn_method)
except FailedAuthentication as exc:
@@ -157,11 +151,9 @@ def verify_user_pass_jinja():
@oidc_op_views.route('/.well-known/')
def well_known(service):
if service == 'openid-configuration':
- _endpoint = current_app.endpoint_context.endpoint['provider_config']
- # if service == 'openid-federation':
- # _endpoint = current_app.endpoint_context.endpoint['provider_info']
+ _endpoint = current_app.server.server_get("endpoint", 'provider_config')
elif service == 'webfinger':
- _endpoint = current_app.endpoint_context.endpoint['discovery']
+ _endpoint = current_app.server.server_get("endpoint", 'discovery')
else:
return make_response('Not supported', 400)
@@ -171,65 +163,69 @@ def well_known(service):
@oidc_op_views.route('/registration', methods=['GET', 'POST'])
def registration():
return service_endpoint(
- current_app.endpoint_context.endpoint['registration'])
+ current_app.server.server_get("endpoint", 'registration'))
@oidc_op_views.route('/registration_api', methods=['GET'])
def registration_api():
return service_endpoint(
- current_app.endpoint_context.endpoint['registration_read'])
+ current_app.server.server_get("endpoint", 'registration_read'))
@oidc_op_views.route('/authorization')
def authorization():
return service_endpoint(
- current_app.endpoint_context.endpoint['authorization'])
+ current_app.server.server_get("endpoint", 'authorization'))
@oidc_op_views.route('/token', methods=['GET', 'POST'])
def token():
return service_endpoint(
- current_app.endpoint_context.endpoint['token'])
+ current_app.server.server_get("endpoint", 'token'))
@oidc_op_views.route('/userinfo', methods=['GET', 'POST'])
def userinfo():
return service_endpoint(
- current_app.endpoint_context.endpoint['userinfo'])
+ current_app.server.server_get("endpoint", 'userinfo'))
@oidc_op_views.route('/session', methods=['GET'])
def session_endpoint():
return service_endpoint(
- current_app.endpoint_context.endpoint['session'])
+ current_app.server.server_get("endpoint", 'session'))
+
+
+IGNORE = ["cookie", "user-agent"]
def service_endpoint(endpoint):
_log = current_app.srv_config.logger
- _log.info('At the "{}" endpoint'.format(endpoint.endpoint_name))
+ _log.info('At the "{}" endpoint'.format(endpoint.name))
- try:
- authn = request.headers['Authorization']
- except KeyError:
- pr_args = {}
- else:
- pr_args = {'auth': authn}
+ http_info = {
+ "headers": {k: v for k, v in request.headers.items(lower=True) if k not in IGNORE},
+ "method": request.method,
+ "url": request.url,
+ # name is not unique
+ "cookie": [{"name": k, "value": v} for k, v in request.cookies.items()]
+ }
if request.method == 'GET':
try:
- req_args = endpoint.parse_request(request.args.to_dict(), **pr_args)
+ req_args = endpoint.parse_request(request.args.to_dict(), http_info=http_info)
except (InvalidClient, UnknownClient) as err:
_log.error(err)
return make_response(json.dumps({
'error': 'unauthorized_client',
'error_description': str(err)
- }), 400)
+ }), 400)
except Exception as err:
_log.error(err)
return make_response(json.dumps({
'error': 'invalid_request',
'error_description': str(err)
- }), 400)
+ }), 400)
else:
if request.data:
if isinstance(request.data, str):
@@ -239,7 +235,7 @@ def service_endpoint(endpoint):
else:
req_args = dict([(k, v) for k, v in request.form.items()])
try:
- req_args = endpoint.parse_request(req_args, **pr_args)
+ req_args = endpoint.parse_request(req_args, http_info=http_info)
except Exception as err:
_log.error(err)
err_msg = ResponseMessage(error='invalid_request', error_description=str(err))
@@ -250,16 +246,10 @@ def service_endpoint(endpoint):
return make_response(req_args.to_json(), 400)
try:
- if request.cookies:
- _log.debug(request.cookies)
- kwargs = {'cookie': request.cookies}
+ if isinstance(endpoint, Token):
+ args = endpoint.process_request(AccessTokenRequest(**req_args), http_info=http_info)
else:
- kwargs = {}
-
- if isinstance(endpoint, AccessToken):
- args = endpoint.process_request(AccessTokenRequest(**req_args), **kwargs)
- else:
- args = endpoint.process_request(req_args, **kwargs)
+ args = endpoint.process_request(req_args, http_info=http_info)
except Exception as err:
message = traceback.format_exception(*sys.exc_info())
_log.error(message)
@@ -273,7 +263,8 @@ def service_endpoint(endpoint):
if 'http_response' in args:
return make_response(args['http_response'], 200)
- return do_response(endpoint, req_args, **args)
+ response = do_response(endpoint, req_args, **args)
+ return response
@oidc_op_views.errorhandler(werkzeug.exceptions.BadRequest)
@@ -292,10 +283,11 @@ 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")
# will contain client_id and origin
- if req_args['origin'] != current_app.endpoint_context.issuer:
+ if req_args['origin'] != _context.issuer:
return 'error'
- if req_args['client_id'] != current_app.endpoint_context.cdb:
+ if req_args['client_id'] != _context.cdb:
return 'error'
return 'OK'
@@ -307,7 +299,7 @@ def check_session_iframe():
@oidc_op_views.route('/verify_logout', methods=['GET', 'POST'])
def verify_logout():
- part = urlparse(current_app.endpoint_context.issuer)
+ part = urlparse(current_app.server.server_get("endpoint_context").issuer)
page = render_template('logout.html', op=part.hostname,
do_logout='rp_logout', sjwt=request.args['sjwt'])
return page
@@ -315,7 +307,7 @@ def verify_logout():
@oidc_op_views.route('/rp_logout', methods=['GET', 'POST'])
def rp_logout():
- _endp = current_app.endpoint_context.endpoint['session']
+ _endp = current_app.server.server_get("endpoint", 'session')
_info = _endp.unpack_signed_jwt(request.form['sjwt'])
try:
request.form['logout']
@@ -333,8 +325,11 @@ def rp_logout():
postLogoutRedirectUri=_info['redirect_uri'])
else:
res = redirect(_info['redirect_uri'])
+
+ # rohe are you sure that _kakor is the right word? :)
_kakor = _endp.kill_cookies()
- _add_cookie(res, _kakor)
+ for cookie in _kakor:
+ _add_cookie(res, cookie)
return res
diff --git a/flask_op/conf.py b/flask_op/conf.py
deleted file mode 100644
index d9e81ce6..00000000
--- a/flask_op/conf.py
+++ /dev/null
@@ -1,177 +0,0 @@
-from oidcendpoint import user_info
-from oidcendpoint.oidc.authorization import Authorization
-from oidcendpoint.oidc.discovery import Discovery
-from oidcendpoint.oidc.provider_config import ProviderConfiguration
-from oidcendpoint.oidc.registration import Registration
-from oidcendpoint.oidc.session import Session
-from oidcendpoint.oidc.token import AccessToken
-from oidcendpoint.oidc.userinfo import UserInfo
-from oidcendpoint.user_authn.authn_context import INTERNETPROTOCOLPASSWORD
-from oidcendpoint.user_authn.authn_context import UNSPECIFIED
-from oidcendpoint.user_authn.user import NoAuthn
-from oidcendpoint.user_authn.user import UserPassJinja2
-from oidcendpoint.util import JSONDictDB
-
-SESSION_COOKIE_NAME = 'flop'
-
-RESPONSE_TYPES_SUPPORTED = [
- ["code"], ["token"], ["id_token"], ["code", "token"], ["code", "id_token"],
- ["id_token", "token"], ["code", "token", "id_token"], ['none']]
-
-CAPABILITIES = {
- "subject_types_supported": ["public", "pairwise"],
- "grant_types_supported": [
- "authorization_code", "implicit",
- "urn:ietf:params:oauth:grant-type:jwt-bearer", "refresh_token"],
-}
-
-KEY_DEF = [
- {"type": "RSA", "use": ["sig"]},
- {"type": "EC", "crv": "P-256", "use": ["sig"]}
-]
-
-PORT = 5000
-DOMAIN = '127.0.0.1'
-SERVER_NAME = '{}:{}'.format(DOMAIN, str(PORT))
-BASE_URL = 'https://{}'.format(SERVER_NAME)
-
-# If we support session management
-CAPABILITIES["check_session_iframe"] = "{}/check_session_iframe".format(BASE_URL)
-
-PATH = {
- 'userinfo:kwargs:db_file': '{}/users.json',
- 'authentication:0:kwargs:db:kwargs:json_path': '{}/passwd.json'
-}
-
-CONFIG = {
- 'provider': {
- 'key_defs': [
- {"type": "RSA", "use": ["sig"]},
- {"type": "EC", "crv": "P-256", "use": ["sig"]}
- ],
- },
- 'server_info': {
- "issuer": BASE_URL,
- "password": "mycket hemlig information",
- "token_expires_in": 600,
- "grant_expires_in": 300,
- "refresh_token_expires_in": 86400,
- "verify_ssl": False,
- "capabilities": CAPABILITIES,
- 'template_dir': 'templates',
- "jwks": {
- 'private_path': 'own/jwks.json',
- 'key_defs': KEY_DEF,
- 'url_path': 'static/jwks.json'
- },
- 'endpoint': {
- 'webfinger': {
- 'path': '.well-known/webfinger',
- 'class': Discovery,
- 'kwargs': {'client_authn_method': None}
- },
- 'provider_info': {
- 'path': '.well-known/openid-configuration',
- 'class': ProviderConfiguration,
- 'kwargs': {'client_authn_method': None}
- },
- 'registration': {
- 'path': 'registration',
- 'class': Registration,
- 'kwargs': {
- 'client_authn_method': None,
- 'client_secret_expiration_time': 5 * 86400
- }
- },
- 'authorization': {
- 'path': 'authorization',
- 'class': Authorization,
- 'kwargs': {
- 'client_authn_method': None,
- "response_types_supported": [" ".join(x) for x in RESPONSE_TYPES_SUPPORTED],
- "response_modes_supported": ['query', 'fragment', 'form_post'],
- "claims_parameter_supported": True,
- "request_parameter_supported": True,
- "request_uri_parameter_supported": True
- }
- },
- 'token': {
- 'path': 'token',
- 'class': AccessToken,
- 'kwargs': {
- "client_authn_method": [
- "client_secret_post", "client_secret_basic",
- "client_secret_jwt", "private_key_jwt"],
-
- }
- },
- 'userinfo': {
- 'path': 'userinfo',
- 'class': UserInfo,
- "kwargs": {
- "claim_types_supported": ["normal", "aggregated", "distributed"],
- }
- },
- 'end_session': {
- 'path': 'session',
- 'class': Session,
- 'kwargs': {
- 'logout_uri': "{}/verify_logout".format(BASE_URL),
- 'post_logout_uri': "{}/post_logout".format(BASE_URL),
- 'signing_alg': "ES256",
- "frontchannel_logout_supported": True,
- "frontchannel_logout_session_supported": True,
- "backchannel_logout_supported": True,
- "backchannel_logout_session_supported": True,
- "check_session_iframe": "{}/check_session_iframe".format(BASE_URL)
- }
- }
- },
- 'userinfo': {
- 'class': user_info.UserInfo,
- 'kwargs': {'db_file': 'users.json'}
- },
- 'authentication': {
- 'user':
- {
- 'acr': INTERNETPROTOCOLPASSWORD,
- 'class': UserPassJinja2,
- 'verify_endpoint': 'verify/user',
- 'kwargs': {
- 'template': 'user_pass.jinja2',
- 'sym_key': '24AA/LR6HighEnergy',
- 'db': {
- 'class': JSONDictDB,
- 'kwargs':
- {'json_path': 'passwd.json'}
- },
- 'page_header': "Testing log in",
- 'submit_btn': "Get me in!",
- 'user_label': "Nickname",
- 'passwd_label': "Secret sauce"
- }
- },
- 'anon':
- {
- 'acr': UNSPECIFIED,
- 'class': NoAuthn,
- 'kwargs': {'user': 'diana'}
- }
- },
- 'cookie_dealer': {
- 'symkey': 'ghsNKDDLshZTPn974nOsIGhedULrsqnsGoBFBLwUKuJhE2ch',
- 'default_values': {
- 'name': 'oidc_op',
- 'domain': DOMAIN,
- 'path': '/',
- 'max_age': 3600
- }
- }
- },
- 'webserver': {
- 'cert': '{}/certs/cert.pem',
- 'key': '{}/certs/key.pem',
- 'cert_chain': '',
- 'port': PORT,
- }
-}
diff --git a/flask_op/config_persistent.yaml b/flask_op/config_persistent.yaml
deleted file mode 100644
index 6ff797ca..00000000
--- a/flask_op/config_persistent.yaml
+++ /dev/null
@@ -1,293 +0,0 @@
-logging:
- version: 1
- root:
- handlers:
- - default
- - console
- level: DEBUG
- loggers:
- bobcat_idp:
- level: DEBUG
- handlers:
- default:
- class: logging.FileHandler
- filename: 'debug.log'
- formatter: default
- console:
- class: logging.StreamHandler
- stream: 'ext://sys.stdout'
- formatter: default
- formatters:
- default:
- format: '%(asctime)s %(name)s %(levelname)s %(message)s'
-
-port: &port 5000
-domain: &domain 127.0.0.1
-server_name: '{domain}:{port}'
-base_url: &base_url 'https://{domain}:{port}'
-
-key_def: &key_def
- -
- type: RSA
- use:
- - sig
- -
- type: EC
- crv: "P-256"
- use:
- - sig
-
-OIDC_KEYS: &oidc_keys
- 'private_path': "private/jwks.json"
- 'key_defs': *key_def
- 'public_path': 'static/jwks.json'
- 'read_only': False
- # otherwise OP metadata will have jwks_uri: https://127.0.0.1:5000/None!
- 'uri_path': 'static/jwks.json'
-
-
-op:
- server_info:
- issuer: *base_url
- http_params:
- verify_ssl: False
- session_key:
- filename: private/session_jwk.json
- type: OCT
- use: sig
- capabilities:
- subject_types_supported:
- - public
- - pairwise
- grant_types_supported:
- - authorization_code
- - implicit
- - urn:ietf:params:oauth:grant-type:jwt-bearer
- - refresh_token
- template_dir: templates
- id_token:
- class: oidcendpoint.id_token.IDToken
- kwargs:
- default_claims:
- email:
- essential: True
- email_verified:
- essential: True
- token_handler_args:
- jwks_def:
- private_path: 'private/token_jwks.json'
- read_only: False
- key_defs:
- -
- type: oct
- bytes: 24
- use:
- - enc
- kid: code
- -
- type: oct
- bytes: 24
- use:
- - enc
- kid: refresh
- code:
- lifetime: 600
- token:
- class: oidcendpoint.jwt_token.JWTToken
- lifetime: 3600
- add_claims:
- - email
- - email_verified
- - phone_number
- - phone_number_verified
- add_claim_by_scope: True
- aud:
- - https://example.org/appl
- refresh:
- lifetime: 86400
- keys:
- *oidc_keys
- endpoint:
- webfinger:
- path: '.well-known/webfinger'
- class: oidcendpoint.oidc.discovery.Discovery
- kwargs:
- client_authn_method: null
- provider_info:
- path: ".well-known/openid-configuration"
- class: oidcendpoint.oidc.provider_config.ProviderConfiguration
- kwargs:
- client_authn_method: null
- registration:
- path: registration
- class: oidcendpoint.oidc.registration.Registration
- kwargs:
- client_authn_method: null
- client_secret_expiration_time: 432000
- registration_api:
- path: registration_api
- class: oidcendpoint.oidc.read_registration.RegistrationRead
- kwargs:
- client_authn_method:
- - bearer_header
- introspection:
- path: introspection
- class: oidcendpoint.oauth2.introspection.Introspection
- kwargs:
- client_authn_method:
- - client_secret_post
- release:
- - username
- authorization:
- path: authorization
- class: oidcendpoint.oidc.authorization.Authorization
- kwargs:
- client_authn_method: null
- claims_parameter_supported: True
- request_parameter_supported: True
- request_uri_parameter_supported: True
- response_types_supported:
- - code
- - token
- - id_token
- - "code token"
- - "code id_token"
- - "id_token token"
- - "code id_token token"
- - none
- response_modes_supported:
- - query
- - fragment
- - form_post
- token:
- path: token
- class: oidcendpoint.oidc.token.AccessToken
- kwargs:
- client_authn_method:
- - client_secret_post
- - client_secret_basic
- - client_secret_jwt
- - private_key_jwt
- userinfo:
- path: userinfo
- class: oidcendpoint.oidc.userinfo.UserInfo
- kwargs:
- claim_types_supported:
- - normal
- - aggregated
- - distributed
- end_session:
- path: session
- class: oidcendpoint.oidc.session.Session
- kwargs:
- logout_verify_url: verify_logout
- post_logout_uri_path: post_logout
- signing_alg: "ES256"
- frontchannel_logout_supported: True
- frontchannel_logout_session_supported: True
- backchannel_logout_supported: True
- backchannel_logout_session_supported: True
- check_session_iframe: 'check_session_iframe'
- userinfo:
- class: oidcendpoint.user_info.UserInfo
- kwargs:
- db_file: users.json
- authentication:
- user:
- acr: oidcendpoint.user_authn.authn_context.INTERNETPROTOCOLPASSWORD
- class: oidcendpoint.user_authn.user.UserPassJinja2
- kwargs:
- verify_endpoint: 'verify/user'
- template: user_pass.jinja2
- db:
- class: oidcendpoint.util.JSONDictDB
- kwargs:
- json_path: passwd.json
- page_header: "Testing log in"
- submit_btn: "Get me in!"
- user_label: "Nickname"
- passwd_label: "Secret sauce"
- #anon:
- #acr: oidcendpoint.user_authn.authn_context.UNSPECIFIED
- #class: oidcendpoint.user_authn.user.NoAuthn
- #kwargs:
- #user: diana
- cookie_dealer:
- class: oidcendpoint.cookie.CookieDealer
- kwargs:
- sign_jwk:
- filename: 'private/cookie_sign_jwk.json'
- type: OCT
- kid: cookie_sign_key_id
- enc_jwk:
- filename: 'private/cookie_enc_jwk.json'
- type: OCT
- kid: cookie_enc_key_id
- # enc_jwk: 'private/cookie_enc_jwk.json'
- default_values:
- name: oidc_op
- domain: *domain
- path: /
- max_age: 3600
- login_hint2acrs:
- class: oidcendpoint.login_hint.LoginHint2Acrs
- kwargs:
- scheme_map:
- email:
- - oidcendpoint.user_authn.authn_context.INTERNETPROTOCOLPASSWORD
-
- # this adds PKCE support as mandatory - disable it if needed (essential: False)
- add_on:
- pkce:
- function: oidcendpoint.oidc.add_on.pkce.add_pkce_support
- kwargs:
- essential: false
- code_challenge_method:
- #plain
- S256
- S384
- S512
-
- claims:
- function: oidcendpoint.oidc.add_on.custom_scopes.add_custom_scopes
- kwargs:
- research_and_scholarship:
- - name
- - given_name
- - family_name
- - email
- - email_verified
- - sub
- - iss
- - eduperson_scoped_affiliation
- db_conf:
- keyjar:
- handler: abstorage.storages.abfile.LabeledAbstractFileSystem
- fdir: storage/keyjar
- key_conv: abstorage.converter.QPKey
- value_conv: cryptojwt.serialize.item.KeyIssuer
- label: 'x'
- default:
- handler: abstorage.storages.abfile.AbstractFileSystem
- fdir: storage
- key_conv: abstorage.converter.QPKey
- value_conv: abstorage.converter.JSON
- session:
- handler: abstorage.storages.abfile.AbstractFileSystem
- fdir: storage/session
- key_conv: abstorage.converter.QPKey
- value_conv: abstorage.converter.JSON
- sso:
- handler: abstorage.storages.abfile.AbstractFileSystem
- fdir: storage/sso
- key_conv: abstorage.converter.QPKey
- value_conv: abstorage.converter.JSON
-
-webserver:
- server_cert: 'certs/89296913_127.0.0.1.cert'
- server_key: 'certs/89296913_127.0.0.1.key'
- ca_bundle: null
- verify_user: false
- port: *port
- domain: *domain
- debug: true
diff --git a/flask_op/templates/check_session_iframe.html b/flask_op/templates/check_session_iframe.html
deleted file mode 100644
index 08f2f420..00000000
--- a/flask_op/templates/check_session_iframe.html
+++ /dev/null
@@ -1,122 +0,0 @@
-
-
-
-
- Session Management - OP iframe
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/flask_op/templates/error.html b/flask_op/templates/error.html
deleted file mode 100644
index 5933d924..00000000
--- a/flask_op/templates/error.html
+++ /dev/null
@@ -1,12 +0,0 @@
-
-
-
-Error: {{ title }}
-
-{% if redirect_url is defined %}
-Continue
-{% else %}
-{% endif %}
-
-
-
diff --git a/flask_op/templates/frontchannel_logout.html b/flask_op/templates/frontchannel_logout.html
deleted file mode 100644
index 0cca93c1..00000000
--- a/flask_op/templates/frontchannel_logout.html
+++ /dev/null
@@ -1,31 +0,0 @@
-
-
-
- Logout
-
-
-
-
-
-
- {{ frames|safe }}
-
-