Skip to content
This repository has been archived by the owner on Jun 23, 2023. It is now read-only.

Commit

Permalink
Merge pull request #185 from IdentityPython/develop
Browse files Browse the repository at this point in the history
v2.4.1
  • Loading branch information
rohe authored Feb 4, 2022
2 parents 8de3acf + 59c1ba7 commit 11194bc
Show file tree
Hide file tree
Showing 8 changed files with 63 additions and 42 deletions.
14 changes: 10 additions & 4 deletions example/flask_op/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@
import werkzeug

from oidcop.exception import FailedAuthentication
from oidcop.exception import InvalidClient
from oidcop.exception import UnknownClient
from oidcop.exception import ClientAuthenticationError
from oidcop.exception import TokenAuthenticationError
from oidcop.oidc.token import Token

# logger = logging.getLogger(__name__)
Expand Down Expand Up @@ -224,12 +224,18 @@ def service_endpoint(endpoint):
if request.method == 'GET':
try:
req_args = endpoint.parse_request(request.args.to_dict(), http_info=http_info)
except (InvalidClient, UnknownClient) as err:
except ClientAuthenticationError as err:
_log.error(err)
return make_response(json.dumps({
'error': 'unauthorized_client',
'error_description': str(err)
}), 400)
}), 401)
except TokenAuthenticationError as err:
_log.error(err)
return make_response(json.dumps({
'error': 'invalid_token',
'error_description': str(err)
}), 401)
except Exception as err:
_log.error(err)
return make_response(json.dumps({
Expand Down
2 changes: 1 addition & 1 deletion src/oidcop/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import secrets

__version__ = "2.4.0"
__version__ = "2.4.1"

DEF_SIGN_ALG = {
"id_token": "RS256",
Expand Down
7 changes: 4 additions & 3 deletions src/oidcop/client_authn.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
from oidcop import JWT_BEARER
from oidcop import sanitize
from oidcop.endpoint_context import EndpointContext
from oidcop.exception import BearerTokenAuthenticationError
from oidcop.exception import InvalidClient
from oidcop.exception import MultipleUsage
from oidcop.exception import NotForMe
Expand Down Expand Up @@ -406,15 +407,15 @@ def verify_client(
elif not client_id and get_client_id_from_token:
if not _token:
logger.warning("No token")
raise ValueError("No token")
raise BearerTokenAuthenticationError("No token")

try:
# get_client_id_from_token is a callback... Do not abuse for code readability.
auth_info["client_id"] = get_client_id_from_token(endpoint_context, _token, request)
except ToOld:
raise ValueError("Expired token")
raise BearerTokenAuthenticationError("Expired token")
except KeyError:
raise ValueError("Unknown token")
raise BearerTokenAuthenticationError("Unknown token")

return auth_info

Expand Down
11 changes: 1 addition & 10 deletions src/oidcop/endpoint.py
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,6 @@ def parse_request(
req = self.request_cls()

# Verify that the client is allowed to do this
_client_id = ""
auth_info = self.client_authentication(req, http_info, endpoint=self, **kwargs)

if "client_id" in auth_info:
Expand Down Expand Up @@ -206,14 +205,6 @@ def parse_request(
request=req, client_id=_client_id, http_info=http_info, **kwargs
)

def get_client_id_from_token(
self,
endpoint_context: EndpointContext,
token: str,
request: Optional[Union[Message, dict]] = None,
):
return ""

def client_authentication(self, request: Message, http_info: Optional[dict] = None, **kwargs):
"""
Do client authentication
Expand All @@ -230,7 +221,7 @@ def client_authentication(self, request: Message, http_info: Optional[dict] = No
endpoint_context=self.server_get("endpoint_context"),
request=request,
http_info=http_info,
get_client_id_from_token=self.get_client_id_from_token,
get_client_id_from_token=getattr(self, "get_client_id_from_token", None),
**kwargs
)

Expand Down
14 changes: 11 additions & 3 deletions src/oidcop/exception.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,15 +58,23 @@ class RedirectURIError(OidcEndpointError):
pass


class UnknownClient(OidcEndpointError):
class ClientAuthenticationError(OidcEndpointError):
pass


class InvalidClient(OidcEndpointError):
class UnknownClient(ClientAuthenticationError):
pass


class UnAuthorizedClient(OidcEndpointError):
class InvalidClient(ClientAuthenticationError):
pass


class UnAuthorizedClient(ClientAuthenticationError):
pass


class BearerTokenAuthenticationError(OidcEndpointError):
pass


Expand Down
28 changes: 24 additions & 4 deletions src/oidcop/oauth2/add_on/extra_args.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
from oidcmsg.oauth2 import AccessTokenResponse
from oidcmsg.oauth2 import AuthorizationResponse
from oidcmsg.oauth2 import TokenExchangeResponse
from oidcmsg.oauth2 import TokenIntrospectionResponse
from oidcmsg.oidc import OpenIDSchema


def pre_construct(response_args, request, endpoint_context, **kwargs):
"""
Add extra arguments to the request.
Expand All @@ -11,12 +18,25 @@ def pre_construct(response_args, request, endpoint_context, **kwargs):

_extra = endpoint_context.add_on.get("extra_args")
if _extra:
for arg, _param in _extra.items():
_val = endpoint_context.get(_param)
if isinstance(response_args, AuthorizationResponse):
_args = _extra.get("authorization", {})
elif isinstance(response_args, AccessTokenResponse):
_args = _extra.get('accesstoken', {})
elif isinstance(response_args, TokenExchangeResponse):
_args = _extra.get('token_exchange', {})
elif isinstance(response_args, TokenIntrospectionResponse):
_args = _extra.get('token_introspection', {})
elif isinstance(response_args, OpenIDSchema):
_args = _extra.get('userinfo', {})
else:
_args = {}

for arg, _param in _args.items():
_val = getattr(endpoint_context, _param)
if _val:
request[arg] = _val
response_args[arg] = _val

return request
return response_args


def add_support(endpoint, **kwargs):
Expand Down
8 changes: 3 additions & 5 deletions tests/test_26_oidc_userinfo_endpoint.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
from oidcop.configure import OPConfiguration
from oidcop.cookie_handler import CookieHandler
from oidcop.exception import ImproperlyConfigured
from oidcop.exception import BearerTokenAuthenticationError
from oidcop.oidc import userinfo
from oidcop.oidc.authorization import Authorization
from oidcop.oidc.provider_config import ProviderConfiguration
Expand Down Expand Up @@ -513,11 +514,8 @@ def mock():

monkeypatch.setattr("oidcop.token.utc_time_sans_frac", mock)

_req = self.endpoint.parse_request({}, http_info=http_info)

assert _req.to_dict() == {
"error": "invalid_token", "error_description": "Expired token"
}
with pytest.raises(BearerTokenAuthenticationError):
self.endpoint.parse_request({}, http_info=http_info)

def test_userinfo_claims(self):
_acr = "https://refeds.org/profile/mfa"
Expand Down
21 changes: 9 additions & 12 deletions tests/test_61_add_on.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import os
from urllib.parse import urlparse

from cryptojwt.jwk.ec import ECKey
from cryptojwt.jwk.ec import new_ec_key
from cryptojwt.jws.jws import factory
from cryptojwt.key_jar import init_key_jar
from oidcmsg.oauth2 import AccessTokenRequest
from oidcmsg.oauth2 import AuthorizationRequest
from oidcmsg.oauth2 import AuthorizationResponse
from oidcmsg.time_util import utc_time_sans_frac

from oidcop.authn_event import create_authn_event
Expand Down Expand Up @@ -155,15 +157,10 @@ def test_process_request(self):
_context = self.endpoint.server_get("endpoint_context")
assert _context.add_on["extra_args"] == {'authorization': {'iss': 'issuer'}}

_pr_resp = self.endpoint.parse_request(AUTH_REQ.to_dict())
_resp = self.endpoint.process_request(_pr_resp)
assert set(_resp.keys()) == {
"response_args",
"fragment_enc",
"return_uri",
"cookie",
"session_id",
}

assert 'iss' in _resp["response_args"]
assert _resp["response_args"]["iss"] == _context.issuer
_pr_resp = self.endpoint.parse_request(AUTH_REQ)
_args = self.endpoint.process_request(_pr_resp)
_resp = self.endpoint.do_response(request=AUTH_REQ, **_args)
parse_res = urlparse(_resp["response"])
_payload = AuthorizationResponse().from_urlencoded(parse_res.query)
assert 'iss' in _payload
assert _payload["iss"] == _context.issuer

0 comments on commit 11194bc

Please sign in to comment.