def passes(self, request: PolicyRequest) -> PolicyResult: if self.password_field not in request.context: LOGGER.warning( "Password field not set in Policy Request", field=self.password_field, fields=request.context.keys(), ) return PolicyResult(False, _("Password not set in context")) password = request.context[self.password_field] filter_regex = [] if self.amount_lowercase > 0: filter_regex.append(r"[a-z]{%d,}" % self.amount_lowercase) if self.amount_uppercase > 0: filter_regex.append(r"[A-Z]{%d,}" % self.amount_uppercase) if self.amount_symbols > 0: filter_regex.append(r"[%s]{%d,}" % (self.symbol_charset, self.amount_symbols)) full_regex = "|".join(filter_regex) LOGGER.debug("Built regex", regexp=full_regex) result = bool(re.compile(full_regex).match(password)) result = result and len(password) >= self.length_min if not result: return PolicyResult(result, self.error_message) return PolicyResult(result)
def passes(self, request: PolicyRequest) -> PolicyResult: """Check if request passes this PolicyBinding, check policy, group or user""" if self.policy: self.policy: Policy return self.policy.passes(request) if self.group: return PolicyResult(self.group.is_member(request.user)) if self.user: return PolicyResult(request.user == self.user) return PolicyResult(False)
def passes(self, request: PolicyRequest) -> PolicyResult: if "event" not in request.context: return PolicyResult(False) event: Event = request.context["event"] if event.action == self.action: return PolicyResult(True, "Action matched.") if event.client_ip == self.client_ip: return PolicyResult(True, "Client IP matched.") if event.app == self.app: return PolicyResult(True, "App matched.") return PolicyResult(False)
def passes(self, request: PolicyRequest) -> PolicyResult: """Check if request passes this PolicyBinding, check policy, group or user""" if self.policy: self.policy: Policy return self.policy.passes(request) if self.group: return PolicyResult( self.group.users.filter(pk=request.user.pk).exists()) if self.user: return PolicyResult(request.user == self.user) return PolicyResult(False)
def passes(self, request: PolicyRequest) -> PolicyResult: """If password change date is more than x days in the past, call set_unusable_password and show a notice""" actual_days = (now() - request.user.password_change_date).days days_since_expiry = (now() - (request.user.password_change_date + timedelta(days=self.days))).days if actual_days >= self.days: if not self.deny_only: request.user.set_unusable_password() request.user.save() message = _(("Password expired %(days)d days ago. " "Please update your password.") % {"days": days_since_expiry}) return PolicyResult(False, message) return PolicyResult(False, _("Password has expired.")) return PolicyResult(True)
def run(self): # pragma: no cover """Task wrapper to run policy checking""" try: self.connection.send(self.profiling_wrapper()) except Exception as exc: # pylint: disable=broad-except LOGGER.warning(str(exc)) self.connection.send(PolicyResult(False, str(exc)))
def execute(self) -> PolicyResult: """Run actual policy, returns result""" LOGGER.debug( "P_ENG(proc): Running policy", policy=self.binding.policy, user=self.request.user, process="PolicyProcess", ) try: policy_result = self.binding.passes(self.request) # Invert result if policy.negate is set if self.binding.negate: policy_result.passing = not policy_result.passing if self.binding.policy and not self.request.debug: if self.binding.policy.execution_logging: self.create_event( EventAction.POLICY_EXECUTION, message="Policy Execution", result=policy_result, ) except PolicyException as exc: # Either use passed original exception or whatever we have src_exc = exc.src_exc if exc.src_exc else exc error_string = ( TRACEBACK_HEADER + "".join(format_tb(src_exc.__traceback__)) + str(src_exc) ) # Create policy exception event, only when we're not debugging if not self.request.debug: self.create_event(EventAction.POLICY_EXCEPTION, message=error_string) LOGGER.debug("P_ENG(proc): error", exc=src_exc) policy_result = PolicyResult(False, str(src_exc)) policy_result.source_binding = self.binding if not self.request.debug: key = cache_key(self.binding, self.request) cache.set(key, policy_result) LOGGER.debug( "P_ENG(proc): finished and cached ", policy=self.binding.policy, result=policy_result, process="PolicyProcess", passing=policy_result.passing, user=self.request.user, ) return policy_result
def check_access(self, request: Request, slug: str) -> Response: """Check access to a single application by slug""" # Don't use self.get_object as that checks for view_application permission # which the user might not have, even if they have access application = get_object_or_404(Application, slug=slug) # If the current user is superuser, they can set `for_user` for_user = self.request.user if self.request.user.is_superuser and "for_user" in request.data: for_user = get_object_or_404(User, pk=request.data.get("for_user")) engine = PolicyEngine(application, for_user, self.request) engine.build() result = engine.result response = PolicyTestResultSerializer(PolicyResult(False)) if result.passing: response = PolicyTestResultSerializer(PolicyResult(True)) if self.request.user.is_superuser: response = PolicyTestResultSerializer(result) return Response(response.data)
def passes(self, request: PolicyRequest) -> PolicyResult: remote_ip = get_client_ip(request.http_request) passing = True if self.check_ip: score = cache.get_or_set(CACHE_KEY_IP_PREFIX + remote_ip, 0) passing = passing and score <= self.threshold if self.check_username: score = cache.get_or_set(CACHE_KEY_USER_PREFIX + request.user.username, 0) passing = passing and score <= self.threshold return PolicyResult(passing)
def result(self) -> PolicyResult: """Get policy-checking result""" process_results: list[PolicyResult] = [ x.result for x in self.__processes if x.result ] all_results = list(process_results + self.__cached_policies) if len(all_results) < self.__expected_result_count: # pragma: no cover raise AssertionError("Got less results than polices") # No results, no policies attached -> passing if len(all_results) == 0: return PolicyResult(self.empty_result) passing = False if self.mode == PolicyEngineMode.MODE_ALL: passing = all(x.passing for x in all_results) if self.mode == PolicyEngineMode.MODE_ANY: passing = any(x.passing for x in all_results) result = PolicyResult(passing) result.source_results = all_results result.messages = tuple(y for x in all_results for y in x.messages) return result
def run(self): # pragma: no cover """Task wrapper to run policy checking""" with Hub.current.start_span(op="policy.process.execute", ) as span: span: Span span.set_data("policy", self.binding.policy) span.set_data("request", self.request) try: self.connection.send(self.execute()) except Exception as exc: # pylint: disable=broad-except LOGGER.warning(str(exc)) self.connection.send(PolicyResult(False, str(exc)))
def evaluate(self, expression_source: str) -> PolicyResult: """Parse and evaluate expression. Policy is expected to return a truthy object. Messages can be added using 'do ak_message()'.""" try: result = super().evaluate(expression_source) except PolicyException as exc: # PolicyExceptions should be propagated back to the process, # which handles recording and returning a correct result raise exc except Exception as exc: # pylint: disable=broad-except LOGGER.warning("Expression error", exc=exc) return PolicyResult(False, str(exc)) else: policy_result = PolicyResult(False, *self._messages) if result is None: LOGGER.warning( "Expression policy returned None", src=expression_source, req=self._context, ) policy_result.passing = False if result: policy_result.passing = bool(result) return policy_result
def passes(self, request: PolicyRequest) -> PolicyResult: remote_ip = get_client_ip(request.http_request) query = Q() if self.check_ip: query |= Q(ip=remote_ip) if self.check_username: query |= Q(identifier=request.user.username) score = (Reputation.objects.filter(query).aggregate( total_score=Sum("score"))["total_score"] or 0) passing = score <= self.threshold LOGGER.debug( "Score for user", username=request.user.username, remote_ip=remote_ip, score=score, passing=passing, ) return PolicyResult(bool(passing))
def passes(self, request: PolicyRequest) -> PolicyResult: if (self.password_field not in request.context and self.password_field not in request.context.get( PLAN_CONTEXT_PROMPT, {})): LOGGER.warning( "Password field not set in Policy Request", field=self.password_field, fields=request.context.keys(), prompt_fields=request.context.get(PLAN_CONTEXT_PROMPT, {}).keys(), ) return PolicyResult(False, _("Password not set in context")) if self.password_field in request.context: password = request.context[self.password_field] else: password = request.context[PLAN_CONTEXT_PROMPT][ self.password_field] if len(password) < self.length_min: LOGGER.debug("password failed", reason="length") return PolicyResult(False, self.error_message) if self.amount_digits > 0 and len( RE_DIGITS.findall(password)) < self.amount_digits: LOGGER.debug("password failed", reason="amount_digits") return PolicyResult(False, self.error_message) if self.amount_lowercase > 0 and len( RE_LOWER.findall(password)) < self.amount_lowercase: LOGGER.debug("password failed", reason="amount_lowercase") return PolicyResult(False, self.error_message) if self.amount_uppercase > 0 and len( RE_UPPER.findall(password)) < self.amount_lowercase: LOGGER.debug("password failed", reason="amount_uppercase") return PolicyResult(False, self.error_message) if self.amount_symbols > 0: count = 0 for symbol in self.symbol_charset: count += password.count(symbol) if count < self.amount_symbols: LOGGER.debug("password failed", reason="amount_symbols") return PolicyResult(False, self.error_message) return PolicyResult(True)
def run(self): # pragma: no cover """Task wrapper to run policy checking""" with Hub.current.start_span( op="policy.process.execute", ) as span, HIST_POLICIES_EXECUTION_TIME.labels( binding_order=self.binding.order, binding_target_type=self.binding.target_type, binding_target_name=self.binding.target_name, object_name=self.request.obj, object_type=f"{self.request.obj._meta.app_label}.{self.request.obj._meta.model_name}", user=str(self.request.user), ).time(): span: Span span.set_data("policy", self.binding.policy) span.set_data("request", self.request) try: self.connection.send(self.execute()) except Exception as exc: # pylint: disable=broad-except LOGGER.warning(str(exc)) self.connection.send(PolicyResult(False, str(exc)))
def dispatch(self, request: HttpRequest, *args: Any, **kwargs: Any) -> HttpResponse: try: self.pre_permission_check() except RequestValidationError as exc: if exc.response: return exc.response return self.handle_no_permission() try: self.resolve_provider_application() except (Application.DoesNotExist, Provider.DoesNotExist) as exc: LOGGER.warning("failed to resolve application", exc=exc) return self.handle_no_permission_authenticated( PolicyResult(False, _("Failed to resolve application"))) # Check if user is unauthenticated, so we pass the application # for the identification stage if not request.user.is_authenticated: LOGGER.warning("user not authenticated") return self.handle_no_permission() # Check permissions result = self.user_has_access() if not result.passing: return self.handle_no_permission_authenticated(result) return super().dispatch(request, *args, **kwargs)
from authentik.flows.markers import ReevaluateMarker, StageMarker from authentik.flows.models import Flow, FlowDesignation, FlowStageBinding, InvalidResponseAction from authentik.flows.planner import FlowPlan, FlowPlanner from authentik.flows.stage import PLAN_CONTEXT_PENDING_USER_IDENTIFIER, StageView from authentik.flows.tests import FlowTestCase from authentik.flows.views.executor import NEXT_ARG_NAME, SESSION_KEY_PLAN, FlowExecutorView from authentik.lib.config import CONFIG from authentik.policies.dummy.models import DummyPolicy from authentik.policies.models import PolicyBinding from authentik.policies.reputation.models import ReputationPolicy from authentik.policies.types import PolicyResult from authentik.stages.deny.models import DenyStage from authentik.stages.dummy.models import DummyStage from authentik.stages.identification.models import IdentificationStage, UserFields POLICY_RETURN_FALSE = PropertyMock(return_value=PolicyResult(False)) POLICY_RETURN_TRUE = MagicMock(return_value=PolicyResult(True)) def to_stage_response(request: HttpRequest, source: HttpResponse): """Mock for to_stage_response that returns the original response, so we can check inheritance and member attributes""" return source TO_STAGE_RESPONSE_MOCK = MagicMock(side_effect=to_stage_response) class TestFlowExecutor(FlowTestCase): """Test executor""" def setUp(self):
def passes(self, request: PolicyRequest) -> PolicyResult: """Wait random time then return result""" wait = SystemRandom().randrange(self.wait_min, self.wait_max) LOGGER.debug("Policy waiting", policy=self, delay=wait) sleep(wait) return PolicyResult(self.result, "dummy")