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

Commit d7d1ac3

Browse files
committed
Allow the functions used to mint subject identifiers to be configurable.
1 parent 73765f4 commit d7d1ac3

4 files changed

Lines changed: 102 additions & 31 deletions

File tree

src/oidcendpoint/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
except ImportError:
66
import random as rnd
77

8-
__version__ = '0.8.3'
8+
__version__ = '0.8.4'
99

1010

1111
DEF_SIGN_ALG = {"id_token": "RS256",

src/oidcendpoint/endpoint_context.py

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,21 @@ def __init__(self, conf, keyjar=None, client_db=None, session_db=None,
189189
raise ValueError('Cookie Dealer already defined')
190190
self.cookie_dealer = init_service(_conf)
191191

192+
try:
193+
_conf = conf['sub_func']
194+
except KeyError:
195+
sub_func = None
196+
else:
197+
sub_func = {}
198+
for key, args in _conf.items():
199+
if 'class' in args:
200+
sub_func[key] = init_service(args)
201+
elif 'function' in args:
202+
if isinstance(args['function'], str):
203+
sub_func[key] = util.importer(args['function'])
204+
else:
205+
sub_func[key] = args['function']
206+
192207
if session_db:
193208
self.sdb = session_db
194209
else:
@@ -212,7 +227,7 @@ def __init__(self, conf, keyjar=None, client_db=None, session_db=None,
212227
_th_args[typ] = {'lifetime': tid}
213228

214229
self.sdb = create_session_db(self, _th_args, db=None,
215-
sso_db=SSODb())
230+
sso_db=SSODb(), sub_func=sub_func)
216231

217232
self.endpoint = build_endpoints(conf['endpoint'],
218233
endpoint_context=self,

src/oidcendpoint/session.py

Lines changed: 44 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -84,9 +84,14 @@ class SessionInfo(Message):
8484
}
8585

8686

87-
def pairwise_id(sub, sector_identifier, seed):
87+
def pairwise_id(uid, sector_identifier, client_salt, **kwargs):
8888
return hashlib.sha256(
89-
("%s%s%s" % (sub, sector_identifier, seed)).encode("utf-8")).hexdigest()
89+
("%s%s%s" % (uid, sector_identifier, client_salt)).encode("utf-8")).hexdigest()
90+
91+
92+
def public_id(uid, user_salt='', **kwargs):
93+
return hashlib.sha256(
94+
"{}{}".format(uid, user_salt).encode("utf-8")).hexdigest()
9095

9196

9297
def dict_match(a, b):
@@ -106,35 +111,28 @@ def dict_match(a, b):
106111
return all(res)
107112

108113

109-
def mint_sub(client_salt, sector_id="", subject_type="public",
110-
uid='', user_salt=''):
111-
"""
112-
Mint a new sub (subject identifier)
113-
114-
:param authn_event: Authentication event information
115-
:param client_salt: client specific salt - used in pairwise
116-
:param sector_id: Possible sector identifier
117-
:param subject_type: 'public'/'pairwise'
118-
:return: Subject identifier
119-
"""
120-
121-
if subject_type == "public":
122-
sub = hashlib.sha256(
123-
"{}{}".format(uid, user_salt).encode("utf-8")).hexdigest()
124-
else:
125-
sub = pairwise_id(uid, sector_id,
126-
"{}{}".format(client_salt, user_salt))
127-
return sub
128-
129-
130114
class SessionDB(object):
131-
def __init__(self, db, handler, sso_db, userinfo=None):
115+
def __init__(self, db, handler, sso_db, userinfo=None, sub_func=None):
132116
# db must implement the InMemoryStateDataBase interface
133117
self._db = db
134118
self.handler = handler
135119
self.sso_db = sso_db
136120
self.userinfo = userinfo
137121

122+
# this allows the subject identifier minters to be defined by someone
123+
# else then me.
124+
if sub_func is None:
125+
self.sub_func = {
126+
'public': public_id,
127+
'pairwise': pairwise_id
128+
}
129+
else:
130+
self.sub_func = sub_func
131+
if 'public' not in sub_func:
132+
self.sub_func['public'] = public_id
133+
if 'pairwise' not in sub_func:
134+
self.sub_func['pairwise'] = pairwise_id
135+
138136
def __getitem__(self, item):
139137
_info = self._db.get(item)
140138

@@ -242,7 +240,20 @@ def get_token(self, sid):
242240

243241
def do_sub(self, sid, uid, client_salt, sector_id='', subject_type='public',
244242
user_salt=''):
245-
sub = mint_sub(client_salt, sector_id, subject_type, uid, user_salt)
243+
"""
244+
Create and store a subject identifier
245+
246+
:param sid: Session ID
247+
:param uid: User ID
248+
:param client_salt:
249+
:param sector_id: For pairwise identifiers, an Identifier for the RP group
250+
:param subject_type: 'pairwaise'/'public'
251+
:param user_salt:
252+
:return:
253+
"""
254+
sub = self.sub_func[subject_type](uid, user_salt=user_salt,
255+
client_salt=client_salt,
256+
sector_identifier=sector_id)
246257

247258
self.sso_db.map_sid2uid(sid, uid)
248259
self.update(sid, sub=sub)
@@ -292,11 +303,14 @@ def replace_token(self, sid, sinfo, token_type):
292303

293304
def _make_at(self, sid, session_info, aud = None, client_id_aud = True):
294305
uid = self.sso_db.get_uid_by_sid(sid)
295-
uinfo = self.userinfo(uid, session_info['client_id'])
306+
307+
uinfo = self.userinfo(uid, session_info['client_id']) or {}
296308
at_aud = aud or []
309+
297310
if client_id_aud:
298311
at_aud.append(session_info['client_id'])
299-
return self.handler['access_token'](sid=sid, sinfo=session_info, uinfo=uinfo, aud=at_aud)
312+
return self.handler['access_token'](sid=sid, sinfo=session_info,
313+
uinfo=uinfo, aud=at_aud)
300314

301315
def upgrade_to_token(self, grant=None, issue_refresh=False, id_token="",
302316
oidreq=None, key=None, scope=None):
@@ -539,10 +553,11 @@ def get_authentication_event(self, sid):
539553
raise ValueError('No Authn event info')
540554

541555

542-
def create_session_db(ec, token_handler_args, db=None, sso_db=SSODb()):
556+
def create_session_db(ec, token_handler_args, db=None, sso_db=SSODb(),
557+
sub_func=None):
543558
_token_handler = token_handler.factory(ec, **token_handler_args)
544559

545560
if not db:
546561
db = InMemoryDataBase()
547562

548-
return SessionDB(db, _token_handler, sso_db)
563+
return SessionDB(db, _token_handler, sso_db, sub_func=sub_func)

tests/test_08_session.py

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -403,3 +403,44 @@ def test_setup_session_upgrade_to_token():
403403

404404
endpoint_context.sdb.revoke_uid('_user_')
405405
assert endpoint_context.sdb.is_session_revoked(sid)
406+
407+
408+
def make_sub_uid(uid, **kwargs):
409+
return uid
410+
411+
412+
def test_sub_minting_function():
413+
conf['sub_func'] = {
414+
'public': {
415+
'function': make_sub_uid
416+
}
417+
}
418+
419+
endpoint_context = EndpointContext(conf)
420+
uid = '_user_'
421+
client_id = 'EXTERNAL'
422+
areq = None
423+
acr = None
424+
sid = setup_session(endpoint_context, areq, uid, client_id, acr, salt='salt')
425+
assert endpoint_context.sdb[sid]['sub'] == uid
426+
427+
428+
class SubMinter(object):
429+
def __call__(self, *args, **kwargs):
430+
return args[0]
431+
432+
433+
def test_sub_minting_class():
434+
conf['sub_func'] = {
435+
'public': {
436+
'class': SubMinter
437+
}
438+
}
439+
440+
endpoint_context = EndpointContext(conf)
441+
uid = '_user_'
442+
client_id = 'EXTERNAL'
443+
areq = None
444+
acr = None
445+
sid = setup_session(endpoint_context, areq, uid, client_id, acr, salt='salt')
446+
assert endpoint_context.sdb[sid]['sub'] == uid

0 commit comments

Comments
 (0)