def process( self, plan: "FlowPlan", binding: FlowStageBinding, http_request: HttpRequest, ) -> Optional[FlowStageBinding]: """Re-evaluate policies bound to stage, and if they fail, remove from plan""" from authentik.flows.planner import PLAN_CONTEXT_PENDING_USER LOGGER.debug( "f(plan_inst)[re-eval marker]: running re-evaluation", binding=binding, policy_binding=self.binding, ) engine = PolicyEngine( self.binding, plan.context.get(PLAN_CONTEXT_PENDING_USER, http_request.user) ) engine.use_cache = False engine.request.set_http_request(http_request) engine.request.context = plan.context engine.build() result = engine.result if result.passing: return binding LOGGER.warning( "f(plan_inst)[re-eval marker]: binding failed re-evaluation", binding=binding, messages=result.messages, ) return None
def event_trigger_handler(event_uuid: str, trigger_name: str): """Check if policies attached to NotificationRule match event""" events = Event.objects.filter(event_uuid=event_uuid) if not events.exists(): LOGGER.warning("event doesn't exist yet or anymore", event_uuid=event_uuid) return event: Event = events.first() triggers: NotificationRule = NotificationRule.objects.filter(name=trigger_name) if not triggers.exists(): return trigger = triggers.first() if "policy_uuid" in event.context: policy_uuid = event.context["policy_uuid"] if PolicyBinding.objects.filter( target__in=NotificationRule.objects.all().values_list("pbm_uuid", flat=True), policy=policy_uuid, ).exists(): # If policy that caused this event to be created is attached # to *any* NotificationRule, we return early. # This is the most effective way to prevent infinite loops. LOGGER.debug("e(trigger): attempting to prevent infinite loop", trigger=trigger) return if not trigger.group: LOGGER.debug("e(trigger): trigger has no group", trigger=trigger) return LOGGER.debug("e(trigger): checking if trigger applies", trigger=trigger) try: user = User.objects.filter(pk=event.user.get("pk")).first() or get_anonymous_user() except User.DoesNotExist: LOGGER.warning("e(trigger): failed to get user", trigger=trigger) return policy_engine = PolicyEngine(trigger, user) policy_engine.mode = PolicyEngineMode.MODE_ANY policy_engine.empty_result = False policy_engine.use_cache = False policy_engine.request.context["event"] = event policy_engine.build() result = policy_engine.result if not result.passing: return LOGGER.debug("e(trigger): event trigger matched", trigger=trigger) # Create the notification objects for transport in trigger.transports.all(): for user in trigger.group.users.all(): LOGGER.debug("created notification") notification = Notification.objects.create( severity=trigger.severity, body=event.summary, event=event, user=user ) notification_transport.apply_async( args=[notification.pk, transport.pk], queue="authentik_events" ) if transport.send_once: break
def user_has_access(self, user: Optional[User] = None) -> PolicyResult: """Check if user has access to application.""" user = user or self.request.user policy_engine = PolicyEngine(self.application, user or self.request.user, self.request) policy_engine.use_cache = False policy_engine.build() result = policy_engine.result LOGGER.debug( "PolicyAccessView user_has_access", user=user, app=self.application, result=result, ) if not result.passing: for message in result.messages: messages.error(self.request, _(message)) return result
def process(self, plan: "FlowPlan", stage: Stage, http_request: Optional[HttpRequest]) -> Optional[Stage]: """Re-evaluate policies bound to stage, and if they fail, remove from plan""" engine = PolicyEngine(self.binding, self.user) engine.use_cache = False if http_request: engine.request.set_http_request(http_request) engine.request.context = plan.context engine.build() result = engine.result if result.passing: return stage LOGGER.warning( "f(plan_inst)[re-eval marker]: stage failed re-evaluation", stage=stage, messages=result.messages, ) return None
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 = request.user if request.user.is_superuser and "for_user" in request.query_params: try: for_user = get_object_or_404( User, pk=request.query_params.get("for_user")) except ValueError: return HttpResponseBadRequest("for_user must be numerical") engine = PolicyEngine(application, for_user, request) engine.use_cache = False engine.build() result = engine.result response = PolicyTestResultSerializer(PolicyResult(False)) if result.passing: response = PolicyTestResultSerializer(PolicyResult(True)) if request.user.is_superuser: response = PolicyTestResultSerializer(result) return Response(response.data)