forked from shaba/openuds
More pep8 related fixes, also some refactoring
This commit is contained in:
parent
dab3e26223
commit
89addaf585
@ -32,6 +32,8 @@
|
||||
|
||||
@author: Adolfo Gómez, dkmaster at dkmon dot com
|
||||
'''
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.utils.translation import ugettext_noop as _
|
||||
from uds.core.ui.UserInterface import gui
|
||||
from uds.core import auths
|
||||
|
@ -36,8 +36,11 @@ from uds.core import auths
|
||||
|
||||
import logging
|
||||
|
||||
__updated__ = '2014-02-19'
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class SampleAuth(auths.Authenticator):
|
||||
'''
|
||||
This class represents a sample authenticator.
|
||||
@ -63,52 +66,51 @@ class SampleAuth(auths.Authenticator):
|
||||
the string when it is sent to the administration client.
|
||||
'''
|
||||
|
||||
#: Name of type, used at administration interface to identify this
|
||||
#: authenticator (i.e. LDAP, SAML, ...)
|
||||
#: This string will be translated when provided to admin interface
|
||||
#: using ugettext, so you can mark it as "_" at derived classes (using ugettext_noop)
|
||||
#: if you want so it can be translated.
|
||||
# : Name of type, used at administration interface to identify this
|
||||
# : authenticator (i.e. LDAP, SAML, ...)
|
||||
# : This string will be translated when provided to admin interface
|
||||
# : using ugettext, so you can mark it as "_" at derived classes (using ugettext_noop)
|
||||
# : if you want so it can be translated.
|
||||
typeName = _('Sample Authenticator')
|
||||
|
||||
#: Name of type used by Managers to identify this type of service
|
||||
#: We could have used here the Class name, but we decided that the
|
||||
#: module implementator will be the one that will provide a name that
|
||||
#: will relation the class (type) and that name.
|
||||
# : Name of type used by Managers to identify this type of service
|
||||
# : We could have used here the Class name, but we decided that the
|
||||
# : module implementator will be the one that will provide a name that
|
||||
# : will relation the class (type) and that name.
|
||||
typeType = 'SampleAuthenticator'
|
||||
|
||||
#: Description shown at administration level for this authenticator.
|
||||
#: This string will be translated when provided to admin interface
|
||||
#: using ugettext, so you can mark it as "_" at derived classes (using ugettext_noop)
|
||||
#: if you want so it can be translated.
|
||||
# : Description shown at administration level for this authenticator.
|
||||
# : This string will be translated when provided to admin interface
|
||||
# : using ugettext, so you can mark it as "_" at derived classes (using ugettext_noop)
|
||||
# : if you want so it can be translated.
|
||||
typeDescription = _('Sample dummy authenticator')
|
||||
|
||||
|
||||
#: Icon file, used to represent this authenticator at administration interface
|
||||
#: This file should be at same folder as this class is, except if you provide
|
||||
#: your own :py:meth:uds.core.BaseModule.BaseModule.icon method.
|
||||
# : Icon file, used to represent this authenticator at administration interface
|
||||
# : This file should be at same folder as this class is, except if you provide
|
||||
# : your own :py:meth:uds.core.BaseModule.BaseModule.icon method.
|
||||
iconFile = 'auth.png'
|
||||
|
||||
#: Mark this authenticator as that the users comes from outside the UDS
|
||||
#: database, that are most authenticator (except Internal DB)
|
||||
#: True is the default value, so we do not need it in fact
|
||||
# : Mark this authenticator as that the users comes from outside the UDS
|
||||
# : database, that are most authenticator (except Internal DB)
|
||||
# : True is the default value, so we do not need it in fact
|
||||
# isExternalSource = True
|
||||
|
||||
#: If we need to enter the password for this user when creating a new
|
||||
#: user at administration interface. Used basically by internal authenticator.
|
||||
#: False is the default value, so this is not needed in fact
|
||||
#: needsPassword = False
|
||||
# : If we need to enter the password for this user when creating a new
|
||||
# : user at administration interface. Used basically by internal authenticator.
|
||||
# : False is the default value, so this is not needed in fact
|
||||
# : needsPassword = False
|
||||
|
||||
#: Label for username field, shown at administration interface user form.
|
||||
# : Label for username field, shown at administration interface user form.
|
||||
userNameLabel = _('Fake User')
|
||||
|
||||
# Label for group field, shown at administration interface user form.
|
||||
groupNameLabel = _('Fake Group')
|
||||
|
||||
#: Definition of this type of authenticator form
|
||||
#: We will define a simple form where we will use a simple
|
||||
#: list editor to allow entering a few group names
|
||||
# : Definition of this type of authenticator form
|
||||
# : We will define a simple form where we will use a simple
|
||||
# : list editor to allow entering a few group names
|
||||
|
||||
groups = gui.EditableList(label=_('Groups'), values = ['Gods', 'Daemons', 'Mortals'])
|
||||
groups = gui.EditableList(label=_('Groups'), values=['Gods', 'Daemons', 'Mortals'])
|
||||
|
||||
def initialize(self, values):
|
||||
'''
|
||||
@ -192,7 +194,7 @@ class SampleAuth(auths.Authenticator):
|
||||
|
||||
:note: groupsManager is an in/out parameter
|
||||
'''
|
||||
if username != credentials: # All users with same username and password are allowed
|
||||
if username != credentials: # All users with same username and password are allowed
|
||||
return False
|
||||
|
||||
# Now the tricky part. We will make this user belong to groups that contains at leat
|
||||
@ -232,22 +234,21 @@ class SampleAuth(auths.Authenticator):
|
||||
# Here there is a sample, commented out
|
||||
# In this sample, we will make a list of valid users, and when clicked,
|
||||
# it will fill up original form with username and same password, and submit it.
|
||||
#res = ''
|
||||
#for u in self.dbAuthenticator().users.all():
|
||||
# res = ''
|
||||
# for u in self.dbAuthenticator().users.all():
|
||||
# res += '<a class="myNames" id="{0}" href="">{0}</a><br/>'.format(u.name)
|
||||
#
|
||||
#res += '<script type="text/javascript">$(".myNames").click(function() { '
|
||||
#res += '$("#id_user").val(this.id); $("#id_password").val(this.id); $("#loginform").submit(); return false;});</script>'
|
||||
#return res
|
||||
# res += '<script type="text/javascript">$(".myNames").click(function() { '
|
||||
# res += '$("#id_user").val(this.id); $("#id_password").val(this.id); $("#loginform").submit(); return false;});</script>'
|
||||
# return res
|
||||
|
||||
# I know, this is a bit ugly, but this is just a sample :-)
|
||||
|
||||
res = '<p>Login name: <input id="logname" type="text"/></p>'
|
||||
res +='<p><a href="" onclick="window.location.replace(\'' + self.callbackUrl() + '?user='
|
||||
res += '<p><a href="" onclick="window.location.replace(\'' + self.callbackUrl() + '?user='
|
||||
res += '\' + $(\'#logname\').val()); return false;">Login</a></p>'
|
||||
return res
|
||||
|
||||
|
||||
def authCallback(self, parameters, gm):
|
||||
'''
|
||||
We provide this as a sample of callback for an user.
|
||||
|
@ -34,5 +34,8 @@ take care of registering it as provider
|
||||
|
||||
.. moduleauthor:: Adolfo Gómez, dkmaster at dkmon dot com
|
||||
'''
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from SampleAuth import SampleAuth
|
||||
|
||||
__updated__ = '2014-02-19'
|
||||
|
@ -32,33 +32,38 @@
|
||||
|
||||
@author: Adolfo Gómez, dkmaster at dkmon dot com
|
||||
'''
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.utils.translation import ugettext_noop as _
|
||||
from uds.core.ui.UserInterface import gui
|
||||
from uds.core.auths import Authenticator
|
||||
import ldap
|
||||
|
||||
import logging
|
||||
from uds.core.auths.Exceptions import AuthenticatorException
|
||||
|
||||
import ldap
|
||||
import logging
|
||||
|
||||
__updated__ = '2014-02-19'
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
LDAP_RESULT_LIMIT = 50
|
||||
|
||||
|
||||
class SimpleLDAPAuthenticator(Authenticator):
|
||||
|
||||
host = gui.TextField(length=64, label = _('Host'), order = 1, tooltip = _('Ldap Server IP or Hostname'), required = True)
|
||||
port = gui.NumericField(length=5, label = _('Port'), defvalue = '389', order = 2, tooltip = _('Ldap port (389 for non ssl, 636 for ssl normally'), required = True)
|
||||
ssl = gui.CheckBoxField(label = _('Use SSL'), order = 3, tooltip = _('If checked, will use a ssl connection to ldap (if port is 389, will use in fact port 636)'))
|
||||
username = gui.TextField(length=64, label = _('Ldap User'), order = 4, tooltip = _('Username with read privileges on the base selected'), required = True)
|
||||
password = gui.PasswordField(lenth=32, label = _('Password'), order = 5, tooltip = _('Password of the ldap user'), required = True)
|
||||
timeout = gui.NumericField(length=3, label = _('Timeout'), defvalue = '10', order = 6, tooltip = _('Timeout in seconds of connection to LDAP'), required = True)
|
||||
ldapBase = gui.TextField(length=64, label = _('Base'), order = 7, tooltip = _('Common search base (used for "users" and "groups"'), required = True)
|
||||
userClass = gui.TextField(length=64, label = _('User class'), defvalue = 'posixAccount', order = 8, tooltip = _('Class for LDAP users (normally posixAccount)'), required = True)
|
||||
userIdAttr = gui.TextField(length=64, label = _('User Id Attr'), defvalue = 'uid', order = 9, tooltip = _('Attribute that contains the user id'), required = True)
|
||||
userNameAttr = gui.TextField(length=64, label = _('User Name Attr'), defvalue = 'uid', order = 10, tooltip = _('Attributes that contains the user name (list of comma separated values)'), required = True)
|
||||
groupClass = gui.TextField(length=64, label = _('Group class'), defvalue = 'posixGroup', order = 11, tooltip = _('Class for LDAP groups (normally poxisGroup)'), required = True)
|
||||
groupIdAttr = gui.TextField(length=64, label = _('Group Id Attr'), defvalue = 'cn', order = 12, tooltip = _('Attribute that contains the group id'), required = True)
|
||||
memberAttr = gui.TextField(length=64, label = _('Group membership attr'), defvalue = 'memberUid', order = 13, tooltip = _('Attribute of the group that contains the users belonging to it'), required = True)
|
||||
host = gui.TextField(length=64, label=_('Host'), order=1, tooltip=_('Ldap Server IP or Hostname'), required=True)
|
||||
port = gui.NumericField(length=5, label=_('Port'), defvalue='389', order=2, tooltip=_('Ldap port (389 for non ssl, 636 for ssl normally'), required=True)
|
||||
ssl = gui.CheckBoxField(label=_('Use SSL'), order=3, tooltip=_('If checked, will use a ssl connection to ldap (if port is 389, will use in fact port 636)'))
|
||||
username = gui.TextField(length=64, label=_('Ldap User'), order=4, tooltip=_('Username with read privileges on the base selected'), required=True)
|
||||
password = gui.PasswordField(lenth=32, label=_('Password'), order=5, tooltip=_('Password of the ldap user'), required=True)
|
||||
timeout = gui.NumericField(length=3, label=_('Timeout'), defvalue='10', order=6, tooltip=_('Timeout in seconds of connection to LDAP'), required=True)
|
||||
ldapBase = gui.TextField(length=64, label=_('Base'), order=7, tooltip=_('Common search base (used for "users" and "groups"'), required=True)
|
||||
userClass = gui.TextField(length=64, label=_('User class'), defvalue='posixAccount', order=8, tooltip=_('Class for LDAP users (normally posixAccount)'), required=True)
|
||||
userIdAttr = gui.TextField(length=64, label=_('User Id Attr'), defvalue='uid', order=9, tooltip=_('Attribute that contains the user id'), required=True)
|
||||
userNameAttr = gui.TextField(length=64, label=_('User Name Attr'), defvalue='uid', order=10, tooltip=_('Attributes that contains the user name (list of comma separated values)'), required=True)
|
||||
groupClass = gui.TextField(length=64, label=_('Group class'), defvalue='posixGroup', order=11, tooltip=_('Class for LDAP groups (normally poxisGroup)'), required=True)
|
||||
groupIdAttr = gui.TextField(length=64, label=_('Group Id Attr'), defvalue='cn', order=12, tooltip=_('Attribute that contains the group id'), required=True)
|
||||
memberAttr = gui.TextField(length=64, label=_('Group membership attr'), defvalue='memberUid', order=13, tooltip=_('Attribute of the group that contains the users belonging to it'), required=True)
|
||||
|
||||
typeName = _('SimpleLDAP Authenticator')
|
||||
typeType = 'SimpleLdapAuthenticator'
|
||||
@ -76,7 +81,7 @@ class SimpleLDAPAuthenticator(Authenticator):
|
||||
# Label for password field
|
||||
passwordLabel = _("Password")
|
||||
|
||||
def __init__(self, dbAuth, environment, values = None):
|
||||
def __init__(self, dbAuth, environment, values=None):
|
||||
super(SimpleLDAPAuthenticator, self).__init__(dbAuth, environment, values)
|
||||
if values != None:
|
||||
self._host = values['host']
|
||||
@ -91,7 +96,7 @@ class SimpleLDAPAuthenticator(Authenticator):
|
||||
self._userIdAttr = values['userIdAttr']
|
||||
self._groupIdAttr = values['groupIdAttr']
|
||||
self._memberAttr = values['memberAttr']
|
||||
self._userNameAttr = values['userNameAttr'].replace(' ', '') # Removes white spaces
|
||||
self._userNameAttr = values['userNameAttr'].replace(' ', '') # Removes white spaces
|
||||
else:
|
||||
self._host = None
|
||||
self._port = None
|
||||
@ -109,12 +114,13 @@ class SimpleLDAPAuthenticator(Authenticator):
|
||||
self._connection = None
|
||||
|
||||
def valuesDict(self):
|
||||
return { 'host' : self._host, 'port' : self._port, 'ssl' : gui.boolToStr(self._ssl),
|
||||
'username' : self._username, 'password' : self._password, 'timeout' : self._timeout,
|
||||
'ldapBase' : self._ldapBase, 'userClass' : self._userClass, 'groupClass' : self._groupClass,
|
||||
'userIdAttr' : self._userIdAttr, 'groupIdAttr' : self._groupIdAttr, 'memberAttr' : self._memberAttr,
|
||||
'userNameAttr' : self._userNameAttr
|
||||
}
|
||||
return {
|
||||
'host': self._host, 'port': self._port, 'ssl': gui.boolToStr(self._ssl),
|
||||
'username': self._username, 'password': self._password, 'timeout': self._timeout,
|
||||
'ldapBase': self._ldapBase, 'userClass': self._userClass, 'groupClass': self._groupClass,
|
||||
'userIdAttr': self._userIdAttr, 'groupIdAttr': self._groupIdAttr, 'memberAttr': self._memberAttr,
|
||||
'userNameAttr': self._userNameAttr
|
||||
}
|
||||
|
||||
def __str__(self):
|
||||
return "Ldap Auth: {0}:{1}@{2}:{3}, base = {4}, userClass = {5}, groupClass = {6}, userIdAttr = {7}, groupIdAttr = {8}, memberAttr = {9}, userName attr = {10}".format(
|
||||
@ -124,24 +130,24 @@ class SimpleLDAPAuthenticator(Authenticator):
|
||||
def marshal(self):
|
||||
return str.join('\t', ['v1',
|
||||
self._host, self._port, gui.boolToStr(self._ssl), self._username, self._password, self._timeout,
|
||||
self._ldapBase, self._userClass, self._groupClass, self._userIdAttr, self._groupIdAttr, self._memberAttr, self._userNameAttr ])
|
||||
self._ldapBase, self._userClass, self._groupClass, self._userIdAttr, self._groupIdAttr, self._memberAttr, self._userNameAttr])
|
||||
|
||||
def unmarshal(self, str):
|
||||
data = str.split('\t')
|
||||
def unmarshal(self, str_):
|
||||
data = str_.split('\t')
|
||||
if data[0] == 'v1':
|
||||
logger.debug("Data: {0}".format(data[1:]))
|
||||
self._host, self._port, self._ssl, self._username, self._password, self._timeout, self._ldapBase, self._userClass, self._groupClass, self._userIdAttr, self._groupIdAttr, self._memberAttr, self._userNameAttr = data[1:]
|
||||
self._ssl = gui.strToBool(self._ssl)
|
||||
|
||||
def __connection(self, username = None, password = None):
|
||||
if self._connection is None or username is not None: # We want this method also to check credentials
|
||||
def __connection(self, username=None, password=None):
|
||||
if self._connection is None or username is not None: # We want this method also to check credentials
|
||||
l = None
|
||||
cache = False
|
||||
try:
|
||||
#ldap.set_option(ldap.OPT_DEBUG_LEVEL, 9)
|
||||
# ldap.set_option(ldap.OPT_DEBUG_LEVEL, 9)
|
||||
ldap.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, ldap.OPT_X_TLS_NEVER)
|
||||
schema = self._ssl and 'ldaps' or 'ldap'
|
||||
port = self._port != '389' and ':' + self._port or ''
|
||||
port = self._port != '389' and ':' + self._port or ''
|
||||
uri = "%s://%s%s" % (schema, self._host, port)
|
||||
logger.debug('Ldap uri: {0}'.format(uri))
|
||||
l = ldap.initialize(uri=uri)
|
||||
@ -153,63 +159,62 @@ class SimpleLDAPAuthenticator(Authenticator):
|
||||
username = self._username
|
||||
password = self._password
|
||||
|
||||
l.simple_bind_s(who = username, cred = password)
|
||||
l.simple_bind_s(who=username, cred=password)
|
||||
except ldap.LDAPError, e:
|
||||
str = _('Ldap connection error: ')
|
||||
str_ = _('Ldap connection error: ')
|
||||
if type(e.message) == dict:
|
||||
str += e.message.has_key('info') and e.message['info'] + ',' or ''
|
||||
str += e.message.has_key('desc') and e.message['desc'] or ''
|
||||
else :
|
||||
str += str(e)
|
||||
raise Exception(str)
|
||||
str_ += 'info' in e.message and e.message['info'] + ',' or ''
|
||||
str_ += 'desc' in e.message and e.message['desc'] or ''
|
||||
else:
|
||||
str_ += str_(e)
|
||||
raise Exception(str_)
|
||||
if cache is True:
|
||||
self._connection = l
|
||||
else:
|
||||
return l # Do not cache nor overwrite "global" connection
|
||||
return l # Do not cache nor overwrite "global" connection
|
||||
return self._connection
|
||||
|
||||
def __getUser(self, username):
|
||||
try:
|
||||
con = self.__connection()
|
||||
filter = '(&(objectClass=%s)(%s=%s))' % (self._userClass, self._userIdAttr, username)
|
||||
filter_ = '(&(objectClass=%s)(%s=%s))' % (self._userClass, self._userIdAttr, username)
|
||||
attrlist = self._userNameAttr.split(',') + [self._userIdAttr]
|
||||
logger.debug('Getuser filter: {0}, attr list: {1}'.format(filter, attrlist))
|
||||
res = con.search_ext_s(base = self._ldapBase, scope = ldap.SCOPE_SUBTREE,
|
||||
filterstr = filter, attrlist = attrlist, sizelimit = LDAP_RESULT_LIMIT)[0]
|
||||
usr = dict(( k, '' ) for k in attrlist)
|
||||
logger.debug('Getuser filter_: {0}, attr list: {1}'.format(filter_, attrlist))
|
||||
res = con.search_ext_s(base=self._ldapBase, scope=ldap.SCOPE_SUBTREE,
|
||||
filterstr=filter_, attrlist=attrlist, sizelimit=LDAP_RESULT_LIMIT)[0]
|
||||
usr = dict((k, '') for k in attrlist)
|
||||
usr.update(res[1])
|
||||
usr.update( {'dn' : res[0], '_id' : username })
|
||||
usr.update({'dn': res[0], '_id': username})
|
||||
logger.debug('Usr: {0}'.format(usr))
|
||||
return usr
|
||||
except Exception, e:
|
||||
except Exception:
|
||||
logger.exception('Exception:')
|
||||
return None
|
||||
|
||||
def __getGroup(self, groupName):
|
||||
try:
|
||||
con = self.__connection()
|
||||
filter = '(&(objectClass=%s)(%s=%s))' % (self._groupClass, self._groupIdAttr, groupName)
|
||||
filter_ = '(&(objectClass=%s)(%s=%s))' % (self._groupClass, self._groupIdAttr, groupName)
|
||||
attrlist = [self._memberAttr]
|
||||
logger.debug('Getgroup filter: {0}, attr list {1}'.format(filter, attrlist))
|
||||
res = con.search_ext_s(base = self._ldapBase, scope = ldap.SCOPE_SUBTREE,
|
||||
filterstr = filter, attrlist = attrlist, sizelimit = LDAP_RESULT_LIMIT)[0]
|
||||
grp = dict(( k, [''] ) for k in attrlist)
|
||||
logger.debug('Getgroup filter_: {0}, attr list {1}'.format(filter_, attrlist))
|
||||
res = con.search_ext_s(base=self._ldapBase, scope=ldap.SCOPE_SUBTREE,
|
||||
filterstr=filter_, attrlist=attrlist, sizelimit=LDAP_RESULT_LIMIT)[0]
|
||||
grp = dict((k, ['']) for k in attrlist)
|
||||
grp.update(res[1])
|
||||
grp.update( {'dn' : res[0], '_id' : groupName })
|
||||
grp.update({'dn': res[0], '_id': groupName})
|
||||
logger.debug('Group: {0}'.format(grp))
|
||||
return grp
|
||||
except Exception, e:
|
||||
except Exception:
|
||||
logger.exception('Exception:')
|
||||
return None
|
||||
|
||||
|
||||
def __getGroups(self, usr):
|
||||
try:
|
||||
con = self.__connection()
|
||||
filter = '(&(objectClass=%s)(|(%s=%s)(%s=%s)))' % (self._groupClass, self._memberAttr, usr['_id'], self._memberAttr, usr['dn'])
|
||||
logger.debug('Filter: {0}'.format(filter))
|
||||
res = con.search_ext_s(base = self._ldapBase, scope = ldap.SCOPE_SUBTREE, filterstr = filter, attrlist = [self._groupIdAttr],
|
||||
sizelimit = LDAP_RESULT_LIMIT)
|
||||
filter_ = '(&(objectClass=%s)(|(%s=%s)(%s=%s)))' % (self._groupClass, self._memberAttr, usr['_id'], self._memberAttr, usr['dn'])
|
||||
logger.debug('Filter: {0}'.format(filter_))
|
||||
res = con.search_ext_s(base=self._ldapBase, scope=ldap.SCOPE_SUBTREE, filterstr=filter_, attrlist=[self._groupIdAttr],
|
||||
sizelimit=LDAP_RESULT_LIMIT)
|
||||
groups = {}
|
||||
for g in res:
|
||||
v = g[1][self._groupIdAttr]
|
||||
@ -223,13 +228,12 @@ class SimpleLDAPAuthenticator(Authenticator):
|
||||
except Exception:
|
||||
return {}
|
||||
|
||||
|
||||
def __getUserRealName(self, usr):
|
||||
'''
|
||||
Tries to extract the real name for this user. Will return all atttributes (joint)
|
||||
specified in _userNameAttr (comma separated).
|
||||
'''
|
||||
return ' '.join([ (type(usr.get(id_, '')) is list and ' '.join(( str(k) for k in usr.get(id_, ''))) or str(usr.get(id_, ''))) for id_ in self._userNameAttr.split(',') ]).strip()
|
||||
return ' '.join([(type(usr.get(id_, '')) is list and ' '.join((str(k) for k in usr.get(id_, ''))) or str(usr.get(id_, ''))) for id_ in self._userNameAttr.split(',')]).strip()
|
||||
|
||||
def authenticate(self, username, credentials, groupsManager):
|
||||
'''
|
||||
@ -249,7 +253,7 @@ class SimpleLDAPAuthenticator(Authenticator):
|
||||
return False
|
||||
|
||||
# Let's see first if it credentials are fine
|
||||
self.__connection(usr['dn'], credentials) # Will raise an exception if it can't connect
|
||||
self.__connection(usr['dn'], credentials) # Will raise an exception if it can't connect
|
||||
|
||||
groupsManager.validate(self.__getGroups(usr).keys())
|
||||
|
||||
@ -301,7 +305,6 @@ class SimpleLDAPAuthenticator(Authenticator):
|
||||
if res is None:
|
||||
raise AuthenticatorException(_('Group not found'))
|
||||
|
||||
|
||||
def getGroups(self, username, groupsManager):
|
||||
'''
|
||||
Looks for the real groups to which the specified user belongs
|
||||
@ -317,13 +320,15 @@ class SimpleLDAPAuthenticator(Authenticator):
|
||||
try:
|
||||
con = self.__connection()
|
||||
res = []
|
||||
for r in con.search_ext_s(base = self._ldapBase, scope = ldap.SCOPE_SUBTREE, filterstr = '(&(objectClass=%s)(%s=%s*))' % (self._userClass, self._userIdAttr, pattern), sizelimit=LDAP_RESULT_LIMIT):
|
||||
for r in con.search_ext_s(base=self._ldapBase, scope=ldap.SCOPE_SUBTREE, filterstr='(&(objectClass=%s)(%s=%s*))' % (self._userClass, self._userIdAttr, pattern), sizelimit=LDAP_RESULT_LIMIT):
|
||||
usrId = r[1].get(self._userIdAttr, '')
|
||||
usrId = type(usrId) == list and usrId[0] or usrId
|
||||
res.append( { 'id' : usrId,
|
||||
'name' : self.__getUserRealName(r[1]) } )
|
||||
res.append({
|
||||
'id': usrId,
|
||||
'name': self.__getUserRealName(r[1])
|
||||
})
|
||||
return res
|
||||
except Exception, e:
|
||||
except Exception:
|
||||
logger.exception("Exception: ")
|
||||
raise AuthenticatorException(_('Too many results, be more specific'))
|
||||
|
||||
@ -331,17 +336,18 @@ class SimpleLDAPAuthenticator(Authenticator):
|
||||
try:
|
||||
con = self.__connection()
|
||||
res = []
|
||||
for r in con.search_ext_s(base = self._ldapBase, scope = ldap.SCOPE_SUBTREE, filterstr = '(&(objectClass=%s)(%s=%s*))' % (self._groupClass, self._groupIdAttr, pattern), sizelimit=LDAP_RESULT_LIMIT):
|
||||
for r in con.search_ext_s(base=self._ldapBase, scope=ldap.SCOPE_SUBTREE, filterstr='(&(objectClass=%s)(%s=%s*))' % (self._groupClass, self._groupIdAttr, pattern), sizelimit=LDAP_RESULT_LIMIT):
|
||||
grpId = r[1].get(self._groupIdAttr, '')
|
||||
grpId = type(grpId) == list and grpId[0] or grpId
|
||||
res.append( { 'id' : grpId,
|
||||
'name' : grpId } )
|
||||
res.append({
|
||||
'id': grpId,
|
||||
'name': grpId
|
||||
})
|
||||
return res
|
||||
except Exception, e:
|
||||
except Exception:
|
||||
logger.exception("Exception: ")
|
||||
raise AuthenticatorException(_('Too many results, be more specific'))
|
||||
|
||||
|
||||
@staticmethod
|
||||
def test(env, data):
|
||||
try:
|
||||
@ -358,12 +364,12 @@ class SimpleLDAPAuthenticator(Authenticator):
|
||||
return [False, str(e)]
|
||||
|
||||
try:
|
||||
con.search_s(base = self._ldapBase, scope = ldap.SCOPE_BASE)
|
||||
con.search_s(base=self._ldapBase, scope=ldap.SCOPE_BASE)
|
||||
except Exception:
|
||||
return [False, _('Ldap search base is incorrect')]
|
||||
|
||||
try:
|
||||
if len(con.search_ext_s(base = self._ldapBase, scope = ldap.SCOPE_SUBTREE, filterstr = '(objectClass=%s)' % self._userClass, sizelimit=1)) == 1:
|
||||
if len(con.search_ext_s(base=self._ldapBase, scope=ldap.SCOPE_SUBTREE, filterstr='(objectClass=%s)' % self._userClass, sizelimit=1)) == 1:
|
||||
raise Exception()
|
||||
return [False, _('Ldap user class seems to be incorrect (no user found by that class)')]
|
||||
except Exception, e:
|
||||
@ -371,7 +377,7 @@ class SimpleLDAPAuthenticator(Authenticator):
|
||||
pass
|
||||
|
||||
try:
|
||||
if len(con.search_ext_s(base = self._ldapBase, scope = ldap.SCOPE_SUBTREE, filterstr = '(objectClass=%s)' % self._groupClass, sizelimit=1)) == 1:
|
||||
if len(con.search_ext_s(base=self._ldapBase, scope=ldap.SCOPE_SUBTREE, filterstr='(objectClass=%s)' % self._groupClass, sizelimit=1)) == 1:
|
||||
raise Exception()
|
||||
return [False, _('Ldap group class seems to be incorrect (no group found by that class)')]
|
||||
except Exception, e:
|
||||
@ -379,7 +385,7 @@ class SimpleLDAPAuthenticator(Authenticator):
|
||||
pass
|
||||
|
||||
try:
|
||||
if len(con.search_ext_s(base = self._ldapBase, scope = ldap.SCOPE_SUBTREE, filterstr = '(%s=*)' % self._userIdAttr, sizelimit=1)) == 1:
|
||||
if len(con.search_ext_s(base=self._ldapBase, scope=ldap.SCOPE_SUBTREE, filterstr='(%s=*)' % self._userIdAttr, sizelimit=1)) == 1:
|
||||
raise Exception()
|
||||
return [False, _('Ldap user id attribute seems to be incorrect (no user found by that attribute)')]
|
||||
except Exception, e:
|
||||
@ -387,7 +393,7 @@ class SimpleLDAPAuthenticator(Authenticator):
|
||||
pass
|
||||
|
||||
try:
|
||||
if len(con.search_ext_s(base = self._ldapBase, scope = ldap.SCOPE_SUBTREE, filterstr = '(%s=*)' % self._groupIdAttr, sizelimit=1)) == 1:
|
||||
if len(con.search_ext_s(base=self._ldapBase, scope=ldap.SCOPE_SUBTREE, filterstr='(%s=*)' % self._groupIdAttr, sizelimit=1)) == 1:
|
||||
raise Exception()
|
||||
return [False, _('Ldap group id attribute seems to be incorrect (no group found by that attribute)')]
|
||||
except Exception, e:
|
||||
@ -396,7 +402,7 @@ class SimpleLDAPAuthenticator(Authenticator):
|
||||
|
||||
# Now test objectclass and attribute of users
|
||||
try:
|
||||
if len(con.search_ext_s(base = self._ldapBase, scope = ldap.SCOPE_SUBTREE, filterstr = '(&(objectClass=%s)(%s=*))' % (self._userClass, self._userIdAttr), sizelimit=1)) == 1:
|
||||
if len(con.search_ext_s(base=self._ldapBase, scope=ldap.SCOPE_SUBTREE, filterstr='(&(objectClass=%s)(%s=*))' % (self._userClass, self._userIdAttr), sizelimit=1)) == 1:
|
||||
raise Exception()
|
||||
return [False, _('Ldap user class or user id attr is probably wrong (can\'t find any user with both conditions)')]
|
||||
except Exception, e:
|
||||
@ -405,12 +411,12 @@ class SimpleLDAPAuthenticator(Authenticator):
|
||||
|
||||
# And group part, with membership
|
||||
try:
|
||||
res = con.search_ext_s(base = self._ldapBase, scope = ldap.SCOPE_SUBTREE, filterstr = '(&(objectClass=%s)(%s=*))' % (self._groupClass, self._groupIdAttr), attrlist = [self._memberAttr])
|
||||
res = con.search_ext_s(base=self._ldapBase, scope=ldap.SCOPE_SUBTREE, filterstr='(&(objectClass=%s)(%s=*))' % (self._groupClass, self._groupIdAttr), attrlist=[self._memberAttr])
|
||||
if len(res) == 0:
|
||||
raise Exception(_('Ldap group class or group id attr is probably wrong (can\'t find any group with both conditions)'))
|
||||
ok = False
|
||||
for r in res:
|
||||
if r[1].has_key(self._memberAttr) is True:
|
||||
if self._memberAttr in r[1]:
|
||||
ok = True
|
||||
break
|
||||
if ok is False:
|
||||
@ -418,7 +424,4 @@ class SimpleLDAPAuthenticator(Authenticator):
|
||||
except Exception, e:
|
||||
return [False, str(e)]
|
||||
|
||||
|
||||
|
||||
return [True, _("Connection params seem correct, test was succesfully executed")]
|
||||
|
@ -32,5 +32,8 @@
|
||||
|
||||
@author: Adolfo Gómez, dkmaster at dkmon dot com
|
||||
'''
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from Authenticator import SimpleLDAPAuthenticator
|
||||
|
||||
__updated__ = '2014-02-19'
|
||||
|
@ -70,7 +70,7 @@ class Serializable(object):
|
||||
In that case, initialize the object with default values
|
||||
|
||||
Args:
|
||||
str _ : String readed from persistent storage to deseralilize
|
||||
str_ _ : String readed from persistent storage to deseralilize
|
||||
|
||||
:note: This method must be overridden
|
||||
'''
|
||||
|
@ -30,6 +30,10 @@
|
||||
'''
|
||||
@author: Adolfo Gómez, dkmaster at dkmon dot com
|
||||
'''
|
||||
from __future__ import unicode_literals
|
||||
|
||||
__updated__ = '2014-02-19'
|
||||
|
||||
|
||||
class AuthsFactory(object):
|
||||
'''
|
||||
@ -48,7 +52,7 @@ class AuthsFactory(object):
|
||||
'''
|
||||
Returns the factory that keeps the register of authentication providers.
|
||||
'''
|
||||
if AuthsFactory._factory == None:
|
||||
if AuthsFactory._factory == None:
|
||||
AuthsFactory._factory = AuthsFactory()
|
||||
return AuthsFactory._factory
|
||||
|
||||
|
@ -31,14 +31,19 @@ Base module for all authenticators
|
||||
|
||||
.. moduleauthor:: Adolfo Gómez, dkmaster at dkmon dot com
|
||||
'''
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from uds.core import Module
|
||||
from django.utils.translation import ugettext_noop as _
|
||||
from GroupsManager import GroupsManager
|
||||
from Exceptions import InvalidUserException
|
||||
import logging
|
||||
|
||||
__updated__ = '2014-02-19'
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class Authenticator(Module):
|
||||
'''
|
||||
This class represents the base interface to implement authenticators.
|
||||
@ -90,65 +95,64 @@ class Authenticator(Module):
|
||||
easier to understand.
|
||||
'''
|
||||
|
||||
#: Name of type, used at administration interface to identify this
|
||||
#: authenticator (i.e. LDAP, SAML, ...)
|
||||
#: This string will be translated when provided to admin interface
|
||||
#: using ugettext, so you can mark it as "_" at derived classes (using ugettext_noop)
|
||||
#: if you want so it can be translated.
|
||||
# : Name of type, used at administration interface to identify this
|
||||
# : authenticator (i.e. LDAP, SAML, ...)
|
||||
# : This string will be translated when provided to admin interface
|
||||
# : using ugettext, so you can mark it as "_" at derived classes (using ugettext_noop)
|
||||
# : if you want so it can be translated.
|
||||
typeName = _('Base Authenticator')
|
||||
|
||||
#: Name of type used by Managers to identify this type of service
|
||||
#: We could have used here the Class name, but we decided that the
|
||||
#: module implementator will be the one that will provide a name that
|
||||
#: will relation the class (type) and that name.
|
||||
# : Name of type used by Managers to identify this type of service
|
||||
# : We could have used here the Class name, but we decided that the
|
||||
# : module implementator will be the one that will provide a name that
|
||||
# : will relation the class (type) and that name.
|
||||
typeType = 'BaseAuthenticator'
|
||||
|
||||
#: Description shown at administration level for this authenticator.
|
||||
#: This string will be translated when provided to admin interface
|
||||
#: using ugettext, so you can mark it as "_" at derived classes (using ugettext_noop)
|
||||
#: if you want so it can be translated.
|
||||
# : Description shown at administration level for this authenticator.
|
||||
# : This string will be translated when provided to admin interface
|
||||
# : using ugettext, so you can mark it as "_" at derived classes (using ugettext_noop)
|
||||
# : if you want so it can be translated.
|
||||
typeDescription = _('Base Authenticator')
|
||||
|
||||
|
||||
#: Icon file, used to represent this authenticator at administration interface
|
||||
#: This file should be at same folder as this class is, except if you provide
|
||||
#: your own :py:meth:uds.core.BaseModule.BaseModule.icon method.
|
||||
# : Icon file, used to represent this authenticator at administration interface
|
||||
# : This file should be at same folder as this class is, except if you provide
|
||||
# : your own :py:meth:uds.core.BaseModule.BaseModule.icon method.
|
||||
iconFile = 'auth.png'
|
||||
|
||||
#: Mark this authenticator as that the users comes from outside the UDS
|
||||
#: database, that are most authenticator (except Internal DB)
|
||||
#: So, isInternalSource means that "user is kept at database only"
|
||||
# : Mark this authenticator as that the users comes from outside the UDS
|
||||
# : database, that are most authenticator (except Internal DB)
|
||||
# : So, isInternalSource means that "user is kept at database only"
|
||||
isExternalSource = True
|
||||
|
||||
#: If we need to enter the password for this user when creating a new
|
||||
#: user at administration interface. Used basically by internal authenticator.
|
||||
# : If we need to enter the password for this user when creating a new
|
||||
# : user at administration interface. Used basically by internal authenticator.
|
||||
needsPassword = False
|
||||
|
||||
#: Label for username field, shown at administration interface user form.
|
||||
# : Label for username field, shown at administration interface user form.
|
||||
userNameLabel = _('User name')
|
||||
|
||||
#: Label for group field, shown at administration interface user form.
|
||||
# : Label for group field, shown at administration interface user form.
|
||||
groupNameLabel = _('Group name')
|
||||
|
||||
#: Label for password field, , shown at administration interface user form.
|
||||
#: Not needed for external authenticators (where credentials are stored with
|
||||
#: an already existing user.
|
||||
# : Label for password field, , shown at administration interface user form.
|
||||
# : Not needed for external authenticators (where credentials are stored with
|
||||
# : an already existing user.
|
||||
passwordLabel = _('Password')
|
||||
|
||||
#: If this authenticators casues a temporal block of an user on repeated login failures
|
||||
# : If this authenticators casues a temporal block of an user on repeated login failures
|
||||
blockUserOnLoginFailures = True
|
||||
|
||||
from User import User
|
||||
from Group import Group
|
||||
|
||||
#: The type of user provided, normally standard user will be enough.
|
||||
#: This is here so if we need it in some case, we can write our own
|
||||
#: user class
|
||||
# : The type of user provided, normally standard user will be enough.
|
||||
# : This is here so if we need it in some case, we can write our own
|
||||
# : user class
|
||||
userType = User
|
||||
|
||||
#: The type of group provided, normally standard group will be enough
|
||||
#: This is here so if we need it in some case, we can write our own
|
||||
#: group class
|
||||
# : The type of group provided, normally standard group will be enough
|
||||
# : This is here so if we need it in some case, we can write our own
|
||||
# : group class
|
||||
groupType = Group
|
||||
|
||||
def __init__(self, dbAuth, environment, values):
|
||||
@ -196,7 +200,7 @@ class Authenticator(Module):
|
||||
if self.isExternalSource == True:
|
||||
groupsManager = GroupsManager(self._dbAuth)
|
||||
self.getGroups(user.name, groupsManager)
|
||||
user.groups = [ g.dbGroup() for g in groupsManager.getValidGroups()]
|
||||
user.groups = [g.dbGroup() for g in groupsManager.getValidGroups()]
|
||||
|
||||
def callbackUrl(self):
|
||||
'''
|
||||
@ -320,7 +324,7 @@ class Authenticator(Module):
|
||||
'''
|
||||
return username
|
||||
|
||||
def internalAuthenticate(self,username, credentials, groupsManager):
|
||||
def internalAuthenticate(self, username, credentials, groupsManager):
|
||||
'''
|
||||
This method is provided so "plugins" (For example, a custom dispatcher), can test
|
||||
the username/credentials in an alternative way.
|
||||
@ -535,7 +539,6 @@ class Authenticator(Module):
|
||||
'''
|
||||
raise InvalidUserException(_('Users can\'t be created inside this authenticator'))
|
||||
|
||||
|
||||
def modifyUser(self, usrData):
|
||||
'''
|
||||
This method is used when modifying an user to allow the authenticator:
|
||||
@ -563,7 +566,6 @@ class Authenticator(Module):
|
||||
'''
|
||||
pass
|
||||
|
||||
|
||||
def createGroup(self, groupData):
|
||||
'''
|
||||
This method is used when creating a new group to allow the authenticator:
|
||||
@ -617,7 +619,6 @@ class Authenticator(Module):
|
||||
'''
|
||||
pass
|
||||
|
||||
|
||||
def removeUser(self, username):
|
||||
'''
|
||||
Remove user is used whenever from the administration interface, or from other
|
||||
|
@ -30,6 +30,10 @@
|
||||
'''
|
||||
.. moduleauthor:: Adolfo Gómez, dkmaster at dkmon dot com
|
||||
'''
|
||||
from __future__ import unicode_literals
|
||||
|
||||
__updated__ = '2014-02-19'
|
||||
|
||||
|
||||
class AuthenticatorException(Exception):
|
||||
'''
|
||||
@ -37,26 +41,29 @@ class AuthenticatorException(Exception):
|
||||
'''
|
||||
pass
|
||||
|
||||
|
||||
class InvalidUserException(AuthenticatorException):
|
||||
'''
|
||||
Invalid user specified. The user cant access the requested service
|
||||
'''
|
||||
pass
|
||||
|
||||
|
||||
class InvalidAuthenticatorException(AuthenticatorException):
|
||||
'''
|
||||
Invalida authenticator has been specified
|
||||
'''
|
||||
pass
|
||||
|
||||
|
||||
class Redirect(Exception):
|
||||
'''
|
||||
This exception indicates that a redirect is required.
|
||||
Used in authUrlCallback to indicate that redirect is needed
|
||||
'''
|
||||
|
||||
|
||||
class Logout(Exception):
|
||||
'''
|
||||
This exceptions redirects logouts an user and redirects to an url
|
||||
'''
|
||||
|
@ -31,11 +31,15 @@
|
||||
'''
|
||||
.. moduleauthor:: Adolfo Gómez, dkmaster at dkmon dot com
|
||||
'''
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import logging
|
||||
|
||||
__updated__ = '2014-02-19'
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class Group(object):
|
||||
'''
|
||||
A group is simply a database group associated with its authenticator instance
|
||||
|
@ -30,6 +30,7 @@
|
||||
'''
|
||||
.. moduleauthor:: Adolfo Gómez, dkmaster at dkmon dot com
|
||||
'''
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from uds.core.util.State import State
|
||||
from uds.models import Group as dbGroup
|
||||
@ -37,8 +38,11 @@ from Group import Group
|
||||
import inspect
|
||||
import logging
|
||||
|
||||
__updated__ = '2014-02-19'
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class GroupsManager(object):
|
||||
'''
|
||||
Manages registered groups for an specific authenticator.
|
||||
@ -67,14 +71,14 @@ class GroupsManager(object):
|
||||
'''
|
||||
self._dbAuthenticator = dbAuthenticator
|
||||
self._groups = {} # We just get active groups, inactive aren't visible to this class
|
||||
for g in dbAuthenticator.groups.filter(state = State.ACTIVE, is_meta = False):
|
||||
self._groups[g.name.lower()] = { 'group': Group(g), 'valid': False }
|
||||
for g in dbAuthenticator.groups.filter(state=State.ACTIVE, is_meta=False):
|
||||
self._groups[g.name.lower()] = {'group': Group(g), 'valid': False}
|
||||
|
||||
def contains(self, groupName):
|
||||
'''
|
||||
Returns true if this groups manager contains the specified group name (string)
|
||||
'''
|
||||
return self._groups.has_key(groupName.lower())
|
||||
return groupName.lower() in self._groups
|
||||
|
||||
def getGroupsNames(self):
|
||||
'''
|
||||
@ -96,11 +100,10 @@ class GroupsManager(object):
|
||||
# Now, get metagroups and also return them
|
||||
for g in dbGroup.objects.filter(manager__id=self._dbAuthenticator.id, is_meta=True):
|
||||
gn = g.groups.filter(id__in=lst, state=State.ACTIVE).count()
|
||||
if gn == g.groups.count(): # If a meta group is empty, all users belongs to it. we can use gn != 0 to check that if it is empty, is not valid
|
||||
if gn == g.groups.count(): # If a meta group is empty, all users belongs to it. we can use gn != 0 to check that if it is empty, is not valid
|
||||
# This group matches
|
||||
yield Group(g)
|
||||
|
||||
|
||||
def hasValidGroups(self):
|
||||
'''
|
||||
Checks if this groups manager has at least one group that has been
|
||||
@ -116,7 +119,7 @@ class GroupsManager(object):
|
||||
If this groups manager contains that group manager, it returns the
|
||||
:py:class:uds.core.auths.Group.Group representing that group name.
|
||||
'''
|
||||
if self._groups.has_key(groupName.lower()):
|
||||
if groupName.lower() in self._groups:
|
||||
return self._groups[groupName.lower()]['group']
|
||||
else:
|
||||
return None
|
||||
@ -137,7 +140,7 @@ class GroupsManager(object):
|
||||
for n in groupName:
|
||||
self.validate(n)
|
||||
else:
|
||||
if self._groups.has_key(groupName.lower()):
|
||||
if groupName.lower() in self._groups:
|
||||
self._groups[groupName.lower()]['valid'] = True
|
||||
|
||||
def isValid(self, groupName):
|
||||
@ -145,11 +148,9 @@ class GroupsManager(object):
|
||||
Checks if this group name is marked as valid inside this groups manager.
|
||||
Returns True if group name is marked as valid, False if it isn't.
|
||||
'''
|
||||
if self._groups.has_key(groupName.lower()):
|
||||
if groupName.lower() in self._groups:
|
||||
return self._groups[groupName.lower()]['valid']
|
||||
return False
|
||||
|
||||
def __str__(self):
|
||||
return "Groupsmanager: {0}".format(self._groups)
|
||||
|
||||
|
||||
|
@ -30,11 +30,15 @@
|
||||
'''
|
||||
.. moduleauthor:: Adolfo Gómez, dkmaster at dkmon dot com
|
||||
'''
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import logging
|
||||
|
||||
__updated__ = '2014-02-19'
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class User(object):
|
||||
'''
|
||||
An user represents a database user, associated with its authenticator (instance)
|
||||
@ -47,7 +51,6 @@ class User(object):
|
||||
self._dbUser = dbUser
|
||||
self._groups = None
|
||||
|
||||
|
||||
def _groupsManager(self):
|
||||
'''
|
||||
If the groups manager for this user already exists, it returns this.
|
||||
@ -89,7 +92,6 @@ class User(object):
|
||||
self._groups = [Group(g) for g in usr.getGroups()]
|
||||
return self._groups
|
||||
|
||||
|
||||
def manager(self):
|
||||
'''
|
||||
Returns the authenticator instance
|
||||
@ -101,4 +103,3 @@ class User(object):
|
||||
Returns the database user
|
||||
'''
|
||||
return self._dbUser
|
||||
|
||||
|
@ -32,17 +32,20 @@ UDS authentication related interfaces and classes
|
||||
|
||||
.. moduleauthor:: Adolfo Gómez, dkmaster at dkmon dot com
|
||||
'''
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from BaseAuthenticator import Authenticator
|
||||
from User import User
|
||||
from Group import Group
|
||||
from GroupsManager import GroupsManager
|
||||
import Exceptions
|
||||
|
||||
__updated__ = '2014-02-19'
|
||||
|
||||
|
||||
def factory():
|
||||
'''
|
||||
Returns factory for register/access to authenticators
|
||||
'''
|
||||
from AuthsFactory import AuthsFactory
|
||||
return AuthsFactory.factory()
|
||||
|
||||
|
||||
|
@ -49,23 +49,27 @@ from uds.models import User
|
||||
|
||||
import logging
|
||||
|
||||
__updated__ = '2014-02-19'
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
authLogger = logging.getLogger('authLog')
|
||||
|
||||
USER_KEY = 'uk'
|
||||
PASS_KEY = 'pk'
|
||||
ROOT_ID = -20091204 # Any negative number will do the trick
|
||||
ROOT_ID = -20091204 # Any negative number will do the trick
|
||||
|
||||
|
||||
def getRootUser():
|
||||
from uds.models import Authenticator
|
||||
u = User(id=ROOT_ID, name=GlobalConfig.SUPER_USER_LOGIN.get(True), real_name=_('System Administrator'), state= State.ACTIVE, staff_member = True, is_admin = True )
|
||||
u = User(id=ROOT_ID, name=GlobalConfig.SUPER_USER_LOGIN.get(True), real_name=_('System Administrator'), state=State.ACTIVE, staff_member=True, is_admin=True)
|
||||
u.manager = Authenticator()
|
||||
u.getGroups = lambda: []
|
||||
u.updateLastAccess = lambda: None
|
||||
u.logout = lambda: None
|
||||
return u
|
||||
|
||||
def getIp(request, translateProxy = True):
|
||||
|
||||
def getIp(request, translateProxy=True):
|
||||
'''
|
||||
Obtains the IP of a Django Request, even behind a proxy
|
||||
|
||||
@ -73,12 +77,13 @@ def getIp(request, translateProxy = True):
|
||||
'''
|
||||
try:
|
||||
if translateProxy is False:
|
||||
raise KeyError() # Do not allow HTTP_X_FORWARDED_FOR
|
||||
raise KeyError() # Do not allow HTTP_X_FORWARDED_FOR
|
||||
request.ip = request.META['HTTP_X_FORWARDED_FOR'].split(",")[0]
|
||||
except KeyError:
|
||||
request.ip = request.META['REMOTE_ADDR']
|
||||
return request.ip
|
||||
|
||||
|
||||
# Decorator to make easier protect pages that needs to be logged in
|
||||
def webLoginRequired(view_func):
|
||||
'''
|
||||
@ -106,12 +111,13 @@ def webLoginRequired(view_func):
|
||||
logger.debug('No user found, redirecting to {0}'.format(url))
|
||||
return HttpResponseRedirect(url)
|
||||
# Refresh session duration
|
||||
#request.session.set_expiry(GlobalConfig.USER_SESSION_LENGTH.getInt())
|
||||
# request.session.set_expiry(GlobalConfig.USER_SESSION_LENGTH.getInt())
|
||||
request.user = user
|
||||
getIp(request)
|
||||
return view_func(request, *args, **kwargs)
|
||||
return _wrapped_view
|
||||
|
||||
|
||||
# Decorator to protect pages that needs to be accessed from "trusted sites"
|
||||
def trustedSourceRequired(view_func):
|
||||
'''
|
||||
@ -149,7 +155,7 @@ def __registerUser(authenticator, authInstance, username):
|
||||
return None
|
||||
|
||||
|
||||
def authenticate(username, password, authenticator, useInternalAuthenticate = False):
|
||||
def authenticate(username, password, authenticator, useInternalAuthenticate=False):
|
||||
'''
|
||||
Given an username, password and authenticator, try to authenticate user
|
||||
@param username: username to authenticate
|
||||
@ -217,6 +223,7 @@ def authenticateViaCallback(authenticator, params):
|
||||
|
||||
return __registerUser(authenticator, authInstance, username)
|
||||
|
||||
|
||||
def authCallbackUrl(authenticator):
|
||||
'''
|
||||
Helper method, so we can get the auth call back url for an authenticator
|
||||
@ -224,18 +231,20 @@ def authCallbackUrl(authenticator):
|
||||
from django.core.urlresolvers import reverse
|
||||
return reverse('uds.web.views.authCallback', kwargs={'authName': authenticator.name})
|
||||
|
||||
|
||||
def authInfoUrl(authenticator):
|
||||
'''
|
||||
Helper method, so we can get the info url for an authenticator
|
||||
'''
|
||||
from django.core.urlresolvers import reverse
|
||||
if isinstance(authenticator,unicode) or isinstance(authenticator, str):
|
||||
if isinstance(authenticator, unicode) or isinstance(authenticator, str):
|
||||
name = authenticator
|
||||
else:
|
||||
name = authenticator.name
|
||||
|
||||
return reverse('uds.web.views.authInfo', kwargs={'authName': name})
|
||||
|
||||
|
||||
def webLogin(request, response, user, password):
|
||||
'''
|
||||
Helper function to, once the user is authenticated, store the information at the user session.
|
||||
@ -243,7 +252,7 @@ def webLogin(request, response, user, password):
|
||||
'''
|
||||
from uds import REST
|
||||
|
||||
if user.id != ROOT_ID: # If not ROOT user (this user is not inside any authenticator)
|
||||
if user.id != ROOT_ID: # If not ROOT user (this user is not inside any authenticator)
|
||||
manager_id = user.manager.id
|
||||
else:
|
||||
manager_id = -1
|
||||
@ -266,7 +275,8 @@ def webPassword(request):
|
||||
'''
|
||||
return CryptoManager.manager().xor(request.session.get(PASS_KEY), request.COOKIES['uds']).decode('utf-8')
|
||||
|
||||
def webLogout(request, exit_url = None):
|
||||
|
||||
def webLogout(request, exit_url=None):
|
||||
'''
|
||||
Helper function to clear user related data from session. If this method is not used, the session we be cleaned anyway
|
||||
by django in regular basis.
|
||||
@ -278,7 +288,8 @@ def webLogout(request, exit_url = None):
|
||||
# Try to delete session
|
||||
return HttpResponseRedirect(request.build_absolute_uri(exit_url))
|
||||
|
||||
def authLogLogin(request, authenticator, userName, java, os, logStr = ''):
|
||||
|
||||
def authLogLogin(request, authenticator, userName, java, os, logStr=''):
|
||||
'''
|
||||
Logs authentication
|
||||
'''
|
||||
@ -303,4 +314,3 @@ def authLogLogin(request, authenticator, userName, java, os, logStr = ''):
|
||||
def authLogLogout(request):
|
||||
log.doLog(request.user.manager, log.INFO, 'user {0} has logged out from {1}'.format(request.user.name, request.ip), log.WEB)
|
||||
log.doLog(request.user, log.INFO, 'has logged out from {0}'.format(request.ip), log.WEB)
|
||||
|
||||
|
@ -7,8 +7,11 @@ Author:
|
||||
from django.db import models, connection
|
||||
import logging
|
||||
|
||||
__updated__ = '2014-02-19'
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
# Table locking in mysql at least is based on thread requesting it, so we should not have problems with a bit of care
|
||||
class LockingManager(models.Manager):
|
||||
""" Add lock/unlock functionality to manager.
|
||||
@ -57,17 +60,17 @@ class LockingManager(models.Manager):
|
||||
con = connection
|
||||
cursor = con.cursor()
|
||||
table = self.model._meta.db_table
|
||||
#logger.debug("Locking table %s" % table)
|
||||
# logger.debug("Locking table %s" % table)
|
||||
cursor.execute("LOCK TABLES %s WRITE" % table)
|
||||
row = cursor.fetchone()
|
||||
return row
|
||||
|
||||
def unlock(self):
|
||||
""" Unlock the table. """
|
||||
#logger.debug("Unlocked tables")
|
||||
# logger.debug("Unlocked tables")
|
||||
con = connection
|
||||
cursor = con.cursor()
|
||||
#table = self.model._meta.db_table
|
||||
# table = self.model._meta.db_table
|
||||
cursor.execute("UNLOCK TABLES")
|
||||
row = cursor.fetchone()
|
||||
return row
|
@ -30,3 +30,4 @@
|
||||
@author: Adolfo Gómez, dkmaster at dkmon dot com
|
||||
'''
|
||||
|
||||
__updated__ = '2014-02-19'
|
||||
|
@ -30,13 +30,16 @@
|
||||
'''
|
||||
@author: Adolfo Gómez, dkmaster at dkmon dot com
|
||||
'''
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from uds.core.Environment import Environmentable
|
||||
import logging
|
||||
|
||||
__updated__ = '2014-02-19'
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class DelayedTask(Environmentable):
|
||||
def __init__(self):
|
||||
'''
|
||||
|
@ -35,19 +35,22 @@ from __future__ import unicode_literals
|
||||
from django.db import transaction
|
||||
from django.db.models import Q
|
||||
from uds.models import DelayedTask as dbDelayedTask, getSqlDatetime
|
||||
from uds.core.util.Decorators import retryOnException
|
||||
from ..Environment import Environment
|
||||
from socket import gethostname
|
||||
from pickle import loads, dumps
|
||||
from datetime import datetime, timedelta
|
||||
import threading, time
|
||||
from datetime import timedelta
|
||||
import threading
|
||||
import time
|
||||
import logging
|
||||
|
||||
__updated__ = '2014-02-19'
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class DelayedTaskThread(threading.Thread):
|
||||
def __init__(self, taskInstance):
|
||||
super(DelayedTaskThread,self).__init__()
|
||||
super(DelayedTaskThread, self).__init__()
|
||||
self._taskInstance = taskInstance
|
||||
|
||||
def run(self):
|
||||
@ -56,6 +59,7 @@ class DelayedTaskThread(threading.Thread):
|
||||
except Exception, e:
|
||||
logger.debug("Exception in thread {0}: {1}".format(e.__class__, e))
|
||||
|
||||
|
||||
class DelayedTaskRunner(object):
|
||||
CODEC = 'base64' # Can be zip, hez, bzip, base64, uuencoded
|
||||
# How often tasks r checked
|
||||
@ -74,7 +78,7 @@ class DelayedTaskRunner(object):
|
||||
|
||||
@staticmethod
|
||||
def runner():
|
||||
if DelayedTaskRunner._runner == None:
|
||||
if DelayedTaskRunner._runner == None:
|
||||
DelayedTaskRunner._runner = DelayedTaskRunner()
|
||||
return DelayedTaskRunner._runner
|
||||
|
||||
@ -84,7 +88,7 @@ class DelayedTaskRunner(object):
|
||||
# If next execution is before now or last execution is in the future (clock changed on this server, we take that task as executable)
|
||||
taskInstance = None
|
||||
try:
|
||||
with transaction.atomic(): # Encloses
|
||||
with transaction.atomic(): # Encloses
|
||||
task = dbDelayedTask.objects.select_for_update().filter(filt).order_by('execution_time')[0]
|
||||
task.delete()
|
||||
taskInstance = loads(task.instance.decode(self.CODEC))
|
||||
@ -100,17 +104,17 @@ class DelayedTaskRunner(object):
|
||||
|
||||
def __insert(self, instance, delay, tag):
|
||||
now = getSqlDatetime()
|
||||
exec_time = now + timedelta(seconds = delay)
|
||||
exec_time = now + timedelta(seconds=delay)
|
||||
cls = instance.__class__
|
||||
instanceDump = dumps(instance).encode(self.CODEC)
|
||||
typeName = str(cls.__module__ + '.' + cls.__name__)
|
||||
|
||||
logger.debug('Inserting delayed task {0} with {1} bytes ({2})'.format(typeName, len(instanceDump), exec_time))
|
||||
|
||||
dbDelayedTask.objects.create(type = typeName, instance = instanceDump,
|
||||
insert_date = now, execution_delay = delay, execution_time = exec_time, tag = tag)
|
||||
dbDelayedTask.objects.create(type=typeName, instance=instanceDump,
|
||||
insert_date=now, execution_delay=delay, execution_time=exec_time, tag=tag)
|
||||
|
||||
def insert(self, instance, delay, tag = ''):
|
||||
def insert(self, instance, delay, tag=''):
|
||||
retries = 3
|
||||
while retries > 0:
|
||||
retries -= 1
|
||||
@ -119,7 +123,7 @@ class DelayedTaskRunner(object):
|
||||
break
|
||||
except Exception, e:
|
||||
logger.info('Exception inserting a delayed task {0}: {1}'.format(str(e.__class__), e))
|
||||
time.sleep(1) # Wait a bit before next try...
|
||||
time.sleep(1) # Wait a bit before next try...
|
||||
# If retries == 0, this is a big error
|
||||
if retries == 0:
|
||||
logger.error("Could not insert delayed task!!!! {0} {1} {2}".format(instance, delay, tag))
|
||||
@ -141,7 +145,7 @@ class DelayedTaskRunner(object):
|
||||
number = 0
|
||||
try:
|
||||
number = dbDelayedTask.objects.filter(tag=tag).count()
|
||||
except Exception as e:
|
||||
except Exception:
|
||||
logger.error('Exception looking for a delayed task tag {0}'.format(tag))
|
||||
return number > 0
|
||||
|
||||
|
@ -30,16 +30,20 @@
|
||||
'''
|
||||
@author: Adolfo Gómez, dkmaster at dkmon dot com
|
||||
'''
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from uds.core import Environmentable
|
||||
import logging
|
||||
|
||||
__updated__ = '2014-02-19'
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class Job(Environmentable):
|
||||
# Default frecuency, once a day. Remenber that precision will be based on "granurality" of Scheduler
|
||||
# If a job is used for delayed execution, this attribute is in fact ignored
|
||||
frecuency = 24*3600+3
|
||||
frecuency = 24 * 3600 + 3
|
||||
friendly_name = 'Unknown'
|
||||
|
||||
def __init__(self, environment):
|
||||
@ -51,7 +55,7 @@ class Job(Environmentable):
|
||||
def execute(self):
|
||||
try:
|
||||
self.run()
|
||||
except Exception, e:
|
||||
except Exception:
|
||||
logger.exception('Job {0} raised an exception:'.format(self.__class__))
|
||||
|
||||
def run(self):
|
||||
|
@ -30,11 +30,16 @@
|
||||
'''
|
||||
@author: Adolfo Gómez, dkmaster at dkmon dot com
|
||||
'''
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import datetime
|
||||
import logging
|
||||
|
||||
__updated__ = '2014-02-19'
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class JobsFactory(object):
|
||||
_factory = None
|
||||
|
||||
@ -43,7 +48,7 @@ class JobsFactory(object):
|
||||
|
||||
@staticmethod
|
||||
def factory():
|
||||
if JobsFactory._factory == None:
|
||||
if JobsFactory._factory == None:
|
||||
JobsFactory._factory = JobsFactory()
|
||||
return JobsFactory._factory
|
||||
|
||||
@ -68,18 +73,17 @@ class JobsFactory(object):
|
||||
# We use database server datetime
|
||||
now = getSqlDatetime()
|
||||
next_ = now
|
||||
job = Scheduler.objects.create(name = name, frecuency = type_.frecuency, last_execution = now, next_execution = next_, state = State.FOR_EXECUTE)
|
||||
except Exception: # already exists
|
||||
job = Scheduler.objects.create(name=name, frecuency=type_.frecuency, last_execution=now, next_execution=next_, state=State.FOR_EXECUTE)
|
||||
except Exception: # already exists
|
||||
logger.debug('Already added {0}'.format(name))
|
||||
job = Scheduler.objects.get(name=name)
|
||||
job.frecuency = type_.frecuency
|
||||
if job.next_execution > job.last_execution + datetime.timedelta(seconds = type_.frecuency):
|
||||
job.next_execution = job.last_execution + datetime.timedelta(seconds = type_.frecuency);
|
||||
if job.next_execution > job.last_execution + datetime.timedelta(seconds=type_.frecuency):
|
||||
job.next_execution = job.last_execution + datetime.timedelta(seconds=type_.frecuency)
|
||||
job.save()
|
||||
except Exception, e:
|
||||
logger.debug('Exception at ensureJobsInDatabase in JobsFactory: {0}, {1}'.format(e.__class__, e))
|
||||
|
||||
|
||||
def lookup(self, typeName):
|
||||
try:
|
||||
return self._jobs[typeName]
|
||||
|
@ -30,6 +30,7 @@
|
||||
'''
|
||||
@author: Adolfo Gómez, dkmaster at dkmon dot com
|
||||
'''
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db.models import Q
|
||||
from django.db import transaction, DatabaseError
|
||||
@ -37,14 +38,18 @@ from uds.models import Scheduler as dbScheduler, getSqlDatetime, State
|
||||
from uds.core.jobs.JobsFactory import JobsFactory
|
||||
from datetime import timedelta
|
||||
from socket import gethostname
|
||||
import threading, time
|
||||
import threading
|
||||
import time
|
||||
import logging
|
||||
|
||||
__updated__ = '2014-02-19'
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class JobThread(threading.Thread):
|
||||
def __init__(self, jobInstance, dbJob):
|
||||
super(JobThread,self).__init__()
|
||||
super(JobThread, self).__init__()
|
||||
self._jobInstance = jobInstance
|
||||
self._dbJobId = dbJob.id
|
||||
|
||||
@ -66,18 +71,18 @@ class JobThread(threading.Thread):
|
||||
logger.info('Database access locked... Retrying')
|
||||
time.sleep(1)
|
||||
|
||||
|
||||
@transaction.atomic
|
||||
def __updateDb(self):
|
||||
job = dbScheduler.objects.select_for_update().get(id=self._dbJobId)
|
||||
job.state = State.FOR_EXECUTE
|
||||
job.owner_server = ''
|
||||
job.next_execution = getSqlDatetime() + timedelta(seconds = job.frecuency)
|
||||
job.next_execution = getSqlDatetime() + timedelta(seconds=job.frecuency)
|
||||
# Update state and last execution time at database
|
||||
job.save()
|
||||
|
||||
|
||||
class Scheduler(object):
|
||||
granularity = 2 # We check for cron jobs every THIS seconds
|
||||
granularity = 2 # We check for cron jobs every THIS seconds
|
||||
|
||||
# to keep singleton Scheduler
|
||||
_scheduler = None
|
||||
@ -88,7 +93,7 @@ class Scheduler(object):
|
||||
|
||||
@staticmethod
|
||||
def scheduler():
|
||||
if Scheduler._scheduler == None:
|
||||
if Scheduler._scheduler == None:
|
||||
Scheduler._scheduler = Scheduler()
|
||||
return Scheduler._scheduler
|
||||
|
||||
@ -101,12 +106,12 @@ class Scheduler(object):
|
||||
'''
|
||||
jobInstance = None
|
||||
try:
|
||||
now = getSqlDatetime() # Datetimes are based on database server times
|
||||
filter = Q(state = State.FOR_EXECUTE) & (Q(owner_server = self._hostname) | Q(owner_server = '')) & (Q(last_execution__gt = now) | Q(next_execution__lt = now))
|
||||
now = getSqlDatetime() # Datetimes are based on database server times
|
||||
fltr = Q(state=State.FOR_EXECUTE) & (Q(owner_server=self._hostname) | Q(owner_server='')) & (Q(last_execution__gt=now) | Q(next_execution__lt=now))
|
||||
with transaction.atomic():
|
||||
# If next execution is before now or last execution is in the future (clock changed on this server, we take that task as executable)
|
||||
# This params are all set inside filter (look at __init__)
|
||||
job = dbScheduler.objects.select_for_update().filter(filter).order_by('next_execution')[0]
|
||||
# This params are all set inside fltr (look at __init__)
|
||||
job = dbScheduler.objects.select_for_update().filter(fltr).order_by('next_execution')[0]
|
||||
job.state = State.RUNNING
|
||||
job.owner_server = self._hostname
|
||||
job.last_execution = now
|
||||
@ -119,7 +124,7 @@ class Scheduler(object):
|
||||
job.delete()
|
||||
return
|
||||
logger.debug('Executing job:>{0}<'.format(job.name))
|
||||
JobThread(jobInstance, job).start() # Do not instatiate thread, just run it
|
||||
JobThread(jobInstance, job).start() # Do not instatiate thread, just run it
|
||||
except IndexError:
|
||||
# Do nothing, there is no jobs for execution
|
||||
return
|
||||
@ -135,8 +140,7 @@ class Scheduler(object):
|
||||
'''
|
||||
Releases all scheduleds being executed by this scheduler
|
||||
'''
|
||||
dbScheduler.objects.select_for_update().filter(owner_server = self._hostname).update(owner_server = '', state = State.FOR_EXECUTE)
|
||||
|
||||
dbScheduler.objects.select_for_update().filter(owner_server=self._hostname).update(owner_server='', state=State.FOR_EXECUTE)
|
||||
|
||||
def run(self):
|
||||
# We ensure that the jobs are also in database so we can
|
||||
@ -150,4 +154,3 @@ class Scheduler(object):
|
||||
self.executeOneJob()
|
||||
except Exception, e:
|
||||
logger.exception('Unexpected exception at run loop {0}: {1}'.format(e.__class__, e))
|
||||
|
||||
|
@ -32,9 +32,14 @@ UDS jobs related modules
|
||||
|
||||
.. moduleauthor:: Adolfo Gómez, dkmaster at dkmon dot com
|
||||
'''
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from Job import Job
|
||||
from DelayedTask import DelayedTask
|
||||
|
||||
__updated__ = '2014-02-19'
|
||||
|
||||
|
||||
def factory():
|
||||
from JobsFactory import JobsFactory
|
||||
return JobsFactory.factory()
|
@ -93,8 +93,8 @@ class RDPTransport(Transport):
|
||||
gui.boolToStr(self._allowDrives), gui.boolToStr(self._allowSerials),
|
||||
self._fixedName, self._fixedPassword, self._fixedDomain ] )
|
||||
|
||||
def unmarshal(self, str):
|
||||
data = str.split('\t')
|
||||
def unmarshal(self, str_):
|
||||
data = str_.split('\t')
|
||||
if data[0] == 'v1':
|
||||
self._useEmptyCreds = gui.strToBool(data[1])
|
||||
self._allowSmartcards = gui.strToBool(data[2])
|
||||
|
@ -104,8 +104,8 @@ class TSRDPTransport(Transport):
|
||||
gui.boolToStr(self._allowDrives), gui.boolToStr(self._allowSerials),
|
||||
self._fixedName, self._fixedPassword, self._fixedDomain, self._tunnelServer, self._tunnelCheckServer ] )
|
||||
|
||||
def unmarshal(self, str):
|
||||
data = str.split('\t')
|
||||
def unmarshal(self, str_):
|
||||
data = str_.split('\t')
|
||||
if data[0] == 'v1':
|
||||
self._useEmptyCreds = gui.strToBool(data[1])
|
||||
self._allowSmartcards = gui.strToBool(data[2])
|
||||
|
Loading…
x
Reference in New Issue
Block a user