Exemple #1
0
    def validate_new_acl(self, values: str):
        if values is None or len(values.strip()) == 0:
            raise ValidationException('blank pattern')

        if self.pattern.match(values) is None:
            raise ValidationException('pattern did not match new value: %s' %
                                      values)

        if '(' in values or ')' in values:
            left = len([a for a in values if a == '('])
            right = len([a for a in values if a == ')'])
            if left != right:
                raise ValidationException(
                    'parenthesis mismatch in pattern: %s' % values)

            opened, closed = 0, 0
            for c in values:
                if c == '(':
                    opened += 1
                elif c == ')':
                    closed += 1
                if abs(opened - closed) > 1 or closed > opened:
                    raise ValidationException(
                        'nest parenthesis not allowed in pattern: %s' % values)

        groups = dict()
        self._split_and_test_clause(groups, values, is_validating_a_user=False)
Exemple #2
0
    def validate_new_acl(self, values: str):
        if values is None or len(values.strip()) == 0:
            raise ValidationException('blank range when creating AclRangeValidator')

        if ':' not in values:
            raise ValidationException('value not a range, no colon in value: "%s"' % values)

        range_min, range_max = values.split(':', 1)
        if range_min != '':
            if not GenericValidator.is_digit(range_min):
                raise ValidationException('first value in range "%s" is not a number' % values)
        if range_max != '':
            if not GenericValidator.is_digit(range_max):
                raise ValidationException('last value in range "%s" is not a number' % values)
Exemple #3
0
    def __init__(self):
        self.acl_type = 'custom'
        pattern = '^[0-9a-z!\|,\(\):=_]*$'

        try:
            import re
            self.pattern = re.compile(pattern)
        except Exception:
            raise ValidationException('invalid pattern: %s' % str(pattern))
Exemple #4
0
    def validate_new_acl(self, values: str):
        # all new values accepted, e.g. for city or country
        if self.valid_csvs is None:
            return

        if values is None or len(values.strip()) == 0:
            return

        new_values = values.split(',')
        for new_value in new_values:
            if new_value in self.valid_csvs:
                continue

            raise ValidationException(
                'new acl values "%s" does not match configured possible values "%s"'
                % (values, self.valid_csvs))
Exemple #5
0
    def _test_a_clause(self,
                       clause,
                       is_validating_a_user: bool,
                       activity: Activity = None,
                       env=None):
        if '=' not in clause:
            raise ValidationException('no equal sign in clause: %s' % clause)

        if len(clause.split('=')) != 2:
            raise ValidationException('equal sign mismatch in clause: %s' %
                                      clause)

        acl_type, acl_value = clause.split('=')
        all_acls = environ.env.config.get(ConfigKeys.ACL)
        all_validators = all_acls['validation']
        if acl_type not in all_validators:
            raise ValidationException('invalid acl "%s" in clause: %s' %
                                      (acl_type, clause))

        if acl_type == 'custom':
            raise ValidationException(
                'nested custom acls not allowed in clause: %s' % clause)

        value_is_negated = False
        if acl_value[0] == '!':
            acl_value = acl_value[1:]
            value_is_negated = True

        validator_func = all_validators[acl_type]['value']
        if not isinstance(validator_func, BaseAclValidator):
            raise ValidationException(
                'validator for acl type "%s" is not of instance BaseAclValidator '
                'but "%s"' % (acl_type, str(type(validator_func))))

        # a user is using the api, so validate his action against set pattern
        if is_validating_a_user:
            if not callable(validator_func):
                raise ValidationException('validator function is not callable')

            is_valid, msg = validator_func(activity, env, acl_type, acl_value,
                                           value_is_negated)
            return is_valid, msg
        # now we're validating a new acl rule set in admin interface
        else:
            validator_func.validate_new_acl(acl_value)
            return True, None
Exemple #6
0
    def _split_and_test_clause(self,
                               groups,
                               clause,
                               is_validating_a_user: bool = False,
                               activity: Activity = None,
                               env=None):
        """
        The default value for is_validating_a_user is False, meaning we're validating a new acl rule someone set in the
        admin web interface. In this case the activity and env variables are not used. On the other hand, if
        is_validating_a_user is set to true, it means we're validating the "custom" acl rule for something a user did
        through the API, and in this case the activity and env is needed, since we'll be validating against the user
        info set on the environment for this user, e.g. age, gender or whatever it could be in the current 7
        implementation.

        :param groups: the first time this method is called this dict has to be empty; it is used to store parenthesis
        clauses, so we can split the and/or tokens without affecting the parenthesises; since this method is recursive
        we have to pass this dict throughout the recursion
        :param clause: the value of the "custom" acl, e.g. "gender=m|age=:35,gender=!m"
        :param is_validating_a_user: true means validate a user api action, false means validate a new custom acl rule
        :param activity: the activity the user supplied (if is_validating_a_user is True, None otherwise)
        :param env: the current environ.env (if is_validating_a_user is True, None otherwise)
        :return: nothing
        """
        while '(' in clause:
            pos = len(groups)
            start = clause.index('(') + 1
            end = clause.index(')')
            groups[pos] = clause[start:end]
            clause = clause[:start - 1] + '@%s@' % pos + clause[end + 1:]

        or_clauses = [clause]
        if '|' in clause:
            or_clauses = clause.split('|')

        for or_clause in or_clauses:
            and_clauses = [or_clause]
            if ',' in or_clause:
                and_clauses = or_clause.split(',')

            all_and_ok = True
            for and_clause in and_clauses:
                if '@' in and_clause:
                    if and_clause[0] != '@' or and_clause[
                            -1] != '@' or and_clause.count('@') != 2:
                        raise ValidationException(
                            'mismatched at-signs in clause: %s' % and_clause)
                    and_clause = groups[int(and_clause[1:len(and_clause) - 1])]

                try:
                    if len([c for c in and_clause if c in '|,']) > 0:
                        self._split_and_test_clause(groups, and_clause,
                                                    is_validating_a_user,
                                                    activity, env)
                    else:
                        is_valid, error_msg = self._test_a_clause(
                            and_clause, is_validating_a_user, activity, env)
                        if not is_valid:
                            logger.error('during AND checks: %s' % error_msg)
                            all_and_ok = False
                            break
                except ValidationException as e:
                    logger.error('during AND checks: %s' % e.msg)
                    raise e
            if not all_and_ok:
                continue

            # at least one OR was ok so we can return
            return

        # if more than two we have or clauses, otherwise just one and clause
        if len(or_clauses) > 1:
            raise ValidationException('no OR clause validated true for: %s' %
                                      ('|'.join(or_clauses)))
        else:
            raise ValidationException(
                'the AND clause did not validate for: %s' % (or_clauses[0]))