Skip to main content

OAuth plugin for repoze.who and repoze.what

Project description

repoze-oauth-plugin is a repoze.who and repoze.what plugin implementing the server side of the OAuth 1.0 protocol. Currently it supports only 2-legged flow where the client is at the same time a resource owner. This happens when a client application has access to the resources on the server on behalf of itself and does not need a user (human) permission for the access.

You can read more about OAuth at hueniverse (2-legged flow).

Source

You can find the source code repository at GitHub.

Installation

easy_install:

$ <env>/bin/easy_install repoze-oauth-plugin

pip:

$ <env>/bin/pip install repoze-oauth-plugin

OAuthPlugin Usage

You can create the plugin with:

>>> from repoze.who.plugins.oauth import OAuthPlugin
>>> oauth_plugin = OAuthPlugin(DBSession=Session,
...     Manager=MyManager,
...     realm='my-realm')

where:

  • Session is an SQLAlchemy Session bound to a valid engine. If you are configuring the plugin through the PasteDeploy configuration file this can be an entry point, e.g. myproject.model.meta:Session.

  • Manager (optional) is a class that is responsible for client management in the database. Default - repoze.who.plugins.oauth:DefaultManager. The Manager has to take the Session as an initialization parameter and provide a get_consumer_by_key(key) instance method. Can be provided as an entry point too.

  • realm (optional) - a realm identifying the protection space.

The repoze.who plugin in repoze-oauth-plugin acts as an Identifier, Authenticator and Challenger. Therefore to get OAuth support you need to give it as identifier, authenticator and challenger to the repoze.who middleware, similar to this (here we create it using repoze.what provided helper):

>>> oauth_plugin = OAuthPlugin(Session, realm='MyRealm')
>>> from repoze.what.middleware import setup_auth
>>> app = PluggableAuthenticationMiddleware(my_app,
...     group_adapters=my_group_adapters,
...     permission_adapters=my_permission_adapters,
...     identifiers=[('oauth', plugin)],
...     authenticators=[('oauth', plugin)],
...     challengers=[('oauth', plugin)],
...     **other_kwargs)

However, usually you would use some higher level middleware maker. Let’s take repoze.what-quickstart as an example:

>>> oauth_plugin = OAuthPlugin(Session, realm='MyRealm')
>>> from repoze.what.plugins.quickstart import setup_sql_auth
>>> app = setup_sql_auth(app, User, Group, Permission, Session,
...     identifiers=[('oauth', oauth_plugin)],
...     authenticators=[('oauth', oauth_plugin)],
...     challengers=[('oauth', oauth_plugin)])

repoze-oauth-plugin uses oauth2 for OAuth specific functionality and plays well with restkit.

Predicate Usage

If you have set the OAuthPlugin with setup_sql_auth (or any other way that includes repoze.what support) you can use OAuth specific predicates provided by repoze-oauth-plugin.

is_consumer([consumer_key=None]) is a predicate that checks whether the current user is a consumer acting on behalf of itself (2-legged flow):

>>> from repoze.what.plugins.oauth import is_consumer
>>> p = is_consumer()
>>> p.check_authorization(environ)
Traceback (most recent call last):
...
repoze.what.predicates.NotAuthorizedError: The current user must be a consumer

Ask for a consumer with a particular key:

>>> p = is_consumer('my-app')

not_oauth() is a predicate that denies access through OAuth. All other methods are allowed (even anonymous!):

>>> from repoze.what.plugins.oauth import not_oauth
>>> p = not_oauth()
>>> p.check_authorization(environ_with_oauth)
Traceback (most recent call last):
...
repoze.what.predicates.NotAuthorizedError: Access through OAuth forbidden
>>> p.check_authorization({})   # Empty environ, no user - ok!

Pylons setup

The following is an example setup for a Pylons application. Let’s assume it is called ExampleApp. We’ll use repoze.what-quickstart and repoze.what-pylons:

$ <env>/bin/pip install repoze.what-quickstart repoze.what-pylons

First, in your exampleapp/config/middleware.py file define imports:

from repoze.what.plugins.quickstart import setup_sql_auth
from repoze.who.plugins.oauth import OAuthPlugin

from exampleapp.model import User, Group, Permission
from exampleapp.model.meta import Session

then just below:

# The Pylons WSGI app
app = PylonsApp(config=config)

create the repoze-oauth-plugin and provide a realm and SQLAlchemy session:

oauth_plugin = OAuthPlugin(realm='exampleapp', DBSession=Session)
app = setup_sql_auth(app, User, Group, Permission, Session,
    identifiers=[('oauth', oauth_plugin)],
    authenticators=[('oauth', oauth_plugin)],
    challengers=[('oauth', oauth_plugin)])

According to the OAuth specification in case of 401 Unauthorized the server has to return a WWW-Authenticate: OAuth realm=”…” header. Pylons StatusCodeRedirect middleware replaces the 401 response with its own custom 401 response discarding even the headers set by the downstream application. In order to avoid this StatusCodeRedirect can be configured to not intercept the 401 response. In exampleapp/config/middleware.py replace:

# Display error documents for 401, 403, 404 status codes (and
# 500 when debug is disabled)
if asbool(config['debug']):
    app = StatusCodeRedirect(app)
else:
    app = StatusCodeRedirect(app, [400, 401, 403, 404, 500])

with:

# Display error documents for 400, 403, 404 status codes (and
# 500 when debug is disabled)
if asbool(config['debug']):
    app = StatusCodeRedirect(app, [400, 403, 404])
else:
    app = StatusCodeRedirect(app, [400, 403, 404, 500])

With the above setup you will have the OAuth consumer information in the environment whenever successful authentication happens.

In order to be sure that only valid consumers can access your controllers and actions you have to protect them with repoze.what-pylons predicates:

# exampleapp/controllers/cars.py
...
from repoze.what.plugins.pylonshq import ActionProtector
from repoze.what.plugins.oauth import is_consumer, not_oauth

class CarsController(BaseController):

    @ActionProtector(is_consumer)
    def index(self):
        return 'Hello, Consumer'

    @ActionProtector(not_oauth)
    def public(self):
        return 'Not for consumer'


# exampleapp/controllers/trucks.py
...
from repoze.what.plugins.pylonshq import ControllerProtector
from repoze.what.plugins.oauth import is_consumer

class TrucksController(BaseController):

    def index(self):
        return 'Hello, all consumers'

TrucksController = ControllerProtector(is_consumer)(TrucksController)

Now these actions can be accessed using restkit:

>>> from restkit import OAuthFilter, request, oauth2
>>> consumer = oauth2.Consumer(key='the-consumer',
...     secret='the-consumer-secret')
>>> auth = OAuthFilter(('*', consumer))
>>> resp = request('http://localhost:5000/cars/index', filters=[auth])
>>> print resp.body

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

repoze-oauth-plugin-0.1.1.tar.gz (7.8 kB view details)

Uploaded Source

File details

Details for the file repoze-oauth-plugin-0.1.1.tar.gz.

File metadata

File hashes

Hashes for repoze-oauth-plugin-0.1.1.tar.gz
Algorithm Hash digest
SHA256 4a2ac90fd2eaa2270cefb17c97e2f484f5959b0300f13129da44c1bc23dd2085
MD5 a15aafbec78f941c73c38528aef87c21
BLAKE2b-256 f1bfbc8d0d4528064a6a1300591fb5086d14e79add9f6351196ff8e6451d9e2a

See more details on using hashes here.

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page