Skip to content

Commit b87e8e9

Browse files
committed
Moved things into better places.
1 parent 80f26e2 commit b87e8e9

File tree

10 files changed

+310
-98
lines changed

10 files changed

+310
-98
lines changed

src/idpyoidc/configure.py

Lines changed: 38 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,7 @@
55
from typing import Optional
66
from typing import Union
77

8-
from cryptojwt.key_jar import init_key_jar
9-
108
from idpyoidc.logging import configure_logging
11-
from idpyoidc.util import instantiate
129
from idpyoidc.util import load_config_file
1310

1411
DEFAULT_FILE_ATTRIBUTE_NAMES = [
@@ -97,13 +94,13 @@ class Base(dict):
9794
parameter = {}
9895

9996
def __init__(
100-
self,
101-
conf: Dict,
102-
base_path: str = "",
103-
file_attributes: Optional[List[str]] = None,
104-
dir_attributes: Optional[List[str]] = None,
105-
domain: Optional[str] = "",
106-
port: Optional[int] = 0,
97+
self,
98+
conf: Dict,
99+
base_path: str = "",
100+
file_attributes: Optional[List[str]] = None,
101+
dir_attributes: Optional[List[str]] = None,
102+
domain: Optional[str] = "",
103+
port: Optional[int] = 0,
107104
):
108105
dict.__init__(self)
109106
if file_attributes is None:
@@ -150,14 +147,14 @@ def items(self):
150147
yield key, getattr(self, key)
151148

152149
def extend(
153-
self,
154-
conf: Dict,
155-
base_path: str,
156-
domain: str,
157-
port: int,
158-
entity_conf: Optional[List[dict]] = None,
159-
file_attributes: Optional[List[str]] = None,
160-
dir_attributes: Optional[List[str]] = None,
150+
self,
151+
conf: Dict,
152+
base_path: str,
153+
domain: str,
154+
port: int,
155+
entity_conf: Optional[List[dict]] = None,
156+
file_attributes: Optional[List[str]] = None,
157+
dir_attributes: Optional[List[str]] = None,
161158
):
162159
for econf in entity_conf:
163160
_path = econf.get("path")
@@ -198,13 +195,13 @@ def complete_paths(self, conf: Dict, keys: List[str], default_config: Dict, base
198195
setattr(self, key, _val)
199196

200197
def format(
201-
self,
202-
conf,
203-
base_path: str,
204-
domain: str,
205-
port: int,
206-
file_attributes: Optional[List[str]] = None,
207-
dir_attributes: Optional[List[str]] = None,
198+
self,
199+
conf,
200+
base_path: str,
201+
domain: str,
202+
port: int,
203+
file_attributes: Optional[List[str]] = None,
204+
dir_attributes: Optional[List[str]] = None,
208205
) -> Union[Dict, str]:
209206
"""
210207
Formats parts of the configuration. That includes replacing the strings {domain} and {port}
@@ -239,14 +236,14 @@ class Configuration(Base):
239236
uris = ["redirect_uris", "issuer", "base_url", "server_name"]
240237

241238
def __init__(
242-
self,
243-
conf: Dict,
244-
base_path: str = "",
245-
entity_conf: Optional[List[dict]] = None,
246-
file_attributes: Optional[List[str]] = None,
247-
domain: Optional[str] = "",
248-
port: Optional[int] = 0,
249-
dir_attributes: Optional[List[str]] = None,
239+
self,
240+
conf: Dict,
241+
base_path: str = "",
242+
entity_conf: Optional[List[dict]] = None,
243+
file_attributes: Optional[List[str]] = None,
244+
domain: Optional[str] = "",
245+
port: Optional[int] = 0,
246+
dir_attributes: Optional[List[str]] = None,
250247
):
251248
Base.__init__(
252249
self,
@@ -293,14 +290,14 @@ def __init__(
293290

294291

295292
def create_from_config_file(
296-
cls,
297-
filename: str,
298-
base_path: Optional[str] = "",
299-
entity_conf: Optional[List[dict]] = None,
300-
file_attributes: Optional[List[str]] = None,
301-
domain: Optional[str] = "",
302-
port: Optional[int] = 0,
303-
dir_attributes: Optional[List[str]] = None,
293+
cls,
294+
filename: str,
295+
base_path: Optional[str] = "",
296+
entity_conf: Optional[List[dict]] = None,
297+
file_attributes: Optional[List[str]] = None,
298+
domain: Optional[str] = "",
299+
port: Optional[int] = 0,
300+
dir_attributes: Optional[List[str]] = None,
304301
):
305302
return cls(
306303
load_config_file(filename),
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
import logging
2+
from typing import Callable
3+
from typing import Optional
4+
5+
from idpyoidc.message import OPTIONAL_LIST_OF_STRINGS
6+
from idpyoidc.message.oidc import RegistrationResponse
7+
from idpyoidc.message.oidc import SINGLE_OPTIONAL_BOOLEAN
8+
from idpyoidc.message.oidc import SINGLE_OPTIONAL_DICT
9+
from idpyoidc.server.session.token import TOKEN_MAP
10+
11+
logger = logging.getLogger(__name__)
12+
13+
14+
class ClientConfiguration(RegistrationResponse):
15+
c_param = RegistrationResponse.c_param.copy()
16+
c_param.update({
17+
"token_usage_rules": SINGLE_OPTIONAL_DICT,
18+
"token_exchange": SINGLE_OPTIONAL_DICT,
19+
"add_claims": SINGLE_OPTIONAL_DICT,
20+
"pkce_essential": SINGLE_OPTIONAL_BOOLEAN,
21+
"revoke_refresh_on_issue": SINGLE_OPTIONAL_BOOLEAN,
22+
"allowed_scopes": OPTIONAL_LIST_OF_STRINGS,
23+
"scopes_to_claims": SINGLE_OPTIONAL_DICT,
24+
#
25+
# These may be added dynamically at run time
26+
# "dpop_jkt": SINGLE_OPTIONAL_STRING,
27+
# "si_redirects": OPTIONAL_LIST_OF_STRINGS,
28+
# "sector_id": SINGLE_OPTIONAL_STRING,
29+
# "client_secret_expires_at": SINGLE_OPTIONAL_INT,
30+
# "registration_access_token": SINGLE_OPTIONAL_STRING
31+
# "auth_method": SINGLE_OPTIONAL_DICT,
32+
})
33+
34+
def verify(self, **kwargs):
35+
RegistrationResponse.verify(self, **kwargs)
36+
_server_get = kwargs.get("server_get")
37+
if _server_get:
38+
_endpoint_context = _server_get("endpoint_context")
39+
else:
40+
_endpoint_context = None
41+
42+
if "add_claims" in self:
43+
if not set(self["add_claims"].keys()).issubset({"always", "by_scope"}):
44+
_diff = set(self["add_claims"].keys()).difference({"always", "by_scope"})
45+
logger.warning(f"Undefined add_claims parameter '{_diff}' used")
46+
47+
if "token_usage_rules" in self:
48+
for _typ, _rule in self["token_usage_rules"].items():
49+
# The allowed rules are: expires_in, supports_minting, max_usage
50+
if _typ not in TOKEN_MAP.keys():
51+
logger.warning(f"Undefined token type '{_typ}' used")
52+
53+
if not set(_rule.keys()).issubset({'expires_in', 'supports_minting', 'max_usage'}):
54+
_diff = set(_rule.keys()).difference(
55+
{'expires_in', 'supports_minting', 'max_usage'})
56+
logger.warning(f"Undefined token_usage_rules parameter '{_diff}' used")
57+
58+
_supports = _rule.get("supports_minting")
59+
if _supports:
60+
if not set(_supports).issubset(set(TOKEN_MAP.keys())):
61+
_diff = set(_supports).difference(set(TOKEN_MAP.keys()))
62+
logger.warning(f"Unknown supports_minting token '{_diff}' used")
63+
64+
if "token_exchange" in self:
65+
pass
66+
67+
68+
def verify_oidc_client_information(conf: dict,
69+
server_get: Optional[Callable] = None,
70+
**kwargs) -> dict:
71+
res = {}
72+
for key, item in conf.items():
73+
_rr = ClientConfiguration(**item)
74+
_rr.verify(server_get=server_get, **kwargs)
75+
if _rr.extra():
76+
logger.info(f"Extras: {_rr.extra()}")
77+
res[key] = _rr
78+
79+
return res

src/idpyoidc/server/configure.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
from idpyoidc.configure import Base
1010
from idpyoidc.server.scopes import SCOPE2CLAIMS
11-
from idpyoidc.util import verify_oidc_client_information
11+
from idpyoidc.server.client_configure import verify_oidc_client_information
1212

1313
logger = logging.getLogger(__name__)
1414

src/idpyoidc/server/oauth2/token_helper.py

Lines changed: 29 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,9 @@
1616
from idpyoidc.server.exception import ToOld
1717
from idpyoidc.server.exception import UnAuthorizedClientScope
1818
from idpyoidc.server.oauth2.authorization import check_unknown_scopes_policy
19-
from idpyoidc.server.session.grant import AuthorizationCode
2019
from idpyoidc.server.session.grant import Grant
21-
from idpyoidc.server.session.grant import RefreshToken
20+
from idpyoidc.server.session.token import AuthorizationCode
21+
from idpyoidc.server.session.token import RefreshToken
2222
from idpyoidc.server.session.token import MintingNotAllowed
2323
from idpyoidc.server.session.token import SessionToken
2424
from idpyoidc.server.token.exception import UnknownToken
@@ -36,7 +36,7 @@ def __init__(self, endpoint, config=None):
3636
self.error_cls = self.endpoint.error_cls
3737

3838
def post_parse_request(
39-
self, request: Union[Message, dict], client_id: Optional[str] = "", **kwargs
39+
self, request: Union[Message, dict], client_id: Optional[str] = "", **kwargs
4040
):
4141
"""Context specific parsing of the request.
4242
This is done after general request parsing and before processing
@@ -49,15 +49,15 @@ def process_request(self, req: Union[Message, dict], **kwargs):
4949
raise NotImplementedError
5050

5151
def _mint_token(
52-
self,
53-
token_class: str,
54-
grant: Grant,
55-
session_id: str,
56-
client_id: str,
57-
based_on: Optional[SessionToken] = None,
58-
scope: Optional[list] = None,
59-
token_args: Optional[dict] = None,
60-
token_type: Optional[str] = "",
52+
self,
53+
token_class: str,
54+
grant: Grant,
55+
session_id: str,
56+
client_id: str,
57+
based_on: Optional[SessionToken] = None,
58+
scope: Optional[list] = None,
59+
token_args: Optional[dict] = None,
60+
token_type: Optional[str] = "",
6161
) -> SessionToken:
6262
_context = self.endpoint.server_get("endpoint_context")
6363
_mngr = _context.session_manager
@@ -171,9 +171,9 @@ def process_request(self, req: Union[Message, dict], **kwargs):
171171
_response["expires_in"] = token.expires_at - utc_time_sans_frac()
172172

173173
if (
174-
issue_refresh
175-
and "refresh_token" in _supports_minting
176-
and "refresh_token" in grant_types_supported
174+
issue_refresh
175+
and "refresh_token" in _supports_minting
176+
and "refresh_token" in grant_types_supported
177177
):
178178
try:
179179
refresh_token = self._mint_token(
@@ -196,7 +196,7 @@ def process_request(self, req: Union[Message, dict], **kwargs):
196196
return _response
197197

198198
def post_parse_request(
199-
self, request: Union[Message, dict], client_id: Optional[str] = "", **kwargs
199+
self, request: Union[Message, dict], client_id: Optional[str] = "", **kwargs
200200
):
201201
"""
202202
This is where clients come to get their access tokens
@@ -300,9 +300,9 @@ def process_request(self, req: Union[Message, dict], **kwargs):
300300
token.register_usage()
301301

302302
if (
303-
"client_id" in req
304-
and req["client_id"] in _context.cdb
305-
and "revoke_refresh_on_issue" in _context.cdb[req["client_id"]]
303+
"client_id" in req
304+
and req["client_id"] in _context.cdb
305+
and "revoke_refresh_on_issue" in _context.cdb[req["client_id"]]
306306
):
307307
revoke_refresh = _context.cdb[req["client_id"]].get("revoke_refresh_on_issue")
308308
else:
@@ -314,7 +314,7 @@ def process_request(self, req: Union[Message, dict], **kwargs):
314314
return _resp
315315

316316
def post_parse_request(
317-
self, request: Union[Message, dict], client_id: Optional[str] = "", **kwargs
317+
self, request: Union[Message, dict], client_id: Optional[str] = "", **kwargs
318318
):
319319
"""
320320
This is where clients come to refresh their access tokens
@@ -405,10 +405,10 @@ def post_parse_request(self, request, client_id="", **kwargs):
405405
try:
406406
request.verify(keyjar=keyjar, opponent_id=client_id)
407407
except (
408-
MissingRequiredAttribute,
409-
ValueError,
410-
MissingRequiredValue,
411-
JWKESTException,
408+
MissingRequiredAttribute,
409+
ValueError,
410+
MissingRequiredValue,
411+
JWKESTException,
412412
) as err:
413413
return self.endpoint.error_cls(error="invalid_request", error_description="%s" % err)
414414

@@ -449,8 +449,8 @@ def _enforce_policy(self, request, token, config):
449449
)
450450

451451
if (
452-
"requested_token_type" in request
453-
and request["requested_token_type"] not in config["requested_token_types_supported"]
452+
"requested_token_type" in request
453+
and request["requested_token_type"] not in config["requested_token_types_supported"]
454454
):
455455
return TokenErrorResponse(
456456
error="invalid_request",
@@ -605,14 +605,14 @@ def validate_token_exchange_policy(request, context, subject_token, **kwargs):
605605
)
606606

607607
if (
608-
"requested_token_type" in request
609-
and request["requested_token_type"] == "urn:ietf:params:oauth:token-type:refresh_token"
608+
"requested_token_type" in request
609+
and request["requested_token_type"] == "urn:ietf:params:oauth:token-type:refresh_token"
610610
):
611611
if "offline_access" not in subject_token.scope:
612612
return TokenErrorResponse(
613613
error="invalid_request",
614614
error_description=f"Exchange {request['subject_token_type']} to refresh token "
615-
f"forbbiden",
615+
f"forbbiden",
616616
)
617617

618618
if "scope" in request:

src/idpyoidc/server/oidc/token_helper.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@
1010
from idpyoidc.message.oidc import RefreshAccessTokenRequest
1111
from idpyoidc.server import oauth2
1212
from idpyoidc.server.oauth2.token_helper import TokenEndpointHelper
13-
from idpyoidc.server.session.grant import AuthorizationCode
14-
from idpyoidc.server.session.grant import RefreshToken
13+
from idpyoidc.server.session.token import AuthorizationCode
14+
from idpyoidc.server.session.token import RefreshToken
1515
from idpyoidc.server.session.token import MintingNotAllowed
1616
from idpyoidc.server.token.exception import UnknownToken
1717
from idpyoidc.util import sanitize

src/idpyoidc/server/session/grant.py

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,14 @@
99
from idpyoidc.message import Message
1010
from idpyoidc.message.oauth2 import AuthorizationRequest
1111
from idpyoidc.server.authn_event import AuthnEvent
12+
from idpyoidc.server.session.token import TOKEN_MAP
1213
from idpyoidc.server.token import Token as TokenHandler
1314
from idpyoidc.util import importer
1415

1516
from ...message.oauth2 import TokenExchangeRequest
1617
from . import MintingNotAllowed
1718
from .claims import claims_match
18-
from .token import AccessToken
19-
from .token import AuthorizationCode
20-
from .token import IDToken
2119
from .token import Item
22-
from .token import RefreshToken
2320
from .token import SessionToken
2421

2522
logger = logging.getLogger(__name__)
@@ -54,14 +51,6 @@ def find_token(issued, token_id):
5451
return None
5552

5653

57-
TOKEN_MAP = {
58-
"authorization_code": AuthorizationCode,
59-
"access_token": AccessToken,
60-
"refresh_token": RefreshToken,
61-
"id_token": IDToken,
62-
}
63-
64-
6554
def qualified_name(cls):
6655
"""Does both classes and class instances
6756

0 commit comments

Comments
 (0)