Skip to content

Commit

Permalink
Add IAuthenticator
Browse files Browse the repository at this point in the history
  • Loading branch information
tobes committed Mar 23, 2013
1 parent e1ba4db commit c6f5cc6
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 13 deletions.
11 changes: 11 additions & 0 deletions ckan/controllers/user.py
Expand Up @@ -16,6 +16,7 @@
import ckan.lib.captcha as captcha
import ckan.lib.mailer as mailer
import ckan.lib.navl.dictization_functions as dictization_functions
import ckan.plugins as p

log = logging.getLogger(__name__)

Expand Down Expand Up @@ -294,6 +295,11 @@ def login(self, error=None):
session.save()
return h.redirect_to(locale=str(lang), controller='user',
action='login')

# Do any plugin login stuff
for item in p.PluginImplementations(p.IAuthenticator):
item.login()

if 'error' in request.params:
h.flash_error(request.params['error'])

Expand Down Expand Up @@ -352,6 +358,11 @@ def logout(self):
# save our language in the session so we don't lose it
session['lang'] = request.environ.get('CKAN_LANG')
session.save()

# Do any plugin logout stuff
for item in p.PluginImplementations(p.IAuthenticator):
item.logout()

h.redirect_to(self._get_repoze_handler('logout_handler_path'))

def set_lang(self, lang):
Expand Down
52 changes: 39 additions & 13 deletions ckan/lib/base.py
Expand Up @@ -23,7 +23,7 @@
import lib.render
import ckan.lib.helpers as h
import ckan.lib.app_globals as app_globals
from ckan.plugins import PluginImplementations, IGenshiStreamFilter
from ckan.plugins import PluginImplementations, IGenshiStreamFilter, IAuthenticator
import ckan.model as model
from ckan.common import json

Expand All @@ -38,6 +38,12 @@


def abort(status_code=None, detail='', headers=None, comment=None):
if status_code == 401:
# Allow IAuthenticator plugins to alter the abort
for item in PluginImplementations(IAuthenticator):
result = item.abort(status_code, detail, headers, comment)
(status_code, detail, headers, comment) = result

if detail and status_code != 503:
h.flash_error(detail)
# #1267 Convert detail to plain text, since WebOb 0.9.7.1 (which comes
Expand Down Expand Up @@ -208,7 +214,9 @@ def __before__(self, action, **params):
c.__timer = time.time()
c.__version__ = ckan.__version__
app_globals.app_globals._check_uptodate()

self._identify_user()

i18n.handle_request(request, c)

# If the user is logged in add their number of new activities to the
Expand All @@ -222,26 +230,49 @@ def __before__(self, action, **params):
c.new_activities = new_activities_count(context, {})

def _identify_user(self):
'''
Identifies the user using two methods:
a) If he has logged into the web interface then repoze.who will
set REMOTE_USER.
b) For API calls he may set a header with his API key.
'''Try to identify the user
If the user is identified then:
c.user = user name (unicode)
c.userobj = user object
c.author = user name
otherwise:
c.user = None
c.userobj = None
c.author = user\'s IP address (unicode)
'''
c.author = user's IP address (unicode)'''
# see if it was proxied first
c.remote_addr = request.environ.get('HTTP_X_FORWARDED_FOR', '')
if not c.remote_addr:
c.remote_addr = request.environ.get('REMOTE_ADDR',
'Unknown IP Address')

# Authentication plugins get a chance to run here break as soon as a
# user is identified.
authenticators = PluginImplementations(IAuthenticator)
if authenticators:
for item in authenticators:
item.identify()
if c.user:
break

# We haven't identified the user so try the default methods
if not c.user:
self._identify_user_default()

# general settings
if c.user:
c.author = c.user
else:
c.author = c.remote_addr
c.author = unicode(c.author)

def _identify_user_default(self):
'''
Identifies the user using two methods:
a) If they logged into the web interface then repoze.who will
set REMOTE_USER.
b) For API calls they may set a header with an API key.
'''

# environ['REMOTE_USER'] is set by repoze.who if it authenticates
# a user's cookie or OpenID. But repoze.who doesn't check the user
# (still) exists in our database - we need to do that here. (Another
Expand Down Expand Up @@ -272,11 +303,6 @@ def _identify_user(self):
c.userobj = self._get_user_for_apikey()
if c.userobj is not None:
c.user = c.userobj.name
if c.user:
c.author = c.user
else:
c.author = c.remote_addr
c.author = unicode(c.author)

def __call__(self, environ, start_response):
"""Invoke the Controller"""
Expand Down
18 changes: 18 additions & 0 deletions ckan/plugins/interfaces.py
Expand Up @@ -19,6 +19,7 @@
'ITagController',
'ITemplateHelpers',
'IFacets',
'IAuthenticator',
]

from inspect import isclass
Expand Down Expand Up @@ -787,3 +788,20 @@ def group_facets(self, facets_dict, group_type, package_type):
def organization_facets(self, facets_dict, organization_type, package_type):
''' Update the facets_dict and return it. '''
return facets_dict


class IAuthenticator(Interface):
'''EXPERIMENTAL'''

def identify(self):
'''called to identify the user.'''

def login(self):
'''called at login.'''

def logout(self):
'''called at logout.'''

def abort(self, status_code, detail, headers, comment):
'''called on abort.'''
return (status_code, detail, headers, comment)

0 comments on commit c6f5cc6

Please sign in to comment.