Skip to content

Commit

Permalink
New auth configuration layer that doesn't require repoze.what anymore…
Browse files Browse the repository at this point in the history
… while still being compatible
  • Loading branch information
amol- committed May 3, 2012
1 parent 9d04797 commit 9d08b1a
Show file tree
Hide file tree
Showing 10 changed files with 578 additions and 329 deletions.
2 changes: 1 addition & 1 deletion setup.cfg
Expand Up @@ -4,7 +4,7 @@ release = egg_info -RDb "" sdist bdist_egg register upload
# A handy alias to install for development # A handy alias to install for development
tgdevelop = develop -i http://tg.gy/beta tgdevelop = develop -i http://tg.gy/beta
# Another alias for installing all possible requirements for testing # Another alias for installing all possible requirements for testing
tgtesting = easy_install -i http://tg.gy/beta AddOns BytecodeAssembler Chameleon coverage DecoratorTools Extremes Genshi Jinja2 Kajiki kid nose PEAK_Rules repoze.tm2 repoze.what repoze.what.plugins.sql repoze.what_pylons repoze.what_quickstart repoze.who repoze.who_friendlyform repoze.who.plugins.sa repoze.who_testutil simplegeneric sprox SQLAlchemy SymbolType tgext.admin tgext.crud ToscaWidgets transaction TurboJson TurboKid tw.forms zope.interface zope.sqlalchemy tw2.forms tw2.core speaklater tgtesting = easy_install -i http://tg.gy/beta AddOns BytecodeAssembler Chameleon coverage DecoratorTools Extremes Genshi Jinja2 Kajiki kid nose PEAK_Rules repoze.tm2 repoze.who repoze.who_friendlyform repoze.who.plugins.sa repoze.who_testutil simplegeneric sprox SQLAlchemy SymbolType tgext.admin tgext.crud ToscaWidgets transaction TurboJson TurboKid tw.forms zope.interface zope.sqlalchemy tw2.forms tw2.core speaklater
tgrelease = easy_install yolk basketweaver sphinx tgrelease = easy_install yolk basketweaver sphinx
tgnose = nosetests --with-coverage --cover-erase --cover-package=turbogears --with-xunit --verbosity=2 tgnose = nosetests --with-coverage --cover-erase --cover-package=turbogears --with-xunit --verbosity=2


Expand Down
3 changes: 0 additions & 3 deletions setup.py
Expand Up @@ -13,12 +13,9 @@
'jinja2', 'jinja2',
'Chameleon < 2.0a', 'Chameleon < 2.0a',
'simplegeneric', 'simplegeneric',
'repoze.what >= 1.0.3',
'repoze.who >= 1.0.18, <= 1.99', 'repoze.who >= 1.0.18, <= 1.99',
'repoze.who.plugins.sa >= 1.0.1', 'repoze.who.plugins.sa >= 1.0.1',
'repoze.what.plugins.sql >= 1.0rc2',
'repoze.who-testutil >= 1.0.1', 'repoze.who-testutil >= 1.0.1',
'repoze.what-pylons >= 1.0',
"repoze.who-friendlyform >=1.0.4", "repoze.who-friendlyform >=1.0.4",
'repoze.tm2 >= 1.0a4', 'repoze.tm2 >= 1.0a4',
'wsgiref', 'wsgiref',
Expand Down
16 changes: 6 additions & 10 deletions tests/test_stack/test_authz.py
@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
""" """
repoze.what & repoze.what-pylons **integration** tests. repoze.who **integration** tests.
Note that it is not necessary to have integration tests for the other auth* Note that it is not necessary to have integration tests for the other auth*
software in this package. They must be in tg.devtools, specifically in the test software in this package. They must be in tg.devtools, specifically in the test
Expand Down Expand Up @@ -29,8 +29,8 @@
from pylons.testutil import ControllerWrap, SetupCacheGlobal from pylons.testutil import ControllerWrap, SetupCacheGlobal


from repoze.who.plugins.auth_tkt import AuthTktCookiePlugin from repoze.who.plugins.auth_tkt import AuthTktCookiePlugin
from repoze.what.middleware import setup_auth from tg.configuration.auth import setup_auth, TGAuthMetadata
from repoze.what.predicates import Not, is_user, not_anonymous from tg.predicates import is_user, not_anonymous


from pylons.middleware import StatusCodeRedirect from pylons.middleware import StatusCodeRedirect
from tg.error import ErrorHandler from tg.error import ErrorHandler
Expand All @@ -56,17 +56,13 @@ def make_app(controller_klass, environ={}, with_errors=False):
app = SessionMiddleware(app, {}, data_dir=session_dir) app = SessionMiddleware(app, {}, data_dir=session_dir)
app = CacheMiddleware(app, {}, data_dir=os.path.join(data_dir, 'cache')) app = CacheMiddleware(app, {}, data_dir=os.path.join(data_dir, 'cache'))


# We're not going to use groups or permissions-related predicates here:
groups_adapters = None
permissions_adapters = None

# Setting repoze.who up: # Setting repoze.who up:
cookie = AuthTktCookiePlugin('secret', 'authtkt') cookie = AuthTktCookiePlugin('secret', 'authtkt')
identifiers = [('cookie', cookie)] identifiers = [('cookie', cookie)]


app = setup_auth(app, groups_adapters, permissions_adapters, app = setup_auth(app, TGAuthMetadata(),
identifiers=identifiers, authenticators=[], identifiers=identifiers, skip_authentication=True,
challengers=[], skip_authentication=True) authenticators=[], challengers=[])


app = httpexceptions.make_middleware(app) app = httpexceptions.make_middleware(app)
return TestApp(app) return TestApp(app)
Expand Down
27 changes: 21 additions & 6 deletions tg/configuration/app_config.py
Expand Up @@ -734,12 +734,27 @@ def add_auth_middleware(self, app, skip_authentication):
"sa_auth.cookie_secret in development.ini" "sa_auth.cookie_secret in development.ini"
raise TGConfigError(msg) raise TGConfigError(msg)


if self.auth_backend == "sqlalchemy": if 'authmetadata' not in auth_args:
from tg.configuration.sqla.auth import setup_sql_auth #authmetadata not provided, fallback to old authentication setup
app = setup_sql_auth(app, skip_authentication=skip_authentication, **auth_args) if self.auth_backend == "sqlalchemy":
elif self.auth_backend == "ming": from repoze.what.plugins.quickstart import setup_sql_auth
from tgming import setup_ming_auth app = setup_sql_auth(app, skip_authentication=skip_authentication, **auth_args)
app = setup_ming_auth(app, skip_authentication=skip_authentication, **auth_args) elif self.auth_backend == "ming":
from tgming import setup_ming_auth
app = setup_ming_auth(app, skip_authentication=skip_authentication, **auth_args)
else:
from tg.configuration.auth import setup_auth
if 'authenticators' not in auth_args:
if self.auth_backend == "sqlalchemy":
from tg.configuration.sqla.auth import create_default_authenticator
auth_args, sqlauth = create_default_authenticator(**auth_args)
auth_args['authenticators'] = [('sqlauth', sqlauth)]
elif self.auth_backend == "ming":
from tgming.auth import MingAuthenticatorPlugin
mingauth = MingAuthenticatorPlugin(auth_args.pop('user_class', None))
auth_args['authenticators'] = [('mingauth', mingauth)]
app = setup_auth(app, skip_authentication=skip_authentication, **auth_args)

return app return app


def add_core_middleware(self, app): def add_core_middleware(self, app):
Expand Down
144 changes: 144 additions & 0 deletions tg/configuration/auth.py
@@ -0,0 +1,144 @@
"""
New TurboGears2 identification, authentication and authorization setup.
This aims to provide an easier way to setup auth layer in TurboGears2
and removes the dependency from repoze.what.
"""
import sys, logging
from zope.interface import implements
from repoze.who.plugins.testutil import make_middleware
from repoze.who.interfaces import IMetadataProvider
from repoze.who.classifiers import default_challenge_decider, default_request_classifier
from repoze.who.config import _LEVELS

class TGAuthMetadata(object):
"""
Provides a way to lookup for user, groups and permissions
given the current identity. This has to be specialized
for each storage backend.
By default it returns empty lists for groups and permissions
and None for the user.
"""
def get_user(self, identity, userid):
return None

def get_groups(self, identity, userid):
return []

def get_permissions(self, identity, userid):
return []

class AuthMetadataProvider(object):
"""
repoze.who metadata provider to load groups and permissions data for
the current user. This uses a :class:`TGAuthMetadata` to fetch
the groups and permissions.
"""
implements(IMetadataProvider)

def __init__(self, tgmdprovider):
self.tgmdprovider = tgmdprovider

# IMetadataProvider
def add_metadata(self, environ, identity):
# Get the userid retrieved by repoze.who Authenticator
userid = identity['repoze.who.userid']

# Finding the user, groups and permissions:
identity['user'] = self.tgmdprovider.get_user(identity, userid)
if identity['user']:
identity['groups'] = self.tgmdprovider.get_groups(identity, userid)
identity['permissions'] = self.tgmdprovider.get_permissions(identity, userid)
else:
identity['groups'] = identity['permissions'] = []

# Adding the groups and permissions to the repoze.what
# credentials for repoze.what compatibility:
if 'repoze.what.credentials' not in environ:
environ['repoze.what.credentials'] = {}
environ['repoze.what.credentials'].update(identity)
environ['repoze.what.credentials']['repoze.what.userid'] = userid

def setup_auth(app, authmetadata,
form_plugin=None, form_identifies=True,
cookie_secret='secret', cookie_name='authtkt',
login_url='/login', login_handler='/login_handler',
post_login_url=None, logout_handler='/logout_handler',
post_logout_url=None, login_counter_name=None,
cookie_timeout=None, cookie_reissue_time=None,
charset="iso-8859-1",
**who_args):
"""
Sets :mod:`repoze.who` up with the provided authenticators and
options to create FriendlyFormPlugin.
It returns a middleware that provides identification,
authentication and authorization in a way that is compatible
with repoze.who and repoze.what.
"""

# If no identifiers are provided in repoze setup arguments
# then create a default one using AuthTktCookiePlugin.
if 'identifiers' not in who_args:
from repoze.who.plugins.auth_tkt import AuthTktCookiePlugin
cookie = AuthTktCookiePlugin(cookie_secret, cookie_name,
timeout=cookie_timeout,
reissue_time=cookie_reissue_time)
who_args['identifiers'] = [('cookie', cookie)]

# If no form plugin is provided then create a default
# one using the provided options.
if form_plugin is None:
from repoze.who.plugins.friendlyform import FriendlyFormPlugin
form = FriendlyFormPlugin(login_url, login_handler, post_login_url,
logout_handler, post_logout_url,
login_counter_name=login_counter_name,
rememberer_name='cookie',
charset=charset)
else:
form = form_plugin

if form_identifies:
who_args['identifiers'].insert(0, ('main_identifier', form))

# Setting the repoze.who challengers:
if 'challengers' not in who_args:
who_args['challengers'] = []
who_args['challengers'].append(('form', form))

# Including logging
log_file = who_args.pop('log_file', None)
if log_file is not None:
if log_file.lower() == 'stdout':
log_stream = sys.stdout
elif log_file.lower() == 'stderr':
log_stream = sys.stderr
else:
log_stream = open(log_file, 'wb')
who_args['log_stream'] = log_stream

log_level = who_args.get('log_level', None)
if log_level is None:
log_level = logging.INFO
else:
log_level = _LEVELS[log_level.lower()]
who_args['log_level'] = log_level

# Setting up the metadata provider for the user informations
authmd = AuthMetadataProvider(authmetadata)
if 'mdproviders' not in who_args:
who_args['mdproviders'] = []
who_args['mdproviders'].append(('authmd', authmd))

# Set up default classifier
if 'classifier' not in who_args:
who_args['classifier'] = default_request_classifier

# Set up default challenger decider
if 'challenge_decider' not in who_args:
who_args['challenge_decider'] = default_challenge_decider

skip_authn = who_args.pop('skip_authentication', False)
middleware = make_middleware(skip_authn, app, **who_args)
return middleware

0 comments on commit 9d08b1a

Please sign in to comment.