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

Commit 89a21dd

Browse files
committed
2 parents a47e71d + 16c01b2 commit 89a21dd

13 files changed

Lines changed: 220 additions & 86 deletions

src/oidcendpoint/__init__.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
except ImportError:
77
import random as rnd
88

9-
__version__ = "0.10.0"
9+
__version__ = "0.10.1"
1010

1111

1212
DEF_SIGN_ALG = {
@@ -37,5 +37,5 @@ def rndstr(size=16):
3737
:param size: The length of the string
3838
:return: string
3939
"""
40-
_basech = string.ascii_letters + string.digits
41-
return "".join([rnd.choice(_basech) for _ in range(size)])
40+
chars = string.ascii_letters + string.digits
41+
return ''.join(rnd.choice(chars) for i in range(size))

src/oidcendpoint/endpoint_context.py

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
from jinja2 import Environment
1212
from jinja2 import FileSystemLoader
1313
from oidcmsg.oidc import IdToken
14-
from oidcmsg.oidc import SCOPE2CLAIMS
1514

1615
from oidcendpoint import authz
1716
from oidcendpoint import rndstr
@@ -23,6 +22,7 @@
2322
from oidcendpoint.sso_db import SSODb
2423
from oidcendpoint.template_handler import Jinja2TemplateHandler
2524
from oidcendpoint.user_authn.authn_context import populate_authn_broker
25+
from oidcendpoint.user_info import SCOPE2CLAIMS
2626
from oidcendpoint.util import build_endpoints
2727
from oidcendpoint.util import importer
2828

@@ -167,6 +167,7 @@ def __init__(
167167
self.args = {}
168168

169169
self._sub_func = None
170+
self.scope2claims = SCOPE2CLAIMS
170171

171172
if cookie_name:
172173
self.cookie_name = cookie_name
@@ -180,12 +181,12 @@ def __init__(
180181
}
181182

182183
for param in [
183-
"verify_ssl",
184-
"issuer",
185-
"sso_ttl",
186-
"symkey",
187-
"client_authn",
188-
"id_token_schema",
184+
"verify_ssl",
185+
"issuer",
186+
"sso_ttl",
187+
"symkey",
188+
"client_authn",
189+
"id_token_schema",
189190
]:
190191
try:
191192
setattr(self, param, conf[param])
@@ -223,7 +224,7 @@ def __init__(
223224
self.keyjar = init_key_jar(**args)
224225

225226
for item in ['cookie_dealer', "sub_func", "authz", "authentication",
226-
"id_token"]:
227+
"id_token", "scope2claims"]:
227228
_func = getattr(self, "do_{}".format(item), None)
228229
if _func:
229230
_func(self.conf)
@@ -393,11 +394,11 @@ def package_capabilities(self):
393394
_provider_info["version"] = "3.0"
394395

395396
_claims = []
396-
for _cl in SCOPE2CLAIMS.values():
397+
for _cl in self.scope2claims.values():
397398
_claims.extend(_cl)
398399
_provider_info["claims_supported"] = list(set(_claims))
399400

400-
_scopes = list(SCOPE2CLAIMS.keys())
401+
_scopes = list(self.scope2claims.keys())
401402
_provider_info["scopes_supported"] = _scopes
402403

403404
# Sort order RS, ES, HS, PS

src/oidcendpoint/id_token.py

Lines changed: 24 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88

99
logger = logging.getLogger(__name__)
1010

11-
1211
DEF_SIGN_ALG = {
1312
"id_token": "RS256",
1413
"userinfo": "RS256",
@@ -20,7 +19,7 @@
2019

2120

2221
def get_sign_and_encrypt_algorithms(
23-
endpoint_context, client_info, payload_type, sign=False, encrypt=False
22+
endpoint_context, client_info, payload_type, sign=False, encrypt=False
2423
):
2524
args = {"sign": sign, "encrypt": encrypt}
2625
if sign:
@@ -76,18 +75,19 @@ class IDToken(object):
7675
def __init__(self, endpoint_context, **kwargs):
7776
self.endpoint_context = endpoint_context
7877
self.kwargs = kwargs
78+
self.scope_to_claims = None
7979

8080
def payload(
81-
self,
82-
session,
83-
acr="",
84-
alg="RS256",
85-
code=None,
86-
access_token=None,
87-
user_info=None,
88-
auth_time=0,
89-
lifetime=None,
90-
extra_claims=None,
81+
self,
82+
session,
83+
acr="",
84+
alg="RS256",
85+
code=None,
86+
access_token=None,
87+
user_info=None,
88+
auth_time=0,
89+
lifetime=None,
90+
extra_claims=None,
9191
):
9292
"""
9393
@@ -148,16 +148,16 @@ def payload(
148148
return {"payload": _args, "lifetime": lifetime}
149149

150150
def sign_encrypt(
151-
self,
152-
session_info,
153-
client_id,
154-
code=None,
155-
access_token=None,
156-
user_info=None,
157-
sign=True,
158-
encrypt=False,
159-
lifetime=None,
160-
extra_claims=None,
151+
self,
152+
session_info,
153+
client_id,
154+
code=None,
155+
access_token=None,
156+
user_info=None,
157+
sign=True,
158+
encrypt=False,
159+
lifetime=None,
160+
extra_claims=None,
161161
):
162162
"""
163163
Signed and or encrypt a IDToken
@@ -222,7 +222,8 @@ def make(self, req, sess_info, authn_req=None, user_claims=False, **kwargs):
222222
)
223223

224224
if user_claims:
225-
info = collect_user_info(_context, sess_info)
225+
info = collect_user_info(_context, sess_info,
226+
scope_to_claims=self.scope_to_claims)
226227
if userinfo is None:
227228
userinfo = info
228229
else:

src/oidcendpoint/jwt_token.py

Lines changed: 26 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,28 @@
11
from typing import Any
22
from typing import Dict
3-
from typing import List
43
from typing import Optional
54

65
from cryptojwt import JWT
7-
from oidcmsg.oidc import scope2claims
86

97
from oidcendpoint.exception import ToOld
108
from oidcendpoint.token_handler import Token
119
from oidcendpoint.token_handler import is_expired
10+
from oidcendpoint.user_info import scope2claims
1211

1312

1413
class JWTToken(Token):
1514
def __init__(
16-
self,
17-
typ,
18-
black_list=None,
19-
keyjar=None,
20-
issuer=None,
21-
aud=None,
22-
alg="ES256",
23-
lifetime=300,
24-
ec=None,
25-
token_type="Bearer",
26-
**kwargs
15+
self,
16+
typ,
17+
black_list=None,
18+
keyjar=None,
19+
issuer=None,
20+
aud=None,
21+
alg="ES256",
22+
lifetime=300,
23+
ec=None,
24+
token_type="Bearer",
25+
**kwargs
2726
):
2827
Token.__init__(self, typ, black_list, **kwargs)
2928
self.token_type = token_type
@@ -35,6 +34,10 @@ def __init__(
3534

3635
self.def_aud = aud or []
3736
self.alg = alg
37+
if 'scope_claims_map' in kwargs:
38+
self.scope_claims_map = kwargs['scope_claims_map']
39+
else:
40+
self.scope_claims_map = None
3841

3942
def add_claims(self, payload, uinfo, claims):
4043
for attr in claims:
@@ -46,13 +49,13 @@ def add_claims(self, payload, uinfo, claims):
4649
pass
4750

4851
def __call__(
49-
self,
50-
sid: str,
51-
uinfo: Dict,
52-
sinfo: Dict,
53-
*args,
54-
aud: Optional[Any],
55-
**kwargs
52+
self,
53+
sid: str,
54+
uinfo: Dict,
55+
sinfo: Dict,
56+
*args,
57+
aud: Optional[Any],
58+
**kwargs
5659
):
5760
"""
5861
Return a token.
@@ -69,7 +72,9 @@ def __call__(
6972
self.add_claims(payload, uinfo, self.args["add_claims"])
7073
if "add_claims_by_scope":
7174
self.add_claims(
72-
payload, uinfo, scope2claims(sinfo["authn_req"]["scope"]).keys()
75+
payload, uinfo,
76+
scope2claims(sinfo["authn_req"]["scope"],
77+
map=self.scope_claims_map).keys()
7378
)
7479

7580
payload.update(kwargs)

src/oidcendpoint/oidc/read_registration.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
from oic.oauth2 import ErrorResponse
21
from oidcmsg.message import Message
2+
from oidcmsg.oauth2 import ResponseMessage
33
from oidcmsg.oidc import RegistrationResponse
44

55
from oidcendpoint.endpoint import Endpoint
@@ -9,7 +9,7 @@
99
class RegistrationRead(Endpoint):
1010
request_cls = Message
1111
response_cls = RegistrationResponse
12-
error_response = ErrorResponse
12+
error_response = ResponseMessage
1313
request_format = "urlencoded"
1414
request_placement = "url"
1515
response_format = "json"

src/oidcendpoint/oidc/userinfo.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22
import logging
33

44
from cryptojwt.exception import MissingValue
5-
from oidcmsg import oidc
65
from cryptojwt.jwt import JWT
6+
from oidcmsg import oidc
77
from oidcmsg.message import Message
88
from oidcmsg.oauth2 import ResponseMessage
99
from oidcmsg.time_util import time_sans_frac
@@ -24,6 +24,10 @@ class UserInfo(Endpoint):
2424
endpoint_name = "userinfo_endpoint"
2525
name = "userinfo"
2626

27+
def __init__(self, endpoint_context, **kwargs):
28+
Endpoint.__init__(self, endpoint_context, **kwargs)
29+
self.scope_to_claims = None
30+
2731
def get_client_id_from_token(self, endpoint_context, token, request=None):
2832
sinfo = self.endpoint_context.sdb[token]
2933
return sinfo["authn_req"]["client_id"]
@@ -104,7 +108,8 @@ def process_request(self, request=None, **kwargs):
104108

105109
if allowed:
106110
# Scope can translate to userinfo_claims
107-
info = collect_user_info(self.endpoint_context, session)
111+
info = collect_user_info(self.endpoint_context, session,
112+
scope_to_claims=self.scope_to_claims)
108113
else:
109114
info = {
110115
"error": "invalid_request",

src/oidcendpoint/sso_db.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,12 @@
1+
import logging
12
from oidcendpoint.in_memory_db import InMemoryDataBase
23

34
KEY_FORMAT = "__{}__{}"
45

56

7+
logger = logging.getLogger(__name__)
8+
9+
610
class SSODb(object):
711
"""
812
Keeps the connection between an user, one or more sub claims and
@@ -19,6 +23,7 @@ def __init__(self, db=None):
1923
self._db = db or InMemoryDataBase()
2024

2125
def set(self, label, key, value):
26+
logger.debug("SSODb set {}: {}".format(key, value))
2227
_key = KEY_FORMAT.format(label, key)
2328
_values = self._db.get(_key)
2429
if not _values:
@@ -29,7 +34,9 @@ def set(self, label, key, value):
2934

3035
def get(self, label, key):
3136
_key = KEY_FORMAT.format(label, key)
32-
return self._db.get(_key)
37+
value = self._db.get(_key)
38+
logger.debug("SSODb get {} [{}]".format(key, value))
39+
return value
3340

3441
def delete(self, label, key):
3542
_key = KEY_FORMAT.format(label, key)

src/oidcendpoint/user_info/__init__.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,3 +77,30 @@ def search(self, **kwargs):
7777
return uid
7878

7979
raise KeyError("No matching user")
80+
81+
82+
SCOPE2CLAIMS = {
83+
"openid": ["sub"],
84+
"profile": ["name", "given_name", "family_name", "middle_name",
85+
"nickname", "profile", "picture", "website", "gender",
86+
"birthdate", "zoneinfo", "locale", "updated_at",
87+
"preferred_username"],
88+
"email": ["email", "email_verified"],
89+
"address": ["address"],
90+
"phone": ["phone_number", "phone_number_verified"],
91+
"offline_access": []
92+
}
93+
94+
95+
def scope2claims(scopes, map=None):
96+
if map is None:
97+
map = SCOPE2CLAIMS
98+
99+
res = {}
100+
for scope in scopes:
101+
try:
102+
claims = dict([(name, None) for name in map[scope]])
103+
res.update(claims)
104+
except KeyError:
105+
continue
106+
return res

0 commit comments

Comments
 (0)