Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 439e2fe

Browse files
authored
Merge branch 'master' into master
2 parents 329c619 + 92b686f commit 439e2fe

16 files changed

+248
-31
lines changed

CODE_OF_CONDUCT.md

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# OAuthlib Code of Conduct
2+
3+
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.
4+
5+
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.
6+
7+
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.
8+
9+
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.
10+
11+
If you believe someone is violating the code of conduct, we ask that you report it by contacting us.
12+
13+
Be friendly and patient.
14+
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.
15+
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.
16+
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.
17+
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:
18+
Violent threats or language directed against another person.
19+
Discriminatory jokes and language.
20+
Posting sexually explicit or violent material.
21+
Posting (or threatening to post) other people's personally identifying information ("doxing").
22+
Personal insults, especially those using racist or sexist terms.
23+
Unwelcome sexual attention.
24+
Advocating for, or encouraging, any of the above behavior.
25+
Repeated harassment of others. In general, if someone asks you to stop, then stop.
26+
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.
27+
28+
For reading the original text, please visit the [Django Code of Conduct](https://www.djangoproject.com/conduct/).

README.rst

+7-4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
OAuthLib
2-
========
1+
OAuthLib - Python Framework for OAuth1 & OAuth2
2+
===============================================
33

44
*A generic, spec-compliant, thorough implementation of the OAuth request-signing
55
logic for Python 2.7 and 3.4+.*
@@ -16,6 +16,9 @@ logic for Python 2.7 and 3.4+.*
1616
.. image:: https://img.shields.io/pypi/l/oauthlib.svg
1717
:target: https://pypi.org/project/oauthlib/
1818
:alt: License
19+
.. image:: https://app.fossa.io/api/projects/git%2Bgithub.com%2Foauthlib%2Foauthlib.svg?type=shield
20+
:target: https://app.fossa.io/projects/git%2Bgithub.com%2Foauthlib%2Foauthlib?ref=badge_shield
21+
:alt: FOSSA Status
1922
.. image:: https://img.shields.io/readthedocs/oauthlib.svg
2023
:target: https://oauthlib.readthedocs.io/en/latest/index.html
2124
:alt: Read the Docs
@@ -34,7 +37,7 @@ both of the following:
3437
.. _`OAuth 1.0 spec`: https://tools.ietf.org/html/rfc5849
3538
.. _`OAuth 2.0 spec`: https://tools.ietf.org/html/rfc6749
3639

37-
OAuthLib is a generic utility which implements the logic of OAuth without
40+
OAuthLib is a framework which implements the logic of OAuth1 or OAuth2 without
3841
assuming a specific HTTP request object or web framework. Use it to graft OAuth
3942
client support onto your favorite HTTP library, or provide support onto your
4043
favourite web framework. If you're a maintainer of such a library, write a thin
@@ -119,7 +122,7 @@ requests.
119122
Changelog
120123
---------
121124

122-
*OAuthLib is in active development, with the core of both OAuth 1 and 2
125+
*OAuthLib is in active development, with the core of both OAuth1 and OAuth2
123126
completed, for providers as well as clients.* See `supported features`_ for
124127
details.
125128

docs/contributing.rst

+25
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,31 @@ personal label matching your GitHub ID will be assigned to that issue.
3030
Feel free to propose issues that aren't described!
3131

3232

33+
oauthlib community rules
34+
========================
35+
36+
oauthlib is a community of developers which adheres to a very simple set of
37+
rules.
38+
39+
Code of Conduct
40+
---------------
41+
This project adheres to a `Code of Conduct`_ based on Django. As a community
42+
member you have to read and agree with it.
43+
44+
For more information please contact us and/or visit the original
45+
`Django Code of Conduct`_ homepage.
46+
47+
.. _`Code of Conduct`: https://github.com/oauthlib/oauthlib/blob/master/CODE_OF_CONDUCT.md
48+
.. _`Django Code of Conduct`: https://www.djangoproject.com/conduct/
49+
50+
Code of Merit
51+
-------------
52+
Please read the community's `Code of Merit`_. Every contributor will know the
53+
real purpose of their contributions to this project.
54+
55+
.. _`Code of Merit`: http://code-of-merit.org/
56+
57+
3358
Setting up topic branches and generating pull requests
3459
======================================================
3560

docs/oauth2/grants/jwt.rst

+12-5
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,14 @@
1-
==========
2-
JWT Tokens
3-
==========
1+
==============================================================
2+
JWT Profile for Client Authentication and Authorization Grants
3+
==============================================================
44

5-
Not yet implemented. Track progress in `GitHub issue 50`_.
5+
If you're looking at JWT Tokens, please see :doc:`Bearer Tokens </oauth2/tokens/bearer>` instead.
66

7-
.. _`GitHub issue 50`: https://github.com/oauthlib/oauthlib/issues/50
7+
The JWT Profile `RFC7523`_ implements the `RFC7521`_ abstract assertion
8+
protocol. It aims to extend the OAuth2 protocol to use JWT as an
9+
additional authorization grant.
10+
11+
Currently, this is not implemented but all PRs are welcome. See how to :doc:`Contribute </contributing>`.
12+
13+
.. _`RFC7521`: https://tools.ietf.org/html/rfc7521
14+
.. _`RFC7523`: https://tools.ietf.org/html/rfc7523

docs/oauth2/preconfigured_servers.rst

+5-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@ Construction is simple, only import your validator and you are good to go::
1212

1313
server = WebApplicationServer(your_validator)
1414

15-
If you prefer to construct tokens yourself you may pass a token generator::
15+
If you prefer to construct tokens yourself you may pass a token generator (see
16+
:doc:`Tokens <tokens/tokens>` for more examples like JWT) ::
1617

1718
def your_token_generator(request, refresh_token=False):
1819
return 'a_custom_token' + request.client_id
@@ -21,6 +22,9 @@ If you prefer to construct tokens yourself you may pass a token generator::
2122

2223
This function is passed the request object and a boolean indicating whether to generate an access token (False) or a refresh token (True).
2324

25+
.. autoclass:: oauthlib.oauth2.Server
26+
:members:
27+
2428
.. autoclass:: oauthlib.oauth2.WebApplicationServer
2529
:members:
2630

docs/oauth2/tokens/bearer.rst

+113-3
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,122 @@
22
Bearer Tokens
33
=============
44

5-
The most common OAuth 2 token type. It provides very little in terms of security
6-
and relies heavily upon the ability of the client to keep the token secret.
5+
The most common OAuth 2 token type.
76

8-
Bearer tokens are the default setting with all configured endpoints. Generally
7+
Bearer tokens is the default setting for all configured endpoints. Generally
98
you will not need to ever construct a token yourself as the provided servers
109
will do so for you.
1110

11+
By default, :doc:`*Server </oauth2/preconfigured_servers>` generate Bearer tokens as
12+
random strings. However, you can change the default behavior to generate JWT
13+
instead. All preconfigured servers take as parameters `token_generator` and
14+
`refresh_token_generator` to fit your needs.
15+
16+
.. contents:: Tutorial Contents
17+
:depth: 3
18+
19+
20+
1. Generate signed JWT
21+
----------------------
22+
23+
A function is available to generate signed JWT (with RS256 PEM key) with static
24+
and dynamic claims.
25+
26+
.. code-block:: python
27+
28+
from oauthlib.oauth2.rfc6749 import tokens
29+
from oauthlib.oauth2 import Server
30+
31+
private_pem_key = <load_your_key_in_pem_format>
32+
validator = <instantiate_your_validator>
33+
34+
server = Server(
35+
your_validator,
36+
token_generator=tokens.signed_token_generator(private_pem_key, issuer="foobar")
37+
)
38+
39+
40+
Note that you can add any custom claims in `RequestValidator` methods by adding them to
41+
`request.claims` dictionary. Example below:
42+
43+
44+
.. code-block:: python
45+
46+
def validate_client_id(self, client_id, request):
47+
(.. your usual checks ..)
48+
49+
request.claims = {
50+
'aud': self.client_id
51+
}
52+
return True
53+
54+
55+
Once completed, the token endpoint will generate access_token in JWT form:
56+
57+
.. code-block:: shell
58+
59+
60+
access_token=eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJy(..)&expires_in=120&token_type=Bearer(..)
61+
62+
63+
And you will find all claims in its decoded form:
64+
65+
66+
.. code-block:: javascript
67+
68+
{
69+
"aud": "<client_id>",
70+
"iss": "foobar",
71+
"scope": "profile calendar",
72+
"exp": 12345,
73+
}
74+
75+
76+
2. Define your own implementation (text, JWT, JWE, ...)
77+
----------------------------------------------------------------
78+
79+
Sometime you may want to generate custom `access_token` with a reference from a
80+
database (as text) or use a HASH signature in JWT or use JWE (encrypted content).
81+
82+
Also, note that you can declare the generate function in your instanciated
83+
validator to benefit of the `self` variables.
84+
85+
See the example below:
86+
87+
.. code-block:: python
88+
89+
class YourValidator(RequestValidator):
90+
def __init__(self, secret, issuer):
91+
self.secret = secret
92+
self.issuer = issuer
93+
94+
def generate_access_token(self, request):
95+
token = jwt.encode({
96+
"ref": str(libuuid.uuid4()),
97+
"aud": request.client_id,
98+
"iss": self.issuer,
99+
"exp": now + datetime.timedelta(seconds=request.expires_in)
100+
}, self.secret, algorithm='HS256').decode()
101+
return token
102+
103+
104+
Then associate it to your `Server`:
105+
106+
.. code-block:: python
107+
108+
validator = YourValidator(secret="<your_secret>", issuer="<your_issuer_id>")
109+
110+
server = Server(
111+
your_validator,
112+
token_generator=validator.generate_access_token
113+
)
114+
115+
116+
3. BearerToken API
117+
------------------
118+
119+
If none of the :doc:`/oauth2/preconfigured_servers` fit your needs, you can
120+
declare your own Endpoints and use the `BearerToken` API as below.
121+
12122
.. autoclass:: oauthlib.oauth2.BearerToken
13123
:members:

docs/oauth2/tokens/tokens.rst

+1-2
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,7 @@ Tokens
33
======
44

55
The main token type of OAuth 2 is Bearer tokens and that is what OAuthLib
6-
currently supports. Other tokens, such as JWT, SAML and possibly MAC (if the
7-
spec matures) can easily be added (and will be in due time).
6+
currently supports. Other tokens, such as SAML and MAC can easily be added.
87

98
The purpose of a token is to authorize access to protected resources to a client
109
(i.e. your G+ feed).

oauthlib/common.py

-1
Original file line numberDiff line numberDiff line change
@@ -426,7 +426,6 @@ def __init__(self, uri, http_method='GET', body=None, headers=None,
426426
}
427427
self._params.update(dict(urldecode(self.uri_query)))
428428
self._params.update(dict(self.decoded_body or []))
429-
self._params.update(self.headers)
430429

431430
def __getattr__(self, name):
432431
if name in self._params:

oauthlib/oauth2/rfc6749/grant_types/authorization_code.py

+11-12
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,6 @@ def create_authorization_response(self, request, token_handler):
140140
oauthlib.oauth2.BearerToken.
141141
:returns: headers, body, status
142142
:raises: FatalClientError on invalid redirect URI or client id.
143-
ValueError if scopes are not set on the request object.
144143
145144
A few examples::
146145
@@ -151,12 +150,6 @@ def create_authorization_response(self, request, token_handler):
151150
>>> from oauthlib.oauth2 import AuthorizationCodeGrant, BearerToken
152151
>>> token = BearerToken(your_validator)
153152
>>> grant = AuthorizationCodeGrant(your_validator)
154-
>>> grant.create_authorization_response(request, token)
155-
Traceback (most recent call last):
156-
File "<stdin>", line 1, in <module>
157-
File "oauthlib/oauth2/rfc6749/grant_types.py", line 513, in create_authorization_response
158-
raise ValueError('Scopes must be set on post auth.')
159-
ValueError: Scopes must be set on post auth.
160153
>>> request.scopes = ['authorized', 'in', 'some', 'form']
161154
>>> grant.create_authorization_response(request, token)
162155
(u'http://client.com/?error=invalid_request&error_description=Missing+response_type+parameter.', None, None, 400)
@@ -182,11 +175,6 @@ def create_authorization_response(self, request, token_handler):
182175
.. _`Section 10.12`: https://tools.ietf.org/html/rfc6749#section-10.12
183176
"""
184177
try:
185-
# request.scopes is only mandated in post auth and both pre and
186-
# post auth use validate_authorization_request
187-
if not request.scopes:
188-
raise ValueError('Scopes must be set on post auth.')
189-
190178
self.validate_authorization_request(request)
191179
log.debug('Pre resource owner authorization validation ok for %r.',
192180
request)
@@ -422,6 +410,17 @@ def validate_token_request(self, request):
422410
# REQUIRED, if the "redirect_uri" parameter was included in the
423411
# authorization request as described in Section 4.1.1, and their
424412
# values MUST be identical.
413+
if request.redirect_uri is None:
414+
request.using_default_redirect_uri = True
415+
request.redirect_uri = self.request_validator.get_default_redirect_uri(
416+
request.client_id, request)
417+
log.debug('Using default redirect_uri %s.', request.redirect_uri)
418+
if not request.redirect_uri:
419+
raise errors.MissingRedirectURIError(request=request)
420+
else:
421+
request.using_default_redirect_uri = False
422+
log.debug('Using provided redirect_uri %s', request.redirect_uri)
423+
425424
if not self.request_validator.confirm_redirect_uri(request.client_id, request.code,
426425
request.redirect_uri, request.client,
427426
request):

oauthlib/oauth2/rfc6749/request_validator.py

-1
Original file line numberDiff line numberDiff line change
@@ -346,7 +346,6 @@ def save_bearer_token(self, token, request, *args, **kwargs):
346346
the claims dict, which should be saved for later use when generating the
347347
id_token and/or UserInfo response content.
348348
349-
:param client_id: Unicode client identifier
350349
:param token: A Bearer token dict
351350
:param request: The HTTP Request (oauthlib.common.Request)
352351
:rtype: The default redirect URI for the client

tests/oauth2/rfc6749/endpoints/test_base_endpoint.py

+3-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,9 @@ def test_error_catching(self):
2424
validator = RequestValidator()
2525
server = Server(validator)
2626
server.catch_errors = True
27-
h, b, s = server.create_authorization_response('https://example.com')
27+
h, b, s = server.create_token_response(
28+
'https://example.com?grant_type=authorization_code&code=abc'
29+
)
2830
self.assertIn("server_error", b)
2931
self.assertEqual(s, 500)
3032

tests/oauth2/rfc6749/endpoints/test_credentials_preservation.py

+21
Original file line numberDiff line numberDiff line change
@@ -116,3 +116,24 @@ def test_default_uri(self):
116116
self.assertRaises(errors.MissingRedirectURIError,
117117
self.mobile.create_authorization_response,
118118
auth_uri + '&response_type=token', scopes=['random'])
119+
120+
def test_default_uri_in_token(self):
121+
auth_uri = 'http://example.com/path?state=xyz&client_id=abc'
122+
token_uri = 'http://example.com/path'
123+
124+
# authorization grant
125+
h, _, s = self.web.create_authorization_response(
126+
auth_uri + '&response_type=code', scopes=['random'])
127+
self.assertEqual(s, 302)
128+
self.assertIn('Location', h)
129+
self.assertTrue(h['Location'].startswith(self.DEFAULT_REDIRECT_URI))
130+
131+
# confirm_redirect_uri should return true if the redirect uri
132+
# was not given in the authorization AND not in the token request.
133+
self.validator.confirm_redirect_uri.return_value = True
134+
code = get_query_credentials(h['Location'])['code'][0]
135+
self.validator.validate_code.side_effect = self.set_state('xyz')
136+
_, body, s = self.web.create_token_response(token_uri,
137+
body='grant_type=authorization_code&code=%s' % code)
138+
self.assertEqual(s, 200)
139+
self.assertEqual(self.validator.confirm_redirect_uri.call_args[0][2], self.DEFAULT_REDIRECT_URI)

tests/oauth2/rfc6749/endpoints/test_error_responses.py

+10
Original file line numberDiff line numberDiff line change
@@ -253,13 +253,23 @@ def test_unauthorized_client(self):
253253

254254
def test_access_denied(self):
255255
self.validator.authenticate_client.side_effect = self.set_client
256+
self.validator.get_default_redirect_uri.return_value = 'https://i.b/cb'
256257
self.validator.confirm_redirect_uri.return_value = False
257258
token_uri = 'https://i.b/token'
258259
# Authorization code grant
259260
_, body, _ = self.web.create_token_response(token_uri,
260261
body='grant_type=authorization_code&code=foo')
261262
self.assertEqual('invalid_request', json.loads(body)['error'])
262263

264+
def test_access_denied_no_default_redirecturi(self):
265+
self.validator.authenticate_client.side_effect = self.set_client
266+
self.validator.get_default_redirect_uri.return_value = None
267+
token_uri = 'https://i.b/token'
268+
# Authorization code grant
269+
_, body, _ = self.web.create_token_response(token_uri,
270+
body='grant_type=authorization_code&code=foo')
271+
self.assertEqual('invalid_request', json.loads(body)['error'])
272+
263273
def test_unsupported_response_type(self):
264274
self.validator.get_default_redirect_uri.return_value = 'https://i.b/cb'
265275

0 commit comments

Comments
 (0)