Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions src/idpyoidc/claims.py
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,15 @@ def supported(self, claim):
def prefers(self):
return self.prefer

def get_claim(self, key, default=None):
_val = self.get_usage(key)
if _val is None:
_val = self.get_preference(key)

if _val is None:
return default
else:
return _val

SIGNING_ALGORITHM_SORT_ORDER = ['RS', 'ES', 'PS', 'HS']

Expand Down
2 changes: 1 addition & 1 deletion src/idpyoidc/client/claims/oidc.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ class Claims(client_claims.Claims):
"contacts": None,
"default_max_age": 86400,
"encrypt_id_token_supported": None,
"grant_types_supported": ["authorization_code", "implicit", "refresh_token"],
# "grant_types_supported": ["authorization_code", "refresh_token"],
"logo_uri": None,
"id_token_signing_alg_values_supported": claims.get_signing_algs,
"id_token_encryption_alg_values_supported": claims.get_encryption_algs,
Expand Down
2 changes: 2 additions & 0 deletions src/idpyoidc/client/oauth2/access_token.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ class AccessToken(Service):
request_body_type = "urlencoded"
response_body_type = "json"

_include = {"grant_types_supported": ['authorization_code']}

_supports = {
"token_endpoint_auth_methods_supported": get_client_authn_methods,
"token_endpoint_auth_signing_alg": get_signing_algs,
Expand Down
43 changes: 43 additions & 0 deletions src/idpyoidc/client/oauth2/client_credentials.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import logging
from typing import Optional
from typing import Union

from idpyoidc.client.service import Service
from idpyoidc.message import Message
from idpyoidc.message import oauth2
from idpyoidc.time_util import time_sans_frac


class CCAccessTokenRequest(Service):
"""The service that talks to the OAuth2 client credentials endpoint."""

msg_type = oauth2.CCAccessTokenRequest
response_cls = oauth2.AccessTokenResponse
error_msg = oauth2.ResponseMessage
endpoint_name = "token_endpoint"
synchronous = True
service_name = "client_credentials"
default_authn_method = ""
http_method = "POST"

def __init__(self, upstream_get, conf=None):
Service.__init__(self, upstream_get, conf=conf)
self.pre_construct.append(self.cc_pre_construct)

def cc_pre_construct(self,
request: Union[Message, dict],
service: Service,
post_args: Optional[dict],
**_args):
_grant_type = request.get('grant_type')
if not _grant_type:
request['grant_type'] = 'client_credentials'
elif _grant_type != 'client_credentials':
logging.error('Wrong grant_type')

return request, post_args

def update_service_context(self, resp, key: Optional[str] = "", **kwargs):
if "expires_in" in resp:
resp["__expires_at"] = time_sans_frac() + int(resp["expires_in"])
self.upstream_get("context").cstate.update(key, resp)
27 changes: 0 additions & 27 deletions src/idpyoidc/client/oauth2/client_credentials/cc_access_token.py

This file was deleted.

This file was deleted.

2 changes: 2 additions & 0 deletions src/idpyoidc/client/oauth2/refresh_access_token.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ class RefreshAccessToken(Service):
default_authn_method = "bearer_header"
http_method = "POST"

_include = {"grant_types_supported": ['refresh_token']}

def __init__(self, upstream_get, conf=None):
Service.__init__(self, upstream_get, conf=conf)
self.pre_construct.append(self.oauth_pre_construct)
Expand Down
43 changes: 43 additions & 0 deletions src/idpyoidc/client/oauth2/resource_owner_password_credentials.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import logging
from typing import Optional
from typing import Union

from idpyoidc.client.service import Service
from idpyoidc.message import Message
from idpyoidc.message import oauth2
from idpyoidc.time_util import time_sans_frac


class ROPCAccessTokenRequest(Service):
"""The service uses the OAuth2 resource owner password credentials flow."""

msg_type = oauth2.ROPCAccessTokenRequest
response_cls = oauth2.AccessTokenResponse
error_msg = oauth2.ResponseMessage
endpoint_name = "token_endpoint"
synchronous = True
service_name = "resource_owner_password_credentials"
default_authn_method = ""
http_method = "POST"

def __init__(self, upstream_get, conf=None):
Service.__init__(self, upstream_get, conf=conf)
self.pre_construct.append(self.ropc_pre_construct)

def ropc_pre_construct(self,
request: Union[Message, dict],
service: Service,
post_args: Optional[dict],
**_args):
_grant_type = request.get('grant_type')
if not _grant_type:
request['grant_type'] = 'password'
elif _grant_type != 'password':
logging.error('Wrong grant_type')

return request, post_args

def update_service_context(self, resp, key: Optional[str] = "", **kwargs):
if "expires_in" in resp:
resp["__expires_at"] = time_sans_frac() + int(resp["expires_in"])
self.upstream_get("context").cstate.update(key, resp)
2 changes: 2 additions & 0 deletions src/idpyoidc/client/oauth2/token_exchange.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ class TokenExchange(Service):
request_body_type = "urlencoded"
response_body_type = "json"

_include = {'grant_types_supported': ['urn:ietf:params:oauth:grant-type:token-exchange']}

def __init__(self, upstream_get, conf=None):
Service.__init__(self, upstream_get, conf=conf)
self.pre_construct.append(self.oauth_pre_construct)
Expand Down
2 changes: 2 additions & 0 deletions src/idpyoidc/client/oidc/access_token.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ class AccessToken(access_token.AccessToken):
error_msg = oidc.ResponseMessage
default_authn_method = "client_secret_basic"

_include = {"grant_types_supported": ['authorization_code']}

_supports = {
"token_endpoint_auth_methods_supported": get_client_authn_methods,
"token_endpoint_auth_signing_alg_values_supported": get_signing_algs
Expand Down
1 change: 1 addition & 0 deletions src/idpyoidc/client/oidc/provider_info_discovery.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ class ProviderInfoDiscovery(server_metadata.ServerMetadata):
error_msg = ResponseMessage
service_name = "provider_info"

_include = {}
_supports = {}

def __init__(self, upstream_get, conf=None):
Expand Down
12 changes: 11 additions & 1 deletion src/idpyoidc/client/service.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
""" The basic Service class upon which all the specific services are built. """
import copy
import json
import logging
from typing import Callable
Expand All @@ -13,8 +14,8 @@
from idpyoidc.impexp import ImpExp
from idpyoidc.item import DLDict
from idpyoidc.message import Message
from idpyoidc.message.oauth2 import ResponseMessage
from idpyoidc.message.oauth2 import is_error_message
from idpyoidc.message.oauth2 import ResponseMessage
from idpyoidc.util import importer
from .client_auth import client_auth_setup
from .client_auth import method_to_item
Expand Down Expand Up @@ -68,6 +69,7 @@ class Service(ImpExp):

init_args = ["upstream_get"]

_include = {}
_supports = {}
_callback_path = {}

Expand Down Expand Up @@ -648,6 +650,14 @@ def supports(self):
res[key] = val
return res

def extends(self, info):
for claim, val in self._include.items():
if claim in info:
info[claim].extend(val)
else:
info[claim] = copy.copy(val)
return info

def get_callback_path(self, callback):
return self._callback_path.get(callback)

Expand Down
1 change: 1 addition & 0 deletions src/idpyoidc/client/service_context.py
Original file line number Diff line number Diff line change
Expand Up @@ -292,6 +292,7 @@ def supports(self):
else:
for service in services.values():
res.update(service.supports())
res = service.extends(res)
res.update(self.claims.supports())
return res

Expand Down
15 changes: 12 additions & 3 deletions src/idpyoidc/message/oauth2/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,8 @@ class ROPCAccessTokenRequest(Message):
"username": SINGLE_OPTIONAL_STRING,
"password": SINGLE_OPTIONAL_STRING,
"scope": OPTIONAL_LIST_OF_SP_SEP_STRINGS,
"client_id": SINGLE_OPTIONAL_STRING,
"client_secret": SINGLE_OPTIONAL_STRING,
}


Expand All @@ -295,9 +297,16 @@ class CCAccessTokenRequest(Message):
Client Credential grant flow access token request
"""

c_param = {"grant_type": SINGLE_REQUIRED_STRING, "scope": OPTIONAL_LIST_OF_SP_SEP_STRINGS}
c_default = {"grant_type": "client_credentials"}
c_allowed_values = {"grant_type": ["client_credentials"]}
c_param = {
"client_id": SINGLE_OPTIONAL_STRING,
"client_secret": SINGLE_OPTIONAL_STRING,
"grant_type": SINGLE_REQUIRED_STRING,
"scope": OPTIONAL_LIST_OF_SP_SEP_STRINGS
}

def verify(self, **kwargs):
if self['grant_type'] != 'client_credentials':
raise ValueError('Grant type MUST be client_credentials')


class RefreshAccessTokenRequest(Message):
Expand Down
2 changes: 1 addition & 1 deletion src/idpyoidc/message/oidc/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -911,7 +911,7 @@ class ProviderConfigurationResponse(ResponseMessage):
"request_parameter_supported": False,
"request_uri_parameter_supported": True,
"require_request_uri_registration": True,
"grant_types_supported": ["authorization_code", "implicit"],
"grant_types_supported": ["authorization_code"],
}

def verify(self, **kwargs):
Expand Down
2 changes: 2 additions & 0 deletions src/idpyoidc/server/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,8 @@ def __init__(
if _token_endp:
_token_endp.allow_refresh = allow_refresh_token(self.context)

self.context.map_supported_to_preferred()

def get_endpoints(self, *arg):
return self.endpoint

Expand Down
3 changes: 1 addition & 2 deletions src/idpyoidc/server/claims/oauth2.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,7 @@ class Claims(claims.Claims):
register2preferred = REGISTER2PREFERRED

_supports = {
# "client_authn_methods": get_client_authn_methods,
"grant_types_supported": ["authorization_code", "implicit", "refresh_token"],
"deny_unknown_scopes": False,
"response_types_supported": ["code"],
"response_modes_supported": ["code"],
"jwks_uri": None,
Expand Down
3 changes: 2 additions & 1 deletion src/idpyoidc/server/claims/oidc.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,10 @@ class Claims(server_claims.Claims):
# "client_authn_methods": get_client_authn_methods,
"contacts": None,
"default_max_age": 86400,
"deny_unknown_scopes": False,
"display_values_supported": None,
"encrypt_id_token_supported": None,
"grant_types_supported": ["authorization_code", "implicit", "refresh_token"],
# "grant_types_supported": ["authorization_code", "implicit", "refresh_token"],
"id_token_signing_alg_values_supported": claims.get_signing_algs,
"id_token_encryption_alg_values_supported": claims.get_encryption_algs,
"id_token_encryption_enc_values_supported": claims.get_encryption_encs,
Expand Down
13 changes: 4 additions & 9 deletions src/idpyoidc/server/configure.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,8 @@
logger = logging.getLogger(__name__)

OP_DEFAULT_CONFIG = {
"capabilities": {
"preference": {
"subject_types_supported": ["public", "pairwise"],
"grant_types_supported": [
"authorization_code",
"implicit",
"urn:ietf:params:oauth:grant-type:jwt-bearer",
"refresh_token",
],
},
"cookie_handler": {
"class": "idpyoidc.server.cookie_handler.CookieHandler",
Expand Down Expand Up @@ -157,6 +151,7 @@ class EntityConfiguration(Base):
"httpc_params": {},
"issuer": "",
"key_conf": None,
'preference': {},
"session_params": None,
"template_dir": None,
"token_handler_args": {},
Expand Down Expand Up @@ -344,11 +339,11 @@ def __init__(
},
}
},
"capabilities": {
"preference": {
"subject_types_supported": ["public", "pairwise"],
"grant_types_supported": [
"authorization_code",
"implicit",
# "implicit",
"urn:ietf:params:oauth:grant-type:jwt-bearer",
"refresh_token",
],
Expand Down
Loading