Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Identity Assurance support has been out in the cold. Time to bring it in again. #83

Merged
merged 18 commits into from
Nov 23, 2023
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
2 changes: 1 addition & 1 deletion demo/oauth2_add_on_dpop.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from common import KEYDEFS
from common import full_path
from flow import Flow
from idpyoidc.claims import get_signing_algs
from idpyoidc.metadata import get_signing_algs
from idpyoidc.client.oauth2 import Client
from idpyoidc.server import Server
from idpyoidc.server.configure import ASConfiguration
Expand Down
2 changes: 1 addition & 1 deletion demo/oidc_add_on_dpop.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from common import KEYDEFS
from common import full_path
from flow import Flow
from idpyoidc.claims import get_signing_algs
from idpyoidc.metadata import get_signing_algs
from idpyoidc.client.oauth2 import Client
from idpyoidc.server import Server
from idpyoidc.server.configure import ASConfiguration
Expand Down
2 changes: 1 addition & 1 deletion example/flask_op/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@
"server_info": {
"add_on": {
"pkce": {
"function": "idpyoidc.server.oidc.add_on.pkce.add_pkce_support",
"function": "idpyoidc.server.oauth2.add_on.pkce.add_support",
"kwargs": {
"essential": false,
"code_challenge_method": "S256 S384 S512"
Expand Down
2 changes: 1 addition & 1 deletion src/idpyoidc/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
__author__ = "Roland Hedberg"
__version__ = "2.1.0"
__version__ = "2.2.0"

VERIFIED_CLAIM_PREFIX = "__verified"

Expand Down
42 changes: 0 additions & 42 deletions src/idpyoidc/claims.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
from functools import cmp_to_key
from typing import Callable
from typing import Optional

from cryptojwt import KeyJar
from cryptojwt.jwe import SUPPORTED
from cryptojwt.jws.jws import SIGNER_ALGS
from cryptojwt.key_jar import init_key_jar
from cryptojwt.utils import importer

Expand Down Expand Up @@ -215,42 +212,3 @@ def get_claim(self, key, default=None):
return default
else:
return _val


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


def cmp(a, b):
return (a > b) - (a < b)


def alg_cmp(a, b):
if a == "none":
return 1
elif b == "none":
return -1

_pos1 = SIGNING_ALGORITHM_SORT_ORDER.index(a[0:2])
_pos2 = SIGNING_ALGORITHM_SORT_ORDER.index(b[0:2])
if _pos1 == _pos2:
return (a > b) - (a < b)
elif _pos1 > _pos2:
return 1
else:
return -1


def get_signing_algs():
# Assumes Cryptojwt
_list = list(SIGNER_ALGS.keys())
# know how to do none but should not
_list.remove("none")
return sorted(_list, key=cmp_to_key(alg_cmp))


def get_encryption_algs():
return SUPPORTED["alg"]


def get_encryption_encs():
return SUPPORTED["enc"]
8 changes: 4 additions & 4 deletions src/idpyoidc/client/claims/oidc.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import os
from typing import Optional

from idpyoidc import claims
from idpyoidc import metadata
from idpyoidc.client import claims as client_claims
from idpyoidc.client.claims.transform import create_registration_request
from idpyoidc.message.oidc import RegistrationRequest
Expand Down Expand Up @@ -75,9 +75,9 @@ class Claims(client_claims.Claims):
"encrypt_id_token_supported": None,
# "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,
"id_token_encryption_enc_values_supported": claims.get_encryption_encs,
"id_token_signing_alg_values_supported": metadata.get_signing_algs,
"id_token_encryption_alg_values_supported": metadata.get_encryption_algs,
"id_token_encryption_enc_values_supported": metadata.get_encryption_encs,
"initiate_login_uri": None,
"jwks": None,
"jwks_uri": None,
Expand Down
5 changes: 3 additions & 2 deletions src/idpyoidc/client/client_auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,15 @@

from idpyoidc.defaults import DEF_SIGN_ALG
from idpyoidc.defaults import JWT_BEARER
from idpyoidc.message.oauth2 import AccessTokenRequest
from idpyoidc.message.oauth2 import SINGLE_OPTIONAL_STRING
from idpyoidc.message.oauth2 import AccessTokenRequest
from idpyoidc.message.oidc import AuthnToken
from idpyoidc.time_util import utc_time_sans_frac
from idpyoidc.util import rndstr
from .util import sanitize

from ..message import VREQUIRED
from ..util import instantiate
from .util import sanitize

# from idpyoidc.oidc.backchannel_authentication import ClientNotificationAuthn

Expand Down
1 change: 1 addition & 0 deletions src/idpyoidc/client/configure.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

from idpyoidc.configure import Base
from idpyoidc.logging import configure_logging

from .util import lower_or_upper

try:
Expand Down
1 change: 1 addition & 0 deletions src/idpyoidc/client/entity.py
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,7 @@ def __init__(
keyjar=self.keyjar,
upstream_get=self.unit_get,
client_type=client_type,
entity_id=self.entity_id,
)

self.setup_client_authn_methods(config)
Expand Down
2 changes: 1 addition & 1 deletion src/idpyoidc/client/http.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@
from http.cookies import CookieError
from http.cookies import SimpleCookie

from requests import request
from idpyoidc.client.exception import NonFatalException
from idpyoidc.client.util import sanitize
from idpyoidc.client.util import set_cookie
from requests import request

__author__ = "roland"

Expand Down
91 changes: 47 additions & 44 deletions src/idpyoidc/client/oauth2/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,22 @@
from typing import Union

from cryptojwt.key_jar import KeyJar
from requests import request

from idpyoidc.client.entity import Entity
from idpyoidc.client.exception import ConfigurationError
from idpyoidc.client.exception import OidcServiceError
from idpyoidc.client.exception import ParseError
from idpyoidc.client.service import REQUEST_INFO
from idpyoidc.client.service import Service
from idpyoidc.client.service import SUCCESSFUL
from idpyoidc.client.service import Service
from idpyoidc.client.util import do_add_ons
from idpyoidc.client.util import get_deserialization_method
from idpyoidc.configure import Configuration
from idpyoidc.context import OidcContext
from idpyoidc.exception import FormatError
from idpyoidc.message import Message
from idpyoidc.message.oauth2 import is_error_message
from requests import request

__author__ = "Roland Hedberg"

Expand All @@ -38,20 +38,20 @@ class Client(Entity):
client_type = "oauth2"

def __init__(
self,
keyjar: Optional[KeyJar] = None,
config: Optional[Union[dict, Configuration]] = None,
services: Optional[dict] = None,
httpc: Optional[Callable] = None,
httpc_params: Optional[dict] = None,
context: Optional[OidcContext] = None,
upstream_get: Optional[Callable] = None,
key_conf: Optional[dict] = None,
entity_id: Optional[str] = "",
verify_ssl: Optional[bool] = True,
jwks_uri: Optional[str] = "",
client_type: Optional[str] = "",
**kwargs
self,
keyjar: Optional[KeyJar] = None,
config: Optional[Union[dict, Configuration]] = None,
services: Optional[dict] = None,
httpc: Optional[Callable] = None,
httpc_params: Optional[dict] = None,
context: Optional[OidcContext] = None,
upstream_get: Optional[Callable] = None,
key_conf: Optional[dict] = None,
entity_id: Optional[str] = "",
verify_ssl: Optional[bool] = True,
jwks_uri: Optional[str] = "",
client_type: Optional[str] = "",
**kwargs
):
"""

Expand All @@ -68,9 +68,12 @@ def __init__(
:return: Client instance
"""

if config is None:
config = {}

if client_type:
self.client_type = client_type
elif config and 'client_type' in config:
elif config and "client_type" in config:
client_type = self.client_type = config["client_type"]
else:
client_type = self.client_type
Expand All @@ -82,7 +85,7 @@ def __init__(
else:
httpc_params = {"verify": False}

jwks_uri = jwks_uri or config.get('jwks_uri', '')
jwks_uri = jwks_uri or config.get("jwks_uri", "")

Entity.__init__(
self,
Expand Down Expand Up @@ -110,12 +113,12 @@ def __init__(
do_add_ons(_add_ons, self._service)

def do_request(
self,
request_type: str,
response_body_type: Optional[str] = "",
request_args: Optional[dict] = None,
behaviour_args: Optional[dict] = None,
**kwargs
self,
request_type: str,
response_body_type: Optional[str] = "",
request_args: Optional[dict] = None,
behaviour_args: Optional[dict] = None,
**kwargs
):
_srv = self._service[request_type]

Expand All @@ -138,14 +141,14 @@ def set_client_id(self, client_id):
self.get_context().set("client_id", client_id)

def get_response(
self,
service: Service,
url: str,
method: Optional[str] = "GET",
body: Optional[dict] = None,
response_body_type: Optional[str] = "",
headers: Optional[dict] = None,
**kwargs
self,
service: Service,
url: str,
method: Optional[str] = "GET",
body: Optional[dict] = None,
response_body_type: Optional[str] = "",
headers: Optional[dict] = None,
**kwargs
):
"""

Expand Down Expand Up @@ -181,14 +184,14 @@ def get_response(
return self.parse_request_response(service, resp, response_body_type, **kwargs)

def service_request(
self,
service: Service,
url: str,
method: Optional[str] = "GET",
body: Optional[dict] = None,
response_body_type: Optional[str] = "",
headers: Optional[dict] = None,
**kwargs
self,
service: Service,
url: str,
method: Optional[str] = "GET",
body: Optional[dict] = None,
response_body_type: Optional[str] = "",
headers: Optional[dict] = None,
**kwargs
) -> Message:
"""
The method that sends the request and handles the response returned.
Expand Down Expand Up @@ -317,10 +320,10 @@ def dynamic_provider_info_discovery(client: Client, behaviour_args: Optional[dic
:param client: A :py:class:`idpyoidc.client.oidc.Client` instance
"""

if client.client_type == 'oidc' and client.get_service("provider_info"):
service = 'provider_info'
elif client.client_type == 'oauth2' and client.get_service('server_metadata'):
service = 'server_metadata'
if client.client_type == "oidc" and client.get_service("provider_info"):
service = "provider_info"
elif client.client_type == "oauth2" and client.get_service("server_metadata"):
service = "server_metadata"
else:
raise ConfigurationError("Can not do dynamic provider info discovery")

Expand Down
2 changes: 1 addition & 1 deletion src/idpyoidc/client/oauth2/access_token.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@
from idpyoidc.client.service import Service
from idpyoidc.message import oauth2
from idpyoidc.message.oauth2 import ResponseMessage
from idpyoidc.metadata import get_signing_algs
from idpyoidc.time_util import time_sans_frac
from idpyoidc.claims import get_signing_algs

LOGGER = logging.getLogger(__name__)

Expand Down
4 changes: 1 addition & 3 deletions src/idpyoidc/client/oauth2/add_on/dpop.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,18 @@
from hashlib import sha256
from typing import Optional

from cryptography.hazmat.primitives import hashes
from cryptojwt.jwk.jwk import key_from_jwk_dict
from cryptojwt.jws.jws import JWS
from cryptojwt.jws.jws import factory
from cryptojwt.jws.jws import SIGNER_ALGS
from cryptojwt.key_bundle import key_by_alg

from idpyoidc.claims import get_signing_algs
from idpyoidc.client.service_context import ServiceContext
from idpyoidc.message import SINGLE_OPTIONAL_STRING
from idpyoidc.message import SINGLE_REQUIRED_INT
from idpyoidc.message import SINGLE_REQUIRED_JSON
from idpyoidc.message import SINGLE_REQUIRED_STRING
from idpyoidc.message import Message
from idpyoidc.metadata import get_signing_algs
from idpyoidc.time_util import utc_time_sans_frac

logger = logging.getLogger(__name__)
Expand Down
5 changes: 3 additions & 2 deletions src/idpyoidc/client/oauth2/add_on/jar.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
from typing import Optional

from idpyoidc import claims
from idpyoidc import metadata
from idpyoidc.client.oidc.utils import construct_request_uri
from idpyoidc.client.oidc.utils import request_object_encryption
from idpyoidc.message.oidc import make_openid_request
Expand Down Expand Up @@ -207,8 +208,8 @@ def add_support(
args["request_dir"] = request_dir

if request_object_encryption_enc and request_object_encryption_alg:
if request_object_encryption_enc in claims.get_encryption_encs():
if request_object_encryption_alg in claims.get_encryption_algs():
if request_object_encryption_enc in metadata.get_encryption_encs():
if request_object_encryption_alg in metadata.get_encryption_algs():
args["request_object_encryption_enc"] = request_object_encryption_enc
args["request_object_encryption_alg"] = request_object_encryption_alg
else:
Expand Down
2 changes: 1 addition & 1 deletion src/idpyoidc/client/oauth2/add_on/par.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@

from cryptojwt import JWT
from cryptojwt.utils import importer
from requests import request

from idpyoidc.client.client_auth import CLIENT_AUTHN_METHOD
from idpyoidc.message import Message
from idpyoidc.message.oauth2 import JWTSecuredAuthorizationRequest
from idpyoidc.util import instantiate
from requests import request

logger = logging.getLogger(__name__)

Expand Down
Loading
Loading