Exemple #1
0
 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()
Exemple #2
0
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()
Exemple #3
0
    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'
Exemple #4
0
    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")
Exemple #5
0
 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
Exemple #6
0
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()
Exemple #7
0
def incFailedIp(ip: str) -> None:
    cache = Cache('actorv3')
    fails = (cache.get(ip) or 0) + 1
    cache.put(ip, fails, GlobalConfig.LOGIN_BLOCK.getInt())
Exemple #8
0
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'))
Exemple #9
0
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')
Exemple #11
0
    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')