def get(self, force=False): # Ensures DB contains configuration values # From Django 1.7, DB can only be accessed AFTER all apps are initialized, curious at least.. :) if apps.ready is True: if GlobalConfig.initDone is False: logger.debug('Initializing configuration & updating db values') GlobalConfig.initialize() else: getLater.append(self) return self._default try: if force or self._data is None: # logger.debug('Accessing db config {0}.{1}'.format(self._section.name(), self._key)) readed = dbConfig.objects.get(section=self._section.name(), key=self._key) # @UndefinedVariable self._data = readed.value self._crypt = [self._crypt, True][readed.crypt] # True has "higher" precedende than False self._longText = readed.long if readed.field_type == -1 and self._type != -1: readed.field_type = self._type readed.save() self._type = readed.field_type except Exception: # Not found if self._default != '' and self._crypt: self.set(CryptoManager.manager().decrypt(self._default)) elif not self._crypt: self.set(self._default) self._data = self._default if self._crypt is True: return CryptoManager.manager().decrypt(self._data) else: return self._data
def webLogin(request, response, user, password): """ Helper function to, once the user is authenticated, store the information at the user session. @return: Always returns True """ from uds import REST 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 # If for any reason the "uds" cookie is removed, recreated it cookie = getUDSCookie(request, response) user.updateLastAccess() request.session.clear() request.session[USER_KEY] = user.id request.session[PASS_KEY] = CryptoManager.manager().xor( password, cookie) # Stores "bytes" # Ensures that this user will have access through REST api if logged in through web interface REST.Handler.storeSessionAuthdata(request.session, manager_id, user.name, password, get_language(), request.os, user.is_admin, user.staff_member, cookie) return True
def unmarshal(self, s): data = s.decode('utf8').split('\t') if data[0] in ('v1', 'v2', 'v3', 'v4'): self._domain = data[1] self._ou = data[2] self._account = data[3] self._password = CryptoManager.manager().decrypt(data[4]) if data[0] in ('v2', 'v3', 'v4'): self._group = data[6] else: self._group = '' if data[0] in ('v3', 'v4'): self._serverHint = data[7] else: self._serverHint = '' if data[0] == 'v4': self._ssl = data[8] self._removeOnExit = data[9] else: self._ssl = 'n' self._removeOnExit = 'y' super(WinDomainOsManager, self).unmarshal(encoders.decode(data[5], 'hex'))
def unmarshal(self, s): data = s.split('\t') if data[0] == 'v1': self._domain = data[1] self._ou = data[2] self._account = data[3] self._password = CryptoManager.manager().decrypt(data[4]) super(WinDomainOsManager, self).unmarshal(data[5].decode('hex'))
def webPassword(request): ''' The password is stored at session using a simple scramble algorithm that keeps the password splited at session (db) and client browser cookies. This method uses this two values to recompose the user password so we can provide it to remote sessions. @param request: DJango Request @return: Unscrambled user password ''' return CryptoManager.manager().xor(request.session.get(PASS_KEY, ''), getUDSCookie(request)).decode('utf-8') # recover as original unicode string
def webPassword(request): ''' The password is stored at session using a simple scramble algorithm that keeps the password splited at session (db) and client browser cookies. This method uses this two values to recompose the user password so we can provide it to remote sessions. @param request: DJango Request @return: Unscrambled user password ''' return CryptoManager.manager().xor(request.session.get(PASS_KEY), request.COOKIES['uds']).decode('utf-8')
def marshal(self): base = super(WinDomainOsManager, self).marshal() ''' Serializes the os manager data so we can store it in database ''' return '\t'.join([ 'v1', self._domain, self._ou, self._account, CryptoManager.manager().encrypt(self._password), base.encode('hex') ])
def __init__(self, section, key, default='', crypt=False, longText=False, **kwargs): self._type = kwargs.get('type', -1) self._section = section self._key = key self._crypt = crypt self._longText = longText if crypt is False: self._default = default else: self._default = CryptoManager.manager().encrypt(default) self._data = None
def marshal(self): base = super(WinDomainOsManager, self).marshal() ''' Serializes the os manager data so we can store it in database ''' return '\t'.join([ 'v3', self._domain, self._ou, self._account, CryptoManager.manager().encrypt(self._password), encoders.encode(base, 'hex', asText=True), self._group, self._serverHint ]).encode('utf8')
def webPassword(request): """ The password is stored at session using a simple scramble algorithm that keeps the password splited at session (db) and client browser cookies. This method uses this two values to recompose the user password so we can provide it to remote sessions. @param request: DJango Request @return: Unscrambled user password """ return CryptoManager.manager().xor( request.session.get(PASS_KEY, ''), getUDSCookie(request)).decode( 'utf-8') # recover as original unicode string
def update(section, key, value): # If cfg value does not exists, simply ignore request try: cfg = dbConfig.objects.filter(section=section, key=key)[0] # @UndefinedVariable if cfg.crypt is True: value = CryptoManager.manager().encrypt(value) cfg.value = value cfg.save() logger.debug('Updated value for {0}.{1} to {2}'.format(section, key, value)) return True except Exception: return False
def marshal(self): base = super(WinDomainOsManager, self).marshal() ''' Serializes the os manager data so we can store it in database ''' return '\t'.join([ 'v3', self._domain, self._ou, self._account, CryptoManager.manager().encrypt(self._password), encoders.encode(base, 'hex', asText=True), self._group, self._serverHint] ).encode('utf8')
def get(self, force: bool = False) -> str: # Ensures DB contains configuration values # From Django 1.7, DB can only be accessed AFTER all apps are initialized, curious at least.. :) if apps.ready is True: if not GlobalConfig.isInitialized(): logger.debug( 'Initializing configuration & updating db values') GlobalConfig.initialize() else: _getLater.append(self) return self._default try: if force or self._data is None: # logger.debug('Accessing db config {0}.{1}'.format(self._section.name(), self._key)) readed = uds.models.Config.objects.get( section=self._section.name(), key=self._key) # @UndefinedVariable self._data = readed.value self._crypt = [ self._crypt, True ][readed.crypt] # True has "higher" precedende than False self._longText = readed.long if self._type != -1: # readed.field_type == -1 and readed.field_type = self._type readed.save() self._type = readed.field_type except Exception: # Not found if self._default != '' and self._crypt: self.set(CryptoManager.manager().decrypt(self._default)) elif not self._crypt: self.set(self._default) self._data = self._default if self._crypt is True: return CryptoManager.manager().decrypt( typing.cast(str, self._data)) return typing.cast(str, self._data)
def __init__(self, section, key, default='', crypt=False, longText=False, **kwargs): logger.debug('Var: {} {} KWARGS: {}'.format(section, key, kwargs)) self._type = kwargs.get('type', -1) self._section = section self._key = key self._crypt = crypt self._longText = longText if crypt is False: self._default = default else: self._default = CryptoManager.manager().encrypt(default) self._data = None
def update(section, key, value): # If cfg value does not exists, simply ignore request try: cfg = uds.models.Config.objects.filter( section=section, key=key)[0] # @UndefinedVariable if cfg.crypt is True: value = CryptoManager.manager().encrypt(value) cfg.value = value cfg.save() logger.debug('Updated value for {0}.{1} to {2}'.format( section, key, value)) return True except Exception: return False
def update(section, key, value, checkType=False): # If cfg value does not exists, simply ignore request try: cfg = uds.models.Config.objects.filter(section=section, key=key)[0] # @UndefinedVariable if checkType and cfg.field_type in (Config.READ_FIELD, Config.HIDDEN_FIELD): return # Skip non writable elements if cfg.crypt is True: value = CryptoManager.manager().encrypt(value) cfg.value = value cfg.save() logger.debug('Updated value for {0}.{1} to {2}'.format(section, key, value)) return True except Exception: return False
def update(section, key, value, checkType=False) -> bool: # If cfg value does not exists, simply ignore request try: cfg = uds.models.Config.objects.filter( section=section, key=key)[0] # @UndefinedVariable if checkType and cfg.field_type in (Config.READ_FIELD, Config.HIDDEN_FIELD): return False # Skip non writable elements if cfg.crypt is True: value = CryptoManager.manager().encrypt(value) cfg.value = value cfg.save() logger.debug('Updated value for %s.%s to %s', section, key, value) return True except Exception: return False
def __init__(self, section: 'Config.Section', key: str, default: str = '', crypt: bool = False, longText: bool = False, **kwargs): logger.debug('Var: %s %s KWARGS: %s', section, key, kwargs) self._type: int = kwargs.get('type', -1) self._section: 'Config.Section' = section self._key: str = key self._crypt: bool = crypt self._longText: bool = longText if crypt is False or not default: self._default: str = default else: self._default = CryptoManager.manager().encrypt(default) self._data: typing.Optional[str] = None
def unmarshal(self, s): data = s.split('\t') if data[0] in ('v1', 'v2', 'v3'): self._domain = data[1] self._ou = data[2] self._account = data[3] self._password = CryptoManager.manager().decrypt(data[4]) if data[0] in ('v2', 'v3'): self._group = data[6] else: self._group = '' if data[0] == 'v3': self._serverHint = data[7] else: self._serverHint = '' super(WinDomainOsManager, self).unmarshal(data[5].decode('hex'))
def set(self, value): if GlobalConfig.initDone is False: saveLater.append((self, value)) return if self._crypt is True: value = CryptoManager.manager().encrypt(value) ''' Editable here means that this configuration value can be edited by admin directly (generally, that this is a "clean text" value) ''' logger.debug('Saving config {0}.{1} as {2}'.format(self._section.name(), self._key, value)) try: obj, _ = dbConfig.objects.get_or_create(section=self._section.name(), key=self._key) # @UndefinedVariable obj.value, obj.crypt, obj.long, obj.field_type = value, self._crypt, self._longText, self._type obj.save() except Exception: logger.exception('Exception') # Probably a migration issue, just ignore it logger.info("Could not save configuration key {0}.{1}".format(self._section.name(), self._key))
def webLogin(request, response, user, password): ''' Helper function to, once the user is authenticated, store the information at the user session. @return: Always returns True ''' from uds import REST 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 # If for any reason the "uds" cookie is removed, recreated it cookie = getUDSCookie(request, response) user.updateLastAccess() request.session.clear() request.session[USER_KEY] = user.id request.session[PASS_KEY] = CryptoManager.manager().xor(password, cookie) # Stores "bytes" # Ensures that this user will have access through REST api if logged in through web interface REST.Handler.storeSessionAuthdata(request.session, manager_id, user.name, get_language(), request.os, user.is_admin, user.staff_member) return True
def set(self, value): if GlobalConfig.initDone is False: saveLater.append((self, value)) return if self._crypt is True: value = CryptoManager.manager().encrypt(value) ''' Editable here means that this configuration value can be edited by admin directly (generally, that this is a "clean text" value) ''' logger.debug('Saving config {0}.{1} as {2}'.format( self._section.name(), self._key, value)) try: obj, _ = uds.models.Config.objects.get_or_create( section=self._section.name(), key=self._key) # @UndefinedVariable obj.value, obj.crypt, obj.long, obj.field_type = value, self._crypt, self._longText, self._type obj.save() except Exception: logger.exception('Exception') # Probably a migration issue, just ignore it logger.info("Could not save configuration key {0}.{1}".format( self._section.name(), self._key))
def marshal(self): base = super(WinRandomPassManager, self).marshal() ''' Serializes the os manager data so we can store it in database ''' return '\t'.join(['v1', self._userAccount, CryptoManager.manager().encrypt(self._password), encoders.encode(base, 'hex', asText=True)]).encode('utf8')
def marshal(self): base = super(WinDomainOsManager, self).marshal() ''' Serializes the os manager data so we can store it in database ''' return '\t'.join(['v2', self._domain, self._ou, self._account, CryptoManager.manager().encrypt(self._password), base.encode('hex'), self._group])
def unmarshal(self, s): data = s.split('\t') if data[0] == 'v1': self._userAccount = data[1] self._password = CryptoManager.manager().decrypt(data[2]) super(WinRandomPassManager, self).unmarshal(data[3].decode('hex'))
def marshal(self): base = super(WinRandomPassManager, self).marshal() ''' Serializes the os manager data so we can store it in database ''' return '\t'.join(['v1', self._userAccount, CryptoManager.manager().encrypt(self._password), base.encode('hex')])
class GlobalConfig(object): """ Simple helper to keep track of global configuration """ SESSION_EXPIRE_TIME = Config.section(GLOBAL_SECTION).value( 'sessionExpireTime', '24', type=Config.NUMERIC_FIELD ) # Max session duration (in use) after a new publishment has been made # Delay between cache checks. reducing this number will increase cache generation speed but also will load service providers CACHE_CHECK_DELAY = Config.section(GLOBAL_SECTION).value( 'cacheCheckDelay', '19', type=Config.NUMERIC_FIELD) # Delayed task number of threads PER SERVER, with higher number of threads, deplayed task will complete sooner, but it will give more load to overall system DELAYED_TASKS_THREADS = Config.section(GLOBAL_SECTION).value( 'delayedTasksThreads', '4', type=Config.NUMERIC_FIELD) # Number of scheduler threads running PER SERVER, with higher number of threads, deplayed task will complete sooner, but it will give more load to overall system SCHEDULER_THREADS = Config.section(GLOBAL_SECTION).value( 'schedulerThreads', '3', type=Config.NUMERIC_FIELD) # Waiting time before removing "errored" and "removed" publications, cache, and user assigned machines. Time is in seconds CLEANUP_CHECK = Config.section(GLOBAL_SECTION).value( 'cleanupCheck', '3607', type=Config.NUMERIC_FIELD) # Time to maintaing "info state" items before removing it, in seconds KEEP_INFO_TIME = Config.section(GLOBAL_SECTION).value( 'keepInfoTime', '14401', type=Config.NUMERIC_FIELD ) # Defaults to 2 days 172800?? better 4 hours xd # Max number of services to be "preparing" at same time MAX_PREPARING_SERVICES = Config.section(GLOBAL_SECTION).value( 'maxPreparingServices', '15', type=Config.NUMERIC_FIELD ) # Defaults to 15 services at once (per service provider) # Max number of service to be at "removal" state at same time MAX_REMOVING_SERVICES = Config.section(GLOBAL_SECTION).value( 'maxRemovingServices', '15', type=Config.NUMERIC_FIELD ) # Defaults to 15 services at once (per service provider) # If we ignore limits (max....) IGNORE_LIMITS = Config.section(GLOBAL_SECTION).value( 'ignoreLimits', '0', type=Config.BOOLEAN_FIELD) # Number of services to initiate removal per run of CacheCleaner USER_SERVICE_CLEAN_NUMBER = Config.section(GLOBAL_SECTION).value( 'userServiceCleanNumber', '3', type=Config.NUMERIC_FIELD) # Defaults to 3 per wun # Removal Check time for cache, publications and deployed services REMOVAL_CHECK = Config.section(GLOBAL_SECTION).value( 'removalCheck', '31', type=Config.NUMERIC_FIELD) # Defaults to 30 seconds # Login URL LOGIN_URL = Config.section(GLOBAL_SECTION).value( 'loginUrl', '/login', type=Config.TEXT_FIELD) # Defaults to /login # Session duration USER_SESSION_LENGTH = Config.section(SECURITY_SECTION).value( 'userSessionLength', '14400', type=Config.NUMERIC_FIELD) # Defaults to 4 hours # Superuser (do not need to be at database!!!) SUPER_USER_LOGIN = Config.section(SECURITY_SECTION).value( 'superUser', 'root', type=Config.TEXT_FIELD) # Superuser password (do not need to be at database!!!) SUPER_USER_PASS = Config.section(SECURITY_SECTION).valueCrypt( 'rootPass', 'udsmam0', type=Config.TEXT_FIELD) # Idle time before closing session on admin SUPER_USER_ALLOW_WEBACCESS = Config.section(SECURITY_SECTION).value( 'allowRootWebAccess', '1', type=Config.BOOLEAN_FIELD) # Time an admi session can be idle before being "logged out" ADMIN_IDLE_TIME = Config.section(SECURITY_SECTION).value( 'adminIdleTime', '14400', type=Config.NUMERIC_FIELD) # Defaults to 4 hous # Time betwen checks of unused services by os managers # Unused services will be invoked for every machine assigned but not in use AND that has been assigned at least this time # (only if os manager asks for this characteristic) CHECK_UNUSED_TIME = Config.section(GLOBAL_SECTION).value( 'checkUnusedTime', '631', type=Config.NUMERIC_FIELD) # Defaults to 10 minutes # Default CSS Used CSS = Config.section(GLOBAL_SECTION).value('css', settings.STATIC_URL + 'css/uds.css', type=Config.TEXT_FIELD) # Max logins before blocking an account MAX_LOGIN_TRIES = Config.section(GLOBAL_SECTION).value( 'maxLoginTries', '3', type=Config.NUMERIC_FIELD) # Block time in second for an user that makes too many mistakes, 5 minutes default LOGIN_BLOCK = Config.section(GLOBAL_SECTION).value( 'loginBlockTime', '300', type=Config.NUMERIC_FIELD) # Do autorun of service if just one service. # 0 = No autorun, 1 = Autorun at login # In a future, maybe necessary another value "2" that means that autorun always AUTORUN_SERVICE = Config.section(GLOBAL_SECTION).value( 'autorunService', '0', type=Config.BOOLEAN_FIELD) # Redirect HTTP to HTTPS REDIRECT_TO_HTTPS = Config.section(GLOBAL_SECTION).value( 'redirectToHttps', '0', type=Config.BOOLEAN_FIELD) # Max time needed to get a service "fully functional" before it's considered "failed" and removed # The time is in seconds MAX_INITIALIZING_TIME = Config.section(GLOBAL_SECTION).value( 'maxInitTime', '3601', type=Config.NUMERIC_FIELD) # Custom HTML for login page CUSTOM_HTML_LOGIN = Config.section(GLOBAL_SECTION).value( 'customHtmlLogin', '', type=Config.LONGTEXT_FIELD) # Maximum logs per user service MAX_LOGS_PER_ELEMENT = Config.section(GLOBAL_SECTION).value( 'maxLogPerElement', '100', type=Config.NUMERIC_FIELD) # Time to restrain a deployed service in case it gives some errors at some point RESTRAINT_TIME = Config.section(GLOBAL_SECTION).value( 'restrainTime', '600', type=Config.NUMERIC_FIELD) # Number of errors that must occurr in RESTRAIN_TIME to restrain deployed service RESTRAINT_COUNT = Config.section(GLOBAL_SECTION).value( 'restrainCount', '3', type=Config.NUMERIC_FIELD) # Statistics duration, in days STATS_DURATION = Config.section(GLOBAL_SECTION).value( 'statsDuration', '365', type=Config.NUMERIC_FIELD) # If disallow login using /login url, and must go to an authenticator DISALLOW_GLOBAL_LOGIN = Config.section(GLOBAL_SECTION).value( 'disallowGlobalLogin', '0', type=Config.BOOLEAN_FIELD) # Allos preferences access to users PREFERENCES_ALLOWED = Config.section(GLOBAL_SECTION).value( 'allowPreferencesAccess', '1', type=Config.BOOLEAN_FIELD) # Allowed "trusted sources" for request TRUSTED_SOURCES = Config.section(SECURITY_SECTION).value( 'Trusted Hosts', '*', type=Config.TEXT_FIELD) # Allow clients to notify their own ip (if set), or use always the request extracted IP HONOR_CLIENT_IP_NOTIFY = Config.section(SECURITY_SECTION).value( 'honorClientNotifyIP', '0', type=Config.BOOLEAN_FIELD) # If there is a proxy in front of us BEHIND_PROXY = Config.section(SECURITY_SECTION).value( 'Behind a proxy', '0', type=Config.BOOLEAN_FIELD) # If we use new logout mechanics EXCLUSIVE_LOGOUT = Config.section(SECURITY_SECTION).value( 'Exclusive Logout', '0', type=Config.BOOLEAN_FIELD) # Clusters related vars # Maximum desired CPU Load. If cpu is over this value, a migration of a service is "desirable" CLUSTER_MIGRATE_CPULOAD = Config.section(CLUSTER_SECTION).value( 'Migration CPU Load', '80', type=Config.NUMERIC_FIELD) # Maximum CPU Load for a node to be elegible for destination of a migration CLUSTER_ELEGIBLE_CPULOAD = Config.section(CLUSTER_SECTION).value( 'Destination CPU Load', '60', type=Config.NUMERIC_FIELD) # Minimum desired Memory free for a cluster node. If free memory (in %) is under this percentage, # a migration of a service inside this node is "desirable" CLUSTER_MIGRATE_MEMORYLOAD = Config.section(CLUSTER_SECTION).value( 'Migration Free Memory', '20', type=Config.NUMERIC_FIELD) # Minimum Free memory for a node to be elegible for a destination of a migration CLUSTER_ELEGIBLE_MEMORYLOAD = Config.section(CLUSTER_SECTION).value( 'Migration Free Memory', '40', type=Config.NUMERIC_FIELD) # Gui vars UDS_THEME = Config.section(GLOBAL_SECTION).value('UDS Theme', 'html5', type=Config.CHOICE_FIELD) RELOAD_TIME = Config.section(GLOBAL_SECTION).value( 'Page reload Time', '300', type=Config.NUMERIC_FIELD) # This is used so templates can change "styles" from admin interface UDS_THEME_VISUAL = Config.section(GLOBAL_SECTION).value( 'UDS Theme Enhaced', '1', type=Config.BOOLEAN_FIELD) # Custom message for error when limiting by calendar LIMITED_BY_CALENDAR_TEXT = Config.section(GLOBAL_SECTION).value( 'Calendar access denied text', '', type=Config.TEXT_FIELD) # Defaults to Nothing # This is used so templates can change "styles" from admin interface LOWERCASE_USERNAME = Config.section(SECURITY_SECTION).value( 'Convert username to lowercase', '1', type=Config.BOOLEAN_FIELD) # Global UDS ID (common for all servers on the same cluster) UDS_ID = Config.section(GLOBAL_SECTION).value( 'UDS ID', CryptoManager.manager().uuid(), type=Config.READ_FIELD) initDone = False @staticmethod def initThemes(): import os themes = [] try: for d in os.listdir( os.path.join(os.path.dirname(uds.__file__), 'templates', 'uds')): if d not in ('admin', 'reports' ): # Exclude folders with own internal templates themes.append(d) except Exception: pass GlobalConfig.UDS_THEME.setParams(themes) @staticmethod def initialize(): if GlobalConfig.initDone is False: try: # Tries to initialize database data for global config so it is stored asap and get cached for use GlobalConfig.initDone = True for v in six.itervalues(GlobalConfig.__dict__): if type(v) is Config._Value: v.get() for c in getLater: logger.debug('Get later: {}'.format(c)) c.get() getLater[:] = [] for c, v in saveLater: logger.debug('Saving delayed value: {}'.format(c)) c.set(v) saveLater[:] = [] # Process some global config parameters # GlobalConfig.UDS_THEME.setParams(['html5', 'semantic']) # Search for themes & set them GlobalConfig.initThemes() except Exception: logger.debug( 'Config table do not exists!!!, maybe we are installing? :-)' )