summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOmer Katz <omer.drow@gmail.com>2018-09-20 16:11:13 +0300
committerGitHub <noreply@github.com>2018-09-20 16:11:13 +0300
commit27c58af3fc4a5d63083d4f46423644a9b5134c5e (patch)
tree29d9bba818de48eb3ab4cacc7e22da6c83b6a4a0
parentf93dca00208fecdb9b4791a33c59b27c4199d0f4 (diff)
parent7ed3c53f8d04634ee8f470a4d621cd26505e977e (diff)
downloadoauthlib-27c58af3fc4a5d63083d4f46423644a9b5134c5e.tar.gz
Merge branch 'master' into invalid-grant-should-respond-with-400
-rw-r--r--.travis.yml3
-rw-r--r--CODE_OF_CONDUCT.md28
-rw-r--r--README.rst13
-rw-r--r--docs/contributing.rst77
-rw-r--r--docs/index.rst6
-rw-r--r--docs/installation.rst2
-rw-r--r--docs/oauth2/endpoints/endpoints.rst2
-rw-r--r--oauthlib/common.py15
-rw-r--r--oauthlib/oauth1/rfc5849/__init__.py5
-rw-r--r--oauthlib/oauth1/rfc5849/endpoints/access_token.py6
-rw-r--r--oauthlib/oauth1/rfc5849/endpoints/authorization.py3
-rw-r--r--oauthlib/oauth1/rfc5849/endpoints/request_token.py6
-rw-r--r--oauthlib/oauth1/rfc5849/request_validator.py63
-rw-r--r--oauthlib/oauth1/rfc5849/signature.py4
-rw-r--r--oauthlib/oauth1/rfc5849/utils.py2
-rw-r--r--oauthlib/oauth2/rfc6749/clients/service_application.py2
-rw-r--r--oauthlib/oauth2/rfc6749/errors.py49
-rw-r--r--oauthlib/oauth2/rfc6749/grant_types/authorization_code.py48
-rw-r--r--oauthlib/oauth2/rfc6749/grant_types/base.py35
-rw-r--r--oauthlib/oauth2/rfc6749/grant_types/client_credentials.py9
-rw-r--r--oauthlib/oauth2/rfc6749/grant_types/implicit.py23
-rw-r--r--oauthlib/oauth2/rfc6749/grant_types/refresh_token.py9
-rw-r--r--oauthlib/oauth2/rfc6749/grant_types/resource_owner_password_credentials.py8
-rw-r--r--oauthlib/oauth2/rfc6749/parameters.py30
-rw-r--r--oauthlib/oauth2/rfc6749/request_validator.py182
-rw-r--r--oauthlib/oauth2/rfc6749/tokens.py54
-rw-r--r--oauthlib/openid/connect/core/request_validator.py21
-rw-r--r--requirements-test.txt1
-rwxr-xr-xsetup.py8
-rw-r--r--tests/oauth1/rfc5849/test_client.py12
-rw-r--r--tests/oauth2/rfc6749/endpoints/test_base_endpoint.py4
-rw-r--r--tests/oauth2/rfc6749/endpoints/test_credentials_preservation.py21
-rw-r--r--tests/oauth2/rfc6749/endpoints/test_error_responses.py10
-rw-r--r--tests/oauth2/rfc6749/grant_types/test_authorization_code.py6
-rw-r--r--tests/oauth2/rfc6749/test_parameters.py4
-rw-r--r--tests/openid/connect/core/grant_types/test_dispatchers.py14
-rw-r--r--tests/test_common.py18
-rw-r--r--tests/unittest/__init__.py21
-rw-r--r--tox.ini9
39 files changed, 593 insertions, 240 deletions
diff --git a/.travis.yml b/.travis.yml
index dd72d5c..f46bf43 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -17,10 +17,11 @@ install:
- pip install -U setuptools
- pip install tox coveralls
script: tox
-after_success: coveralls
+after_success: COVERALLS_PARALLEL=true coveralls
notifications:
webhooks:
urls:
+ - https://coveralls.io/webhook
- https://webhooks.gitter.im/e/6008c872bf0ecee344f4
on_success: change
on_failure: always
diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md
new file mode 100644
index 0000000..3f242ff
--- /dev/null
+++ b/CODE_OF_CONDUCT.md
@@ -0,0 +1,28 @@
+# OAuthlib Code of Conduct
+
+Like the technical community as a whole, the OAuthlib team and community is made up of a mixture of professionals and volunteers from all over the world, working on every aspect of the mission - including mentorship, teaching, and connecting people.
+
+Diversity is one of our huge strengths, but it can also lead to communication issues and unhappiness. To that end, we have a few ground rules that we ask people to adhere to. This code applies equally to founders, mentors and those seeking help and guidance.
+
+This isn't an exhaustive list of things that you can't do. Rather, take it in the spirit in which it's intended - a guide to make it easier to enrich all of us and the technical communities in which we participate.
+
+This code of conduct applies to all spaces managed by the OAuthlib project. This includes Gitter, the mailing lists, the issue tracker, and any other forums created by the project team which the community uses for communication. In addition, violations of this code outside these spaces may affect a person's ability to participate within them.
+
+If you believe someone is violating the code of conduct, we ask that you report it by contacting us.
+
+ Be friendly and patient.
+ Be welcoming. We strive to be a community that welcomes and supports people of all backgrounds and identities. This includes, but is not limited to members of any race, ethnicity, culture, national origin, colour, immigration status, social and economic class, educational level, sex, sexual orientation, gender identity and expression, age, size, family status, political belief, religion, and mental and physical ability.
+ Be considerate. Your work will be used by other people, and you in turn will depend on the work of others. Any decision you take will affect users and colleagues, and you should take those consequences into account when making decisions. Remember that we're a world-wide community, so you might not be communicating in someone else's primary language.
+ Be respectful. Not all of us will agree all the time, but disagreement is no excuse for poor behavior and poor manners. We might all experience some frustration now and then, but we cannot allow that frustration to turn into a personal attack. It's important to remember that a community where people feel uncomfortable or threatened is not a productive one. Members of the OAuthlib community should be respectful when dealing with other members as well as with people outside the OAuthlib community.
+ Be careful in the words that you choose. We are a community of professionals, and we conduct ourselves professionally. Be kind to others. Do not insult or put down other participants. Harassment and other exclusionary behavior aren't acceptable. This includes, but is not limited to:
+ Violent threats or language directed against another person.
+ Discriminatory jokes and language.
+ Posting sexually explicit or violent material.
+ Posting (or threatening to post) other people's personally identifying information ("doxing").
+ Personal insults, especially those using racist or sexist terms.
+ Unwelcome sexual attention.
+ Advocating for, or encouraging, any of the above behavior.
+ Repeated harassment of others. In general, if someone asks you to stop, then stop.
+ When we disagree, try to understand why. Disagreements, both social and technical, happen all the time and OAuthlib is no exception. It is important that we resolve disagreements and differing views constructively. Remember that we're different. The strength of OAuthlib comes from its varied community, people from a wide range of backgrounds. Different people have different perspectives on issues. Being unable to understand why someone holds a viewpoint doesn't mean that they're wrong. Don't forget that it is human to err and blaming each other doesn't get us anywhere. Instead, focus on helping to resolve issues and learning from mistakes.
+
+For reading the original text, please visit the [Django Code of Conduct](https://www.djangoproject.com/conduct/).
diff --git a/README.rst b/README.rst
index 394a984..7c41a80 100644
--- a/README.rst
+++ b/README.rst
@@ -1,5 +1,5 @@
-OAuthLib
-========
+OAuthLib - Python Framework for OAuth1 & OAuth2
+===============================================
*A generic, spec-compliant, thorough implementation of the OAuth request-signing
logic for Python 2.7 and 3.4+.*
@@ -12,10 +12,13 @@ logic for Python 2.7 and 3.4+.*
:alt: Coveralls
.. image:: https://img.shields.io/pypi/pyversions/oauthlib.svg
:target: https://pypi.org/project/oauthlib/
- :alt: Download from PyPi
+ :alt: Download from PyPI
.. image:: https://img.shields.io/pypi/l/oauthlib.svg
:target: https://pypi.org/project/oauthlib/
:alt: License
+.. image:: https://app.fossa.io/api/projects/git%2Bgithub.com%2Foauthlib%2Foauthlib.svg?type=shield
+ :target: https://app.fossa.io/projects/git%2Bgithub.com%2Foauthlib%2Foauthlib?ref=badge_shield
+ :alt: FOSSA Status
.. image:: https://img.shields.io/readthedocs/oauthlib.svg
:target: https://oauthlib.readthedocs.io/en/latest/index.html
:alt: Read the Docs
@@ -34,7 +37,7 @@ both of the following:
.. _`OAuth 1.0 spec`: https://tools.ietf.org/html/rfc5849
.. _`OAuth 2.0 spec`: https://tools.ietf.org/html/rfc6749
-OAuthLib is a generic utility which implements the logic of OAuth without
+OAuthLib is a framework which implements the logic of OAuth1 or OAuth2 without
assuming a specific HTTP request object or web framework. Use it to graft OAuth
client support onto your favorite HTTP library, or provide support onto your
favourite web framework. If you're a maintainer of such a library, write a thin
@@ -119,7 +122,7 @@ requests.
Changelog
---------
-*OAuthLib is in active development, with the core of both OAuth 1 and 2
+*OAuthLib is in active development, with the core of both OAuth1 and OAuth2
completed, for providers as well as clients.* See `supported features`_ for
details.
diff --git a/docs/contributing.rst b/docs/contributing.rst
index 3a23d70..771262d 100644
--- a/docs/contributing.rst
+++ b/docs/contributing.rst
@@ -30,6 +30,31 @@ personal label matching your GitHub ID will be assigned to that issue.
Feel free to propose issues that aren't described!
+oauthlib community rules
+========================
+
+oauthlib is a community of developers which adheres to a very simple set of
+rules.
+
+Code of Conduct
+---------------
+This project adheres to a `Code of Conduct`_ based on Django. As a community
+member you have to read and agree with it.
+
+For more information please contact us and/or visit the original
+`Django Code of Conduct`_ homepage.
+
+.. _`Code of Conduct`: https://github.com/oauthlib/oauthlib/blob/master/CODE_OF_CONDUCT.md
+.. _`Django Code of Conduct`: https://www.djangoproject.com/conduct/
+
+Code of Merit
+-------------
+Please read the community's `Code of Merit`_. Every contributor will know the
+real purpose of their contributions to this project.
+
+.. _`Code of Merit`: http://code-of-merit.org/
+
+
Setting up topic branches and generating pull requests
======================================================
@@ -213,6 +238,58 @@ Furthermore, the pixel shortage is over. We want to see:
* `grid` instead of `g`
* `my_function_that_does_things` instead of `mftdt`
+Be sure to write documentation!
+-------------------------------
+
+Documentation isn't just good, it's great - and necessary with large packages
+like OAuthlib. Please make sure the next person who reads your function/method
+can quickly understand what it does and how. Also, please ensure the parameters
+passed to each function are properly documented as well.
+
+The project has these goals/requests for docstrings that are designed to make
+the autogenerated documentation read more cleanly:
+
+#. Every parameter in the function should be listed in the docstring, and
+ should appear in the same order as they appear in the function itself.
+#. If you are unsure of the best wording for a parameter description, leave it
+ blank, but still include the `:param foo:` line. This will make it easier for
+ maintainers to see and edit.
+#. Use an existing standardized description of a parameter that appears
+ elsewhere in this project's documentation whenever possible. For example,
+ `request` is used as a parameter throughout the project with the description
+ "OAuthlib request." - there is no reason to describe it differently in your
+ function. Parameter descriptions should be a sentence that ends with a
+ period - even if it is just two words.
+#. When possible, include a `type` declaration for the parameter. For example,
+ a "request" param is often accompanied with `:type request: oauthlib.common.Request`.
+ The type is expected to be an object type reference, and should never end
+ in a period.
+#. If there is a textual docstring (recommended), use a single blank line to
+ separate the docstring and the params.
+#. When you cite class functions, please use backticks.
+
+Consolidated example
+
+ def foo(self, request, client, bar=None, key=None):
+ """
+ This method checks the `key` against the `client`. The `request` is
+ passed to maintain context.
+
+ Example MAC Authorization header, linebreaks added for clarity
+
+ Authorization: MAC id="h480djs93hd8",
+ nonce="1336363200:dj83hs9s",
+ mac="bhCQXTVyfj5cmA9uKkPFx1zeOXM="
+
+ .. _`MAC Access Authentication`: https://tools.ietf.org/html/draft-ietf-oauth-v2-http-mac-01
+
+ :param request: OAuthlib request.
+ :type request: oauthlib.common.Request
+ :param client: Client object set by you, see ``.authenticate_client``.
+ :param bar:
+ :param key: MAC given provided by token endpoint.
+ """
+
How pull requests are checked, tested, and done
===============================================
diff --git a/docs/index.rst b/docs/index.rst
index 1da2ca5..b6ce191 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -7,14 +7,14 @@ Welcome to OAuthLib's documentation!
====================================
If you can't find what you need or have suggestions for improvement, don't
-hesitate to open a `new issue on GitHub`_!
+hesitate to open a `new issue on GitHub`_!
Check out :doc:`error_reporting` for details on how to be an awesome bug reporter.
-For news and discussions please head over to our `G+ OAuthLib community`_.
+For news and discussions please head over to our `Gitter OAuthLib community`_.
.. _`new issue on GitHub`: https://github.com/oauthlib/oauthlib/issues/new
-.. _`G+ OAuthLib community`: https://plus.google.com/communities/101889017375384052571
+.. _`Gitter OAuthLib community`: https://gitter.im/oauthlib/Lobby
.. toctree::
:maxdepth: 1
diff --git a/docs/installation.rst b/docs/installation.rst
index 48e4288..72d7b08 100644
--- a/docs/installation.rst
+++ b/docs/installation.rst
@@ -9,7 +9,7 @@ For various reasons you may wish to install using your OS packaging system and
install instructions for a few are shown below. Please send a PR to add a
missing one.
-Latest release on PYPI
+Latest release on PyPI
----------------------
diff --git a/docs/oauth2/endpoints/endpoints.rst b/docs/oauth2/endpoints/endpoints.rst
index 80d5fbe..98599e8 100644
--- a/docs/oauth2/endpoints/endpoints.rst
+++ b/docs/oauth2/endpoints/endpoints.rst
@@ -24,7 +24,7 @@ handles user authorization, the token endpoint which provides tokens and the
resource endpoint which provides access to protected resources. It is to the
endpoints you will feed requests and get back an almost complete response. This
process is simplified for you using a decorator such as the django one described
-later (but it's applicable to all other web frameworks librairies).
+later (but it's applicable to all other web frameworks libraries).
The main purpose of the endpoint in OAuthLib is to figure out which grant type
or token to dispatch the request to.
diff --git a/oauthlib/common.py b/oauthlib/common.py
index c1180e6..bd6ec56 100644
--- a/oauthlib/common.py
+++ b/oauthlib/common.py
@@ -54,10 +54,8 @@ PY3 = sys.version_info[0] == 3
if PY3:
unicode_type = str
- bytes_type = bytes
else:
unicode_type = unicode
- bytes_type = str
# 'safe' must be bytes (Python 2.6 requires bytes, other versions allow either)
@@ -66,7 +64,7 @@ def quote(s, safe=b'/'):
s = _quote(s, safe)
# PY3 always returns unicode. PY2 may return either, depending on whether
# it had to modify the string.
- if isinstance(s, bytes_type):
+ if isinstance(s, bytes):
s = s.decode('utf-8')
return s
@@ -76,7 +74,7 @@ def unquote(s):
# PY3 always returns unicode. PY2 seems to always return what you give it,
# which differs from quote's behavior. Just to be safe, make sure it is
# unicode before we return.
- if isinstance(s, bytes_type):
+ if isinstance(s, bytes):
s = s.decode('utf-8')
return s
@@ -109,8 +107,8 @@ def decode_params_utf8(params):
decoded = []
for k, v in params:
decoded.append((
- k.decode('utf-8') if isinstance(k, bytes_type) else k,
- v.decode('utf-8') if isinstance(v, bytes_type) else v))
+ k.decode('utf-8') if isinstance(k, bytes) else k,
+ v.decode('utf-8') if isinstance(v, bytes) else v))
return decoded
@@ -174,7 +172,7 @@ def extract_params(raw):
empty list of parameters. Any other input will result in a return
value of None.
"""
- if isinstance(raw, bytes_type) or isinstance(raw, unicode_type):
+ if isinstance(raw, bytes) or isinstance(raw, unicode_type):
try:
params = urldecode(raw)
except ValueError:
@@ -309,7 +307,7 @@ def to_unicode(data, encoding='UTF-8'):
if isinstance(data, unicode_type):
return data
- if isinstance(data, bytes_type):
+ if isinstance(data, bytes):
return unicode_type(data, encoding=encoding)
if hasattr(data, '__iter__'):
@@ -426,7 +424,6 @@ class Request(object):
}
self._params.update(dict(urldecode(self.uri_query)))
self._params.update(dict(self.decoded_body or []))
- self._params.update(self.headers)
def __getattr__(self, name):
if name in self._params:
diff --git a/oauthlib/oauth1/rfc5849/__init__.py b/oauthlib/oauth1/rfc5849/__init__.py
index 87a8e6b..887ab69 100644
--- a/oauthlib/oauth1/rfc5849/__init__.py
+++ b/oauthlib/oauth1/rfc5849/__init__.py
@@ -18,11 +18,6 @@ try:
except ImportError:
import urllib.parse as urlparse
-if sys.version_info[0] == 3:
- bytes_type = bytes
-else:
- bytes_type = str
-
from oauthlib.common import Request, urlencode, generate_nonce
from oauthlib.common import generate_timestamp, to_unicode
from . import parameters, signature
diff --git a/oauthlib/oauth1/rfc5849/endpoints/access_token.py b/oauthlib/oauth1/rfc5849/endpoints/access_token.py
index 12d13e9..bea8274 100644
--- a/oauthlib/oauth1/rfc5849/endpoints/access_token.py
+++ b/oauthlib/oauth1/rfc5849/endpoints/access_token.py
@@ -37,7 +37,8 @@ class AccessTokenEndpoint(BaseEndpoint):
Similar to OAuth 2, indication of granted scopes will be included as a
space separated list in ``oauth_authorized_realms``.
- :param request: An oauthlib.common.Request object.
+ :param request: OAuthlib request.
+ :type request: oauthlib.common.Request
:returns: The token as an urlencoded string.
"""
request.realms = self.request_validator.get_realms(
@@ -120,7 +121,8 @@ class AccessTokenEndpoint(BaseEndpoint):
def validate_access_token_request(self, request):
"""Validate an access token request.
- :param request: An oauthlib.common.Request object.
+ :param request: OAuthlib request.
+ :type request: oauthlib.common.Request
:raises: OAuth1Error if the request is invalid.
:returns: A tuple of 2 elements.
1. The validation result (True or False).
diff --git a/oauthlib/oauth1/rfc5849/endpoints/authorization.py b/oauthlib/oauth1/rfc5849/endpoints/authorization.py
index 1751a45..b465946 100644
--- a/oauthlib/oauth1/rfc5849/endpoints/authorization.py
+++ b/oauthlib/oauth1/rfc5849/endpoints/authorization.py
@@ -42,7 +42,8 @@ class AuthorizationEndpoint(BaseEndpoint):
def create_verifier(self, request, credentials):
"""Create and save a new request token.
- :param request: An oauthlib.common.Request object.
+ :param request: OAuthlib request.
+ :type request: oauthlib.common.Request
:param credentials: A dict of extra token credentials.
:returns: The verifier as a dict.
"""
diff --git a/oauthlib/oauth1/rfc5849/endpoints/request_token.py b/oauthlib/oauth1/rfc5849/endpoints/request_token.py
index 88fd6c0..e9ca331 100644
--- a/oauthlib/oauth1/rfc5849/endpoints/request_token.py
+++ b/oauthlib/oauth1/rfc5849/endpoints/request_token.py
@@ -34,7 +34,8 @@ class RequestTokenEndpoint(BaseEndpoint):
def create_request_token(self, request, credentials):
"""Create and save a new request token.
- :param request: An oauthlib.common.Request object.
+ :param request: OAuthlib request.
+ :type request: oauthlib.common.Request
:param credentials: A dict of extra token credentials.
:returns: The token as an urlencoded string.
"""
@@ -111,7 +112,8 @@ class RequestTokenEndpoint(BaseEndpoint):
def validate_request_token_request(self, request):
"""Validate a request token request.
- :param request: An oauthlib.common.Request object.
+ :param request: OAuthlib request.
+ :type request: oauthlib.common.Request
:raises: OAuth1Error if the request is invalid.
:returns: A tuple of 2 elements.
1. The validation result (True or False).
diff --git a/oauthlib/oauth1/rfc5849/request_validator.py b/oauthlib/oauth1/rfc5849/request_validator.py
index bc62ea0..330bcbb 100644
--- a/oauthlib/oauth1/rfc5849/request_validator.py
+++ b/oauthlib/oauth1/rfc5849/request_validator.py
@@ -267,7 +267,8 @@ class RequestValidator(object):
"""Retrieves the client secret associated with the client key.
:param client_key: The client/consumer key.
- :param request: An oauthlib.common.Request object.
+ :param request: OAuthlib request.
+ :type request: oauthlib.common.Request
:returns: The client secret as a string.
This method must allow the use of a dummy client_key value.
@@ -303,7 +304,8 @@ class RequestValidator(object):
:param client_key: The client/consumer key.
:param token: The request token string.
- :param request: An oauthlib.common.Request object.
+ :param request: OAuthlib request.
+ :type request: oauthlib.common.Request
:returns: The token secret as a string.
This method must allow the use of a dummy values and the running time
@@ -335,7 +337,8 @@ class RequestValidator(object):
:param client_key: The client/consumer key.
:param token: The access token string.
- :param request: An oauthlib.common.Request object.
+ :param request: OAuthlib request.
+ :type request: oauthlib.common.Request
:returns: The token secret as a string.
This method must allow the use of a dummy values and the running time
@@ -366,7 +369,8 @@ class RequestValidator(object):
"""Get the default realms for a client.
:param client_key: The client/consumer key.
- :param request: An oauthlib.common.Request object.
+ :param request: OAuthlib request.
+ :type request: oauthlib.common.Request
:returns: The list of default realms associated with the client.
The list of default realms will be set during client registration and
@@ -382,7 +386,8 @@ class RequestValidator(object):
"""Get realms associated with a request token.
:param token: The request token string.
- :param request: An oauthlib.common.Request object.
+ :param request: OAuthlib request.
+ :type request: oauthlib.common.Request
:returns: The list of realms associated with the request token.
This method is used by
@@ -396,7 +401,8 @@ class RequestValidator(object):
"""Get the redirect URI associated with a request token.
:param token: The request token string.
- :param request: An oauthlib.common.Request object.
+ :param request: OAuthlib request.
+ :type request: oauthlib.common.Request
:returns: The redirect URI associated with the request token.
It may be desirable to return a custom URI if the redirect is set to "oob".
@@ -413,7 +419,8 @@ class RequestValidator(object):
"""Retrieves a previously stored client provided RSA key.
:param client_key: The client/consumer key.
- :param request: An oauthlib.common.Request object.
+ :param request: OAuthlib request.
+ :type request: oauthlib.common.Request
:returns: The rsa public key as a string.
This method must allow the use of a dummy client_key value. Fetching
@@ -437,7 +444,8 @@ class RequestValidator(object):
:param client_key: The client/consumer key.
:param request_token: The request token string.
- :param request: An oauthlib.common.Request object.
+ :param request: OAuthlib request.
+ :type request: oauthlib.common.Request
:returns: None
Per `Section 2.3`__ of the spec:
@@ -462,7 +470,8 @@ class RequestValidator(object):
"""Validates that supplied client key is a registered and valid client.
:param client_key: The client/consumer key.
- :param request: An oauthlib.common.Request object.
+ :param request: OAuthlib request.
+ :type request: oauthlib.common.Request
:returns: True or False
Note that if the dummy client is supplied it should validate in same
@@ -499,7 +508,8 @@ class RequestValidator(object):
:param client_key: The client/consumer key.
:param token: The request token string.
- :param request: An oauthlib.common.Request object.
+ :param request: OAuthlib request.
+ :type request: oauthlib.common.Request
:returns: True or False
Note that if the dummy request_token is supplied it should validate in
@@ -533,7 +543,8 @@ class RequestValidator(object):
:param client_key: The client/consumer key.
:param token: The access token string.
- :param request: An oauthlib.common.Request object.
+ :param request: OAuthlib request.
+ :type request: oauthlib.common.Request
:returns: True or False
Note that if the dummy access token is supplied it should validate in
@@ -571,7 +582,8 @@ class RequestValidator(object):
:param nonce: The ``oauth_nonce`` parameter.
:param request_token: Request token string, if any.
:param access_token: Access token string, if any.
- :param request: An oauthlib.common.Request object.
+ :param request: OAuthlib request.
+ :type request: oauthlib.common.Request
:returns: True or False
Per `Section 3.3`_ of the spec.
@@ -618,7 +630,8 @@ class RequestValidator(object):
:param client_key: The client/consumer key.
:param redirect_uri: The URI the client which to redirect back to after
authorization is successful.
- :param request: An oauthlib.common.Request object.
+ :param request: OAuthlib request.
+ :type request: oauthlib.common.Request
:returns: True or False
It is highly recommended that OAuth providers require their clients
@@ -650,7 +663,8 @@ class RequestValidator(object):
:param client_key: The client/consumer key.
:param realms: The list of realms that client is requesting access to.
- :param request: An oauthlib.common.Request object.
+ :param request: OAuthlib request.
+ :type request: oauthlib.common.Request
:returns: True or False
This method is invoked when obtaining a request token and should
@@ -669,7 +683,8 @@ class RequestValidator(object):
:param client_key: The client/consumer key.
:param token: A request token string.
- :param request: An oauthlib.common.Request object.
+ :param request: OAuthlib request.
+ :type request: oauthlib.common.Request
:param uri: The URI the realms is protecting.
:param realms: A list of realms that must have been granted to
the access token.
@@ -703,7 +718,8 @@ class RequestValidator(object):
:param client_key: The client/consumer key.
:param token: A request token string.
:param verifier: The authorization verifier string.
- :param request: An oauthlib.common.Request object.
+ :param request: OAuthlib request.
+ :type request: oauthlib.common.Request
:returns: True or False
OAuth providers issue a verification code to clients after the
@@ -732,7 +748,8 @@ class RequestValidator(object):
"""Verify that the given OAuth1 request token is valid.
:param token: A request token string.
- :param request: An oauthlib.common.Request object.
+ :param request: OAuthlib request.
+ :type request: oauthlib.common.Request
:returns: True or False
This method is used only in AuthorizationEndpoint to check whether the
@@ -751,7 +768,8 @@ class RequestValidator(object):
:param token: An access token string.
:param realms: A list of realms the client attempts to access.
- :param request: An oauthlib.common.Request object.
+ :param request: OAuthlib request.
+ :type request: oauthlib.common.Request
:returns: True or False
This prevents the list of authorized realms sent by the client during
@@ -773,7 +791,8 @@ class RequestValidator(object):
"""Save an OAuth1 access token.
:param token: A dict with token credentials.
- :param request: An oauthlib.common.Request object.
+ :param request: OAuthlib request.
+ :type request: oauthlib.common.Request
The token dictionary will at minimum include
@@ -796,7 +815,8 @@ class RequestValidator(object):
"""Save an OAuth1 request token.
:param token: A dict with token credentials.
- :param request: An oauthlib.common.Request object.
+ :param request: OAuthlib request.
+ :type request: oauthlib.common.Request
The token dictionary will at minimum include
@@ -818,7 +838,8 @@ class RequestValidator(object):
:param token: A request token string.
:param verifier A dictionary containing the oauth_verifier and
oauth_token
- :param request: An oauthlib.common.Request object.
+ :param request: OAuthlib request.
+ :type request: oauthlib.common.Request
We need to associate verifiers with tokens for validation during the
access token request.
diff --git a/oauthlib/oauth1/rfc5849/signature.py b/oauthlib/oauth1/rfc5849/signature.py
index 4e672ba..e90d6f3 100644
--- a/oauthlib/oauth1/rfc5849/signature.py
+++ b/oauthlib/oauth1/rfc5849/signature.py
@@ -28,7 +28,7 @@ import hashlib
import hmac
import logging
-from oauthlib.common import (bytes_type, extract_params, safe_string_equals,
+from oauthlib.common import (extract_params, safe_string_equals,
unicode_type, urldecode)
from . import utils
@@ -635,7 +635,7 @@ def verify_hmac_sha1(request, client_secret=None,
def _prepare_key_plus(alg, keystr):
- if isinstance(keystr, bytes_type):
+ if isinstance(keystr, bytes):
keystr = keystr.decode('utf-8')
return alg.prepare_key(keystr)
diff --git a/oauthlib/oauth1/rfc5849/utils.py b/oauthlib/oauth1/rfc5849/utils.py
index 3762e3b..735f21d 100644
--- a/oauthlib/oauth1/rfc5849/utils.py
+++ b/oauthlib/oauth1/rfc5849/utils.py
@@ -8,7 +8,7 @@ spec.
"""
from __future__ import absolute_import, unicode_literals
-from oauthlib.common import bytes_type, quote, unicode_type, unquote
+from oauthlib.common import quote, unicode_type, unquote
try:
import urllib2
diff --git a/oauthlib/oauth2/rfc6749/clients/service_application.py b/oauthlib/oauth2/rfc6749/clients/service_application.py
index 7f336bb..3045676 100644
--- a/oauthlib/oauth2/rfc6749/clients/service_application.py
+++ b/oauthlib/oauth2/rfc6749/clients/service_application.py
@@ -54,7 +54,7 @@ class ServiceApplicationClient(Client):
``https://provider.com/oauth2/token``.
:param kwargs: Additional arguments to pass to base client, such as
- state and token. See Client.__init__.__doc__ for
+ state and token. See ``Client.__init__.__doc__`` for
details.
"""
super(ServiceApplicationClient, self).__init__(client_id, **kwargs)
diff --git a/oauthlib/oauth2/rfc6749/errors.py b/oauthlib/oauth2/rfc6749/errors.py
index 7b31d47..482c740 100644
--- a/oauthlib/oauth2/rfc6749/errors.py
+++ b/oauthlib/oauth2/rfc6749/errors.py
@@ -21,23 +21,26 @@ class OAuth2Error(Exception):
def __init__(self, description=None, uri=None, state=None,
status_code=None, request=None):
"""
- description: A human-readable ASCII [USASCII] text providing
- additional information, used to assist the client
- developer in understanding the error that occurred.
- Values for the "error_description" parameter MUST NOT
- include characters outside the set
- x20-21 / x23-5B / x5D-7E.
-
- uri: A URI identifying a human-readable web page with information
- about the error, used to provide the client developer with
- additional information about the error. Values for the
- "error_uri" parameter MUST conform to the URI- Reference
- syntax, and thus MUST NOT include characters outside the set
- x21 / x23-5B / x5D-7E.
-
- state: A CSRF protection value received from the client.
-
- request: Oauthlib Request object
+ :param description: A human-readable ASCII [USASCII] text providing
+ additional information, used to assist the client
+ developer in understanding the error that occurred.
+ Values for the "error_description" parameter
+ MUST NOT include characters outside the set
+ x20-21 / x23-5B / x5D-7E.
+
+ :param uri: A URI identifying a human-readable web page with information
+ about the error, used to provide the client developer with
+ additional information about the error. Values for the
+ "error_uri" parameter MUST conform to the URI- Reference
+ syntax, and thus MUST NOT include characters outside the set
+ x21 / x23-5B / x5D-7E.
+
+ :param state: A CSRF protection value received from the client.
+
+ :param status_code:
+
+ :param request: OAuthlib request.
+ :type request: oauthlib.common.Request
"""
if description is not None:
self.description = description
@@ -313,6 +316,7 @@ class ConsentRequired(OAuth2Error):
error = 'consent_required'
status_code = 401
+
class LoginRequired(OAuth2Error):
"""
The Authorization Server requires End-User authentication.
@@ -325,6 +329,16 @@ class LoginRequired(OAuth2Error):
status_code = 401
+class CustomOAuth2Error(OAuth2Error):
+ """
+ This error is a placeholder for all custom errors not described by the RFC.
+ Some of the popular OAuth2 providers are using custom errors.
+ """
+ def __init__(self, error, *args, **kwargs):
+ self.error = error
+ super(CustomOAuth2Error, self).__init__(*args, **kwargs)
+
+
def raise_from_error(error, params=None):
import inspect
import sys
@@ -336,3 +350,4 @@ def raise_from_error(error, params=None):
for _, cls in inspect.getmembers(sys.modules[__name__], inspect.isclass):
if cls.error == error:
raise cls(**kwargs)
+ raise CustomOAuth2Error(error=error, **kwargs)
diff --git a/oauthlib/oauth2/rfc6749/grant_types/authorization_code.py b/oauthlib/oauth2/rfc6749/grant_types/authorization_code.py
index 3d08871..8ebae49 100644
--- a/oauthlib/oauth2/rfc6749/grant_types/authorization_code.py
+++ b/oauthlib/oauth2/rfc6749/grant_types/authorization_code.py
@@ -98,7 +98,12 @@ class AuthorizationCodeGrant(GrantTypeBase):
response_types = ['code']
def create_authorization_code(self, request):
- """Generates an authorization grant represented as a dictionary."""
+ """
+ Generates an authorization grant represented as a dictionary.
+
+ :param request: OAuthlib request.
+ :type request: oauthlib.common.Request
+ """
grant = {'code': common.generate_token()}
if hasattr(request, 'state') and request.state:
grant['state'] = request.state
@@ -135,12 +140,12 @@ class AuthorizationCodeGrant(GrantTypeBase):
HTTP redirection response, or by other means available to it via the
user-agent.
- :param request: oauthlib.commong.Request
- :param token_handler: A token handler instace, for example of type
+ :param request: OAuthlib request.
+ :type request: oauthlib.common.Request
+ :param token_handler: A token handler instance, for example of type
oauthlib.oauth2.BearerToken.
:returns: headers, body, status
:raises: FatalClientError on invalid redirect URI or client id.
- ValueError if scopes are not set on the request object.
A few examples::
@@ -151,12 +156,6 @@ class AuthorizationCodeGrant(GrantTypeBase):
>>> from oauthlib.oauth2 import AuthorizationCodeGrant, BearerToken
>>> token = BearerToken(your_validator)
>>> grant = AuthorizationCodeGrant(your_validator)
- >>> grant.create_authorization_response(request, token)
- Traceback (most recent call last):
- File "<stdin>", line 1, in <module>
- File "oauthlib/oauth2/rfc6749/grant_types.py", line 513, in create_authorization_response
- raise ValueError('Scopes must be set on post auth.')
- ValueError: Scopes must be set on post auth.
>>> request.scopes = ['authorized', 'in', 'some', 'form']
>>> grant.create_authorization_response(request, token)
(u'http://client.com/?error=invalid_request&error_description=Missing+response_type+parameter.', None, None, 400)
@@ -182,11 +181,6 @@ class AuthorizationCodeGrant(GrantTypeBase):
.. _`Section 10.12`: https://tools.ietf.org/html/rfc6749#section-10.12
"""
try:
- # request.scopes is only mandated in post auth and both pre and
- # post auth use validate_authorization_request
- if not request.scopes:
- raise ValueError('Scopes must be set on post auth.')
-
self.validate_authorization_request(request)
log.debug('Pre resource owner authorization validation ok for %r.',
request)
@@ -232,6 +226,12 @@ class AuthorizationCodeGrant(GrantTypeBase):
MUST deny the request and SHOULD revoke (when possible) all tokens
previously issued based on that authorization code. The authorization
code is bound to the client identifier and redirection URI.
+
+ :param request: OAuthlib request.
+ :type request: oauthlib.common.Request
+ :param token_handler: A token handler instance, for example of type
+ oauthlib.oauth2.BearerToken.
+
"""
headers = {
'Content-Type': 'application/json',
@@ -265,6 +265,9 @@ class AuthorizationCodeGrant(GrantTypeBase):
missing. These must be caught by the provider and handled, how this
is done is outside of the scope of OAuthLib but showing an error
page describing the issue is a good idea.
+
+ :param request: OAuthlib request.
+ :type request: oauthlib.common.Request
"""
# First check for fatal errors
@@ -365,6 +368,10 @@ class AuthorizationCodeGrant(GrantTypeBase):
return request.scopes, request_info
def validate_token_request(self, request):
+ """
+ :param request: OAuthlib request.
+ :type request: oauthlib.common.Request
+ """
# REQUIRED. Value MUST be set to "authorization_code".
if request.grant_type not in ('authorization_code', 'openid'):
raise errors.UnsupportedGrantTypeError(request=request)
@@ -422,6 +429,17 @@ class AuthorizationCodeGrant(GrantTypeBase):
# REQUIRED, if the "redirect_uri" parameter was included in the
# authorization request as described in Section 4.1.1, and their
# values MUST be identical.
+ if request.redirect_uri is None:
+ request.using_default_redirect_uri = True
+ request.redirect_uri = self.request_validator.get_default_redirect_uri(
+ request.client_id, request)
+ log.debug('Using default redirect_uri %s.', request.redirect_uri)
+ if not request.redirect_uri:
+ raise errors.MissingRedirectURIError(request=request)
+ else:
+ request.using_default_redirect_uri = False
+ log.debug('Using provided redirect_uri %s', request.redirect_uri)
+
if not self.request_validator.confirm_redirect_uri(request.client_id, request.code,
request.redirect_uri, request.client,
request):
diff --git a/oauthlib/oauth2/rfc6749/grant_types/base.py b/oauthlib/oauth2/rfc6749/grant_types/base.py
index e5d8ddd..43f9db4 100644
--- a/oauthlib/oauth2/rfc6749/grant_types/base.py
+++ b/oauthlib/oauth2/rfc6749/grant_types/base.py
@@ -116,14 +116,32 @@ class GrantTypeBase(object):
def register_token_modifier(self, modifier):
self._token_modifiers.append(modifier)
-
def create_authorization_response(self, request, token_handler):
+ """
+ :param request: OAuthlib request.
+ :type request: oauthlib.common.Request
+ :param token_handler: A token handler instance, for example of type
+ oauthlib.oauth2.BearerToken.
+ """
raise NotImplementedError('Subclasses must implement this method.')
def create_token_response(self, request, token_handler):
+ """
+ :param request: OAuthlib request.
+ :type request: oauthlib.common.Request
+ :param token_handler: A token handler instance, for example of type
+ oauthlib.oauth2.BearerToken.
+ """
raise NotImplementedError('Subclasses must implement this method.')
def add_token(self, token, token_handler, request):
+ """
+ :param token:
+ :param token_handler: A token handler instance, for example of type
+ oauthlib.oauth2.BearerToken.
+ :param request: OAuthlib request.
+ :type request: oauthlib.common.Request
+ """
# Only add a hybrid access token on auth step if asked for
if not request.response_type in ["token", "code token", "id_token token", "code id_token token"]:
return token
@@ -132,6 +150,10 @@ class GrantTypeBase(object):
return token
def validate_grant_type(self, request):
+ """
+ :param request: OAuthlib request.
+ :type request: oauthlib.common.Request
+ """
client_id = getattr(request, 'client_id', None)
if not self.request_validator.validate_grant_type(client_id,
request.grant_type, request.client, request):
@@ -140,6 +162,10 @@ class GrantTypeBase(object):
raise errors.UnauthorizedClientError(request=request)
def validate_scopes(self, request):
+ """
+ :param request: OAuthlib request.
+ :type request: oauthlib.common.Request
+ """
if not request.scopes:
request.scopes = utils.scope_to_list(request.scope) or utils.scope_to_list(
self.request_validator.get_default_scopes(request.client_id, request))
@@ -154,6 +180,13 @@ class GrantTypeBase(object):
Base classes can define a default response mode for their authorization
response by overriding the static `default_response_mode` member.
+
+ :param request: OAuthlib request.
+ :type request: oauthlib.common.Request
+ :param token:
+ :param headers:
+ :param body:
+ :param status:
"""
request.response_mode = request.response_mode or self.default_response_mode
diff --git a/oauthlib/oauth2/rfc6749/grant_types/client_credentials.py b/oauthlib/oauth2/rfc6749/grant_types/client_credentials.py
index 4c50a78..7d4f74c 100644
--- a/oauthlib/oauth2/rfc6749/grant_types/client_credentials.py
+++ b/oauthlib/oauth2/rfc6749/grant_types/client_credentials.py
@@ -53,6 +53,11 @@ class ClientCredentialsGrant(GrantTypeBase):
def create_token_response(self, request, token_handler):
"""Return token or error in JSON format.
+ :param request: OAuthlib request.
+ :type request: oauthlib.common.Request
+ :param token_handler: A token handler instance, for example of type
+ oauthlib.oauth2.BearerToken.
+
If the access token request is valid and authorized, the
authorization server issues an access token as described in
`Section 5.1`_. A refresh token SHOULD NOT be included. If the request
@@ -85,6 +90,10 @@ class ClientCredentialsGrant(GrantTypeBase):
return headers, json.dumps(token), 200
def validate_token_request(self, request):
+ """
+ :param request: OAuthlib request.
+ :type request: oauthlib.common.Request
+ """
for validator in self.custom_validators.pre_token:
validator(request)
diff --git a/oauthlib/oauth2/rfc6749/grant_types/implicit.py b/oauthlib/oauth2/rfc6749/grant_types/implicit.py
index bdab814..b29953b 100644
--- a/oauthlib/oauth2/rfc6749/grant_types/implicit.py
+++ b/oauthlib/oauth2/rfc6749/grant_types/implicit.py
@@ -121,6 +121,12 @@ class ImplicitGrant(GrantTypeBase):
def create_authorization_response(self, request, token_handler):
"""Create an authorization response.
+
+ :param request: OAuthlib request.
+ :type request: oauthlib.common.Request
+ :param token_handler: A token handler instance, for example of type
+ oauthlib.oauth2.BearerToken.
+
The client constructs the request URI by adding the following
parameters to the query component of the authorization endpoint URI
using the "application/x-www-form-urlencoded" format, per `Appendix B`_:
@@ -163,6 +169,11 @@ class ImplicitGrant(GrantTypeBase):
def create_token_response(self, request, token_handler):
"""Return token or error embedded in the URI fragment.
+ :param request: OAuthlib request.
+ :type request: oauthlib.common.Request
+ :param token_handler: A token handler instance, for example of type
+ oauthlib.oauth2.BearerToken.
+
If the resource owner grants the access request, the authorization
server issues an access token and delivers it to the client by adding
the following parameters to the fragment component of the redirection
@@ -200,11 +211,6 @@ class ImplicitGrant(GrantTypeBase):
.. _`Section 7.1`: https://tools.ietf.org/html/rfc6749#section-7.1
"""
try:
- # request.scopes is only mandated in post auth and both pre and
- # post auth use validate_authorization_request
- if not request.scopes:
- raise ValueError('Scopes must be set on post auth.')
-
self.validate_token_request(request)
# If the request fails due to a missing, invalid, or mismatching
@@ -248,11 +254,18 @@ class ImplicitGrant(GrantTypeBase):
request, token, {}, None, 302)
def validate_authorization_request(self, request):
+ """
+ :param request: OAuthlib request.
+ :type request: oauthlib.common.Request
+ """
return self.validate_token_request(request)
def validate_token_request(self, request):
"""Check the token request for normal and fatal errors.
+ :param request: OAuthlib request.
+ :type request: oauthlib.common.Request
+
This method is very similar to validate_authorization_request in
the AuthorizationCodeGrant but differ in a few subtle areas.
diff --git a/oauthlib/oauth2/rfc6749/grant_types/refresh_token.py b/oauthlib/oauth2/rfc6749/grant_types/refresh_token.py
index c2d86f7..5f7382a 100644
--- a/oauthlib/oauth2/rfc6749/grant_types/refresh_token.py
+++ b/oauthlib/oauth2/rfc6749/grant_types/refresh_token.py
@@ -33,6 +33,11 @@ class RefreshTokenGrant(GrantTypeBase):
def create_token_response(self, request, token_handler):
"""Create a new access token from a refresh_token.
+ :param request: OAuthlib request.
+ :type request: oauthlib.common.Request
+ :param token_handler: A token handler instance, for example of type
+ oauthlib.oauth2.BearerToken.
+
If valid and authorized, the authorization server issues an access
token as described in `Section 5.1`_. If the request failed
verification or is invalid, the authorization server returns an error
@@ -72,6 +77,10 @@ class RefreshTokenGrant(GrantTypeBase):
return headers, json.dumps(token), 200
def validate_token_request(self, request):
+ """
+ :param request: OAuthlib request.
+ :type request: oauthlib.common.Request
+ """
# REQUIRED. Value MUST be set to "refresh_token".
if request.grant_type != 'refresh_token':
raise errors.UnsupportedGrantTypeError(request=request)
diff --git a/oauthlib/oauth2/rfc6749/grant_types/resource_owner_password_credentials.py b/oauthlib/oauth2/rfc6749/grant_types/resource_owner_password_credentials.py
index e5f04af..87e8015 100644
--- a/oauthlib/oauth2/rfc6749/grant_types/resource_owner_password_credentials.py
+++ b/oauthlib/oauth2/rfc6749/grant_types/resource_owner_password_credentials.py
@@ -73,6 +73,11 @@ class ResourceOwnerPasswordCredentialsGrant(GrantTypeBase):
def create_token_response(self, request, token_handler):
"""Return token or error in json format.
+ :param request: OAuthlib request.
+ :type request: oauthlib.common.Request
+ :param token_handler: A token handler instance, for example of type
+ oauthlib.oauth2.BearerToken.
+
If the access token request is valid and authorized, the
authorization server issues an access token and optional refresh
token as described in `Section 5.1`_. If the request failed client
@@ -114,6 +119,9 @@ class ResourceOwnerPasswordCredentialsGrant(GrantTypeBase):
def validate_token_request(self, request):
"""
+ :param request: OAuthlib request.
+ :type request: oauthlib.common.Request
+
The client makes a request to the token endpoint by adding the
following parameters using the "application/x-www-form-urlencoded"
format per Appendix B with a character encoding of UTF-8 in the HTTP
diff --git a/oauthlib/oauth2/rfc6749/parameters.py b/oauthlib/oauth2/rfc6749/parameters.py
index c5127e7..74a15f9 100644
--- a/oauthlib/oauth2/rfc6749/parameters.py
+++ b/oauthlib/oauth2/rfc6749/parameters.py
@@ -37,14 +37,14 @@ def prepare_grant_uri(uri, client_id, response_type, redirect_uri=None,
using the ``application/x-www-form-urlencoded`` format as defined by
[`W3C.REC-html401-19991224`_]:
+ :param uri:
+ :param client_id: The client identifier as described in `Section 2.2`_.
:param response_type: To indicate which OAuth 2 grant/flow is required,
"code" and "token".
- :param client_id: The client identifier as described in `Section 2.2`_.
:param redirect_uri: The client provided URI to redirect back to after
authorization as described in `Section 3.1.2`_.
:param scope: The scope of the access request as described by
`Section 3.3`_.
-
:param state: An opaque value used by the client to maintain
state between the request and callback. The authorization
server includes this value when redirecting the user-agent
@@ -95,7 +95,7 @@ def prepare_token_request(grant_type, body='', **kwargs):
format in the HTTP request entity-body:
:param grant_type: To indicate grant type being used, i.e. "password",
- "authorization_code" or "client_credentials".
+ "authorization_code" or "client_credentials".
:param body: Existing request body to embed parameters in.
:param code: If using authorization code grant, pass the previously
obtained authorization code as the ``code`` argument.
@@ -133,15 +133,19 @@ def prepare_token_revocation_request(url, token, token_type_hint="access_token",
using the "application/x-www-form-urlencoded" format in the HTTP request
entity-body:
- token REQUIRED. The token that the client wants to get revoked.
+ :param token: REQUIRED. The token that the client wants to get revoked.
- token_type_hint OPTIONAL. A hint about the type of the token submitted
- for revocation. Clients MAY pass this parameter in order to help the
- authorization server to optimize the token lookup. If the server is unable
- to locate the token using the given hint, it MUST extend its search across
- all of its supported token types. An authorization server MAY ignore this
- parameter, particularly if it is able to detect the token type
- automatically. This specification defines two such values:
+ :param token_type_hint: OPTIONAL. A hint about the type of the token
+ submitted for revocation. Clients MAY pass this
+ parameter in order to help the authorization server
+ to optimize the token lookup. If the server is
+ unable to locate the token using the given hint, it
+ MUST extend its search across all of its supported
+ token types. An authorization server MAY ignore
+ this parameter, particularly if it is able to detect
+ the token type automatically.
+
+ This specification defines two values for `token_type_hint`:
* access_token: An access token as defined in [RFC6749],
`Section 1.4`_
@@ -264,6 +268,10 @@ def parse_implicit_response(uri, state=None, scope=None):
authorization request. The exact value received from the
client.
+ :param uri:
+ :param state:
+ :param scope:
+
Similar to the authorization code response, but with a full token provided
in the URL fragment:
diff --git a/oauthlib/oauth2/rfc6749/request_validator.py b/oauthlib/oauth2/rfc6749/request_validator.py
index bf1515d..2cf1b82 100644
--- a/oauthlib/oauth2/rfc6749/request_validator.py
+++ b/oauthlib/oauth2/rfc6749/request_validator.py
@@ -26,7 +26,8 @@ class RequestValidator(object):
client credentials or whenever Client provided client authentication, see
`Section 6`_
- :param request: oauthlib.common.Request
+ :param request: OAuthlib request.
+ :type request: oauthlib.common.Request
:rtype: True or False
Method is used by:
@@ -51,7 +52,8 @@ class RequestValidator(object):
both body and query can be obtained by direct attribute access, i.e.
request.client_id for client_id in the URL query.
- :param request: oauthlib.common.Request
+ :param request: OAuthlib request.
+ :type request: oauthlib.common.Request
:rtype: True or False
Method is used by:
@@ -74,7 +76,9 @@ class RequestValidator(object):
to set request.client to the client object associated with the
given client_id.
- :param request: oauthlib.common.Request
+ :param client_id: Unicode client identifier.
+ :param request: OAuthlib request.
+ :type request: oauthlib.common.Request
:rtype: True or False
Method is used by:
@@ -93,11 +97,12 @@ class RequestValidator(object):
the client's allowed redirect URIs, but against the URI used when the
code was saved.
- :param client_id: Unicode client identifier
+ :param client_id: Unicode client identifier.
:param code: Unicode authorization_code.
- :param redirect_uri: Unicode absolute URI
- :param client: Client object set by you, see authenticate_client.
- :param request: The HTTP Request (oauthlib.common.Request)
+ :param redirect_uri: Unicode absolute URI.
+ :param client: Client object set by you, see ``.authenticate_client``.
+ :param request: OAuthlib request.
+ :type request: oauthlib.common.Request
:rtype: True or False
Method is used by:
@@ -108,8 +113,9 @@ class RequestValidator(object):
def get_default_redirect_uri(self, client_id, request, *args, **kwargs):
"""Get the default redirect URI for the client.
- :param client_id: Unicode client identifier
- :param request: The HTTP Request (oauthlib.common.Request)
+ :param client_id: Unicode client identifier.
+ :param request: OAuthlib request.
+ :type request: oauthlib.common.Request
:rtype: The default redirect URI for the client
Method is used by:
@@ -121,8 +127,9 @@ class RequestValidator(object):
def get_default_scopes(self, client_id, request, *args, **kwargs):
"""Get the default scopes for the client.
- :param client_id: Unicode client identifier
- :param request: The HTTP Request (oauthlib.common.Request)
+ :param client_id: Unicode client identifier.
+ :param request: OAuthlib request.
+ :type request: oauthlib.common.Request
:rtype: List of default scopes
Method is used by all core grant types:
@@ -136,8 +143,9 @@ class RequestValidator(object):
def get_original_scopes(self, refresh_token, request, *args, **kwargs):
"""Get the list of scopes associated with the refresh token.
- :param refresh_token: Unicode refresh token
- :param request: The HTTP Request (oauthlib.common.Request)
+ :param refresh_token: Unicode refresh token.
+ :param request: OAuthlib request.
+ :type request: oauthlib.common.Request
:rtype: List of scopes.
Method is used by:
@@ -156,9 +164,10 @@ class RequestValidator(object):
used in situations where returning all valid scopes from the
get_original_scopes is not practical.
- :param request_scopes: A list of scopes that were requested by client
- :param refresh_token: Unicode refresh_token
- :param request: The HTTP Request (oauthlib.common.Request)
+ :param request_scopes: A list of scopes that were requested by client.
+ :param refresh_token: Unicode refresh_token.
+ :param request: OAuthlib request.
+ :type request: oauthlib.common.Request
:rtype: True or False
Method is used by:
@@ -196,7 +205,8 @@ class RequestValidator(object):
:param token: The token string.
:param token_type_hint: access_token or refresh_token.
- :param request: The HTTP Request (oauthlib.common.Request)
+ :param request: OAuthlib request.
+ :type request: oauthlib.common.Request
Method is used by:
- Introspect Endpoint (all grants are compatible)
@@ -209,9 +219,10 @@ class RequestValidator(object):
def invalidate_authorization_code(self, client_id, code, request, *args, **kwargs):
"""Invalidate an authorization code after use.
- :param client_id: Unicode client identifier
+ :param client_id: Unicode client identifier.
:param code: The authorization code grant (request.code).
- :param request: The HTTP Request (oauthlib.common.Request)
+ :param request: OAuthlib request.
+ :type request: oauthlib.common.Request
Method is used by:
- Authorization Code Grant
@@ -223,7 +234,8 @@ class RequestValidator(object):
:param token: The token string.
:param token_type_hint: access_token or refresh_token.
- :param request: The HTTP Request (oauthlib.common.Request)
+ :param request: OAuthlib request.
+ :type request: oauthlib.common.Request
Method is used by:
- Revocation Endpoint
@@ -237,7 +249,8 @@ class RequestValidator(object):
or replaced with a new one (rotated). Return True to rotate and
and False for keeping original.
- :param request: oauthlib.common.Request
+ :param request: OAuthlib request.
+ :type request: oauthlib.common.Request
:rtype: True or False
Method is used by:
@@ -269,9 +282,10 @@ class RequestValidator(object):
http://openid.net/specs/openid-connect-core-1_0.html#ClaimsParameter
This value should be saved in this method and used again in 'validate_code'.
- :param client_id: Unicode client identifier
+ :param client_id: Unicode client identifier.
:param code: A dict of the authorization code grant and, optionally, state.
- :param request: The HTTP Request (oauthlib.common.Request)
+ :param request: OAuthlib request.
+ :type request: oauthlib.common.Request
Method is used by:
- Authorization Code Grant
@@ -292,10 +306,12 @@ class RequestValidator(object):
blank value `""` don't forget to check it before using those values
in a select query if a database is used.
- :param client_id: Unicode client identifier
- :param code: Unicode authorization code grant
- :param redirect_uri: Unicode absolute URI
- :return: A list of scope
+ :param client_id: Unicode client identifier.
+ :param code: Unicode authorization code grant.
+ :param redirect_uri: Unicode absolute URI.
+ :param request: OAuthlib request.
+ :type request: oauthlib.common.Request
+ :return: A list of scopes
Method is used by:
- Authorization Token Grant Dispatcher
@@ -306,6 +322,10 @@ class RequestValidator(object):
"""Persist the token with a token type specific method.
Currently, only save_bearer_token is supported.
+
+ :param token: A (Bearer) token dict.
+ :param request: OAuthlib request.
+ :type request: oauthlib.common.Request
"""
return self.save_bearer_token(token, request, *args, **kwargs)
@@ -346,9 +366,9 @@ class RequestValidator(object):
the claims dict, which should be saved for later use when generating the
id_token and/or UserInfo response content.
- :param client_id: Unicode client identifier
- :param token: A Bearer token dict
- :param request: The HTTP Request (oauthlib.common.Request)
+ :param token: A Bearer token dict.
+ :param request: OAuthlib request.
+ :type request: oauthlib.common.Request
:rtype: The default redirect URI for the client
Method is used by all core grant types issuing Bearer tokens:
@@ -364,9 +384,10 @@ class RequestValidator(object):
If using OpenID Connect this SHOULD call `oauthlib.oauth2.RequestValidator.get_id_token`
- :param token: A Bearer token dict
- :param token_handler: the token handler (BearerToken class)
- :param request: the HTTP Request (oauthlib.common.Request)
+ :param token: A Bearer token dict.
+ :param token_handler: The token handler (BearerToken class).
+ :param request: OAuthlib request.
+ :type request: oauthlib.common.Request
:return: The JWT Bearer token or OpenID Connect ID token (a JWS signed JWT)
Method is used by JWT Bearer and OpenID Connect tokens:
@@ -399,9 +420,10 @@ class RequestValidator(object):
.. _`3.2.2.10`: http://openid.net/specs/openid-connect-core-1_0.html#ImplicitIDToken
.. _`3.3.2.11`: http://openid.net/specs/openid-connect-core-1_0.html#HybridIDToken
- :param token: A Bearer token dict
- :param token_handler: the token handler (BearerToken class)
- :param request: the HTTP Request (oauthlib.common.Request)
+ :param token: A Bearer token dict.
+ :param token_handler: The token handler (BearerToken class)
+ :param request: OAuthlib request.
+ :type request: oauthlib.common.Request
:return: The ID Token (a JWS signed JWT)
"""
# the request.scope should be used by the get_id_token() method to determine which claims to include in the resulting id_token
@@ -420,9 +442,10 @@ class RequestValidator(object):
- http://openid.net/specs/openid-connect-core-1_0.html#HybridIDTValidation
- http://openid.net/specs/openid-connect-core-1_0.html#HybridIDTValidation2
- :param token: Unicode Bearer token
- :param scopes: List of scopes (defined by you)
- :param request: The HTTP Request (oauthlib.common.Request)
+ :param token: Unicode Bearer token.
+ :param scopes: List of scopes (defined by you).
+ :param request: OAuthlib request.
+ :type request: oauthlib.common.Request
:rtype: True or False
Method is indirectly used by all core OpenID connect JWT token issuing grant types:
@@ -441,9 +464,10 @@ class RequestValidator(object):
- http://openid.net/specs/openid-connect-core-1_0.html#HybridIDTValidation
- http://openid.net/specs/openid-connect-core-1_0.html#HybridIDTValidation2
- :param token: Unicode Bearer token
- :param scopes: List of scopes (defined by you)
- :param request: The HTTP Request (oauthlib.common.Request)
+ :param token: Unicode Bearer token.
+ :param scopes: List of scopes (defined by you).
+ :param request: OAuthlib request.
+ :type request: oauthlib.common.Request
:rtype: True or False
Method is indirectly used by all core OpenID connect JWT token issuing grant types:
@@ -458,7 +482,8 @@ class RequestValidator(object):
:param token: A string of random characters.
:param scopes: A list of scopes associated with the protected resource.
- :param request: The HTTP Request (oauthlib.common.Request)
+ :param request: OAuthlib request.
+ :type request: oauthlib.common.Request
A key to OAuth 2 security and restricting impact of leaked tokens is
the short expiration time of tokens, *always ensure the token has not
@@ -492,7 +517,8 @@ class RequestValidator(object):
:param token: Unicode Bearer token
:param scopes: List of scopes (defined by you)
- :param request: The HTTP Request (oauthlib.common.Request)
+ :param request: OAuthlib request.
+ :type request: oauthlib.common.Request
:rtype: True or False
Method is indirectly used by all core Bearer token issuing grant types:
@@ -510,7 +536,9 @@ class RequestValidator(object):
to set request.client to the client object associated with the
given client_id.
- :param request: oauthlib.common.Request
+ :param client_id: Unicode client identifier.
+ :param request: OAuthlib request.
+ :type request: oauthlib.common.Request
:rtype: True or False
Method is used by:
@@ -536,10 +564,11 @@ class RequestValidator(object):
The request.claims property, if it was given, should assigned a dict.
- :param client_id: Unicode client identifier
- :param code: Unicode authorization code
- :param client: Client object set by you, see authenticate_client.
- :param request: The HTTP Request (oauthlib.common.Request)
+ :param client_id: Unicode client identifier.
+ :param code: Unicode authorization code.
+ :param client: Client object set by you, see ``.authenticate_client``.
+ :param request: OAuthlib request.
+ :type request: oauthlib.common.Request
:rtype: True or False
Method is used by:
@@ -550,10 +579,11 @@ class RequestValidator(object):
def validate_grant_type(self, client_id, grant_type, client, request, *args, **kwargs):
"""Ensure client is authorized to use the grant_type requested.
- :param client_id: Unicode client identifier
+ :param client_id: Unicode client identifier.
:param grant_type: Unicode grant type, i.e. authorization_code, password.
- :param client: Client object set by you, see authenticate_client.
- :param request: The HTTP Request (oauthlib.common.Request)
+ :param client: Client object set by you, see ``.authenticate_client``.
+ :param request: OAuthlib request.
+ :type request: oauthlib.common.Request
:rtype: True or False
Method is used by:
@@ -570,9 +600,10 @@ class RequestValidator(object):
All clients should register the absolute URIs of all URIs they intend
to redirect to. The registration is outside of the scope of oauthlib.
- :param client_id: Unicode client identifier
- :param redirect_uri: Unicode absolute URI
- :param request: The HTTP Request (oauthlib.common.Request)
+ :param client_id: Unicode client identifier.
+ :param redirect_uri: Unicode absolute URI.
+ :param request: OAuthlib request.
+ :type request: oauthlib.common.Request
:rtype: True or False
Method is used by:
@@ -587,9 +618,10 @@ class RequestValidator(object):
OBS! The request.user attribute should be set to the resource owner
associated with this refresh token.
- :param refresh_token: Unicode refresh token
- :param client: Client object set by you, see authenticate_client.
- :param request: The HTTP Request (oauthlib.common.Request)
+ :param refresh_token: Unicode refresh token.
+ :param client: Client object set by you, see ``.authenticate_client``.
+ :param request: OAuthlib request.
+ :type request: oauthlib.common.Request
:rtype: True or False
Method is used by:
@@ -602,10 +634,11 @@ class RequestValidator(object):
def validate_response_type(self, client_id, response_type, client, request, *args, **kwargs):
"""Ensure client is authorized to use the response_type requested.
- :param client_id: Unicode client identifier
+ :param client_id: Unicode client identifier.
:param response_type: Unicode response type, i.e. code, token.
- :param client: Client object set by you, see authenticate_client.
- :param request: The HTTP Request (oauthlib.common.Request)
+ :param client: Client object set by you, see ``.authenticate_client``.
+ :param request: OAuthlib request.
+ :type request: oauthlib.common.Request
:rtype: True or False
Method is used by:
@@ -617,10 +650,11 @@ class RequestValidator(object):
def validate_scopes(self, client_id, scopes, client, request, *args, **kwargs):
"""Ensure the client is authorized access to requested scopes.
- :param client_id: Unicode client identifier
- :param scopes: List of scopes (defined by you)
- :param client: Client object set by you, see authenticate_client.
- :param request: The HTTP Request (oauthlib.common.Request)
+ :param client_id: Unicode client identifier.
+ :param scopes: List of scopes (defined by you).
+ :param client: Client object set by you, see ``.authenticate_client``.
+ :param request: OAuthlib request.
+ :type request: oauthlib.common.Request
:rtype: True or False
Method is used by all core grant types:
@@ -637,7 +671,8 @@ class RequestValidator(object):
Silent OpenID authorization allows access tokens and id tokens to be
granted to clients without any user prompt or interaction.
- :param request: The HTTP Request (oauthlib.common.Request)
+ :param request: OAuthlib request.
+ :type request: oauthlib.common.Request
:rtype: True or False
Method is used by:
@@ -657,7 +692,8 @@ class RequestValidator(object):
not selected which one to link to the token then this method should
raise an oauthlib.oauth2.AccountSelectionRequired error.
- :param request: The HTTP Request (oauthlib.common.Request)
+ :param request: OAuthlib request.
+ :type request: oauthlib.common.Request
:rtype: True or False
Method is used by:
@@ -675,10 +711,11 @@ class RequestValidator(object):
not set you will be unable to associate a token with a user in the
persistance method used (commonly, save_bearer_token).
- :param username: Unicode username
- :param password: Unicode password
- :param client: Client object set by you, see authenticate_client.
- :param request: The HTTP Request (oauthlib.common.Request)
+ :param username: Unicode username.
+ :param password: Unicode password.
+ :param client: Client object set by you, see ``.authenticate_client``.
+ :param request: OAuthlib request.
+ :type request: oauthlib.common.Request
:rtype: True or False
Method is used by:
@@ -695,7 +732,8 @@ class RequestValidator(object):
:param id_token_hint: User identifier string.
:param scopes: List of OAuth 2 scopes and OpenID claims (strings).
:param claims: OpenID Connect claims dict.
- :param request: The HTTP Request (oauthlib.common.Request)
+ :param request: OAuthlib request.
+ :type request: oauthlib.common.Request
:rtype: True or False
Method is used by:
diff --git a/oauthlib/oauth2/rfc6749/tokens.py b/oauthlib/oauth2/rfc6749/tokens.py
index 1d2b5eb..d78df09 100644
--- a/oauthlib/oauth2/rfc6749/tokens.py
+++ b/oauthlib/oauth2/rfc6749/tokens.py
@@ -96,10 +96,14 @@ def prepare_mac_header(token, uri, key, http_method,
.. _`MAC Access Authentication`: https://tools.ietf.org/html/draft-ietf-oauth-v2-http-mac-01
.. _`extension algorithms`: https://tools.ietf.org/html/draft-ietf-oauth-v2-http-mac-01#section-7.1
+ :param token:
:param uri: Request URI.
- :param headers: Request headers as a dictionary.
- :param http_method: HTTP Request method.
:param key: MAC given provided by token endpoint.
+ :param http_method: HTTP Request method.
+ :param nonce:
+ :param headers: Request headers as a dictionary.
+ :param body:
+ :param ext:
:param hash_algorithm: HMAC algorithm provided by token endpoint.
:param issue_time: Time when the MAC credentials were issued (datetime).
:param draft: MAC authentication specification version.
@@ -181,6 +185,9 @@ def prepare_bearer_uri(token, uri):
http://www.example.com/path?access_token=h480djs93hd8
.. _`Bearer Token`: https://tools.ietf.org/html/rfc6750
+
+ :param token:
+ :param uri:
"""
return add_params_to_uri(uri, [(('access_token', token))])
@@ -192,6 +199,9 @@ def prepare_bearer_headers(token, headers=None):
Authorization: Bearer h480djs93hd8
.. _`Bearer Token`: https://tools.ietf.org/html/rfc6750
+
+ :param token:
+ :param headers:
"""
headers = headers or {}
headers['Authorization'] = 'Bearer %s' % token
@@ -204,15 +214,26 @@ def prepare_bearer_body(token, body=''):
access_token=h480djs93hd8
.. _`Bearer Token`: https://tools.ietf.org/html/rfc6750
+
+ :param token:
+ :param body:
"""
return add_params_to_qs(body, [(('access_token', token))])
def random_token_generator(request, refresh_token=False):
+ """
+ :param request: OAuthlib request.
+ :type request: oauthlib.common.Request
+ :param refresh_token:
+ """
return common.generate_token()
def signed_token_generator(private_pem, **kwargs):
+ """
+ :param private_pem:
+ """
def signed_token_generator(request):
request.claims = kwargs
return common.generate_signed_token(private_pem, request)
@@ -223,7 +244,9 @@ def signed_token_generator(private_pem, **kwargs):
def get_token_from_header(request):
"""
Helper function to extract a token from the request header.
- :param request: The request object
+
+ :param request: OAuthlib request.
+ :type request: oauthlib.common.Request
:return: Return the token or None if the Authorization header is malformed.
"""
token = None
@@ -244,9 +267,17 @@ class TokenBase(object):
raise NotImplementedError('Subclasses must implement this method.')
def validate_request(self, request):
+ """
+ :param request: OAuthlib request.
+ :type request: oauthlib.common.Request
+ """
raise NotImplementedError('Subclasses must implement this method.')
def estimate_type(self, request):
+ """
+ :param request: OAuthlib request.
+ :type request: oauthlib.common.Request
+ """
raise NotImplementedError('Subclasses must implement this method.')
@@ -266,7 +297,14 @@ class BearerToken(TokenBase):
self.expires_in = expires_in or 3600
def create_token(self, request, refresh_token=False, save_token=True):
- """Create a BearerToken, by default without refresh token."""
+ """
+ Create a BearerToken, by default without refresh token.
+
+ :param request: OAuthlib request.
+ :type request: oauthlib.common.Request
+ :param refresh_token:
+ :param save_token:
+ """
if callable(self.expires_in):
expires_in = self.expires_in(request)
@@ -304,11 +342,19 @@ class BearerToken(TokenBase):
return token
def validate_request(self, request):
+ """
+ :param request: OAuthlib request.
+ :type request: oauthlib.common.Request
+ """
token = get_token_from_header(request)
return self.request_validator.validate_bearer_token(
token, request.scopes, request)
def estimate_type(self, request):
+ """
+ :param request: OAuthlib request.
+ :type request: oauthlib.common.Request
+ """
if request.headers.get('Authorization', '').split(' ')[0] == 'Bearer':
return 9
elif request.access_token is not None:
diff --git a/oauthlib/openid/connect/core/request_validator.py b/oauthlib/openid/connect/core/request_validator.py
index f3bcbdb..1587754 100644
--- a/oauthlib/openid/connect/core/request_validator.py
+++ b/oauthlib/openid/connect/core/request_validator.py
@@ -45,7 +45,8 @@ class RequestValidator(OAuth2RequestValidator):
:param token: A Bearer token dict
:param token_handler: the token handler (BearerToken class)
- :param request: the HTTP Request (oauthlib.common.Request)
+ :param request: OAuthlib request.
+ :type request: oauthlib.common.Request
:return: The JWT Bearer token or OpenID Connect ID token (a JWS signed JWT)
Method is used by JWT Bearer and OpenID Connect tokens:
@@ -80,7 +81,8 @@ class RequestValidator(OAuth2RequestValidator):
:param token: A Bearer token dict
:param token_handler: the token handler (BearerToken class)
- :param request: the HTTP Request (oauthlib.common.Request)
+ :param request: OAuthlib request.
+ :type request: oauthlib.common.Request
:return: The ID Token (a JWS signed JWT)
"""
# the request.scope should be used by the get_id_token() method to determine which claims to include in the resulting id_token
@@ -101,7 +103,8 @@ class RequestValidator(OAuth2RequestValidator):
:param token: Unicode Bearer token
:param scopes: List of scopes (defined by you)
- :param request: The HTTP Request (oauthlib.common.Request)
+ :param request: OAuthlib request.
+ :type request: oauthlib.common.Request
:rtype: True or False
Method is indirectly used by all core OpenID connect JWT token issuing grant types:
@@ -122,7 +125,8 @@ class RequestValidator(OAuth2RequestValidator):
:param token: Unicode Bearer token
:param scopes: List of scopes (defined by you)
- :param request: The HTTP Request (oauthlib.common.Request)
+ :param request: OAuthlib request.
+ :type request: oauthlib.common.Request
:rtype: True or False
Method is indirectly used by all core OpenID connect JWT token issuing grant types:
@@ -138,7 +142,8 @@ class RequestValidator(OAuth2RequestValidator):
Silent OpenID authorization allows access tokens and id tokens to be
granted to clients without any user prompt or interaction.
- :param request: The HTTP Request (oauthlib.common.Request)
+ :param request: OAuthlib request.
+ :type request: oauthlib.common.Request
:rtype: True or False
Method is used by:
@@ -158,7 +163,8 @@ class RequestValidator(OAuth2RequestValidator):
not selected which one to link to the token then this method should
raise an oauthlib.oauth2.AccountSelectionRequired error.
- :param request: The HTTP Request (oauthlib.common.Request)
+ :param request: OAuthlib request.
+ :type request: oauthlib.common.Request
:rtype: True or False
Method is used by:
@@ -177,7 +183,8 @@ class RequestValidator(OAuth2RequestValidator):
:param id_token_hint: User identifier string.
:param scopes: List of OAuth 2 scopes and OpenID claims (strings).
:param claims: OpenID Connect claims dict.
- :param request: The HTTP Request (oauthlib.common.Request)
+ :param request: OAuthlib request.
+ :type request: oauthlib.common.Request
:rtype: True or False
Method is used by:
diff --git a/requirements-test.txt b/requirements-test.txt
index 5bf6e06..c3e0a7b 100644
--- a/requirements-test.txt
+++ b/requirements-test.txt
@@ -1,4 +1,3 @@
-r requirements.txt
coverage>=3.7.1
-nose==1.3.7
mock>=2.0
diff --git a/setup.py b/setup.py
index 1d69e0d..640bbe1 100755
--- a/setup.py
+++ b/setup.py
@@ -18,10 +18,9 @@ def fread(fn):
with open(join(dirname(__file__), fn), 'r') as f:
return f.read()
-if sys.version_info[0] == 3:
- tests_require = ['nose', 'cryptography', 'pyjwt>=1.0.0', 'blinker']
-else:
- tests_require = ['nose', 'unittest2', 'cryptography', 'mock>=2.0', 'pyjwt>=1.0.0', 'blinker']
+tests_require = ['cryptography', 'pyjwt>=1.0.0', 'blinker']
+if sys.version_info[0] == 2:
+ tests_require.append('mock>=2.0')
rsa_require = ['cryptography']
signedtoken_require = ['cryptography', 'pyjwt>=1.0.0']
signals_require = ['blinker']
@@ -41,7 +40,6 @@ setup(
platforms='any',
license='BSD',
packages=find_packages(exclude=('docs', 'tests', 'tests.*')),
- test_suite='nose.collector',
tests_require=tests_require,
extras_require={
'test': tests_require,
diff --git a/tests/oauth1/rfc5849/test_client.py b/tests/oauth1/rfc5849/test_client.py
index 777efc2..e1f83de 100644
--- a/tests/oauth1/rfc5849/test_client.py
+++ b/tests/oauth1/rfc5849/test_client.py
@@ -5,7 +5,7 @@ from oauthlib.common import Request
from oauthlib.oauth1 import (SIGNATURE_PLAINTEXT, SIGNATURE_HMAC_SHA1,
SIGNATURE_HMAC_SHA256, SIGNATURE_RSA,
SIGNATURE_TYPE_BODY, SIGNATURE_TYPE_QUERY)
-from oauthlib.oauth1.rfc5849 import Client, bytes_type
+from oauthlib.oauth1.rfc5849 import Client
from ...unittest import TestCase
@@ -39,7 +39,7 @@ class ClientConstructorTests(TestCase):
def test_convert_to_unicode_resource_owner(self):
client = Client('client-key',
resource_owner_key=b'owner key')
- self.assertFalse(isinstance(client.resource_owner_key, bytes_type))
+ self.assertNotIsInstance(client.resource_owner_key, bytes)
self.assertEqual(client.resource_owner_key, 'owner key')
def test_give_explicit_timestamp(self):
@@ -57,11 +57,11 @@ class ClientConstructorTests(TestCase):
uri, headers, body = client.sign('http://a.b/path?query',
http_method='POST', body='a=b',
headers={'Content-Type': 'application/x-www-form-urlencoded'})
- self.assertIsInstance(uri, bytes_type)
- self.assertIsInstance(body, bytes_type)
+ self.assertIsInstance(uri, bytes)
+ self.assertIsInstance(body, bytes)
for k, v in headers.items():
- self.assertIsInstance(k, bytes_type)
- self.assertIsInstance(v, bytes_type)
+ self.assertIsInstance(k, bytes)
+ self.assertIsInstance(v, bytes)
def test_hmac_sha1(self):
client = Client('client_key')
diff --git a/tests/oauth2/rfc6749/endpoints/test_base_endpoint.py b/tests/oauth2/rfc6749/endpoints/test_base_endpoint.py
index 4ad0ed9..4f78d9b 100644
--- a/tests/oauth2/rfc6749/endpoints/test_base_endpoint.py
+++ b/tests/oauth2/rfc6749/endpoints/test_base_endpoint.py
@@ -24,7 +24,9 @@ class BaseEndpointTest(TestCase):
validator = RequestValidator()
server = Server(validator)
server.catch_errors = True
- h, b, s = server.create_authorization_response('https://example.com')
+ h, b, s = server.create_token_response(
+ 'https://example.com?grant_type=authorization_code&code=abc'
+ )
self.assertIn("server_error", b)
self.assertEqual(s, 500)
diff --git a/tests/oauth2/rfc6749/endpoints/test_credentials_preservation.py b/tests/oauth2/rfc6749/endpoints/test_credentials_preservation.py
index 0eb719f..50c2956 100644
--- a/tests/oauth2/rfc6749/endpoints/test_credentials_preservation.py
+++ b/tests/oauth2/rfc6749/endpoints/test_credentials_preservation.py
@@ -116,3 +116,24 @@ class PreservationTest(TestCase):
self.assertRaises(errors.MissingRedirectURIError,
self.mobile.create_authorization_response,
auth_uri + '&response_type=token', scopes=['random'])
+
+ def test_default_uri_in_token(self):
+ auth_uri = 'http://example.com/path?state=xyz&client_id=abc'
+ token_uri = 'http://example.com/path'
+
+ # authorization grant
+ h, _, s = self.web.create_authorization_response(
+ auth_uri + '&response_type=code', scopes=['random'])
+ self.assertEqual(s, 302)
+ self.assertIn('Location', h)
+ self.assertTrue(h['Location'].startswith(self.DEFAULT_REDIRECT_URI))
+
+ # confirm_redirect_uri should return true if the redirect uri
+ # was not given in the authorization AND not in the token request.
+ self.validator.confirm_redirect_uri.return_value = True
+ code = get_query_credentials(h['Location'])['code'][0]
+ self.validator.validate_code.side_effect = self.set_state('xyz')
+ _, body, s = self.web.create_token_response(token_uri,
+ body='grant_type=authorization_code&code=%s' % code)
+ self.assertEqual(s, 200)
+ self.assertEqual(self.validator.confirm_redirect_uri.call_args[0][2], self.DEFAULT_REDIRECT_URI)
diff --git a/tests/oauth2/rfc6749/endpoints/test_error_responses.py b/tests/oauth2/rfc6749/endpoints/test_error_responses.py
index de0d834..ef05c4d 100644
--- a/tests/oauth2/rfc6749/endpoints/test_error_responses.py
+++ b/tests/oauth2/rfc6749/endpoints/test_error_responses.py
@@ -253,6 +253,7 @@ class ErrorResponseTest(TestCase):
def test_access_denied(self):
self.validator.authenticate_client.side_effect = self.set_client
+ self.validator.get_default_redirect_uri.return_value = 'https://i.b/cb'
self.validator.confirm_redirect_uri.return_value = False
token_uri = 'https://i.b/token'
# Authorization code grant
@@ -260,6 +261,15 @@ class ErrorResponseTest(TestCase):
body='grant_type=authorization_code&code=foo')
self.assertEqual('invalid_request', json.loads(body)['error'])
+ def test_access_denied_no_default_redirecturi(self):
+ self.validator.authenticate_client.side_effect = self.set_client
+ self.validator.get_default_redirect_uri.return_value = None
+ token_uri = 'https://i.b/token'
+ # Authorization code grant
+ _, body, _ = self.web.create_token_response(token_uri,
+ body='grant_type=authorization_code&code=foo')
+ self.assertEqual('invalid_request', json.loads(body)['error'])
+
def test_unsupported_response_type(self):
self.validator.get_default_redirect_uri.return_value = 'https://i.b/cb'
diff --git a/tests/oauth2/rfc6749/grant_types/test_authorization_code.py b/tests/oauth2/rfc6749/grant_types/test_authorization_code.py
index 704a254..acb23ac 100644
--- a/tests/oauth2/rfc6749/grant_types/test_authorization_code.py
+++ b/tests/oauth2/rfc6749/grant_types/test_authorization_code.py
@@ -77,6 +77,12 @@ class AuthorizationCodeGrantTest(TestCase):
self.assertTrue(self.mock_validator.validate_response_type.called)
self.assertTrue(self.mock_validator.validate_scopes.called)
+ def test_create_authorization_grant_no_scopes(self):
+ bearer = BearerToken(self.mock_validator)
+ self.request.response_mode = 'query'
+ self.request.scopes = []
+ self.auth.create_authorization_response(self.request, bearer)
+
def test_create_authorization_grant_state(self):
self.request.state = 'abc'
self.request.redirect_uri = None
diff --git a/tests/oauth2/rfc6749/test_parameters.py b/tests/oauth2/rfc6749/test_parameters.py
index b211d1e..c42f516 100644
--- a/tests/oauth2/rfc6749/test_parameters.py
+++ b/tests/oauth2/rfc6749/test_parameters.py
@@ -103,6 +103,7 @@ class ParameterTests(TestCase):
' "refresh_token": "tGzv3JOkF0XG5Qx2TlKWIA",'
' "example_parameter": "example_value" }')
+ json_custom_error = '{ "error": "incorrect_client_credentials" }'
json_error = '{ "error": "access_denied" }'
json_notoken = ('{ "token_type": "example",'
@@ -197,6 +198,9 @@ class ParameterTests(TestCase):
self.assertRaises(ValueError, parse_implicit_response,
self.implicit_wrongstate, state=self.state)
+ def test_custom_json_error(self):
+ self.assertRaises(CustomOAuth2Error, parse_token_response, self.json_custom_error)
+
def test_json_token_response(self):
"""Verify correct parameter parsing and validation for token responses. """
self.assertEqual(parse_token_response(self.json_response), self.json_dict)
diff --git a/tests/openid/connect/core/grant_types/test_dispatchers.py b/tests/openid/connect/core/grant_types/test_dispatchers.py
index f90ec46..84f2688 100644
--- a/tests/openid/connect/core/grant_types/test_dispatchers.py
+++ b/tests/openid/connect/core/grant_types/test_dispatchers.py
@@ -36,23 +36,23 @@ class ImplicitTokenGrantDispatcherTest(TestCase):
self.request.scopes = ('hello', 'openid')
self.request.response_type = 'id_token'
handler = self.dispatcher._handler_for_request(self.request)
- self.assertTrue(isinstance(handler, ImplicitGrant))
+ self.assertIsInstance(handler, ImplicitGrant)
def test_validate_authorization_request_openid(self):
self.request.scopes = ('hello', 'openid')
self.request.response_type = 'id_token'
handler = self.dispatcher._handler_for_request(self.request)
- self.assertTrue(isinstance(handler, ImplicitGrant))
+ self.assertIsInstance(handler, ImplicitGrant)
def test_create_authorization_response_oauth(self):
self.request.scopes = ('hello', 'world')
handler = self.dispatcher._handler_for_request(self.request)
- self.assertTrue(isinstance(handler, ImplicitGrant))
+ self.assertIsInstance(handler, ImplicitGrant)
def test_validate_authorization_request_oauth(self):
self.request.scopes = ('hello', 'world')
handler = self.dispatcher._handler_for_request(self.request)
- self.assertTrue(isinstance(handler, ImplicitGrant))
+ self.assertIsInstance(handler, ImplicitGrant)
class DispatcherTest(TestCase):
@@ -82,7 +82,7 @@ class AuthTokenGrantDispatcherOpenIdTest(DispatcherTest):
def test_create_token_response_openid(self):
handler = self.dispatcher._handler_for_request(self.request)
- self.assertTrue(isinstance(handler, AuthorizationCodeGrant))
+ self.assertIsInstance(handler, AuthorizationCodeGrant)
self.assertTrue(self.dispatcher.request_validator.get_authorization_code_scopes.called)
@@ -104,7 +104,7 @@ class AuthTokenGrantDispatcherOpenIdWithoutCodeTest(DispatcherTest):
def test_create_token_response_openid_without_code(self):
handler = self.dispatcher._handler_for_request(self.request)
- self.assertTrue(isinstance(handler, OAuth2AuthorizationCodeGrant))
+ self.assertIsInstance(handler, OAuth2AuthorizationCodeGrant)
self.assertFalse(self.dispatcher.request_validator.get_authorization_code_scopes.called)
@@ -121,5 +121,5 @@ class AuthTokenGrantDispatcherOAuthTest(DispatcherTest):
def test_create_token_response_oauth(self):
handler = self.dispatcher._handler_for_request(self.request)
- self.assertTrue(isinstance(handler, OAuth2AuthorizationCodeGrant))
+ self.assertIsInstance(handler, OAuth2AuthorizationCodeGrant)
self.assertTrue(self.dispatcher.request_validator.get_authorization_code_scopes.called)
diff --git a/tests/test_common.py b/tests/test_common.py
index fb4bd5b..20d9f5b 100644
--- a/tests/test_common.py
+++ b/tests/test_common.py
@@ -10,11 +10,6 @@ from oauthlib.common import (CaseInsensitiveDict, Request, add_params_to_uri,
from .unittest import TestCase
-if sys.version_info[0] == 3:
- bytes_type = bytes
-else:
- bytes_type = lambda s, e: str(s)
-
PARAMS_DICT = {'foo': 'bar', 'baz': '123', }
PARAMS_TWOTUPLE = [('foo', 'bar'), ('baz', '123')]
PARAMS_FORMENCODED = 'foo=bar&baz=123'
@@ -122,11 +117,11 @@ class RequestTest(TestCase):
def test_non_unicode_params(self):
r = Request(
- bytes_type('http://a.b/path?query', 'utf-8'),
- http_method=bytes_type('GET', 'utf-8'),
- body=bytes_type('you=shall+pass', 'utf-8'),
+ b'http://a.b/path?query',
+ http_method=b'GET',
+ body=b'you=shall+pass',
headers={
- bytes_type('a', 'utf-8'): bytes_type('b', 'utf-8')
+ b'a': b'b',
}
)
self.assertEqual(r.uri, 'http://a.b/path?query')
@@ -214,6 +209,11 @@ class RequestTest(TestCase):
self.assertNotIn('bar', repr(r))
self.assertIn('<SANITIZED>', repr(r))
+ def test_headers_params(self):
+ r = Request(URI, headers={'token': 'foobar'}, body='token=banana')
+ self.assertEqual(r.headers['token'], 'foobar')
+ self.assertEqual(r.token, 'banana')
+
class CaseInsensitiveDictTest(TestCase):
diff --git a/tests/unittest/__init__.py b/tests/unittest/__init__.py
index 35b239a..6cb79a6 100644
--- a/tests/unittest/__init__.py
+++ b/tests/unittest/__init__.py
@@ -1,32 +1,15 @@
import collections
import sys
+from unittest import TestCase
try:
import urlparse
except ImportError:
import urllib.parse as urlparse
-try:
- # check the system path first
- from unittest2 import *
-except ImportError:
- if sys.version_info >= (2, 7):
- # unittest2 features are native in Python 2.7
- from unittest import *
- else:
- raise
-
-# Python 3.1 does not provide assertIsInstance
-if sys.version_info[1] == 1:
- TestCase.assertIsInstance = lambda self, obj, cls: self.assertTrue(isinstance(obj, cls))
# Somewhat consistent itemsequal between all python versions
-if sys.version_info[1] == 3:
+if sys.version_info[0] == 3:
TestCase.assertItemsEqual = TestCase.assertCountEqual
-elif sys.version_info[0] == 2 and sys.version_info[1] == 6:
- pass
-else:
- TestCase.assertItemsEqual = lambda self, a, b: self.assertEqual(
- collections.Counter(list(a)), collections.Counter(list(b)))
# URL comparison where query param order is insignifcant
diff --git a/tox.ini b/tox.ini
index 03e25b1..c45f657 100644
--- a/tox.ini
+++ b/tox.ini
@@ -4,11 +4,10 @@ envlist = py27,py34,py35,py36,pypy,docs,readme
[testenv]
deps=
-rrequirements-test.txt
-commands=nosetests --with-coverage --cover-html --cover-html-dir={toxinidir}/htmlcov-{envname} --cover-erase --cover-package=oauthlib -w tests
+commands=
+ coverage run --source oauthlib -m unittest discover
+ coverage report
-[testenv:py27]
-deps=unittest2
- {[testenv]deps}
# tox -e docs to mimick readthedocs build.
# as of today, RTD is using python2.7 and doesn't run "setup.py install"
@@ -20,7 +19,7 @@ changedir=docs
whitelist_externals=make
commands=make clean html
-# tox -e readme to mimick pypi long_description check
+# tox -e readme to mimick PyPI long_description check
[testenv:readme]
skipsdist=True
deps=readme