Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 9 additions & 4 deletions pyramid_oauth2_provider/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@
from pyramid.exceptions import ConfigurationError
from pyramid.interfaces import IAuthenticationPolicy

from .models import initialize_sql
from pyramid.authorization import ACLAuthorizationPolicy

from .interfaces import IAuthCheck
from .authentication import OauthAuthenticationPolicy

Expand All @@ -25,9 +26,13 @@

def includeme(config):
settings = config.registry.settings
engine = engine_from_config(settings, 'sqlalchemy.')

initialize_sql(engine, settings)
config.include('.models')

# Security policies
# a default authorization policy is mandatory
authz_policy = ACLAuthorizationPolicy()
config.set_authorization_policy(authz_policy)

if not config.registry.queryUtility(IAuthenticationPolicy):
config.set_authentication_policy(OauthAuthenticationPolicy())
Expand All @@ -48,6 +53,6 @@ def includeme(config):
def main(global_config, **settings):
""" This function returns a Pyramid WSGI application.
"""
config = Configurator(settings=settings)
config = Configurator(settings=settings, root_factory='pyramid_oauth2_provider.security.RootFactory')
includeme(config)
return config.make_wsgi_app()
3 changes: 1 addition & 2 deletions pyramid_oauth2_provider/authentication.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@
from pyramid.httpexceptions import HTTPUnauthorized

from .models import Oauth2Token
from .models import DBSession as db
from .errors import InvalidToken
from .errors import InvalidRequest
from .util import getClientCredentials
Expand All @@ -43,7 +42,7 @@ def _get_auth_token(self, request):
if token_type != 'bearer':
return None

auth_token = db.query(Oauth2Token).filter_by(access_token=token).first()
auth_token = request.dbsession.query(Oauth2Token).filter_by(access_token=token).first()
# Bad input, return 400 Invalid Request
if not auth_token:
raise HTTPBadRequest(InvalidRequest())
Expand Down
4 changes: 3 additions & 1 deletion pyramid_oauth2_provider/jsonerrors.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ def prepare(self, environ):
html_comment = escape(comment)
else:
self.content_type = 'aplication/json'
self.charset = 'UTF-8'
escape = _quote_escape
page_template = self.json_template_obj
br = '\n'
Expand All @@ -80,10 +81,11 @@ def prepare(self, environ):
args[k] = escape(v)
for k, v in list(self.headers.items()):
args[k.lower()] = escape(v)

page = page_template.substitute(status=self.status,
code=self.code, **args)
if isinstance(page, text_type):
page = page.encode(self.charset)
page = page.encode(self.charset if self.charset else 'UTF-8')
self.app_iter = [page]
self.body = page

Expand Down
71 changes: 62 additions & 9 deletions pyramid_oauth2_provider/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,23 +17,23 @@
from sqlalchemy import Column
from sqlalchemy import ForeignKey

from sqlalchemy import Binary
from sqlalchemy import LargeBinary
from sqlalchemy import String
from sqlalchemy import Integer
from sqlalchemy import Boolean
from sqlalchemy import DateTime
from sqlalchemy import Unicode
from sqlalchemy import engine_from_config

from sqlalchemy.ext.declarative import declarative_base
import zope.sqlalchemy

from sqlalchemy.orm import backref
from sqlalchemy.orm import relationship
from sqlalchemy.orm import sessionmaker
from sqlalchemy.orm import scoped_session
from sqlalchemy.orm import synonym

from zope.sqlalchemy import ZopeTransactionExtension

from cryptography.hazmat.primitives.kdf.scrypt import Scrypt
from cryptography.hazmat.backends import default_backend
from .util import oauth2_settings
Expand All @@ -42,7 +42,6 @@
from .generators import gen_client_id
from .generators import gen_client_secret

DBSession = scoped_session(sessionmaker(extension=ZopeTransactionExtension()))
Base = declarative_base()
backend = default_backend()

Expand All @@ -51,7 +50,7 @@ class Oauth2Client(Base):
__tablename__ = 'oauth2_provider_clients'
id = Column(Integer, primary_key=True)
client_id = Column(Unicode(64), unique=True, nullable=False)
_client_secret = Column(Binary(255), nullable=False)
_client_secret = Column(LargeBinary(length=255), nullable=False)
revoked = Column(Boolean, default=False)
revocation_date = Column(DateTime)
_salt = None
Expand Down Expand Up @@ -206,7 +205,61 @@ def asJSON(self, **kwargs):
return kwargs


def initialize_sql(engine, settings):
DBSession.configure(bind=engine)
Base.metadata.bind = engine
Base.metadata.create_all(engine)
def get_engine(settings, prefix='sqlalchemy.'):
return engine_from_config(settings, prefix)


def get_session_factory(engine):
factory = sessionmaker()
factory.configure(bind=engine)
return factory


def get_tm_session(session_factory, transaction_manager):
"""
Get a ``sqlalchemy.orm.Session`` instance backed by a transaction.

This function will hook the session to the transaction manager which
will take care of committing any changes.

- When using pyramid_tm it will automatically be committed or aborted
depending on whether an exception is raised.

- When using scripts you should wrap the session in a manager yourself.
For example::

import transaction

engine = get_engine(settings)
session_factory = get_session_factory(engine)
with transaction.manager:
dbsession = get_tm_session(session_factory, transaction.manager)

"""
dbsession = session_factory()
zope.sqlalchemy.register(dbsession,
transaction_manager=transaction_manager)
return dbsession

def includeme(config):
"""
Initialize the model for a Pyramid app.

Activate this setup using ``config.include('test_alch.models')``.

"""
settings = config.get_settings()
settings['tm.manager_hook'] = 'pyramid_tm.explicit_manager'

# use pyramid_tm to hook the transaction lifecycle to the request
config.include('pyramid_tm')

session_factory = get_session_factory(get_engine(settings))
config.registry['dbsession_factory'] = session_factory

# make request.dbsession available for use in Pyramid
config.add_request_method(
# r.tm is the transaction manager used by pyramid_tm
lambda r: get_tm_session(session_factory, r.tm),
'dbsession',
reify=True)
15 changes: 9 additions & 6 deletions pyramid_oauth2_provider/scripts/create_client_credentials.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,15 +23,15 @@
)

from pyramid_oauth2_provider.models import (
DBSession,
initialize_sql,
Oauth2Client,
get_session_factory,
get_tm_session
)

def create_client(salt=None):
def create_client(dbsession, salt=None):
client = Oauth2Client(salt=salt)
client_secret = client.new_client_secret()
DBSession.add(client)
dbsession.add(client)
return client.client_id, client_secret

def usage(argv):
Expand All @@ -46,6 +46,8 @@ def main(argv=sys.argv):
config_uri = argv[1]
section = argv[2]
setup_logging(config_uri)

print("loading configuration section", section)
settings = get_appsettings(config_uri, section)
engine = engine_from_config(settings, 'sqlalchemy.')
try:
Expand All @@ -54,10 +56,11 @@ def main(argv=sys.argv):
raise ValueError(
'oauth2_provider.salt configuration required.'
)
initialize_sql(engine, settings)

session_factory = get_session_factory(engine)
with transaction.manager:
id, secret = create_client(salt=salt)
dbsession = get_tm_session(session_factory, transaction.manager)
id, secret = create_client(dbsession, salt=salt)
print('client_id:', id)
print('client_secret:', secret)

Expand Down
18 changes: 13 additions & 5 deletions pyramid_oauth2_provider/scripts/initializedb.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,18 @@
import json

from sqlalchemy import engine_from_config
import transaction

from pyramid.paster import (
get_appsettings,
setup_logging,
)

from ..models import (
DBSession,
Base,
get_engine,
get_session_factory,
get_tm_session,
)

def usage(argv):
Expand All @@ -35,12 +38,17 @@ def usage(argv):
def main(argv=sys.argv):
if len(argv) != 3:
usage(argv)

config_uri = argv[1]
drop = json.loads(argv[2].lower())
setup_logging(config_uri)
settings = get_appsettings(config_uri)
engine = engine_from_config(settings, 'sqlalchemy.')
DBSession.configure(bind=engine)
if drop:
Base.metadata.drop_all(engine)
Base.metadata.create_all(engine)

session_factory = get_session_factory(engine)
with transaction.manager:
dbsession = get_tm_session(session_factory, transaction.manager)

if drop:
Base.metadata.drop_all(engine)
Base.metadata.create_all(engine)
29 changes: 29 additions & 0 deletions pyramid_oauth2_provider/security.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#
# Copyright (c) Elliot Peele <[email protected]>
#
# This program is distributed under the terms of the MIT License as found
# in a file called LICENSE. If it is not present, the license
# is always available at http://www.opensource.org/licenses/mit-license.php.
#
# This program is distributed in the hope that it will be useful, but
# without any warrenty; without even the implied warranty of merchantability
# or fitness for a particular purpose. See the MIT License for full details.
#

from pyramid.security import (
Allow,
Everyone,
Authenticated,
)

class RootFactory(object):
"""
The default root factory.
"""

__acl__ = [ (Allow, Authenticated, 'system.Authenticated') ]

def __init__(self, request):
"""
"""
pass
Loading