Skip to content
This repository was archived by the owner on Jun 1, 2023. It is now read-only.

Commit d9531e9

Browse files
committed
Adding default configurations. base_url is the only required argument to RPHandler.
The remaining arguments has reasonable defaults. If you go with the defaults you get an RPHandler that can spawn RPs that does everything dynamically.
1 parent 1f5164f commit d9531e9

4 files changed

Lines changed: 108 additions & 45 deletions

File tree

chrp/rp.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -88,10 +88,9 @@
8888
else:
8989
_verify_ssl = True
9090

91-
rph = RPHandler(base_url=_base_url, hash_seed="BabyHoldOn", keyjar=_kj,
92-
jwks_path=config.PUBLIC_JWKS_PATH,
93-
client_configs=config.CLIENTS,
94-
services=config.SERVICES, verify_ssl=_verify_ssl)
91+
rph = RPHandler(_base_url, config.CLIENTS, services=config.SERVICES,
92+
hash_seed="BabyHoldOn", keyjar=_kj, jwks_path=config.PUBLIC_JWKS_PATH,
93+
verify_ssl=_verify_ssl)
9594

9695
cherrypy.tree.mount(cprp.Consumer(rph, 'html'), '/', provider_config)
9796

flask_rp/application.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,9 @@ def init_oidc_rp_handler(app):
2424
_path = ''
2525
_kj.httpc_params = _rp_conf.httpc_params
2626

27-
rph = RPHandler(base_url=_rp_conf.base_url,
27+
rph = RPHandler(_rp_conf.base_url, _rp_conf.clients, services=_rp_conf.services,
2828
hash_seed=_rp_conf.hash_seed, keyjar=_kj, jwks_path=_path,
29-
client_configs=_rp_conf.clients,
30-
services=_rp_conf.services, httpc_params=_rp_conf.httpc_params)
29+
httpc_params=_rp_conf.httpc_params)
3130

3231
return rph
3332

src/oidcrp/__init__.py

Lines changed: 93 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import traceback
55

66
from cryptojwt.key_bundle import keybundle_from_local_file
7+
from cryptojwt.key_jar import init_key_jar
78
from cryptojwt.utils import as_bytes
89
from cryptojwt.utils import as_unicode
910
from oidcmsg.exception import MessageException
@@ -54,6 +55,53 @@ def token_secret_key(sid):
5455
SERVICE_NAME = "OIC"
5556
CLIENT_CONFIG = {}
5657

58+
DEFAULT_SEVICES = {
59+
'web_finger': {'class': 'oidcservice.oidc.webfinger.WebFinger'},
60+
'discovery': {'class': 'oidcservice.oidc.provider_info_discovery.ProviderInfoDiscovery'},
61+
'registration': {'class': 'oidcservice.oidc.registration.Registration'},
62+
'authorization': {'class': 'oidcservice.oidc.authorization.Authorization'},
63+
'access_token': {'class': 'oidcservice.oidc.access_token.AccessToken'},
64+
'refresh_access_token': {'class': 'oidcservice.oidc.refresh_access_token.RefreshAccessToken'},
65+
'userinfo': {'class': 'oidcservice.oidc.userinfo.UserInfo'}
66+
}
67+
68+
DEFAULT_CLIENT_PREFS = {
69+
'application_type': 'web',
70+
'application_name': 'rphandler',
71+
'response_types': ['code', 'id_token', 'id_token token', 'code id_token', 'code id_token token',
72+
'code token'],
73+
'scope': ['openid'],
74+
'token_endpoint_auth_method': 'client_secret_basic'
75+
}
76+
77+
# Using PKCE is default
78+
DEFAULT_CLIENT_CONFIGS = {
79+
"": {
80+
"client_preferences": DEFAULT_CLIENT_PREFS,
81+
"add_ons": {
82+
"pkce": {
83+
"function": "oidcservice.oidc.add_on.pkce.add_pkce_support",
84+
"kwargs": {
85+
"code_challenge_length": 64,
86+
"code_challenge_method": "S256"
87+
}
88+
}
89+
}
90+
}
91+
}
92+
93+
DEFAULT_KEY_DEFS = [
94+
{"type": "RSA", "use": ["sig"]},
95+
{"type": "EC", "crv": "P-256", "use": ["sig"]},
96+
]
97+
98+
DEFAULT_RP_KEY_DEFS = {
99+
'private_path': 'private/jwks.json',
100+
'key_defs': DEFAULT_KEY_DEFS,
101+
'public_path': 'static/jwks.json',
102+
'read_only': False
103+
}
104+
57105

58106
def add_path(url, path):
59107
if url.endswith('/'):
@@ -113,14 +161,30 @@ def dynamic_provider_info_discovery(client):
113161

114162

115163
class RPHandler(object):
116-
def __init__(self, base_url='', hash_seed="", keyjar=None, verify_ssl=True,
117-
services=None, client_configs=None, client_authn_factory=None,
164+
def __init__(self, base_url, client_configs=None, services=None, keyjar=None,
165+
hash_seed="", verify_ssl=True, client_authn_factory=None,
118166
client_cls=None, state_db=None, http_lib=None, httpc_params=None,
119167
**kwargs):
120168

121169
self.base_url = base_url
122-
self.hash_seed = as_bytes(hash_seed)
123-
self.keyjar = keyjar
170+
if hash_seed:
171+
self.hash_seed = as_bytes(hash_seed)
172+
else:
173+
self.hash_seed = as_bytes(rndstr(32))
174+
175+
_jwks_path = kwargs.get('jwks_path')
176+
if keyjar is None:
177+
self.keyjar = init_key_jar(**DEFAULT_RP_KEY_DEFS, owner='')
178+
self.keyjar.import_jwks_as_json(self.keyjar.export_jwks_as_json(True, ''), base_url)
179+
if _jwks_path is None:
180+
_jwks_path = DEFAULT_RP_KEY_DEFS['public_path']
181+
else:
182+
self.keyjar = keyjar
183+
184+
try:
185+
self.jwks_uri = add_path(base_url, _jwks_path)
186+
except KeyError:
187+
self.jwks_uri = ""
124188

125189
if state_db:
126190
self.state_db = state_db
@@ -129,22 +193,26 @@ def __init__(self, base_url='', hash_seed="", keyjar=None, verify_ssl=True,
129193

130194
self.session_interface = StateInterface(self.state_db)
131195

132-
try:
133-
self.jwks_uri = add_path(base_url, kwargs['jwks_path'])
134-
except KeyError:
135-
self.jwks_uri = ""
136-
137196
self.extra = kwargs
138197

139198
self.client_cls = client_cls or oidc.RP
140-
self.services = services
199+
if services is None:
200+
self.services = DEFAULT_SEVICES
201+
else:
202+
self.services = services
203+
141204
self.client_authn_factory = client_authn_factory
142-
self.client_configs = client_configs
205+
206+
if client_configs is None:
207+
self.client_configs = DEFAULT_CLIENT_CONFIGS
208+
else:
209+
self.client_configs = client_configs
143210

144211
# keep track on which RP instance that serves with OP
145212
self.issuer2rp = {}
146213
self.hash2issuer = {}
147214
self.httplib = http_lib
215+
148216
if not httpc_params:
149217
self.httpc_params = {'verify': verify_ssl}
150218
else:
@@ -193,7 +261,12 @@ def init_client(self, issuer):
193261
:param issuer: An issuer ID
194262
:return: A Client instance
195263
"""
196-
_cnf = self.pick_config(issuer)
264+
try:
265+
_cnf = self.pick_config(issuer)
266+
except KeyError:
267+
_cnf = self.pick_config('')
268+
_cnf['issuer'] = issuer
269+
197270
try:
198271
_services = _cnf['services']
199272
except KeyError:
@@ -310,6 +383,13 @@ def do_client_registration(self, client=None, iss_id='', state=''):
310383
if not client.service_context.client_id:
311384
load_registration_response(client)
312385

386+
def add_callbacks(self, service_context):
387+
_callbacks = self.create_callbacks(service_context.provider_info['issuer'])
388+
service_context.redirect_uris = [
389+
v for k, v in _callbacks.items() if not k.startswith('__')]
390+
service_context.callbacks = _callbacks
391+
return _callbacks
392+
313393
def client_setup(self, iss_id='', user=''):
314394
"""
315395
First if no issuer ID is given then the identifier for the user is
@@ -365,10 +445,7 @@ def client_setup(self, iss_id='', user=''):
365445
_sc.client_id = client.client_id = add_path(_fe.entity_id, iss_id)
366446
self.hash2issuer[iss_id] = issuer
367447
else:
368-
_callbacks = self.create_callbacks(_sc.provider_info['issuer'])
369-
_sc.redirect_uris = [
370-
v for k, v in _callbacks.items() if not k.startswith('__')]
371-
_sc.callbacks = _callbacks
448+
_callbacks = self.add_callbacks(_sc)
372449
_sc.client_id = client.client_id = add_path(_fe.entity_id, _callbacks['__hex'])
373450
else: # explicit
374451
logger.debug("Do client registration")

tests/test_20_rp_handler.py

Lines changed: 10 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -202,7 +202,7 @@ def iss_id(iss):
202202
class TestRPHandler(object):
203203
@pytest.fixture(autouse=True)
204204
def rphandler_setup(self):
205-
self.rph = RPHandler(base_url=BASE_URL, client_configs=CLIENT_CONFIG,
205+
self.rph = RPHandler(BASE_URL, CLIENT_CONFIG,
206206
keyjar=CLI_KEY, module_dirs=['oidc'])
207207

208208
def test_pick_config(self):
@@ -303,25 +303,15 @@ def test_create_callbacks(self):
303303
cb = self.rph.create_callbacks('https://op.example.com/')
304304

305305
assert set(cb.keys()) == {'code', 'implicit', 'form_post', '__hex'}
306-
assert cb == {
307-
'code': 'https://example.com/rp/authz_cb'
308-
'/7f729285244adafbf5412e06b097e0e1f92049bfc432fed0a13cbcb5661b137d',
309-
'implicit':
310-
'https://example.com/rp/authz_im_cb'
311-
'/7f729285244adafbf5412e06b097e0e1f92049bfc432fed0a13cbcb5661b137d',
312-
'form_post':
313-
'https://example.com/rp/authz_fp_cb'
314-
'/7f729285244adafbf5412e06b097e0e1f92049bfc432fed0a13cbcb5661b137d',
315-
'__hex':
316-
'7f729285244adafbf5412e06b097e0e1f92049bfc432fed0a13cbcb5661b137d'
317-
}
306+
_hash = cb['__hex']
307+
308+
assert cb['code'] == 'https://example.com/rp/authz_cb/{}'.format(_hash)
309+
assert cb['implicit'] == 'https://example.com/rp/authz_im_cb/{}'.format(_hash)
310+
assert cb['form_post'] == 'https://example.com/rp/authz_fp_cb/{}'.format(_hash)
318311

319-
assert list(self.rph.hash2issuer.keys()) == [
320-
'7f729285244adafbf5412e06b097e0e1f92049bfc432fed0a13cbcb5661b137d']
312+
assert list(self.rph.hash2issuer.keys()) == [_hash]
321313

322-
assert self.rph.hash2issuer[
323-
'7f729285244adafbf5412e06b097e0e1f92049bfc432fed0a13cbcb5661b137d'
324-
] == 'https://op.example.com/'
314+
assert self.rph.hash2issuer[_hash] == 'https://op.example.com/'
325315

326316
def test_begin(self):
327317
res = self.rph.begin(issuer_id='github')
@@ -615,8 +605,7 @@ def test_get_provider_specific_service():
615605
class TestRPHandlerTier2(object):
616606
@pytest.fixture(autouse=True)
617607
def rphandler_setup(self, httpserver):
618-
self.rph = RPHandler(base_url=BASE_URL, client_configs=CLIENT_CONFIG,
619-
keyjar=CLI_KEY)
608+
self.rph = RPHandler(BASE_URL, CLIENT_CONFIG, keyjar=CLI_KEY)
620609
res = self.rph.begin(issuer_id='github')
621610
_session = self.rph.get_session_information(res['state'])
622611
client = self.rph.issuer2rp[_session['iss']]
@@ -800,8 +789,7 @@ class TestRPHandlerWithMockOP(object):
800789
def rphandler_setup(self):
801790
self.issuer = 'https://github.com/login/oauth/authorize'
802791
self.mock_op = MockOP(issuer=self.issuer)
803-
self.rph = RPHandler(
804-
base_url=BASE_URL, client_configs=CLIENT_CONFIG,
792+
self.rph = RPHandler(BASE_URL, CLIENT_CONFIG,
805793
http_lib=self.mock_op, keyjar=KeyJar())
806794

807795
def test_finalize(self):

0 commit comments

Comments
 (0)