More pep8 related fixes, also some refactoring

This commit is contained in:
Adolfo Gómez 2014-02-19 15:17:55 +00:00
parent dab3e26223
commit 89addaf585
24 changed files with 975 additions and 905 deletions

View File

@ -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

View File

@ -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.

View File

@ -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'

View File

@ -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")]

View File

@ -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'

View File

@ -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
'''

View File

@ -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

View File

@ -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

View File

@ -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
'''

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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()

View File

@ -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)

View File

@ -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

View File

@ -30,3 +30,4 @@
@author: Adolfo Gómez, dkmaster at dkmon dot com
'''
__updated__ = '2014-02-19'

View File

@ -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):
'''

View File

@ -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

View File

@ -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):

View File

@ -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]

View File

@ -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))

View File

@ -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()

View File

@ -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])

View File

@ -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])