diff options
author | Joseph Tate <joseph@crunch.io> | 2015-04-14 12:30:44 -0400 |
---|---|---|
committer | Joseph Tate <joseph@crunch.io> | 2015-04-14 12:30:44 -0400 |
commit | fc2d1218e015adcf65ba01965884430c47895cd0 (patch) | |
tree | c3324d8e5731a0d2866848ee642c09b22db377f2 | |
parent | e1eee129c074d0de411122d6e1f34a3533952615 (diff) | |
download | oauthlib-fc2d1218e015adcf65ba01965884430c47895cd0.tar.gz |
Support newer PyJWT (1.0.0). remove PyCrypto completely for cryptography and PyJWT helpers. Reformat some test certificates to be easier to maintain. Update documentation to match use of cryptography instead of PyCrypto
-rw-r--r-- | CHANGELOG.rst | 6 | ||||
-rw-r--r-- | docs/faq.rst | 13 | ||||
-rw-r--r-- | docs/feature_matrix.rst | 4 | ||||
-rw-r--r-- | docs/oauth1/client.rst | 31 | ||||
-rw-r--r-- | oauthlib/common.py | 16 | ||||
-rw-r--r-- | oauthlib/oauth1/rfc5849/signature.py | 41 | ||||
-rw-r--r-- | oauthlib/oauth2/rfc6749/clients/service_application.py | 3 | ||||
-rw-r--r-- | oauthlib/oauth2/rfc6749/utils.py | 2 | ||||
-rw-r--r-- | requirements.txt | 6 | ||||
-rwxr-xr-x | setup.py | 8 | ||||
-rw-r--r-- | tests/oauth1/rfc5849/test_signatures.py | 44 | ||||
-rw-r--r-- | tests/oauth2/rfc6749/clients/test_service_application.py | 51 | ||||
-rw-r--r-- | tests/oauth2/rfc6749/test_server.py | 73 | ||||
-rw-r--r-- | tests/oauth2/rfc6749/test_utils.py | 3 |
14 files changed, 153 insertions, 148 deletions
diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 8fdd72d..5b8649f 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -1,5 +1,11 @@ Changelog ========= +Unreleased +-------------------------------------------------- + +* Replace pycrypto with cryptography from https://cryptography.io +* Update jwt to 1.0.0 (which is backwards incompatible) no oauthlib api changes + were made. 0.7.2 (2014-11-13) ------------------ diff --git a/docs/faq.rst b/docs/faq.rst index d48e7ef..4d896f5 100644 --- a/docs/faq.rst +++ b/docs/faq.rst @@ -11,24 +11,23 @@ What parts of OAuth 1 & 2 are supported? See :doc:`feature_matrix`. -OAuth 1 with RSA-SHA1 signatures says "could not import Crypto". What should I do? +OAuth 1 with RSA-SHA1 signatures says "could not import cryptography". What should I do? ---------------------------------------------------------------------------------- - Install either PyCrypto or Cryptography via pip. + Install cryptography via pip. .. code-block:: sh - $ pip install pycrypto $ pip install cryptography -OAuth 2 ServiceApplicationClient says "could not import jwt". What should I do? -------------------------------------------------------------------------------- +OAuth 2 ServiceApplicationClient and OAuth 1 with RSA-SHA1 signatures say "could not import jwt". What should I do? +------------------------------------------------------------------------------------------------------------------- - Install pyjwt and pycrypto with pip. + Install pyjwt and cryptography with pip. .. code-block:: sh - $ pip install pyjwt pycrypto + $ pip install pyjwt cryptography What does ValueError `Only unicode objects are escapable. Got one of type X.` mean? ----------------------------------------------------------------------------------- diff --git a/docs/feature_matrix.rst b/docs/feature_matrix.rst index cd9b509..d1b3f43 100644 --- a/docs/feature_matrix.rst +++ b/docs/feature_matrix.rst @@ -27,6 +27,6 @@ Supported platforms OAuthLib is mainly developed/tested on 64 bit Linux but works on Unix (incl. OS X) and Windows as well. Unless you are using the RSA features of OAuth 1 you should be able to use OAuthLib on any platform that supports Python. If you use -RSA you are limited to the platforms supported by `PyCrypto`_. +RSA you are limited to the platforms supported by `cryptography`_. -.. _`PyCrypto`: https://www.dlitz.net/software/pycrypto/ +.. _`cryptography`: https://cryptography.io/en/latest/installation/ diff --git a/docs/oauth1/client.rst b/docs/oauth1/client.rst index 2586075..bc326e6 100644 --- a/docs/oauth1/client.rst +++ b/docs/oauth1/client.rst @@ -64,25 +64,18 @@ Using the Client **RSA Signatures** - OAuthLib supports the 'RSA-SHA1' signature but does not install the PyCrypto - dependency by default. This is not done because PyCrypto is fairly - cumbersome to install, especially on Windows. Linux and Mac OS X (?) users - can install PyCrypto using pip:: - - pip install pycrypto - - Windows users will have to jump through a few hoops. The following links may be helpful: - - * `Voidspace Python prebuilt binaries for PyCrypto <http://www.voidspace.org.uk/python/modules.shtml#pycrypto>`_ - - * `Can I install Python Windows packages into virtualenvs <http://stackoverflow.com/questions/3271590/can-i-install-python-windows-packages-into-virtualenvs>`_ - - * `Compiling pycrypto on Windows 7 (64bit) <http://yorickdowne.wordpress.com/2010/12/22/compiling-pycrypto-on-win7-64/>`_ - - When you have pycrypto installed using RSA signatures is similar to HMAC but - differ in a few aspects. RSA signatures does not make use of client secrets - nor resource owner secrets (token secrets) and requires you to specify the - signature type when constructing a client:: + OAuthLib supports the 'RSA-SHA1' signature but does not install the jwt or + cryptography dependency by default. The cryptography package is much better + supported on Windows and Mac OS X than PyCrypto, and simpler to install. + OAuthLib uses the jwt package to smooth out its internal code. + Users can install cryptography using pip:: + + pip install jwt cryptography + + When you have cryptography and jwt installed using RSA signatures is + similar to HMAC but differ in a few aspects. RSA signatures does not make + use of client secrets nor resource owner secrets (token secrets) and + requires you to specify the signature type when constructing a client:: client = oauthlib.oauth1.Client('your client key', signature_method=oauthlib.oauth1.SIGNATURE_RSA, diff --git a/oauthlib/common.py b/oauthlib/common.py index 9cd7a61..0179b8e 100644 --- a/oauthlib/common.py +++ b/oauthlib/common.py @@ -229,11 +229,8 @@ def generate_token(length=30, chars=UNICODE_ASCII_CHARACTER_SET): def generate_signed_token(private_pem, request): - import Crypto.PublicKey.RSA as RSA import jwt - private_key = RSA.importKey(private_pem) - now = datetime.datetime.utcnow() claims = { @@ -243,23 +240,16 @@ def generate_signed_token(private_pem, request): claims.update(request.claims) - token = jwt.encode(claims, private_key, 'RS256') + token = jwt.encode(claims, private_pem, 'RS256') token = to_unicode(token, "UTF-8") return token -def verify_signed_token(private_pem, token): - import Crypto.PublicKey.RSA as RSA +def verify_signed_token(public_pem, token): import jwt - public_key = RSA.importKey(private_pem).publickey() - - try: - # return jwt.verify_jwt(token.encode(), public_key) - return jwt.decode(token, public_key) - except: - raise Exception + return jwt.decode(token, public_pem, algorithms=['RS256']) def generate_client_id(length=30, chars=CLIENT_ID_CHARACTER_SET): diff --git a/oauthlib/oauth1/rfc5849/signature.py b/oauthlib/oauth1/rfc5849/signature.py index f2d7ee4..f57d80a 100644 --- a/oauthlib/oauth1/rfc5849/signature.py +++ b/oauthlib/oauth1/rfc5849/signature.py @@ -464,6 +464,15 @@ def sign_hmac_sha1(base_string, client_secret, resource_owner_secret): # .. _`RFC2045, Section 6.8`: http://tools.ietf.org/html/rfc2045#section-6.8 return binascii.b2a_base64(signature.digest())[:-1].decode('utf-8') +_jwtrs1 = None + +#jwt has some nice pycrypto/cryptography abstractions +def _jwt_rs1_signing_algorithm(): + global _jwtrs1 + if _jwtrs1 is None: + import jwt.algorithms as jwtalgo + _jwtrs1 = jwtalgo.RSAAlgorithm(jwtalgo.hashes.SHA1) + return _jwtrs1 def sign_rsa_sha1(base_string, rsa_private_key): """**RSA-SHA1** @@ -481,16 +490,13 @@ def sign_rsa_sha1(base_string, rsa_private_key): .. _`RFC3447, Section 8.2`: http://tools.ietf.org/html/rfc3447#section-8.2 """ - # TODO: finish RSA documentation - from Crypto.PublicKey import RSA - from Crypto.Signature import PKCS1_v1_5 - from Crypto.Hash import SHA - key = RSA.importKey(rsa_private_key) if isinstance(base_string, unicode_type): base_string = base_string.encode('utf-8') - h = SHA.new(base_string) - p = PKCS1_v1_5.new(key) - return binascii.b2a_base64(p.sign(h))[:-1].decode('utf-8') + # TODO: finish RSA documentation + alg = _jwt_rs1_signing_algorithm() + key = _prepare_key_plus(alg, rsa_private_key) + s=alg.sign(base_string, key) + return binascii.b2a_base64(s)[:-1].decode('utf-8') def sign_rsa_sha1_with_client(base_string, client): @@ -560,13 +566,17 @@ def verify_hmac_sha1(request, client_secret=None, resource_owner_secret) return safe_string_equals(signature, request.signature) +def _prepare_key_plus(alg, keystr): + if isinstance(keystr, bytes_type): + keystr = keystr.decode('utf-8') + return alg.prepare_key(keystr) def verify_rsa_sha1(request, rsa_public_key): """Verify a RSASSA-PKCS #1 v1.5 base64 encoded signature. Per `section 3.4.3`_ of the spec. - Note this method requires the PyCrypto library. + Note this method requires the jwt and cryptography libraries. .. _`section 3.4.3`: http://tools.ietf.org/html/rfc5849#section-3.4.3 @@ -578,17 +588,14 @@ def verify_rsa_sha1(request, rsa_public_key): .. _`RFC2616 section 5.2`: http://tools.ietf.org/html/rfc2616#section-5.2 """ - from Crypto.PublicKey import RSA - from Crypto.Signature import PKCS1_v1_5 - from Crypto.Hash import SHA - key = RSA.importKey(rsa_public_key) norm_params = normalize_parameters(request.params) uri = normalize_base_string_uri(request.uri) - message = construct_base_string(request.http_method, uri, norm_params) - h = SHA.new(message.encode('utf-8')) - p = PKCS1_v1_5.new(key) + message = construct_base_string(request.http_method, uri, norm_params).encode('utf-8') sig = binascii.a2b_base64(request.signature.encode('utf-8')) - return p.verify(h, sig) + + alg = _jwt_rs1_signing_algorithm() + key = _prepare_key_plus(alg, rsa_public_key) + return alg.verify(message, key, sig) def verify_plaintext(request, client_secret=None, resource_owner_secret=None): diff --git a/oauthlib/oauth2/rfc6749/clients/service_application.py b/oauthlib/oauth2/rfc6749/clients/service_application.py index f60ac4f..36da98b 100644 --- a/oauthlib/oauth2/rfc6749/clients/service_application.py +++ b/oauthlib/oauth2/rfc6749/clients/service_application.py @@ -140,14 +140,11 @@ class ServiceApplicationClient(Client): .. _`Section 3.2.1`: http://tools.ietf.org/html/rfc6749#section-3.2.1 """ import jwt - import Crypto.PublicKey.RSA as RSA key = private_key or self.private_key if not key: raise ValueError('An encryption key must be supplied to make JWT' ' token requests.') - key = RSA.importKey(key) - claim = { 'iss': issuer or self.issuer, 'aud': audience or self.issuer, diff --git a/oauthlib/oauth2/rfc6749/utils.py b/oauthlib/oauth2/rfc6749/utils.py index e8ffba4..6a8e24b 100644 --- a/oauthlib/oauth2/rfc6749/utils.py +++ b/oauthlib/oauth2/rfc6749/utils.py @@ -24,7 +24,7 @@ def list_to_scope(scope): """Convert a list of scopes to a space separated string.""" if isinstance(scope, unicode_type) or scope is None: return scope - elif isinstance(scope, list): + elif isinstance(scope, (tuple, list)): return " ".join([unicode_type(s) for s in scope]) elif isinstance(scope, set): return list_to_scope(list(scope)) diff --git a/requirements.txt b/requirements.txt index 9818e25..0dfa994 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,3 @@ -pycrypto==2.6.1 -pyjwt==0.3.2 -blinker==1.3
\ No newline at end of file +pyjwt==1.0.0 +blinker==1.3 +cryptography==0.8.1 @@ -18,11 +18,11 @@ def fread(fn): return f.read() if sys.version_info[0] == 3: - tests_require = ['nose', 'pycrypto', 'pyjwt', 'blinker'] + tests_require = ['nose', 'cryptography', 'pyjwt>=1.0.0', 'blinker'] else: - tests_require = ['nose', 'unittest2', 'pycrypto', 'mock', 'pyjwt', 'blinker'] -rsa_require = ['pycrypto'] -signedtoken_require = ['pycrypto', 'pyjwt'] + tests_require = ['nose', 'unittest2', 'cryptography', 'mock', 'pyjwt>=1.0.0', 'blinker'] +rsa_require = ['cryptography'] +signedtoken_require = ['cryptography', 'pyjwt>=1.0.0'] signals_require = ['blinker'] requires = [] diff --git a/tests/oauth1/rfc5849/test_signatures.py b/tests/oauth1/rfc5849/test_signatures.py index aca6142..51e01ef 100644 --- a/tests/oauth1/rfc5849/test_signatures.py +++ b/tests/oauth1/rfc5849/test_signatures.py @@ -269,31 +269,25 @@ class SignatureTests(TestCase): b"th_nonce%253D%25227d8f3e4a%2522%252Coauth_signature" b"%253D%2522bYT5CMsGcbgUdFHObYMEfcx6bsw%25253D%2522") - @property - def rsa_private_key(self): - # Generated using: $ openssl genrsa -out <key>.pem 1024 - # PyCrypto / python-rsa requires the key to be concatenated with - # linebreaks. - return ( - b"-----BEGIN RSA PRIVATE KEY-----\nMIICXgIBAAKBgQDk1/bxy" - b"S8Q8jiheHeYYp/4rEKJopeQRRKKpZI4s5i+UPwVpupG\nAlwXWfzXw" - b"SMaKPAoKJNdu7tqKRniqst5uoHXw98gj0x7zamu0Ck1LtQ4c7pFMVa" - b"h\n5IYGhBi2E9ycNS329W27nJPWNCbESTu7snVlG8V8mfvGGg3xNjT" - b"MO7IdrwIDAQAB\nAoGBAOQ2KuH8S5+OrsL4K+wfjoCi6MfxCUyqVU9" - b"GxocdM1m30WyWRFMEz2nKJ8fR\np3vTD4w8yplTOhcoXdQZl0kRoaD" - b"zrcYkm2VvJtQRrX7dKFT8dR8D/Tr7dNQLOXfC\nDY6xveQczE7qt7V" - b"k7lp4FqmxBsaaEuokt78pOOjywZoInjZhAkEA9wz3zoZNT0/i\nrf6" - b"qv2qTIeieUB035N3dyw6f1BGSWYaXSuerDCD/J1qZbAPKKhyHZbVaw" - b"Ft3UMhe\n542UftBaxQJBAO0iJy1I8GQjGnS7B3yvyH3CcLYGy296+" - b"XO/2xKp/d/ty1OIeovx\nC60pLNwuFNF3z9d2GVQAdoQ89hUkOtjZL" - b"eMCQQD0JO6oPHUeUjYT+T7ImAv7UKVT\nSuy30sKjLzqoGw1kR+wv7" - b"C5PeDRvscs4wa4CW9s6mjSrMDkDrmCLuJDtmf55AkEA\nkmaMg2PNr" - b"jUR51F0zOEFycaaqXbGcFwe1/xx9zLmHzMDXd4bsnwt9kk+fe0hQzV" - b"S\nJzatanQit3+feev1PN3QewJAWv4RZeavEUhKv+kLe95Yd0su7lT" - b"LVduVgh4v5yLT\nGa6FHdjGPcfajt+nrpB1n8UQBEH9ZxniokR/IPv" - b"dMlxqXA==\n-----END RSA PRIVATE KEY-----" - ) - + # Generated using: $ openssl genrsa -out <key>.pem 1024 + # PEM encoding requires the key to be concatenated with + # linebreaks. + rsa_private_key = b"""-----BEGIN RSA PRIVATE KEY----- +MIICXgIBAAKBgQDk1/bxyS8Q8jiheHeYYp/4rEKJopeQRRKKpZI4s5i+UPwVpupG +AlwXWfzXwSMaKPAoKJNdu7tqKRniqst5uoHXw98gj0x7zamu0Ck1LtQ4c7pFMVah +5IYGhBi2E9ycNS329W27nJPWNCbESTu7snVlG8V8mfvGGg3xNjTMO7IdrwIDAQAB +AoGBAOQ2KuH8S5+OrsL4K+wfjoCi6MfxCUyqVU9GxocdM1m30WyWRFMEz2nKJ8fR +p3vTD4w8yplTOhcoXdQZl0kRoaDzrcYkm2VvJtQRrX7dKFT8dR8D/Tr7dNQLOXfC +DY6xveQczE7qt7Vk7lp4FqmxBsaaEuokt78pOOjywZoInjZhAkEA9wz3zoZNT0/i +rf6qv2qTIeieUB035N3dyw6f1BGSWYaXSuerDCD/J1qZbAPKKhyHZbVawFt3UMhe +542UftBaxQJBAO0iJy1I8GQjGnS7B3yvyH3CcLYGy296+XO/2xKp/d/ty1OIeovx +C60pLNwuFNF3z9d2GVQAdoQ89hUkOtjZLeMCQQD0JO6oPHUeUjYT+T7ImAv7UKVT +Suy30sKjLzqoGw1kR+wv7C5PeDRvscs4wa4CW9s6mjSrMDkDrmCLuJDtmf55AkEA +kmaMg2PNrjUR51F0zOEFycaaqXbGcFwe1/xx9zLmHzMDXd4bsnwt9kk+fe0hQzVS +JzatanQit3+feev1PN3QewJAWv4RZeavEUhKv+kLe95Yd0su7lTLVduVgh4v5yLT +Ga6FHdjGPcfajt+nrpB1n8UQBEH9ZxniokR/IPvdMlxqXA== +-----END RSA PRIVATE KEY----- +""" @property def control_signature_rsa_sha1(self): # Base string saved in "<message>". Signature obtained using: diff --git a/tests/oauth2/rfc6749/clients/test_service_application.py b/tests/oauth2/rfc6749/clients/test_service_application.py index a14750e..de57291 100644 --- a/tests/oauth2/rfc6749/clients/test_service_application.py +++ b/tests/oauth2/rfc6749/clients/test_service_application.py @@ -5,7 +5,6 @@ import os from time import time import jwt -from Crypto.PublicKey import RSA from mock import patch from oauthlib.common import Request @@ -18,25 +17,32 @@ class ServiceApplicationClientTest(TestCase): gt = ServiceApplicationClient.grant_type - private_key = ( - "-----BEGIN RSA PRIVATE KEY-----\nMIICXgIBAAKBgQDk1/bxy" - "S8Q8jiheHeYYp/4rEKJopeQRRKKpZI4s5i+UPwVpupG\nAlwXWfzXw" - "SMaKPAoKJNdu7tqKRniqst5uoHXw98gj0x7zamu0Ck1LtQ4c7pFMVa" - "h\n5IYGhBi2E9ycNS329W27nJPWNCbESTu7snVlG8V8mfvGGg3xNjT" - "MO7IdrwIDAQAB\nAoGBAOQ2KuH8S5+OrsL4K+wfjoCi6MfxCUyqVU9" - "GxocdM1m30WyWRFMEz2nKJ8fR\np3vTD4w8yplTOhcoXdQZl0kRoaD" - "zrcYkm2VvJtQRrX7dKFT8dR8D/Tr7dNQLOXfC\nDY6xveQczE7qt7V" - "k7lp4FqmxBsaaEuokt78pOOjywZoInjZhAkEA9wz3zoZNT0/i\nrf6" - "qv2qTIeieUB035N3dyw6f1BGSWYaXSuerDCD/J1qZbAPKKhyHZbVaw" - "Ft3UMhe\n542UftBaxQJBAO0iJy1I8GQjGnS7B3yvyH3CcLYGy296+" - "XO/2xKp/d/ty1OIeovx\nC60pLNwuFNF3z9d2GVQAdoQ89hUkOtjZL" - "eMCQQD0JO6oPHUeUjYT+T7ImAv7UKVT\nSuy30sKjLzqoGw1kR+wv7" - "C5PeDRvscs4wa4CW9s6mjSrMDkDrmCLuJDtmf55AkEA\nkmaMg2PNr" - "jUR51F0zOEFycaaqXbGcFwe1/xx9zLmHzMDXd4bsnwt9kk+fe0hQzV" - "S\nJzatanQit3+feev1PN3QewJAWv4RZeavEUhKv+kLe95Yd0su7lT" - "LVduVgh4v5yLT\nGa6FHdjGPcfajt+nrpB1n8UQBEH9ZxniokR/IPv" - "dMlxqXA==\n-----END RSA PRIVATE KEY-----" - ) + private_key = """ +-----BEGIN RSA PRIVATE KEY----- +MIICXgIBAAKBgQDk1/bxyS8Q8jiheHeYYp/4rEKJopeQRRKKpZI4s5i+UPwVpupG +AlwXWfzXwSMaKPAoKJNdu7tqKRniqst5uoHXw98gj0x7zamu0Ck1LtQ4c7pFMVah +5IYGhBi2E9ycNS329W27nJPWNCbESTu7snVlG8V8mfvGGg3xNjTMO7IdrwIDAQAB +AoGBAOQ2KuH8S5+OrsL4K+wfjoCi6MfxCUyqVU9GxocdM1m30WyWRFMEz2nKJ8fR +p3vTD4w8yplTOhcoXdQZl0kRoaDzrcYkm2VvJtQRrX7dKFT8dR8D/Tr7dNQLOXfC +DY6xveQczE7qt7Vk7lp4FqmxBsaaEuokt78pOOjywZoInjZhAkEA9wz3zoZNT0/i +rf6qv2qTIeieUB035N3dyw6f1BGSWYaXSuerDCD/J1qZbAPKKhyHZbVawFt3UMhe +542UftBaxQJBAO0iJy1I8GQjGnS7B3yvyH3CcLYGy296+XO/2xKp/d/ty1OIeovx +C60pLNwuFNF3z9d2GVQAdoQ89hUkOtjZLeMCQQD0JO6oPHUeUjYT+T7ImAv7UKVT +Suy30sKjLzqoGw1kR+wv7C5PeDRvscs4wa4CW9s6mjSrMDkDrmCLuJDtmf55AkEA +kmaMg2PNrjUR51F0zOEFycaaqXbGcFwe1/xx9zLmHzMDXd4bsnwt9kk+fe0hQzVS +JzatanQit3+feev1PN3QewJAWv4RZeavEUhKv+kLe95Yd0su7lTLVduVgh4v5yLT +Ga6FHdjGPcfajt+nrpB1n8UQBEH9ZxniokR/IPvdMlxqXA== +-----END RSA PRIVATE KEY----- +""" + + public_key = """ +-----BEGIN PUBLIC KEY----- +MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDk1/bxyS8Q8jiheHeYYp/4rEKJ +opeQRRKKpZI4s5i+UPwVpupGAlwXWfzXwSMaKPAoKJNdu7tqKRniqst5uoHXw98g +j0x7zamu0Ck1LtQ4c7pFMVah5IYGhBi2E9ycNS329W27nJPWNCbESTu7snVlG8V8 +mfvGGg3xNjTMO7IdrwIDAQAB +-----END PUBLIC KEY----- +""" subject = 'resource-owner@provider.com' @@ -86,11 +92,10 @@ class ServiceApplicationClientTest(TestCase): self.assertEqual(r.isnot, 'empty') self.assertEqual(r.grant_type, ServiceApplicationClient.grant_type) - key = RSA.importKey(self.private_key).publickey() - claim = jwt.decode(r.assertion, key) + claim = jwt.decode(r.assertion, self.public_key, audience=self.audience, algorithms=['RS256']) self.assertEqual(claim['iss'], self.issuer) - self.assertEqual(claim['aud'], self.audience) + # audience verification is handled during decode now self.assertEqual(claim['sub'], self.subject) self.assertEqual(claim['iat'], int(t.return_value)) diff --git a/tests/oauth2/rfc6749/test_server.py b/tests/oauth2/rfc6749/test_server.py index 24c9fb9..fde785e 100644 --- a/tests/oauth2/rfc6749/test_server.py +++ b/tests/oauth2/rfc6749/test_server.py @@ -1,7 +1,6 @@ # -*- coding: utf-8 -*- from __future__ import absolute_import, unicode_literals from ...unittest import TestCase -import Crypto.PublicKey.RSA as RSA import json import jwt import mock @@ -177,35 +176,47 @@ class SignedTokenEndpointTest(TestCase): self.mock_validator.authenticate_client.side_effect = set_user self.addCleanup(setattr, self, 'mock_validator', mock.MagicMock()) - self.private_pem = ( - "-----BEGIN RSA PRIVATE KEY-----\n" - "MIIEpAIBAAKCAQEA6TtDhWGwzEOWZP6m/zHoZnAPLABfetvoMPmxPGjFjtDuMRPv\n" - "EvI1sbixZBjBtdnc5rTtHUUQ25Am3JzwPRGo5laMGbj1pPyCPxlVi9LK82HQNX0B\n" - "YK7tZtVfDHElQA7F4v3j9d3rad4O9/n+lyGIQ0tT7yQcBm2A8FEaP0bZYCLMjwMN\n" - "WfaVLE8eXHyv+MfpNNLI9wttLxygKYM48I3NwsFuJgOa/KuodXaAmf8pJnx8t1Wn\n" - "nxvaYXFiUn/TxmhM/qhemPa6+0nqq+aWV5eT7xn4K/ghLgNs09v6Yge0pmPl9Oz+\n" - "+bjJ+aKRnAmwCOY8/5U5EilAiUOeBoO9+8OXtwIDAQABAoIBAGFTTbXXMkPK4HN8\n" - "oItVdDlrAanG7hECuz3UtFUVE3upS/xG6TjqweVLwRqYCh2ssDXFwjy4mXRGDzF4\n" - "e/e/6s9Txlrlh/w1MtTJ6ZzTdcViR9RKOczysjZ7S5KRlI3KnGFAuWPcG2SuOWjZ\n" - "dZfzcj1Crd/ZHajBAVFHRsCo/ATVNKbTRprFfb27xKpQ2BwH/GG781sLE3ZVNIhs\n" - "aRRaED4622kI1E/WXws2qQMqbFKzo0m1tPbLb3Z89WgZJ/tRQwuDype1Vfm7k6oX\n" - "xfbp3948qSe/yWKRlMoPkleji/WxPkSIalzWSAi9ziN/0Uzhe65FURgrfHL3XR1A\n" - "B8UR+aECgYEA7NPQZV4cAikk02Hv65JgISofqV49P8MbLXk8sdnI1n7Mj10TgzU3\n" - "lyQGDEX4hqvT0bTXe4KAOxQZx9wumu05ejfzhdtSsEm6ptGHyCdmYDQeV0C/pxDX\n" - "JNCK8XgMku2370XG0AnyBCT7NGlgtDcNCQufcesF2gEuoKiXg6Zjo7sCgYEA/Bzs\n" - "9fWGZZnSsMSBSW2OYbFuhF3Fne0HcxXQHipl0Rujc/9g0nccwqKGizn4fGOE7a8F\n" - "usQgJoeGcinL7E9OEP/uQ9VX1C9RNVjIxP1O5/Guw1zjxQQYetOvbPhN2QhD1Ye7\n" - "0TRKrW1BapcjwLpFQlVg1ZeTPOi5lv24W/wX9jUCgYEAkrMSX/hPuTbrTNVZ3L6r\n" - "NV/2hN+PaTPeXei/pBuXwOaCqDurnpcUfFcgN/IP5LwDVd+Dq0pHTFFDNv45EFbq\n" - "R77o5n3ZVsIVEMiyJ1XgoK8oLDw7e61+15smtjT69Piz+09pu+ytMcwGn4y3Dmsb\n" - "dALzHYnL8iLRU0ubrz0ec4kCgYAJiVKRTzNBPptQom49h85d9ac3jJCAE8o3WTjh\n" - "Gzt0uHXrWlqgO280EY/DTnMOyXjqwLcXxHlu26uDP/99tdY/IF8z46sJ1KxetzgI\n" - "84f7kBHLRAU9m5UNeFpnZdEUB5MBTbwWAsNcYgiabpMkpCcghjg+fBhOsoLqqjhC\n" - "CnwhjQKBgQDkv0QTdyBU84TE8J0XY3eLQwXbrvG2yD5A2ntN3PyxGEneX5WTJGMZ\n" - "xJxwaFYQiDS3b9E7b8Q5dg8qa5Y1+epdhx3cuQAWPm+AoHKshDfbRve4txBDQAqh\n" - "c6MxSWgsa+2Ld5SWSNbGtpPcmEM3Fl5ttMCNCKtNc0UE16oHwaPAIw==\n" - "-----END RSA PRIVATE KEY-----" - ) + self.private_pem = """ +-----BEGIN RSA PRIVATE KEY----- +MIIEpAIBAAKCAQEA6TtDhWGwzEOWZP6m/zHoZnAPLABfetvoMPmxPGjFjtDuMRPv +EvI1sbixZBjBtdnc5rTtHUUQ25Am3JzwPRGo5laMGbj1pPyCPxlVi9LK82HQNX0B +YK7tZtVfDHElQA7F4v3j9d3rad4O9/n+lyGIQ0tT7yQcBm2A8FEaP0bZYCLMjwMN +WfaVLE8eXHyv+MfpNNLI9wttLxygKYM48I3NwsFuJgOa/KuodXaAmf8pJnx8t1Wn +nxvaYXFiUn/TxmhM/qhemPa6+0nqq+aWV5eT7xn4K/ghLgNs09v6Yge0pmPl9Oz+ ++bjJ+aKRnAmwCOY8/5U5EilAiUOeBoO9+8OXtwIDAQABAoIBAGFTTbXXMkPK4HN8 +oItVdDlrAanG7hECuz3UtFUVE3upS/xG6TjqweVLwRqYCh2ssDXFwjy4mXRGDzF4 +e/e/6s9Txlrlh/w1MtTJ6ZzTdcViR9RKOczysjZ7S5KRlI3KnGFAuWPcG2SuOWjZ +dZfzcj1Crd/ZHajBAVFHRsCo/ATVNKbTRprFfb27xKpQ2BwH/GG781sLE3ZVNIhs +aRRaED4622kI1E/WXws2qQMqbFKzo0m1tPbLb3Z89WgZJ/tRQwuDype1Vfm7k6oX +xfbp3948qSe/yWKRlMoPkleji/WxPkSIalzWSAi9ziN/0Uzhe65FURgrfHL3XR1A +B8UR+aECgYEA7NPQZV4cAikk02Hv65JgISofqV49P8MbLXk8sdnI1n7Mj10TgzU3 +lyQGDEX4hqvT0bTXe4KAOxQZx9wumu05ejfzhdtSsEm6ptGHyCdmYDQeV0C/pxDX +JNCK8XgMku2370XG0AnyBCT7NGlgtDcNCQufcesF2gEuoKiXg6Zjo7sCgYEA/Bzs +9fWGZZnSsMSBSW2OYbFuhF3Fne0HcxXQHipl0Rujc/9g0nccwqKGizn4fGOE7a8F +usQgJoeGcinL7E9OEP/uQ9VX1C9RNVjIxP1O5/Guw1zjxQQYetOvbPhN2QhD1Ye7 +0TRKrW1BapcjwLpFQlVg1ZeTPOi5lv24W/wX9jUCgYEAkrMSX/hPuTbrTNVZ3L6r +NV/2hN+PaTPeXei/pBuXwOaCqDurnpcUfFcgN/IP5LwDVd+Dq0pHTFFDNv45EFbq +R77o5n3ZVsIVEMiyJ1XgoK8oLDw7e61+15smtjT69Piz+09pu+ytMcwGn4y3Dmsb +dALzHYnL8iLRU0ubrz0ec4kCgYAJiVKRTzNBPptQom49h85d9ac3jJCAE8o3WTjh +Gzt0uHXrWlqgO280EY/DTnMOyXjqwLcXxHlu26uDP/99tdY/IF8z46sJ1KxetzgI +84f7kBHLRAU9m5UNeFpnZdEUB5MBTbwWAsNcYgiabpMkpCcghjg+fBhOsoLqqjhC +CnwhjQKBgQDkv0QTdyBU84TE8J0XY3eLQwXbrvG2yD5A2ntN3PyxGEneX5WTJGMZ +xJxwaFYQiDS3b9E7b8Q5dg8qa5Y1+epdhx3cuQAWPm+AoHKshDfbRve4txBDQAqh +c6MxSWgsa+2Ld5SWSNbGtpPcmEM3Fl5ttMCNCKtNc0UE16oHwaPAIw== +-----END RSA PRIVATE KEY----- + """ + + self.public_pem = """ +-----BEGIN PUBLIC KEY----- +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA6TtDhWGwzEOWZP6m/zHo +ZnAPLABfetvoMPmxPGjFjtDuMRPvEvI1sbixZBjBtdnc5rTtHUUQ25Am3JzwPRGo +5laMGbj1pPyCPxlVi9LK82HQNX0BYK7tZtVfDHElQA7F4v3j9d3rad4O9/n+lyGI +Q0tT7yQcBm2A8FEaP0bZYCLMjwMNWfaVLE8eXHyv+MfpNNLI9wttLxygKYM48I3N +wsFuJgOa/KuodXaAmf8pJnx8t1WnnxvaYXFiUn/TxmhM/qhemPa6+0nqq+aWV5eT +7xn4K/ghLgNs09v6Yge0pmPl9Oz++bjJ+aKRnAmwCOY8/5U5EilAiUOeBoO9+8OX +twIDAQAB +-----END PUBLIC KEY----- + """ signed_token = tokens.signed_token_generator(self.private_pem, user_id=123) @@ -254,7 +265,7 @@ class SignedTokenEndpointTest(TestCase): access_token = json.loads(body)['access_token'] - claims = common.verify_signed_token(self.private_pem, access_token) + claims = common.verify_signed_token(self.public_pem, access_token) self.assertEqual(claims['scope'], 'all of them') self.assertEqual(claims['user_id'], 123) diff --git a/tests/oauth2/rfc6749/test_utils.py b/tests/oauth2/rfc6749/test_utils.py index d292eeb..858cf1f 100644 --- a/tests/oauth2/rfc6749/test_utils.py +++ b/tests/oauth2/rfc6749/test_utils.py @@ -73,6 +73,9 @@ class UtilsTests(TestCase): string_list = ['foo', 'bar', 'baz'] self.assertEqual(list_to_scope(string_list), expected) + string_tuple = ('foo', 'bar', 'baz') + self.assertEqual(list_to_scope(string_tuple), expected) + obj_list = [ScopeObject('foo'), ScopeObject('bar'), ScopeObject('baz')] self.assertEqual(list_to_scope(obj_list), expected) |