def clearRelatedData(self): """ Removes all related information from database for this environment. """ Cache.delete(self._key) Storage.delete(self._key) for _, v in self._idGenerators.items(): v.release()
def checkBlockedIp(ip: str) -> None: cache = Cache('actorv3') fails = cache.get(ip) or 0 if fails > ALLOWED_FAILS: logger.info( 'Access to actor from %s is blocked for %s seconds since last fail', ip, GlobalConfig.LOGIN_BLOCK.getInt()) raise BlockAccess()
def get(self): """ Processes get method. Basically, clears & purges the cache, no matter what params """ logger.debug('Params: %s', self._params) if not self._args: return {} if len(self._args) != 1: raise RequestError('Invalid Request') uCache.purge() djCache.clear() return 'done'
def handle(self, *args, **options): sys.stdout.write("Cleaning up UDS\n") GlobalConfig.initialize() sys.stdout.write("Cache...\n") # UDSs cache Cache.cleanUp() # Django caches cache.clear() sys.stdout.write("Releasing schedulers...\n") # Release all Schedulers Scheduler.objects.all().update(owner_server='', state=State.FOR_EXECUTE) sys.stdout.write("UDS Cleaned UP\n")
def __init__(self, uniqueKey: str, idGenerators: typing.Optional[typing.Dict[str, UniqueIDGenerator]] = None): """ Initialized the Environment for the specified id @param uniqueKey: Key for this environment @param idGenerators: Hash of generators of ids for this environment. This "generators of ids" feature is used basically at User Services to auto-create ids for macs or names, using {'mac' : UniqueMacGenerator, 'name' : UniqueNameGenerator } as argument. """ if idGenerators is None: idGenerators = dict() self._key = uniqueKey self._cache = Cache(uniqueKey) self._storage = Storage(uniqueKey) self._idGenerators = idGenerators
import pickle import logging import datetime import typing from uds import models from uds.core.util.stats import counters from uds.core.util.cache import Cache from uds.core.util.state import State from uds.core.util import encoders from uds.REST import Handler, RequestError, ResponseError logger = logging.getLogger(__name__) cache = Cache('StatsDispatcher') # Enclosed methods under /syatem path POINTS = 365 SINCE = 365 # Days USE_MAX = True def getServicesPoolsCounters( servicePool: typing.Optional[models.ServicePool], counter_type: int) -> typing.List[typing.Dict[str, typing.Any]]: # pylint: disable=no-value-for-parameter try: cacheKey = (servicePool and servicePool.id or 'all') + str(counter_type) + str(POINTS) + str(SINCE) to = models.getSqlDatetime()
def incFailedIp(ip: str) -> None: cache = Cache('actorv3') fails = (cache.get(ip) or 0) + 1 cache.put(ip, fails, GlobalConfig.LOGIN_BLOCK.getInt())
def checkLogin( # pylint: disable=too-many-branches, too-many-statements request: 'HttpRequest', form: 'LoginForm', tag: typing.Optional[str] = None ) -> typing.Tuple[typing.Optional['User'], typing.Any]: host = request.META.get('HTTP_HOST') or request.META.get( 'SERVER_NAME' ) or 'auth_host' # Last one is a placeholder in case we can't locate host name # Get Authenticators limitation logger.debug('Host: %s', host) if GlobalConfig.DISALLOW_GLOBAL_LOGIN.getBool(False) is True: if tag is None: try: Authenticator.objects.get(small_name=host) tag = host except Exception: try: tag = Authenticator.objects.order_by( 'priority')[0].small_name except Exception: # There is no authenticators yet, simply allow global login to nowhere.. :-) tag = None logger.debug('Tag: %s', tag) if 'uds' not in request.COOKIES: logger.debug('Request does not have uds cookie') return (None, errors.COOKIES_NEEDED) if form.is_valid(): os = request.os try: authenticator = Authenticator.objects.get( uuid=processUuid(form.cleaned_data['authenticator'])) except Exception: authenticator = Authenticator() userName = form.cleaned_data['user'] if GlobalConfig.LOWERCASE_USERNAME.getBool(True) is True: userName = userName.lower() cache = Cache('auth') cacheKey = str(authenticator.id) + userName tries = cache.get(cacheKey) or 0 triesByIp = cache.get(request.ip) or 0 maxTries = GlobalConfig.MAX_LOGIN_TRIES.getInt() if (authenticator.getInstance().blockUserOnLoginFailures is True and (tries >= maxTries) or triesByIp >= maxTries): authLogLogin(request, authenticator, userName, 'Temporarily blocked') return ( None, _('Too many authentication errrors. User temporarily blocked')) password = form.cleaned_data['password'] user = None if password == '': password = '******' # Random string, in fact, just a placeholder that will not be used :) user = authenticate(userName, password, authenticator) logger.debug('User: %s', user) if user is None: logger.debug("Invalid user %s (access denied)", userName) cache.put(cacheKey, tries + 1, GlobalConfig.LOGIN_BLOCK.getInt()) cache.put(request.ip, triesByIp + 1, GlobalConfig.LOGIN_BLOCK.getInt()) authLogLogin(request, authenticator, userName, 'Access denied (user not allowed by UDS)') return (None, _('Access denied')) request.session.cycle_key() logger.debug('User %s has logged in', userName) cache.remove(cacheKey) # Valid login, remove cached tries # Add the "java supported" flag to session request.session['OS'] = os if form.cleaned_data['logouturl'] != '': logger.debug('The logoout url will be %s', form.cleaned_data['logouturl']) request.session['logouturl'] = form.cleaned_data['logouturl'] authLogLogin(request, authenticator, user.name) return (user, form.cleaned_data['password']) logger.info('Invalid form received') return (None, _('Invalid data'))
class CalendarChecker: calendar: Calendar # For performance checking updates: int = 0 cache_hit: int = 0 hits: int = 0 cache = Cache('calChecker') def __init__(self, calendar: Calendar): self.calendar = calendar def _updateData(self, dtime: datetime.datetime): logger.debug('Updating %s', dtime) # Else, update the array CalendarChecker.updates += 1 data = bitarray.bitarray(60 * 24) # Granurality is minute data.setall(False) data_date = dtime.date() start = datetime.datetime.combine(data_date, datetime.datetime.min.time()) end = datetime.datetime.combine(data_date, datetime.datetime.max.time()) for rule in self.calendar.rules.all(): rr = rule.as_rrule() r_end = datetime.datetime.combine(rule.end, datetime.datetime.max.time()) if rule.end is not None else None ruleDurationMinutes = rule.duration_as_minutes ruleFrequencyMinutes = rule.frequency_as_minutes # Skip "bogus" definitions if ruleDurationMinutes == 0 or ruleFrequencyMinutes == 0: continue # ruleDurationMinutes = ruleDurationMinutes # Relative start, rrule can "spawn" the days, so we get the start at least the ruleDurationMinutes of rule to see if it "matches" # This means, we need the previous matching day to be "executed" so we can get the "actives" correctly diff = ruleFrequencyMinutes if ruleFrequencyMinutes > ruleDurationMinutes else ruleDurationMinutes _start = (start if start > rule.start else rule.start) - datetime.timedelta(minutes=diff) _end = end if r_end is None or end < r_end else r_end for val in rr.between(_start, _end, inc=True): if val.date() != data_date: diff = int((start - val).total_seconds() / 60) pos = 0 posdur = ruleDurationMinutes - diff if posdur <= 0: continue else: pos = val.hour * 60 + val.minute posdur = pos + ruleDurationMinutes if posdur > 60 * 24: posdur = 60 * 24 data[pos:posdur] = True return data def _updateEvents(self, checkFrom, startEvent=True): next_event = None for rule in self.calendar.rules.all(): # logger.debug('RULE: start = {}, checkFrom = {}, end'.format(rule.start.date(), checkFrom.date())) if rule.end is not None and rule.end < checkFrom.date(): continue # logger.debug('Rule in check interval...') if startEvent: event = rule.as_rrule().after(checkFrom) # At start else: event = rule.as_rrule_end().after(checkFrom) # At end if next_event is None or next_event > event: next_event = event return next_event def check(self, dtime=None): """ Checks if the given time is a valid event on calendar @param dtime: Datetime object to check TODO: We can improve performance of this by getting from a cache first if we can """ if dtime is None: dtime = getSqlDatetime() # First, try to get data from cache if it is valid cacheKey = str(hash(self.calendar.modified)) + str(dtime.date().toordinal()) + self.calendar.uuid + 'checker' cached = CalendarChecker.cache.get(cacheKey, None) if cached is not None: data = bitarray.bitarray() # Empty bitarray data.frombytes(cached) CalendarChecker.cache_hit += 1 else: data = self._updateData(dtime) # Now data can be accessed as an array of booleans. # Store data on persistent cache CalendarChecker.cache.put(cacheKey, data.tobytes(), 3600 * 24) return data[dtime.hour * 60 + dtime.minute] def nextEvent(self, checkFrom=None, startEvent=True, offset=None): """ Returns next event for this interval Returns a list of two elements. First is datetime of event begining, second is timedelta of duration """ logger.debug('Obtaining nextEvent') if checkFrom is None: checkFrom = getSqlDatetime() if offset is None: offset = datetime.timedelta(minutes=0) cacheKey = str(hash(self.calendar.modified)) + self.calendar.uuid + str( offset.seconds) + str(int(time.mktime(checkFrom.timetuple()))) + 'event' + ('x' if startEvent is True else '_') next_event = CalendarChecker.cache.get(cacheKey, None) if next_event is None: logger.debug('Regenerating cached nextEvent') next_event = self._updateEvents(checkFrom + offset, startEvent) # We substract on checkin, so we can take into account for next execution the "offset" on start & end (just the inverse of current, so we substract it) if next_event is not None: next_event += offset CalendarChecker.cache.put(cacheKey, next_event, 3600) else: logger.debug('nextEvent cache hit') CalendarChecker.hits += 1 return next_event def debug(self): return "Calendar checker for {}".format(self.calendar)
def run(self): logger.debug('Starting cache cleanup') Cache.cleanUp() logger.debug('Done cache cleanup')
def post(self) -> typing.Any: """ This login uses parameters to generate auth token The alternative is to use the template tag inside "REST" that is called auth_token, that extracts an auth token from an user session We can use any of this forms due to the fact that the auth token is in fact a session key Parameters: mandatory: username: password: authId or auth or authSmallName: (must include at least one. If multiple are used, precedence is the list order) optional: platform: From what platform are we connecting. If not specified, will try to deduct it from user agent. Valid values: Linux = 'Linux' WindowsPhone = 'Windows Phone' Windows = 'Windows' Macintosh = 'Mac' Android = 'Android' iPad = 'iPad' iPhone = 'iPhone' Defaults to: Unknown = 'Unknown' Result: on success: { 'result': 'ok', 'auth': [auth_code] } on error: { 'result: 'error', 'error': [error string] } Locale comes on "Header", as any HTTP Request (Accept-Language header) Calls to any method of REST that must be authenticated needs to be called with "X-Auth-Token" Header added """ # Checks if client is "blocked" cache = Cache('RESTapi') fails = cache.get(self._request.ip) or 0 if fails > ALLOWED_FAILS: logger.info('Access to REST API %s is blocked for %s seconds since last fail', self._request.ip, GlobalConfig.LOGIN_BLOCK.getInt()) try: if 'authId' not in self._params and 'authSmallName' not in self._params and 'auth' not in self._params: raise RequestError('Invalid parameters (no auth)') scrambler: str = ''.join(random.SystemRandom().choice(string.ascii_letters + string.digits) for _ in range(32)) # @UndefinedVariable authId: typing.Optional[str] = self._params.get('authId', None) authSmallName: typing.Optional[str] = self._params.get('authSmallName', None) authName: typing.Optional[str] = self._params.get('auth', None) platform: str = self._params.get('platform', self._request.os) username: str password: str username, password = self._params['username'], self._params['password'] locale: str = self._params.get('locale', 'en') if authName == 'admin' or authSmallName == 'admin': if GlobalConfig.SUPER_USER_LOGIN.get(True) == username and GlobalConfig.SUPER_USER_PASS.get(True) == password: self.genAuthToken(-1, username, password, locale, platform, True, True, scrambler) return Login.result(result='ok', token=self.getAuthToken()) return Login.result(error='Invalid credentials') # Will raise an exception if no auth found if authId: auth = Authenticator.objects.get(uuid=processUuid(authId)) elif authName: auth = Authenticator.objects.get(name=authName) else: auth = Authenticator.objects.get(small_name=authSmallName) if not password: password = '******' # Extrange password if credential left empty. Value is not important, just not empty logger.debug('Auth obj: %s', auth) user = authenticate(username, password, auth, True) if user is None: # invalid credentials # Sleep a while here to "prottect" time.sleep(3) # Wait 3 seconds if credentials fails for "protection" # And store in cache for blocking for a while if fails cache.put(self._request.ip, fails+1, GlobalConfig.LOGIN_BLOCK.getInt()) return Login.result(error='Invalid credentials') return Login.result( result='ok', token=self.genAuthToken(auth.id, user.name, password, locale, platform, user.is_admin, user.staff_member, scrambler), scrambler=scrambler ) except Exception: # logger.exception('exception') pass return Login.result(error='Invalid credentials')