diff --git a/setup.py b/setup.py index ad27e12..da943f6 100644 --- a/setup.py +++ b/setup.py @@ -12,7 +12,6 @@ description='OpenID Connect Provider (OP) library in Python.', install_requires=[ 'oic >= 1.2.1', - 'pynacl', 'pymongo' ] ) diff --git a/src/pyop/provider.py b/src/pyop/provider.py index 656fa28..e69140c 100644 --- a/src/pyop/provider.py +++ b/src/pyop/provider.py @@ -6,8 +6,6 @@ from urllib.parse import parse_qsl from urllib.parse import urlparse -import nacl.hash -from nacl.encoding import URLSafeBase64Encoder from jwkest import jws from oic import rndstr from oic.exception import MessageException @@ -23,6 +21,7 @@ from oic.oic.message import RefreshAccessTokenRequest from oic.oic.message import RegistrationRequest from oic.oic.message import RegistrationResponse +from oic.extension.provider import Provider as OICProviderExtensions from .message import AuthorizationRequest from .message import AccessTokenRequest @@ -330,23 +329,6 @@ def handle_token_request(self, request_body, # type: str raise InvalidTokenRequest('grant_type \'{}\' unknown'.format(token_request['grant_type']), token_request, oauth_error='unsupported_grant_type') - def _compute_code_challenge(self, - code_verifier # type: str - ): - # type: (...) -> str - """ - Given a code verifier compute the code_challenge. This code_challenge is computed as defined (https://datatracker.ietf.org/doc/html/rfc7636#section-4.2): - - code_challenge = BASE64URL-ENCODE(SHA256(ASCII(code_verifier))). - - This shows that the SHA256 of the ascii encoded code_verifier is URLSafe base64 encoded. We have adjusted the encoding to the ISO_8859_1 encoding, - conform to the AppAuth SDK for Android and IOS. Moreover, we remove the base64 padding (=). - - :param code_verifier: the code verifier to transform to the Code Challenge - """ - verifier_hash = nacl.hash.sha256(code_verifier.encode('ISO_8859_1'), encoder=URLSafeBase64Encoder) - return verifier_hash.decode().replace('=', '') - def _PKCE_verify(self, token_request, # type: AccessTokenRequest authentication_request # type: AuthorizationRequest @@ -368,12 +350,10 @@ def _PKCE_verify(self, raise InvalidTokenRequest("A code_challenge and code_verifier have been supplied" "but missing code_challenge_method in authentication_request", token_request) - code_challenge_method = authentication_request['code_challenge_method'] - if code_challenge_method == 'plain': - return authentication_request['code_challenge'] == token_request['code_verifier'] - - code_challenge = self._compute_code_challenge(token_request['code_verifier']) - return code_challenge == authentication_request['code_challenge'] + # OIC Provider extension returns either a boolean or Response object containing an error. To support + # stricter typing guidelines, return if True. Error handling support should be in encapsulating function. + return OICProviderExtensions.verify_code_challenge(token_request['code_verifier'], + authentication_request['code_challenge'], authentication_request['code_challenge_method']) == True def _verify_code_exchange_req(self, token_request, # type: AccessTokenRequest diff --git a/tests/pyop/test_provider.py b/tests/pyop/test_provider.py index da82699..9c20fa0 100644 --- a/tests/pyop/test_provider.py +++ b/tests/pyop/test_provider.py @@ -333,20 +333,6 @@ def test_pkce_code_exchange_request(self): assert_id_token_base_claims(response['id_token'], self.provider.signing_key, self.provider, self.authn_request_args) - @patch('time.time', MOCK_TIME) - def test_pkce_code_exchange_request_plaintext(self): - self.authorization_code_exchange_request_args['code'] = self.create_authz_code( - { - "code_challenge": "SoOEDN-mZKNhw7Mc52VXxyiqTvFB3mod36MwPru253c", - "code_challenge_method": "plain" - } - ) - self.authorization_code_exchange_request_args['code_verifier'] = "SoOEDN-mZKNhw7Mc52VXxyiqTvFB3mod36MwPru253c" - response = self.provider._do_code_exchange(self.authorization_code_exchange_request_args, None) - assert response['access_token'] in self.provider.authz_state.access_tokens - assert_id_token_base_claims(response['id_token'], self.provider.signing_key, self.provider, - self.authn_request_args) - @patch('time.time', MOCK_TIME) def test_code_exchange_request_with_claims_requested_in_id_token(self): claims_req = {'claims': ClaimsRequest(id_token=Claims(email=None))}