Code Monkey home page Code Monkey logo

oauthlib's Introduction

OAuthLib - Python Framework for OAuth1 & OAuth2

A generic, spec-compliant, thorough implementation of the OAuth request-signing logic for Python 3.8+

GitHub Actions

Coveralls

Download from PyPI

License

FOSSA Status

Read the Docs

Chat on Gitter

OAuth + Python = OAuthlib Python Framework

OAuth often seems complicated and difficult-to-implement. There are several prominent libraries for handling OAuth requests, but they all suffer from one or both of the following:

  1. They predate the OAuth 1.0 spec, AKA RFC 5849.
  2. They predate the OAuth 2.0 spec, AKA RFC 6749.
  3. They assume the usage of a specific HTTP request library.

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 veneer on top of OAuthLib and get OAuth support for very little effort.

Documentation

Full documentation is available on Read the Docs. All contributions are very welcome! The documentation is still quite sparse, please open an issue for what you'd like to know, or discuss it in our Gitter community, or even better, send a pull request!

Interested in making OAuth requests?

Then you might be more interested in using requests which has OAuthLib powered OAuth support provided by the requests-oauthlib library.

Which web frameworks are supported?

The following packages provide OAuth support using OAuthLib.

If you have written an OAuthLib package that supports your favorite framework, please open a Pull Request, updating the documentation.

Using OAuthLib? Please get in touch!

Patching OAuth support onto an http request framework? Creating an OAuth provider extension for a web framework? Simply using OAuthLib to Get Things Done or to learn?

No matter which we'd love to hear from you in our Gitter community or if you have anything in particular you would like to have, change or comment on don't hesitate for a second to send a pull request or open an issue. We might be quite busy and therefore slow to reply but we love feedback!

Chances are you have run into something annoying that you wish there was documentation for, if you wish to gain eternal fame and glory, and a drink if we have the pleasure to run into each other, please send a docs pull request =)

License

OAuthLib is yours to use and abuse according to the terms of the BSD license. Check the LICENSE file for full details.

Credits

OAuthLib has been started and maintained several years by Idan Gazit and other amazing AUTHORS. Thanks to their wonderful work, the open-source community creation has been possible and the project can stay active and reactive to users requests.

Changelog

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.

For a full changelog see CHANGELOG.rst.

oauthlib's People

Contributors

abhishek8394 avatar andreif avatar auvipy avatar bjmc avatar calebbrown avatar cclauss avatar chadwhitacre avatar dasevilla avatar dasm avatar dgouldin avatar flippmoke avatar hoylen avatar hugovk avatar ib-lundgren avatar idan avatar jdufresne avatar jonathanhuot avatar jturmel avatar jvanasco avatar kdazzle avatar lepture avatar luhn avatar mvo5 avatar nsklikas avatar ondrowan avatar pydanny avatar skion avatar stephane avatar thedrow avatar tomchristie avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

oauthlib's Issues

Investigate possibly PyPy and Jython support

Investigate whether it would be useful to add PyPy and Jython support and what would be necessary for it to happen. As far as the OAuthLib code goes neither should be an issue but that might not be the case for the dependencies.

The biggest concern is likely to be PyCrypto.

I vaguely remember seeing threads about issues with that combination but not sure about the current status.

Jython could be tricky, there might be wrappers or suitable alternatives but needs some research.

Travis & Python 3

Not sure if Travis supports Python 3 yet, if it does we should add that to our config.

Installation instruction docs

Most people are likely to use OAuthLib indirectly, either through requests or through an extension to their favorite web framework, it would be good to make this explicit in the docs.

However some will be interested in installing (rather than cloning) and at least PyPi instructions would be useful. Furthermore OAuthLib is included in ubuntu and possibly in other distros, maybe a few unices too, have a look around and add installation instructions.

OAuth1 doesn't seem to do anything with dummy tokens

In the OAuth1 provider, where dummy tokens are fetched they're just assigned to a local variable, which is henceforth unused. e.g.:

client_key = self.dummy_client_key

Should we not be assigning these to the request object?

request.client_key = self.dummy_client_key

Add some form of debug logging

If I am using the oauth1 Client class to sign requests, I'd like to be able to see debugging information when signing requests: what are the parameters it sees, how do they look normalized, what is the base signing string produced, etc.

Perhaps using the logging framework?

cannot use non-ASCII unicode values in query string or request body of oauth1.Client

The following fails with an exception on Python 2.7.3 with latest oauthlib HEAD (comment out the GET request signing to see the failure of POST request signing)

from oauthlib import oauth1

uchar = u"\N{GREEK SMALL LETTER LAMDA}"

client = oauth1.Client(u'foo', u'bar', u'baz', u'quuz')

client.sign(u'http://example.com?foo=' + uchar, u'GET')
client.sign(u'http://example.com', u'POST', {u'foo': uchar},
            {u'Content-Type': u'application/x-www-form-urlencoded'})

OAuth1aClient & OAuth1aServer

Curious to why they are named OAuth1a when OAuth 1a is obsoleted by the OAuth RFC 5849? (http://oauth.net/core/1.0a/)

I suggest renaming them to OAuthClient and OAuthServer and have the module define the version:

# OAuth 1
from oauthlib.oauth import OAuthClient

# Possible future OAuth 2 scenario...
from oauthlib.oauth2 import OAuthConfidentialClient , OAuthPublicClient

What do you think?

Also, does questions like this one go under "Issues" or somewhere else?

OAuth 2 Tests depend on dict ordering

URL strings may be generated differently depending on the internal dict order which is fine. Our tests however do naive string comparisons which is not adequate and breaks in python 3.3. There might already be a function such as assertURLEquals but I've not looked into this. If not it is worth monkey patching this onto TestCase and using it. It should be quite straightforward using urlsparse and just making sure all query and fragment pairs are present in both strings.

Test output

======================================================================
FAIL: test_request_body (tests.oauth2.draft25.test_client.WebApplicationClientTest)
----------------------------------------------------------------------
Traceback (most recent call last):
    File "/home/ib/Testing/oauthlib/tests/oauth2/draft25/test_client.py", line 181, in test_request_body
      self.assertEqual(body, self.body_redirect)
AssertionError: 'not=empty&grant_type=authorization_code&redirect_uri=http%3A%2F%2Fmy.page.com%2 [truncated]... != 'not=empty&grant_type=authorization_code&code=zzzzaaaa&redirect_uri=http%3A%2F%2 [truncated]...
- not=empty&grant_type=authorization_code&redirect_uri=http%3A%2F%2Fmy.page.com%2Fcallback&code=zzzzaaaa
?                                                                                         --------------
+ not=empty&grant_type=authorization_code&code=zzzzaaaa&redirect_uri=http%3A%2F%2Fmy.page.com%2Fcallback
?                                        ++++++++++++++


======================================================================
FAIL: Verify correct access token request body construction.
----------------------------------------------------------------------
Traceback (most recent call last):
    File "/home/ib/Testing/oauthlib/tests/oauth2/draft25/test_parameters.py", line 124, in test_prepare_token_request
      self.assertEqual(prepare_token_request(**self.grant_body), self.auth_grant_body)
AssertionError: 'grant_type=authorization_code&redirect_uri=https%3A%2F%2Fclient.example.com%2Fc [truncated]... != 'grant_type=authorization_code&code=SplxlOBeZQQYbYS6WxSbIA&redirect_uri=https%3A [truncated]...
- grant_type=authorization_code&redirect_uri=https%3A%2F%2Fclient.example.com%2Fcb&code=SplxlOBeZQQYbYS6WxSbIA
+ grant_type=authorization_code&code=SplxlOBeZQQYbYS6WxSbIA&redirect_uri=https%3A%2F%2Fclient.example.com%2Fcb


======================================================================
FAIL: test_dict_body (tests.test_common.CommonTests)
----------------------------------------------------------------------
Traceback (most recent call last):
    File "/home/ib/Testing/oauthlib/tests/test_common.py", line 82, in test_dict_body
      self.assertEqual(r.decoded_body, self.params_twotuple)
AssertionError: Lists differ: [('baz', '123'), ('foo', 'bar'... != [('foo', 'bar'), ('baz', '123'...

First differing element 0:
('baz', '123')
('foo', 'bar')

- [('baz', '123'), ('foo', 'bar')]
+ [('foo', 'bar'), ('baz', '123')]

======================================================================
FAIL: test_extract_params_dict (tests.test_common.CommonTests)
----------------------------------------------------------------------
Traceback (most recent call last):
    File "/home/ib/Testing/oauthlib/tests/test_common.py", line 30, in test_extract_params_dict
      self.assertEqual(extract_params(self.params_dict), self.params_twotuple)
AssertionError: Lists differ: [('baz', '123'), ('foo', 'bar'... != [('foo', 'bar'), ('baz', '123'...

First differing element 0:
('baz', '123')
('foo', 'bar')

- [('baz', '123'), ('foo', 'bar')]
+ [('foo', 'bar'), ('baz', '123')]

----------------------------------------------------------------------

Installing pycrypto on Windows

This is just to help people with problems installing oauthlib on Windows due to pycrypto dependency.

oauth library depends on pycrypto library which is not pure Python library (has some c extensions). For this reason pycrypto can't be installed from source on Windows without Visual Studio 2008 installed (needed to compile these c extensions of pycrypto). The simplest solution is to download binary installers and install them using easy_install (pip doesn't support installing of binaries). 32bit binary installers for Python 2.2-2.7 and 64bit binary installer for Python 2.6 are at The Voidspace Python Modules and 64bit binary installer for Python 2.7 is at Compiling pycrypto on Win7-64. Binary installers can be installed in virtualenv - see http://stackoverflow.com/q/3271590/95735

Client usage docs

While most users are likely better of using requests (http://docs.python-requests.org/en/latest/index.html) to make OAuth requests some might not have that option. A few examples of how to use the Client class would be useful.

Some users might try to use OAuthLib with urllib2 not knowing there are better alternatives out there, a little note in the docs would help them out.

raising ValueError in escape() seems unfortunate

Porting a library from oauth to oauthlib, is fairly straightforward. One thing I ran into was the test for unicode_type in oauth1/rfc5849/utils.py escape() function.

This happens because the old api passes the token (a.k.a. resource_owner) key/secret and consumer (a.k.a. client) token/key as Python 2 8-bit strings. When Client.sign() is subsequently called, these values are passed to escape() which throws the ValueError.

The workaround in my own code is to .decode('utf-8') them when they are isinstance(value, bytes), but it seems crufty to require this in clients which will support both python 2 and python 3 (e.g. using un-prefixed string literals in test cases).

Why couldn't unescape() do the decoding for you?

OAuth2 draft25 issues

Dear Sir/Madam,

I was trying to use oauthlib by the code below.

oauth = oauthlib.oauth2.draft25.Server('code')
verified = oauth.verify_request(uri = self.request.uri, http_method = 'GET', body = None, headers = self.request.headers)

But I got an error: object has no attribute '_tokens'.
As I thought, using 'class Server(AuthorizationEndpoint, TokenEndpoint, ResourceEndpoint):' may only allows the __init__ of AuthorizationEndpoint works. So there is no initation for ResourceEndpoint either no _tokens.

So I added the code below.

oauth._tokens = {'Bearer': oauthlib.oauth2.draft25.tokens.BearerToken()}
oauth._default_token_type = 'Bearer'

Then got an error: AttributeError: 'str' object has no attribute 'estimate_type'.
So I am confusing now.

Am I wrong or this part of oauthlib is not completed yet?

Thanks for your work.

Regards,
Evlos

Nasty side effects needed for realms in "get request token" flow

Let me preface this with a disclaimer: I'm learning OAuth (1.0) by implementing a provider using this library, so I might just be misunderstanding something: please set me straight if necessary.

It seems to me as if implementing realms in the "get request token" flow will require verify_request to have some nasty side effects, which will mean that Server instances are not thread-safe. If this is correct it is rather a shame, since the rest of the library is very cleanly implemented. (I can't say for sure that other flows are thread-safe since I haven't got to implementing them yet. I don't see any reason they shouldn't be though.)

Here's what I think happens: the `verify_

OAuth1 ignore path segments when signing request.

When signing a url like http://www.sample.com/mylogs;version=1.1 the ";version=1.1" won't be taken in account, so the request will probably fail due to invalid signature.

path segment are ignored on:

oauthlib/oauth1/rfc5849/signature.py:

def normalize_base_string_uri(...)
return urlparse.urlunparse((scheme, netloc, path, u'',u'',u''))

This should fix it:
return urlparse.urlunparse((scheme, netloc, path, params, u'',u''))

Some tests in 0.3.0 fail

When running "python setup.py test", I get nine failures. Eight say:

Failure: ValueError (Attempted relative import beyond toplevel package) ... ERROR

And one says:

Failure: AttributeError ('module' object has no attribute 'TestResult') ... ERROR

This is on Ubuntu 12.10 Alpha with Python 2.7.3. Do you not get these errors?

OAuth2 Server Discussion

@ib-lundgren

I need an OAuth2 authorization server as well as a resource server, and no existing implementations exist besides some django-specific stuff. oauthlib looks like a worthy place to contribute one. I'm willing to do all of the work, as I need this to do my job, but I'd like some discussion. My initial thoughts after reading the spec:

  • There is leeway for lots of extensibility, which might be difficult to wrap
  • There isn't actually a lot that needs to be done

Similar to the discussion of the client, the only thing that really needs to be done here is provide a nice API. I think an interface very similar to oauthlib.oauth1.rfc5849.Server would be fine.

0.3.5 mistakenly includes non-application/x-www-form-urlencoded body in oauth params

This looks like a regression between 0.3.4 and 0.3.5 to me. I'm guessing it was caused by the automatic urlencoding introduced between those tags. (cf. #96)

Here's a test program:

from __future__ import unicode_literals
import logging
from pprint import pprint

import requests
from requests_oauthlib import OAuth1


logging.basicConfig(level=logging.DEBUG)

client_key = 'aclientkey'
client_secret = 'aclientsecret'
token_credentials = {
    'oauth_token': ['atokentoken'],
    'oauth_token_secret': ['atokensecret']
}
resource_url = 'http://example.com/'
method = 'POST'

oauth = OAuth1(client_key, client_secret,
               unicode(token_credentials['oauth_token'][0]),
               unicode(token_credentials['oauth_token_secret'][0]),
               signature_type='QUERY')
req = requests.Request(method=method, url=resource_url,
                       headers={ 'Content-Type': 'text/plain' },
                       data='some body data that is not application/x-www-form-urlencoded',
                       auth=oauth).prepare()

pprint(req.__dict__)

And here's the output in 0.3.5 vs 0.3.4. Note the inclusion of the body in the base signing string in 0.3.5 and that the Content-Type somehow gets set to application/x-www-formurlencoded despite my having set it to text/plain.

[mlm@vagrant-centos-5-8 oauthlib (improve-logging-0.3.5)]$ pip freeze | grep 'requests\|oauthlib'
-e git+https://github.com/matthewlmcclure/oauthlib.git@48ce49a74cb0adbe69d4737ef62ec46931e3e49a#egg=oauthlib-matthewlmcclure/improve-logging-0.3.5
-e git+https://github.com/matthewlmcclure/requests.git@628e393b9a251c3d2b9910c697b9e4ac4f3d8d6a#egg=requests-issues/1096
-e git+https://github.com/matthewlmcclure/requests-oauthlib.git@66021a8b323881519761d4fbab9491f0f0f9a12e#egg=requests_oauthlib-kennethreitz/requests/issues/1096[mlm@vagrant-centos-5-8 oauthlib (improve-logging-0.3.5)]$ python /tmp/oauthlib-0.3.5-regression.py DEBUG:oauthlib.oauth1.rfc5849:Collected params: [(u'oauth_nonce', u'125539647820718445311360017645'), (u'oauth_timestamp', u'1360017645'), (u'oauth_version', u'1.0'), (u'oauth_signature_method', u'HMAC-SHA1'), (u'oauth_consumer_key', u'aclientkey'), (u'oauth_token', u'atokentoken'), (u'some body data that is not application/x-www-form-urlencoded', u'')]
DEBUG:oauthlib.oauth1.rfc5849:Normalized params: oauth_consumer_key=aclientkey&oauth_nonce=125539647820718445311360017645&oauth_signature_method=HMAC-SHA1&oauth_timestamp=1360017645&oauth_token=atokentoken&oauth_version=1.0&some%20body%20data%20that%20is%20not%20application%2Fx-www-form-urlencoded=
DEBUG:oauthlib.oauth1.rfc5849:Normalized URI: http://example.com/
DEBUG:oauthlib.oauth1.rfc5849:Base signing string: POST&http%3A%2F%2Fexample.com%2F&oauth_consumer_key%3Daclientkey%26oauth_nonce%3D125539647820718445311360017645%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3D1360017645%26oauth_token%3Datokentoken%26oauth_version%3D1.0%26some%2520body%2520data%2520that%2520is%2520not%2520application%252Fx-www-form-urlencoded%3D
DEBUG:oauthlib.oauth1.rfc5849:Signature: mKAPXv9RBJ3KojG8DJ/pcn90d2E=
{'body': u'some body data that is not application/x-www-form-urlencoded',
 'headers': {u'Content-Length': u'60',
             u'Content-Type': u'application/x-www-form-urlencoded'},
 'hooks': {'response': []},
 'method': u'POST',
 'url': u'http://example.com/?oauth_nonce=125539647820718445311360017645&oauth_timestamp=1360017645&oauth_version=1.0&oauth_signature_method=HMAC-SHA1&oauth_consumer_key=aclientkey&oauth_token=atokentoken&oauth_signature=mKAPXv9RBJ3KojG8DJ%2Fpcn90d2E%3D'}
[mlm@vagrant-centos-5-8 oauthlib (improve-logging-0.3.5)]$ git checkout improve-logging-0.3.4 
Switched to branch 'improve-logging-0.3.4'
[mlm@vagrant-centos-5-8 oauthlib (improve-logging-0.3.4)]$ python /tmp/oauthlib-0.3.5-regression.py 
DEBUG:oauthlib.oauth1.rfc5849:Collected params: [(u'oauth_nonce', u'79041121459018830601360017665'), (u'oauth_timestamp', u'1360017665'), (u'oauth_version', u'1.0'), (u'oauth_signature_method', u'HMAC-SHA1'), (u'oauth_consumer_key', u'aclientkey'), (u'oauth_token', u'atokentoken')]
DEBUG:oauthlib.oauth1.rfc5849:Normalized params: oauth_consumer_key=aclientkey&oauth_nonce=79041121459018830601360017665&oauth_signature_method=HMAC-SHA1&oauth_timestamp=1360017665&oauth_token=atokentoken&oauth_version=1.0
DEBUG:oauthlib.oauth1.rfc5849:Normalized URI: http://example.com/
DEBUG:oauthlib.oauth1.rfc5849:Base signing string: POST&http%3A%2F%2Fexample.com%2F&oauth_consumer_key%3Daclientkey%26oauth_nonce%3D79041121459018830601360017665%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3D1360017665%26oauth_token%3Datokentoken%26oauth_version%3D1.0
DEBUG:oauthlib.oauth1.rfc5849:Signature: gX+h3Kgsp14kl93Q1/GlYbVsDU0=
{'body': u'some body data that is not application/x-www-form-urlencoded',
 'headers': {'Content-Length': u'60', u'Content-Type': u'text/plain'},
 'hooks': {'response': []},
 'method': u'POST',
 'url': u'http://example.com/?oauth_nonce=79041121459018830601360017665&oauth_timestamp=1360017665&oauth_version=1.0&oauth_signature_method=HMAC-SHA1&oauth_consumer_key=aclientkey&oauth_token=atokentoken&oauth_signature=gX%2Bh3Kgsp14kl93Q1%2FGlYbVsDU0%3D'}
[mlm@vagrant-centos-5-8 oauthlib (improve-logging-0.3.4)]$ 

OAuth 2 MAC tokens 01

Currently tokens.py match the 00 version of the MAC token spec which is also the one linked from the OAuth 26 draft. A new 01 version of the MAC token spec removes hashing of the body and possibly other things. The OAuth 2 draft is considered stable by now but I am uncertain if this is the case for MAC tokens too.

Update: The MAC token type is currently not maintained and considered incomplete. Might be better to let it stay on v.00 and wait until the mac token spec is picked up and approaching stable.

Insensible defaults in constructors

Hi,

I needed a really simple OAuth 2 server implementation to test my client against, and figured I would use this lib. I is not very easy, partly because you have to go back and forth through the source code, and quite some class constructors have arguments with defaults that don't make sense, as you can't use the class with those defaults.

I'll give some examples:

class AuthorizationEndpoint(object):
    def __init__(self, default_response_type, default_token=None,
            response_types=None):
        self._response_types = response_types or {}
        self._default_response_type = default_response_type
        self._default_token = default_token or tokens.BearerToken()

response_types needs to be a dict with with at least one grant type class.

class TokenEndpoint(object):

    def __init__(self, default_grant_type, default_token=None,
            grant_types=None):
        self._grant_types = grant_types or {}
        self._default_token = default_token or tokens.BearerToken()
        self._default_grant_type = default_grant_type

default_token can be left None, but that will result in an error later on, as tokens.BearerToken is a placeholder-class that needs to be overriden to define it's save_token method.

class BearerToken(TokenBase):

    def __init__(self, request_validator=None):
        self.request_validator = request_validator

Later on self.request_validator is assumed a class with methods, and not None. If will fail with an obscure AttributeError: 'NoneType' object has no attribute 'validate_bearer_token.

So I think we should make them all args instead of kwargs, or at least fail if they are ill defined.

Support Python 3

Python 3 support would be nice. It would probably best be done by supporting both Python 2 and 3 in the same codebase, with some care.

It might involve bumping the minimum version to Python 2.6.

I have the start of a patch, hopefully will have a complete one soon.

Setup multi-version testing with tox?

Travis is doing a lovely job as a CI suite, but I'd like to be able to run tests locally. The cool kids seem to be using tox these days for that sort of thing. If somebody feels like figuring that out and setting it up, that'd be groovy.

tests depend on dict ordering, causing them to fail under pypy

Two tests fail with pypy:

======================================================================
FAIL: test_collect_parameters (tests.oauth1.rfc5849.test_signatures.SignatureTests)
We check against parameters multiple times in case things change after more
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/tmp/oauthlib/tests/oauth1/rfc5849/test_signatures.py", line 123, in test_collect_parameters
    self.assertEquals(parameters[6], ('oauth_nonce', '7d8f3e4a'))
AssertionError: Tuples differ: (u'oauth_token', u'kkk9d7dh3k3... != ('oauth_nonce', '7d8f3e4a')

First differing element 0:
oauth_token
oauth_nonce

- (u'oauth_token', u'kkk9d7dh3k39sjv7')
+ ('oauth_nonce', '7d8f3e4a')

======================================================================
FAIL: test_parse_authorization_header (tests.oauth1.rfc5849.test_utils.UtilsTests)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/tmp/oauthlib/tests/oauth1/rfc5849/test_utils.py", line 149, in test_parse_authorization_header
    self.assertEquals(authorization_headers[1][0], u"oauth_nonce")
AssertionError: u'oauth_token' != u'oauth_nonce'
- oauth_token+ oauth_nonce

----------------------------------------------------------------------

In both cases the problem is oauthlib.oauth1.rfc5849.parse_authorization_header returning d.items(), and the tests making assumptions about the order those items are in. Dict order is undefined, has changed in cpython before, and is different in pypy. This can be fixed in the tests, for example by sorting the list from parse_authorization_header, but I think it might make sense to sort the list in parse_authorization_header before returning it. I'd be happy to provide (and test) a patch for either approach.

Timing attack test for OAuth 1 provider

Timing attacks are used to reveal secrets using statistical sampling in large quantities and could in worst case reveal secret keys.

It would be really awesome to have a test that could be used against OAuthLibs verify_request to ensure it does not introduce variance in execution time between different requests in a way that would allow user enumeration or secret key guessing.

A large bonus if this could easily be imported by developers implementing oauth providers and ran against their setup.

Server Example

As it took me a while to figure out how to setup a really simple, dumb, Authorization Server, I thought it would be nice to share it.

This gist https://gist.github.com/4461572 shows the minimal code. Lines 7 - 72 are oauthlib specific code, the rest are the django views.

I would be nice to add this to the documentation in some form.

Running tox docs

Tox is great and I use it all the time to test against py 2.6 up to 3.3. In the contributing docs it would be nice to have information on how to use and setup tox for various environments. i.e. a little description together with links to OS X / Ubuntu / Fedora / Windows setup instructions.

Designing OAuth2 client support

Thought I'd get some discussion going on how to best approach the versatility of OAuth2 client profiles and token types. While OAuth 2 is a fair bit simpler than OAuth1 I still think having several Client classes would be advantageous. Mainly because each client comes with its own set of "quirks" in the request/response flow. Also, unlike OAuth1 extensibility plays a major role in OAuth2 and I think it would be easy to add extension client classes this way. For example the Google Service Accounts grant model. Furthermore, having several clients make it more explicit that there are differences between them, this is very important from a security point of view because although they may look similar they are built on vastly different security premises (im looking at you auth code and implicit grant).

My idea for how these clients might look is based on thinly wrapping #18. The clients share enough functionality to work well of a base class with 3 polymorhpic methods.

Client(object):
    # the base client, has the ability to add "bearer" and "mac" tokens

    def __init__(self, ....):
        # sets up token type and related values

    def add_token(self, uri, http_method=u'GET', body=None, headers=None):
        # attaches tokens either to uri, auth header or body in the case of
        # bearer tokens, and to auth header if mac token
        # this is a very basic operation for both token types

    def validate_token_params(self, ...):
        # param validation is the same for all client profiles but highly
        # recommended by the spec for security reasons

    def prepare_token_uri(self, ...):
        raise NotImplementedError(..)

    def parse_token_uri_response(self, response):
        # extracts and validates params from response
        # params are added to self 
        # abstract because it differs in implicit/auth code
        raise NotImplementedError(..) 

    def prepare_token_body(self, ...):
        raise NotImplementedError(..)

    def parse_token_body_response(self, response):
        # extracts and validates params from response
        # params are added to self   
        # not abstract since its the same for all profiles

ConfidentialClient(Client):
    # follows the authorization code grant model
    # overrides all abstract methods:
    # prepare_token_uri, parse_token_uri_response, prepare_token_body

PublicClient(Client):
    # follows the implicit code grant model
    # overrides prepare_token_uri & parse_token_uri_response

CredentialsClient(Client):
    # follows the client credentials grant model
    # overrides prepare_token_body

PasswordClient(Client):
    # follows the resource owner password credentials grant
    # overrides prepare_token_body

Any input on how to properly name the parse-and-populate methods would be awesome. Oh, and remember that the responses for OAuth2 are clearly defined and thus easily parsable =)

oauthlib 0.3.5: Django-related test error

oauthlib 0.3.4 passes all tests.
oauthlib 0.3.5 introduced 1 test error.
I use Django 1.4.3.

$ nosetests-2.7
E.............................................................................................................
======================================================================
ERROR: Failure: ImportError (Settings cannot be imported, because environment variable DJANGO_SETTINGS_MODULE is undefined.)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/usr/lib64/python2.7/site-packages/nose/loader.py", line 390, in loadTestsFromName
    addr.filename, addr.module)
  File "/usr/lib64/python2.7/site-packages/nose/importer.py", line 39, in importFromPath
    return self.importFromDir(dir_path, fqname)
  File "/usr/lib64/python2.7/site-packages/nose/importer.py", line 86, in importFromDir
    mod = load_module(part_fqname, fh, filename, desc)
  File "/tmp/oauthlib-0.3.5/oauthlib/oauth2/ext/django/__init__.py", line 3, in <module>
    from django.views.decorators.csrf import csrf_exempt
  File "/usr/lib64/python2.7/site-packages/django/views/decorators/csrf.py", line 3, in <module>
    from django.middleware.csrf import CsrfViewMiddleware, get_token
  File "/usr/lib64/python2.7/site-packages/django/middleware/csrf.py", line 14, in <module>
    from django.utils.cache import patch_vary_headers
  File "/usr/lib64/python2.7/site-packages/django/utils/cache.py", line 25, in <module>
    from django.core.cache import get_cache
  File "/usr/lib64/python2.7/site-packages/django/core/cache/__init__.py", line 76, in <module>
    if not settings.CACHES:
  File "/usr/lib64/python2.7/site-packages/django/utils/functional.py", line 184, in inner
    self._setup()
  File "/usr/lib64/python2.7/site-packages/django/conf/__init__.py", line 40, in _setup
    raise ImportError("Settings cannot be imported, because environment variable %s is undefined." % ENVIRONMENT_VARIABLE)
ImportError: Settings cannot be imported, because environment variable DJANGO_SETTINGS_MODULE is undefined.

----------------------------------------------------------------------
Ran 110 tests in 0.765s

FAILED (errors=1)

Additionally test suite now fails when Django is not installed:

$ nosetests-3.3
E.............................................................................................................
======================================================================
ERROR: Failure: ImportError (No module named 'django')
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/usr/lib64/python3.3/site-packages/nose/failure.py", line 37, in runTest
    raise self.exc_class(self.exc_val).with_traceback(self.tb)
  File "/usr/lib64/python3.3/site-packages/nose/loader.py", line 390, in loadTestsFromName
    addr.filename, addr.module)
  File "/usr/lib64/python3.3/site-packages/nose/importer.py", line 39, in importFromPath
    return self.importFromDir(dir_path, fqname)
  File "/usr/lib64/python3.3/site-packages/nose/importer.py", line 86, in importFromDir
    mod = load_module(part_fqname, fh, filename, desc)
  File "/usr/lib64/python3.3/imp.py", line 166, in load_module
    return load_package(name, filename)
  File "/usr/lib64/python3.3/imp.py", line 140, in load_package
    return _bootstrap.SourceFileLoader(name, path).load_module(name)
  File "<frozen importlib._bootstrap>", line 586, in _check_name_wrapper
  File "<frozen importlib._bootstrap>", line 1023, in load_module
  File "<frozen importlib._bootstrap>", line 1004, in load_module
  File "<frozen importlib._bootstrap>", line 562, in module_for_loader_wrapper
  File "<frozen importlib._bootstrap>", line 869, in _load_module
  File "<frozen importlib._bootstrap>", line 313, in _call_with_frames_removed
  File "/tmp/oauthlib-0.3.5/oauthlib/oauth2/ext/django/__init__.py", line 2, in <module>
    from django.http import HttpResponseRedirect, HttpResponse, HttpResponseForbidden
ImportError: No module named 'django'

----------------------------------------------------------------------
Ran 110 tests in 0.749s

FAILED (errors=1)

From OAuth2 draft to RFC

OAuth 2 Core (http://tools.ietf.org/html/rfc6749) and Bearer Token Usage (http://tools.ietf.org/html/rfc6750) have been released and we should follow.

This is a glorious and adventorous task, that includes the somewhat time consuming task of going over whats in oauth2/draft25 and making sure it matches what is instructed in the RFCs =)

The code should match well but the links will need some updating. When that is done simply rename the directory and ensure all imports are ok.

OAuth 1 Server / Provider plans

There are two main issues with OAuth 1 provider as it stands today

  • there is some testing but much can be improved
  • verify_request is overly complex and should be split up

I'd like to see the second one addressed by instead using

  • verify_request_token_request
  • verify_access_token_request
  • verify_resource_request (not yet stubbed)
    and have whatever functionality they share in verify_request refactored into private methods.

Additionally I'd like to move to inheritance by composition and move request validation (basically all abstract methods) to a request validator object. Similar to what I've begun doing with the w.i.p. oauth 2 server.

Currently the testing ultimately boils down to checking for ValueErrors or false which makes it easy to introduce subtle errors such as #94. I propose that in addition to this (with a request validator as mentioned above) use mock objects to assert that the False/ValueError is caused the way the test intended it to, i.e. missing parameter or invalid credentials etc.

I'm planning on implementing this when I find a free afternoon which may or may not be soon. If you are interested in giving it a go, please drop me a line =)

Provide a "sign to GET query url" API

So, one other thing I had to do with a recent port of code using oauth to oauthlib is that the client required the signed request be represented as a GET query string (i.e. $3.5.3 of RFC 5849). AFAICT, Client doesn't provide an API to return such a string, so I had to write my own "signature triplet to query" conversion routine.

It would probably be nicer if Client had a .sign_to_query() method which took the same inputs as .sign() but returned a $3.5.3 style query string instead of the url/signed_headers/body triplet.

Passing in our own oauth_timestamp value

I'm currently trying to convert a package from oauth to oauthlib (specifically ubuntu-sso-client) and I've hit a snag. The library wants to generate its own timestamp values, which it gets through various rendezvous with the sso server. There doesn't seem to be a way in oauthlib to pass this timestamp in through the oauth_timestamp parameter, because oauthlib always generates its own timestamp. AFAICT, there is no API for passing in our own oauth_timestamp value.

This is a problem both for the conversion (i.e. test suite failures), and for functionality, since the server uses the generated timestamp values for validation.

Am I missing how to do this, or is there really no way? If the latter, this should probably be a wishlist bug. ;)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.