diff --git a/docs/source/contents/conf.rst b/docs/source/contents/conf.rst index ea23e089..b4472aa6 100644 --- a/docs/source/contents/conf.rst +++ b/docs/source/contents/conf.rst @@ -156,9 +156,32 @@ An example:: backchannel_logout_session_supported: True check_session_iframe: https://127.0.0.1:5000/check_session_iframe -------------- +--------- +client_db +--------- + +If you're running an OP with static client registration you want to keep the +registered clients in a database separate from the session database since +it will change independent of the OP process. In this case you need this. +If you are on the other hand only allowing dynamic client registration then +keeping registered clients in the session database makes total sense. + +The class you reference in the specification MUST be a subclass of +oidcmsg.storage.DictType and have some of the methods a dictionary has. + +An example:: + + client_db: { + "class": 'oidcmsg.abfile.AbstractFileSystem', + "kwargs": { + 'fdir': full_path("afs"), + 'value_conv': 'oidcmsg.util.JSON' + } + } + +-------------- cookie_handler -------------- +-------------- An example:: diff --git a/pyproject.toml b/pyproject.toml index cff54529..7564b0ee 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -7,7 +7,7 @@ build-backend = "setuptools.build_meta" [metadata] name = "oidcop" -version = "2.0.0" +version = "2.1.0" author = "Roland Hedberg" author_email = "roland@catalogix.se" description = "Python implementation of an OAuth2 AS and an OIDC Provider" diff --git a/setup.py b/setup.py index 4ac7ce57..d707fd8a 100644 --- a/setup.py +++ b/setup.py @@ -72,7 +72,7 @@ def run_tests(self): "Programming Language :: Python :: 3.9", "Topic :: Software Development :: Libraries :: Python Modules"], install_requires=[ - "oidcmsg==1.3.3-1", + "oidcmsg==1.4.0", "cryptojwt==1.5.2", "pyyaml", "jinja2>=2.11.3", diff --git a/src/oidcop/__init__.py b/src/oidcop/__init__.py index 83246c0e..9b05f0cf 100644 --- a/src/oidcop/__init__.py +++ b/src/oidcop/__init__.py @@ -1,6 +1,6 @@ import secrets -__version__ = "2.0.1" +__version__ = "2.1.0" DEF_SIGN_ALG = { "id_token": "RS256", diff --git a/src/oidcop/configure.py b/src/oidcop/configure.py index edd270c9..042593fa 100755 --- a/src/oidcop/configure.py +++ b/src/oidcop/configure.py @@ -192,6 +192,7 @@ class EntityConfiguration(Base): "base_url": "", "capabilities": None, "claims_interface": None, + "client_db": None, "cookie_handler": None, "endpoint": {}, "httpc_params": {}, diff --git a/src/oidcop/endpoint_context.py b/src/oidcop/endpoint_context.py index e3c19dbe..9a683f2b 100755 --- a/src/oidcop/endpoint_context.py +++ b/src/oidcop/endpoint_context.py @@ -93,7 +93,7 @@ class EndpointContext(OidcContext): "args": {}, # "authn_broker": AuthnBroker, # "authz": AuthzHandling, - "cdb": {}, + "cdb": "DICT_TYPE", "conf": {}, # "cookie_handler": None, "cwd": "", @@ -129,8 +129,15 @@ def __init__( OidcContext.__init__(self, conf, keyjar, entity_id=conf.get("issuer", "")) self.conf = conf + _client_db = conf.get("client_db") + if _client_db: + logger.debug(f"Loading client db using: {_client_db}") + self.cdb = importer(_client_db["class"])(**_client_db["kwargs"]) + else: + logger.debug("No special client db, will use memory based dictionary") + self.cdb = {} + # For my Dev environment - self.cdb = {} self.jti_db = {} self.registration_access_token = {} # self.session_db = {} diff --git a/tests/test_00_server.py b/tests/test_00_server.py index d6bd726c..1a92ffb3 100755 --- a/tests/test_00_server.py +++ b/tests/test_00_server.py @@ -1,13 +1,15 @@ +from copy import copy +from copy import deepcopy import io import json import os -from copy import copy -import yaml from cryptojwt.key_jar import build_keyjar +from oidcmsg.storage.abfile import AbstractFileSystem +import yaml -import oidcop.login_hint from oidcop.configure import OPConfiguration +import oidcop.login_hint from oidcop.oidc.add_on.pkce import add_pkce_support from oidcop.oidc.authorization import Authorization from oidcop.oidc.provider_config import ProviderConfiguration @@ -32,7 +34,7 @@ def full_path(local_file): KEYJAR = build_keyjar(KEYDEFS) -conf = { +CONF = { "issuer": "https://example.com/", "password": "mycket hemligt", "verify_ssl": False, @@ -44,8 +46,8 @@ def full_path(local_file): "class": ProviderConfiguration, "kwargs": {}, }, - "registration_endpoint": {"path": "registration", "class": Registration, "kwargs": {},}, - "authorization_endpoint": {"path": "authorization", "class": Authorization, "kwargs": {},}, + "registration_endpoint": {"path": "registration", "class": Registration, "kwargs": {}, }, + "authorization_endpoint": {"path": "authorization", "class": Authorization, "kwargs": {}, }, "token_endpoint": {"path": "token", "class": Token, "kwargs": {}}, "userinfo_endpoint": { "path": "userinfo", @@ -114,14 +116,14 @@ def test_capabilities_default(): def test_capabilities_subset1(): - _cnf = copy(conf) + _cnf = deepcopy(CONF) _cnf["capabilities"] = {"response_types_supported": ["code"]} server = Server(_cnf) assert server.endpoint_context.provider_info["response_types_supported"] == ["code"] def test_capabilities_subset2(): - _cnf = copy(conf) + _cnf = deepcopy(CONF) _cnf["capabilities"] = {"response_types_supported": ["code", "id_token"]} server = Server(_cnf) assert set(server.endpoint_context.provider_info["response_types_supported"]) == { @@ -131,15 +133,29 @@ def test_capabilities_subset2(): def test_capabilities_bool(): - _cnf = copy(conf) + _cnf = deepcopy(CONF) _cnf["capabilities"] = {"request_uri_parameter_supported": False} server = Server(_cnf) assert server.endpoint_context.provider_info["request_uri_parameter_supported"] is False def test_cdb(): - server = Server(conf) + _cnf = deepcopy(CONF) + server = Server(_cnf) _clients = yaml.safe_load(io.StringIO(client_yaml)) server.endpoint_context.cdb = _clients["oidc_clients"] assert set(server.endpoint_context.cdb.keys()) == {"client1", "client2", "client3"} + + +def test_cdb_afs(): + _cnf = copy(CONF) + _cnf["client_db"] = { + "class": 'oidcmsg.storage.abfile.AbstractFileSystem', + "kwargs": { + 'fdir': full_path("afs"), + 'value_conv': 'oidcmsg.util.JSON' + } + } + server = Server(_cnf) + assert isinstance(server.endpoint_context.cdb, AbstractFileSystem)