From 1140d7806f7d1d55b28fc52a30b4cf888293cc20 Mon Sep 17 00:00:00 2001 From: Jimmy Thrasibule Date: Fri, 13 Apr 2018 09:27:01 +0100 Subject: Add request argument to confirm_redirect_uri (#504) (#504) (cherry picked from commit d49b9f0) --- examples/skeleton_oauth2_web_application_server.py | 2 +- oauthlib/oauth2/rfc6749/grant_types/authorization_code.py | 3 ++- oauthlib/oauth2/rfc6749/request_validator.py | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/examples/skeleton_oauth2_web_application_server.py b/examples/skeleton_oauth2_web_application_server.py index 8bfd936..e53232f 100644 --- a/examples/skeleton_oauth2_web_application_server.py +++ b/examples/skeleton_oauth2_web_application_server.py @@ -67,7 +67,7 @@ class SkeletonValidator(RequestValidator): # state and user to request.scopes and request.user. pass - def confirm_redirect_uri(self, client_id, code, redirect_uri, client, *args, **kwargs): + def confirm_redirect_uri(self, client_id, code, redirect_uri, client, request, *args, **kwargs): # You did save the redirect uri with the authorization code right? pass diff --git a/oauthlib/oauth2/rfc6749/grant_types/authorization_code.py b/oauthlib/oauth2/rfc6749/grant_types/authorization_code.py index 7bea650..0660263 100644 --- a/oauthlib/oauth2/rfc6749/grant_types/authorization_code.py +++ b/oauthlib/oauth2/rfc6749/grant_types/authorization_code.py @@ -421,7 +421,8 @@ class AuthorizationCodeGrant(GrantTypeBase): # authorization request as described in Section 4.1.1, and their # values MUST be identical. if not self.request_validator.confirm_redirect_uri(request.client_id, request.code, - request.redirect_uri, request.client): + request.redirect_uri, request.client, + request): log.debug('Redirect_uri (%r) invalid for client %r (%r).', request.redirect_uri, request.client_id, request.client) raise errors.MismatchingRedirectURIError(request=request) diff --git a/oauthlib/oauth2/rfc6749/request_validator.py b/oauthlib/oauth2/rfc6749/request_validator.py index 26b0041..fee7b8c 100644 --- a/oauthlib/oauth2/rfc6749/request_validator.py +++ b/oauthlib/oauth2/rfc6749/request_validator.py @@ -82,7 +82,7 @@ class RequestValidator(object): """ raise NotImplementedError('Subclasses must implement this method.') - def confirm_redirect_uri(self, client_id, code, redirect_uri, client, + def confirm_redirect_uri(self, client_id, code, redirect_uri, client, request, *args, **kwargs): """Ensure that the authorization process represented by this authorization code began with this 'redirect_uri'. -- cgit v1.2.1 From 28bc7e2140fea893c5d23e1893b5f25e36f5d4e7 Mon Sep 17 00:00:00 2001 From: Olaf Conradi Date: Fri, 13 Apr 2018 09:32:01 +0100 Subject: Use secrets module in Python 3.6 and later (#533) The secrets module should be used for generating cryptographically strong random numbers suitable for managing data such as passwords, account authentication, security tokens, and related secrets. In particularly, secrets should be used in preference to the default pseudo-random number generator in the random module, which is designed for modelling and simulation, not security or cryptography. (cherry picked from commit d21fd53) --- AUTHORS | 1 + docs/oauth1/security.rst | 12 +++++++----- oauthlib/common.py | 11 ++++++++--- 3 files changed, 16 insertions(+), 8 deletions(-) diff --git a/AUTHORS b/AUTHORS index 7d5d9ad..f52ce9a 100644 --- a/AUTHORS +++ b/AUTHORS @@ -28,3 +28,4 @@ Joel Stevenson Brendan McCollam Jonathan Huot Pieter Ennes +Olaf Conradi diff --git a/docs/oauth1/security.rst b/docs/oauth1/security.rst index a1432a9..df1e2a0 100644 --- a/docs/oauth1/security.rst +++ b/docs/oauth1/security.rst @@ -16,11 +16,13 @@ A few important facts regarding OAuth security * **Tokens must be random**, OAuthLib provides a method for generating secure tokens and it's packed into ``oauthlib.common.generate_token``, - use it. If you decide to roll your own, use ``random.SystemRandom`` - which is based on ``os.urandom`` rather than the default ``random`` - based on the effecient but not truly random Mersenne Twister. - Predictable tokens allow attackers to bypass virtually all defences - OAuth provides. + use it. If you decide to roll your own, use ``secrets.SystemRandom`` + for Python 3.6 and later. The ``secrets`` module is designed for + generating cryptographically strong random numbers. For earlier versions + of Python, use ``random.SystemRandom`` which is based on ``os.urandom`` + rather than the default ``random`` based on the effecient but not truly + random Mersenne Twister. Predictable tokens allow attackers to bypass + virtually all defences OAuth provides. * **Timing attacks are real** and more than possible if you host your application inside a shared datacenter. Ensure all ``validate_`` methods diff --git a/oauthlib/common.py b/oauthlib/common.py index afcc09c..f25656f 100644 --- a/oauthlib/common.py +++ b/oauthlib/common.py @@ -11,11 +11,16 @@ from __future__ import absolute_import, unicode_literals import collections import datetime import logging -import random import re import sys import time +try: + from secrets import randbits + from secrets import SystemRandom +except ImportError: + from random import getrandbits as randbits + from random import SystemRandom try: from urllib import quote as _quote from urllib import unquote as _unquote @@ -202,7 +207,7 @@ def generate_nonce(): .. _`section 3.2.1`: https://tools.ietf.org/html/draft-ietf-oauth-v2-http-mac-01#section-3.2.1 .. _`section 3.3`: https://tools.ietf.org/html/rfc5849#section-3.3 """ - return unicode_type(unicode_type(random.getrandbits(64)) + generate_timestamp()) + return unicode_type(unicode_type(randbits(64)) + generate_timestamp()) def generate_timestamp(): @@ -225,7 +230,7 @@ def generate_token(length=30, chars=UNICODE_ASCII_CHARACTER_SET): and entropy when generating the random characters is important. Which is why SystemRandom is used instead of the default random.choice method. """ - rand = random.SystemRandom() + rand = SystemRandom() return ''.join(rand.choice(chars) for x in range(length)) -- cgit v1.2.1 From 11c7fb1765773ea1bc839c287bd301aba88ae475 Mon Sep 17 00:00:00 2001 From: paulie4 Date: Fri, 13 Apr 2018 09:39:07 +0100 Subject: Fixed some copy and paste typos (#535) Fixed some copy and paste typos, see issue #532. (cherry picked from commit 1b3498a) --- oauthlib/oauth2/rfc6749/clients/service_application.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/oauthlib/oauth2/rfc6749/clients/service_application.py b/oauthlib/oauth2/rfc6749/clients/service_application.py index 84ea0e9..7f336bb 100644 --- a/oauthlib/oauth2/rfc6749/clients/service_application.py +++ b/oauthlib/oauth2/rfc6749/clients/service_application.py @@ -146,8 +146,8 @@ class ServiceApplicationClient(Client): ' token requests.') claim = { 'iss': issuer or self.issuer, - 'aud': audience or self.issuer, - 'sub': subject or self.issuer, + 'aud': audience or self.audience, + 'sub': subject or self.subject, 'exp': int(expires_at or time.time() + 3600), 'iat': int(issued_at or time.time()), } -- cgit v1.2.1 From 522919e38986d8095a686da6510b6fe5b51caed3 Mon Sep 17 00:00:00 2001 From: Pieter Ennes Date: Tue, 8 May 2018 21:14:35 +0100 Subject: Avoid populating spurious token credentials (#542) (cherry picked from commit 657065d) --- oauthlib/oauth2/rfc6749/clients/base.py | 19 ++++++++++++------- oauthlib/oauth2/rfc6749/clients/mobile_application.py | 2 +- oauthlib/oauth2/rfc6749/clients/web_application.py | 2 +- .../oauth2/rfc6749/clients/test_mobile_application.py | 12 ++++++++++++ tests/oauth2/rfc6749/clients/test_web_application.py | 19 +++++++++++++++++++ 5 files changed, 45 insertions(+), 9 deletions(-) diff --git a/oauthlib/oauth2/rfc6749/clients/base.py b/oauthlib/oauth2/rfc6749/clients/base.py index a07a5c9..3c5372c 100644 --- a/oauthlib/oauth2/rfc6749/clients/base.py +++ b/oauthlib/oauth2/rfc6749/clients/base.py @@ -111,8 +111,10 @@ class Client(object): self.state_generator = state_generator self.state = state self.redirect_url = redirect_url + self.code = None + self.expires_in = None self._expires_at = None - self._populate_attributes(self.token) + self._populate_token_attributes(self.token) @property def token_types(self): @@ -406,7 +408,7 @@ class Client(object): .. _`Section 7.1`: https://tools.ietf.org/html/rfc6749#section-7.1 """ self.token = parse_token_response(body, scope=scope) - self._populate_attributes(self.token) + self._populate_token_attributes(self.token) return self.token def prepare_refresh_body(self, body='', refresh_token=None, scope=None, **kwargs): @@ -459,8 +461,14 @@ class Client(object): hash_algorithm=self.mac_algorithm, **kwargs) return uri, headers, body - def _populate_attributes(self, response): - """Add commonly used values such as access_token to self.""" + def _populate_code_attributes(self, response): + """Add attributes from an auth code response to self.""" + + if 'code' in response: + self.code = response.get('code') + + def _populate_token_attributes(self, response): + """Add attributes from a token exchange response to self.""" if 'access_token' in response: self.access_token = response.get('access_token') @@ -478,9 +486,6 @@ class Client(object): if 'expires_at' in response: self._expires_at = int(response.get('expires_at')) - if 'code' in response: - self.code = response.get('code') - if 'mac_key' in response: self.mac_key = response.get('mac_key') diff --git a/oauthlib/oauth2/rfc6749/clients/mobile_application.py b/oauthlib/oauth2/rfc6749/clients/mobile_application.py index 311aacf..965185d 100644 --- a/oauthlib/oauth2/rfc6749/clients/mobile_application.py +++ b/oauthlib/oauth2/rfc6749/clients/mobile_application.py @@ -168,5 +168,5 @@ class MobileApplicationClient(Client): .. _`Section 3.3`: https://tools.ietf.org/html/rfc6749#section-3.3 """ self.token = parse_implicit_response(uri, state=state, scope=scope) - self._populate_attributes(self.token) + self._populate_token_attributes(self.token) return self.token diff --git a/oauthlib/oauth2/rfc6749/clients/web_application.py b/oauthlib/oauth2/rfc6749/clients/web_application.py index 0dd5f6e..cf9367b 100644 --- a/oauthlib/oauth2/rfc6749/clients/web_application.py +++ b/oauthlib/oauth2/rfc6749/clients/web_application.py @@ -172,5 +172,5 @@ class WebApplicationClient(Client): oauthlib.oauth2.rfc6749.errors.MismatchingStateError """ response = parse_authorization_code_response(uri, state=state) - self._populate_attributes(response) + self._populate_code_attributes(response) return response diff --git a/tests/oauth2/rfc6749/clients/test_mobile_application.py b/tests/oauth2/rfc6749/clients/test_mobile_application.py index 309220b..51e4dab 100644 --- a/tests/oauth2/rfc6749/clients/test_mobile_application.py +++ b/tests/oauth2/rfc6749/clients/test_mobile_application.py @@ -69,6 +69,18 @@ class MobileApplicationClientTest(TestCase): uri = client.prepare_request_uri(self.uri, **self.kwargs) self.assertURLEqual(uri, self.uri_kwargs) + def test_populate_attributes(self): + + client = MobileApplicationClient(self.client_id) + + response_uri = (self.response_uri + "&code=EVIL-CODE") + + client.parse_request_uri_response(response_uri, scope=self.scope) + + # We must not accidentally pick up any further security + # credentials at this point. + self.assertIsNone(client.code) + def test_parse_token_response(self): client = MobileApplicationClient(self.client_id) diff --git a/tests/oauth2/rfc6749/clients/test_web_application.py b/tests/oauth2/rfc6749/clients/test_web_application.py index 85b247d..fa6643e 100644 --- a/tests/oauth2/rfc6749/clients/test_web_application.py +++ b/tests/oauth2/rfc6749/clients/test_web_application.py @@ -117,6 +117,25 @@ class WebApplicationClientTest(TestCase): self.response_uri, state="invalid") + def test_populate_attributes(self): + + client = WebApplicationClient(self.client_id) + + response_uri = (self.response_uri + + "&access_token=EVIL-TOKEN" + "&refresh_token=EVIL-TOKEN" + "&mac_key=EVIL-KEY") + + client.parse_request_uri_response(response_uri, self.state) + + self.assertEqual(client.code, self.code) + + # We must not accidentally pick up any further security + # credentials at this point. + self.assertIsNone(client.access_token) + self.assertIsNone(client.refresh_token) + self.assertIsNone(client.mac_key) + def test_parse_token_response(self): client = WebApplicationClient(self.client_id) -- cgit v1.2.1 From b7b5aaf891e6b5d8b5f457ded47ca063f85a3162 Mon Sep 17 00:00:00 2001 From: Pieter Ennes Date: Thu, 17 May 2018 23:34:21 +0100 Subject: Make populate attributes API public. (cherry picked from commit 0b6f7e2) --- oauthlib/oauth2/rfc6749/clients/base.py | 14 ++++++++++---- oauthlib/oauth2/rfc6749/clients/mobile_application.py | 2 +- oauthlib/oauth2/rfc6749/clients/web_application.py | 2 +- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/oauthlib/oauth2/rfc6749/clients/base.py b/oauthlib/oauth2/rfc6749/clients/base.py index 3c5372c..07ef894 100644 --- a/oauthlib/oauth2/rfc6749/clients/base.py +++ b/oauthlib/oauth2/rfc6749/clients/base.py @@ -9,6 +9,7 @@ for consuming OAuth 2.0 RFC6749. from __future__ import absolute_import, unicode_literals import time +import warnings from oauthlib.common import generate_token from oauthlib.oauth2.rfc6749 import tokens @@ -114,7 +115,7 @@ class Client(object): self.code = None self.expires_in = None self._expires_at = None - self._populate_token_attributes(self.token) + self.populate_token_attributes(self.token) @property def token_types(self): @@ -408,7 +409,7 @@ class Client(object): .. _`Section 7.1`: https://tools.ietf.org/html/rfc6749#section-7.1 """ self.token = parse_token_response(body, scope=scope) - self._populate_token_attributes(self.token) + self.populate_token_attributes(self.token) return self.token def prepare_refresh_body(self, body='', refresh_token=None, scope=None, **kwargs): @@ -461,13 +462,18 @@ class Client(object): hash_algorithm=self.mac_algorithm, **kwargs) return uri, headers, body - def _populate_code_attributes(self, response): + def _populate_attributes(self, response): + warnings.warn("Please switch to the public method " + "populate_token_attributes.", DeprecationWarning) + return self.populate_token_attributes(response) + + def populate_code_attributes(self, response): """Add attributes from an auth code response to self.""" if 'code' in response: self.code = response.get('code') - def _populate_token_attributes(self, response): + def populate_token_attributes(self, response): """Add attributes from a token exchange response to self.""" if 'access_token' in response: diff --git a/oauthlib/oauth2/rfc6749/clients/mobile_application.py b/oauthlib/oauth2/rfc6749/clients/mobile_application.py index 965185d..aa20daa 100644 --- a/oauthlib/oauth2/rfc6749/clients/mobile_application.py +++ b/oauthlib/oauth2/rfc6749/clients/mobile_application.py @@ -168,5 +168,5 @@ class MobileApplicationClient(Client): .. _`Section 3.3`: https://tools.ietf.org/html/rfc6749#section-3.3 """ self.token = parse_implicit_response(uri, state=state, scope=scope) - self._populate_token_attributes(self.token) + self.populate_token_attributes(self.token) return self.token diff --git a/oauthlib/oauth2/rfc6749/clients/web_application.py b/oauthlib/oauth2/rfc6749/clients/web_application.py index cf9367b..25280bf 100644 --- a/oauthlib/oauth2/rfc6749/clients/web_application.py +++ b/oauthlib/oauth2/rfc6749/clients/web_application.py @@ -172,5 +172,5 @@ class WebApplicationClient(Client): oauthlib.oauth2.rfc6749.errors.MismatchingStateError """ response = parse_authorization_code_response(uri, state=state) - self._populate_code_attributes(response) + self.populate_code_attributes(response) return response -- cgit v1.2.1 From 5c76855eac8ba002289fa53e6ae82f00a64d0d9f Mon Sep 17 00:00:00 2001 From: Pieter Ennes Date: Mon, 23 Apr 2018 21:47:51 +0100 Subject: Prepare 2.1.0 release. --- CHANGELOG.rst | 9 +++++++++ oauthlib/__init__.py | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 7389af0..a8e1941 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -1,6 +1,15 @@ Changelog ========= +2.1.0 (2018-05-21) +------------------ + +* Fixed some copy and paste typos (#535) +* Use secrets module in Python 3.6 and later (#533) +* Add request argument to confirm_redirect_uri (#504) +* Avoid populating spurious token credentials (#542) +* Make populate attributes API public (#546) + 2.0.7 (2018-03-19) ------------------ diff --git a/oauthlib/__init__.py b/oauthlib/__init__.py index 3645010..3393efe 100644 --- a/oauthlib/__init__.py +++ b/oauthlib/__init__.py @@ -10,7 +10,7 @@ """ __author__ = 'The OAuthlib Community' -__version__ = '2.0.7' +__version__ = '2.1.0' import logging -- cgit v1.2.1