Merge pull request #216 from nsoranzo/release_15.05

[15.05] Fix AuthManager.active_authenticators(). Partially re...
This commit is contained in:
John Chilton
2015-05-06 15:15:19 -05:00
7 changed files with 78 additions and 60 deletions
+30
View File
@@ -1,5 +1,35 @@
<?xml version="1.0"?>
<auth>
<!--<authenticator>
<type>ldap</type>
-->
<!-- Filter users for which this authenticator applies. This is a Python
expression which is evaluated after replacing instances of {email}
and {username} with the corresponding user's values. -->
<!-- <filter>'{email}'.endswith('@example.com')</filter>
<options>
<auto-register>True</auto-register>
<server>ldap://dc1.example.com</server>
-->
<!-- If search-fields is not present, all other search-* elements are ignored -->
<!-- <search-fields>sAMAccountName,mail</search-fields>
<search-filter>(&amp;(objectClass=user)(mail={email}))</search-filter>
<search-base>dc=dc1,dc=example,dc=com</search-base>
-->
<!-- If search-user not specified will bind anonymously to LDAP for search -->
<!-- <search-user>jsmith</search-user>
<search-password>mysecret</search-password>
<bind-user>{sAMAccountName}@example.com</bind-user>
<bind-password>{password}</bind-password>
<auto-register-username>{sAMAccountName}</auto-register-username>
<auto-register-email>{mail}</auto-register-email>
-->
<!-- To allow login with username instead of email, default is False -->
<!-- <login-use-username>True</login-use-username>
</options>
</authenticator>
-->
<authenticator>
<type>localdb</type>
<options>
+15 -34
View File
@@ -18,31 +18,6 @@ from galaxy.util import plugin_config
import logging
log = logging.getLogger(__name__)
# <auth>
# <authenticator>
# <type>ldap</type>
# <filter>'[login]'.endswith('@students.latrobe.edu.au')</filter>
# <options>
# <auto-register>True</auto-register>
# <server>ldap://STUDENTS.ltu.edu.au</server>
# [<search-filter>(&amp;(objectClass=user)(mail={login}))</search-filter>
# <search-base>dc=STUDENTS,dc=ltu,dc=edu,dc=au</search-base>
# <!-- If search-user not specified will bind anonymously to LDAP for search -->
# <search-user>jsmith</search-user>
# <search-password>mysecret</search-password>
# <search-fields>sAMAccountName,mail</search-fields>]
# <bind-user>{sAMAccountName}@STUDENTS.ltu.edu.au</bind-user>
# <bind-password>{password}</bind-password>
# <auto-register-username>{sAMAccountName}</auto-register-username>
# <auto-register-email>{mail}</auto-register-email>
# <!-- To allow login with username instead of email
# <login-use-username>True</login-use-username>
# -->
# </options>
# </authenticator>
# ...
# </auth>
class AuthManager(object):
@@ -85,14 +60,14 @@ class AuthManager(object):
authenticators.append(authenticator)
self.authenticators = authenticators
def check_registration_allowed(self, login, password):
def check_registration_allowed(self, email, username, password):
"""Checks if the provided email/username is allowed to register."""
message = ''
status = 'done'
for provider, options in self.active_authenticators(login, password):
for provider, options in self.active_authenticators(email, username, password):
allow_reg = _get_tri_state(options, 'allow-register', True)
if allow_reg is None: # i.e. challenge
auth_result, msg = provider.authenticate(login, password, options)
auth_result, msg = provider.authenticate(email, username, password, options)
if auth_result is True:
break
if auth_result is None:
@@ -112,11 +87,17 @@ class AuthManager(object):
Checks the username/email & password using auth providers in order.
If a match is found, returns the 'auto-register' option for that provider.
"""
for provider, options in self.active_authenticators(login, password):
if '@' in login:
email = login
username = None
else:
email = None
username = login
for provider, options in self.active_authenticators(email, username, password):
if provider is None:
log.debug( "Unable to find module: %s" % options )
else:
auth_result, auto_email, auto_username = provider.authenticate(login, password, options)
auth_result, auto_email, auto_username = provider.authenticate(email, username, password, options)
auto_email = str(auto_email).lower()
auto_username = str(auto_username).lower()
if auth_result is True:
@@ -139,7 +120,7 @@ class AuthManager(object):
def check_password(self, user, password):
"""Checks the username/email and password using auth providers."""
for provider, options in self.active_authenticators(user, password):
for provider, options in self.active_authenticators(user.email, user.username, password):
if provider is None:
log.debug( "Unable to find module: %s" % options )
else:
@@ -154,7 +135,7 @@ class AuthManager(object):
"""Checks that auth provider allows password changes and current_password
matches.
"""
for provider, options in self.active_authenticators(user, current_password):
for provider, options in self.active_authenticators(user.email, user.username, current_password):
if provider is None:
log.debug( "Unable to find module: %s" % options )
else:
@@ -168,7 +149,7 @@ class AuthManager(object):
return (False, 'Password change not supported')
return (False, 'Invalid current password')
def active_authenticators(self, login, password):
def active_authenticators(self, email, username, password):
"""Yields AuthProvider instances for the provided configfile that match the
filters.
"""
@@ -176,7 +157,7 @@ class AuthManager(object):
for authenticator in self.authenticators:
filter_template = authenticator.filter_template
if filter_template:
filter_str = filter_template.format(login=login, password=password)
filter_str = filter_template.format(email=email, username=username, password=password)
passed_filter = eval(filter_str, {"__builtins__": None}, {'str': str})
if not passed_filter:
continue # skip to next
+8 -6
View File
@@ -16,15 +16,17 @@ class AuthProvider(object):
""" Short string providing labelling this plugin """
@abc.abstractmethod
def authenticate(self, login, password, options):
def authenticate(self, email, username, password, options):
"""
Check that the username and password are correct.
Check that the user credentials are correct.
NOTE: Used within auto-registration to check it is ok to register this
user.
:param login: the user's email address or username
:type login: str
:param email: the user's email address
:type email: str
:param username: the user's username
:type username: str
:param password: the plain text password they typed
:type password: str
:param options: options provided in auth_config_file
@@ -44,8 +46,8 @@ class AuthProvider(object):
NOTE: used on normal login to check authentication and update user
details if required.
:param username: the user's email address or username
:type username: str
:param user: the user to authenticate
:type user: galaxy.model.User
:param password: the plain text password they typed
:type password: str
:param options: options provided in auth_config_file
+1 -1
View File
@@ -16,7 +16,7 @@ class AlwaysReject(AuthProvider):
"""
plugin_type = 'alwaysreject'
def authenticate(self, login, password, options):
def authenticate(self, email, username, password, options):
"""
See abstract method documentation.
"""
+22 -17
View File
@@ -30,26 +30,35 @@ class LDAP(AuthProvider):
"""
plugin_type = 'ldap'
def authenticate(self, login, password, options):
def authenticate(self, email, username, password, options):
"""
See abstract method documentation.
"""
log.debug("Login: %s" % login)
log.debug("Options: %s" % options)
log.debug("LDAP authenticate: email is %s" % email)
log.debug("LDAP authenticate: username is %s" % username)
log.debug("LDAP authenticate: options are %s" % options)
failure_mode = False # reject but continue
if options.get('continue-on-failure', 'False') == 'False':
failure_mode = None # reject and do not continue
if _get_bool(options, 'login-use-username', False):
if username is None:
log.debug('LDAP authenticate: username must be used to login, cannot be None')
return (failure_mode, '', '')
else:
if email is None:
log.debug('LDAP authenticate: email must be used to login, cannot be None')
return (failure_mode, '', '')
try:
import ldap
except:
log.debug(
"Login: %s, LDAP: False (could not load ldap module)" % (login))
return (failure_mode, '')
log.debug('LDAP authenticate: could not load ldap module')
return (failure_mode, '', '')
# do LDAP search (if required)
params = {'login': login, 'password': password}
params = {'email': email, 'username': username, 'password': password}
if 'search-fields' in options:
try:
# setup connection
@@ -74,8 +83,8 @@ class LDAP(AuthProvider):
# parse results
_, suser = l.result(result, 60)
dn, attrs = suser[0]
log.debug(("LDAP dn: %s" % dn))
log.debug(("LDAP Search attributes: %s" % attrs))
log.debug(("LDAP authenticate: dn is %s" % dn))
log.debug(("LDAP authenticate: search attributes are %s" % attrs))
if hasattr(attrs, 'has_key'):
for attr in attributes:
if attr in attrs:
@@ -84,7 +93,7 @@ class LDAP(AuthProvider):
params[attr] = ""
params['dn'] = dn
except Exception:
log.exception('LDAP Search Exception for login: %s' % login)
log.exception('LDAP authenticate: search exception')
return (failure_mode, '', '')
# end search
@@ -97,10 +106,10 @@ class LDAP(AuthProvider):
l.simple_bind_s(_get_subs(
options, 'bind-user', params), _get_subs(options, 'bind-password', params))
except Exception:
log.exception('LDAP Authentication Exception for login %s' % login)
log.exception('LDAP authenticate: bind exception')
return (failure_mode, '', '')
log.debug("Login: %s, LDAP: True" % (login))
log.debug('LDAP authentication successful')
return (True,
_get_subs(options, 'auto-register-email', params),
_get_subs(options, 'auto-register-username', params))
@@ -109,11 +118,7 @@ class LDAP(AuthProvider):
"""
See abstract method documentation.
"""
if _get_bool(options, 'login-use-username', False):
return self.authenticate(user.username, password, options)[0]
else:
return self.authenticate(user.email, password, options)[0]
return self.authenticate(user.email, user.username, password, options)[0]
class ActiveDirectory(LDAP):
+1 -1
View File
@@ -13,7 +13,7 @@ class LocalDB(AuthProvider):
"""Authenticate users against the local Galaxy database (as per usual)."""
plugin_type = 'localdb'
def authenticate(self, login, password, options):
def authenticate(self, email, username, password, options):
"""
See abstract method documentation.
"""
@@ -678,7 +678,7 @@ class User( BaseUIController, UsesFormDefinitionsMixin, CreatesUsersMixin, Creat
status = 'error'
else:
# check user is allowed to register
message, status = trans.app.auth_manager.check_registration_allowed(email, password)
message, status = trans.app.auth_manager.check_registration_allowed(email, username, password)
if message == '':
if not refresh_frames:
if trans.webapp.name == 'galaxy':