Beispiel #1
0
 def from_http(
     self, request: HttpRequest, user: Optional[settings.AUTH_USER_MODEL] = None
 ) -> "Event":
     """Add data from a Django-HttpRequest, allowing the creation of
     Events independently from requests.
     `user` arguments optionally overrides user from requests."""
     if hasattr(request, "user"):
         original_user = None
         if hasattr(request, "session"):
             original_user = request.session.get(
                 SESSION_IMPERSONATE_ORIGINAL_USER, None
             )
         self.user = get_user(request.user, original_user)
     if user:
         self.user = get_user(user)
     # Check if we're currently impersonating, and add that user
     if hasattr(request, "session"):
         if SESSION_IMPERSONATE_ORIGINAL_USER in request.session:
             self.user = get_user(request.session[SESSION_IMPERSONATE_ORIGINAL_USER])
             self.user["on_behalf_of"] = get_user(
                 request.session[SESSION_IMPERSONATE_USER]
             )
     # User 255.255.255.255 as fallback if IP cannot be determined
     self.client_ip = get_client_ip(request)
     # Apply GeoIP Data, when enabled
     self.with_geoip()
     # If there's no app set, we get it from the requests too
     if not self.app:
         self.app = Event._get_app_from_request(request)
     self.save()
     return self
Beispiel #2
0
 def get(self, request: HttpRequest, *args, **kwargs) -> HttpResponse:
     """Start FlowPLanner, return to flow executor shell"""
     # After we've checked permissions, and the user has access, check if we need
     # to re-authenticate the user
     if self.params.max_age:
         current_age: timedelta = (
             timezone.now()
             - Event.objects.filter(
                 action=EventAction.LOGIN, user=get_user(self.request.user)
             )
             .latest("created")
             .created
         )
         if current_age.total_seconds() > self.params.max_age:
             return self.handle_no_permission()
     # If prompt=login, we need to re-authenticate the user regardless
     if (
         PROMPT_LOGIN in self.params.prompt
         and SESSION_NEEDS_LOGIN not in self.request.session
     ):
         self.request.session[SESSION_NEEDS_LOGIN] = True
         return self.handle_no_permission()
     # Regardless, we start the planner and return to it
     planner = FlowPlanner(self.provider.authorization_flow)
     # planner.use_cache = False
     planner.allow_empty_flows = True
     scope_descriptions = UserInfoView().get_scope_descriptions(self.params.scope)
     plan: FlowPlan = planner.plan(
         self.request,
         {
             PLAN_CONTEXT_SSO: True,
             PLAN_CONTEXT_APPLICATION: self.application,
             # OAuth2 related params
             PLAN_CONTEXT_PARAMS: self.params,
             # Consent related params
             PLAN_CONTEXT_CONSENT_HEADER: _(
                 "You're about to sign into %(application)s."
             )
             % {"application": self.application.name},
             PLAN_CONTEXT_CONSENT_PERMISSIONS: scope_descriptions,
         },
     )
     # OpenID clients can specify a `prompt` parameter, and if its set to consent we
     # need to inject a consent stage
     if PROMPT_CONSNET in self.params.prompt:
         if not any(isinstance(x, ConsentStageView) for x in plan.stages):
             # Plan does not have any consent stage, so we add an in-memory one
             stage = ConsentStage(
                 name="OAuth2 Provider In-memory consent stage",
                 mode=ConsentMode.ALWAYS_REQUIRE,
             )
             plan.append(stage)
     plan.append(in_memory_stage(OAuthFulfillmentStage))
     self.request.session[SESSION_KEY_PLAN] = plan
     return redirect_with_qs(
         "authentik_core:if-flow",
         self.request.GET,
         flow_slug=self.provider.authorization_flow.slug,
     )
Beispiel #3
0
 def from_http(self,
               request: HttpRequest,
               user: Optional[settings.AUTH_USER_MODEL] = None) -> "Event":
     """Add data from a Django-HttpRequest, allowing the creation of
     Events independently from requests.
     `user` arguments optionally overrides user from requests."""
     if request:
         self.context["http_request"] = {
             "path": request.path,
             "method": request.method,
             "args": QueryDict(request.META.get("QUERY_STRING", "")),
         }
     if hasattr(request, "tenant"):
         tenant: Tenant = request.tenant
         # Because self.created only gets set on save, we can't use it's value here
         # hence we set self.created to now and then use it
         self.created = now()
         self.expires = self.created + timedelta_from_string(
             tenant.event_retention)
         self.tenant = sanitize_dict(model_to_dict(tenant))
     if hasattr(request, "user"):
         original_user = None
         if hasattr(request, "session"):
             original_user = request.session.get(
                 SESSION_IMPERSONATE_ORIGINAL_USER, None)
         self.user = get_user(request.user, original_user)
     if user:
         self.user = get_user(user)
     # Check if we're currently impersonating, and add that user
     if hasattr(request, "session"):
         if SESSION_IMPERSONATE_ORIGINAL_USER in request.session:
             self.user = get_user(
                 request.session[SESSION_IMPERSONATE_ORIGINAL_USER])
             self.user["on_behalf_of"] = get_user(
                 request.session[SESSION_IMPERSONATE_USER])
     # User 255.255.255.255 as fallback if IP cannot be determined
     self.client_ip = get_client_ip(request)
     # Apply GeoIP Data, when enabled
     self.with_geoip()
     # If there's no app set, we get it from the requests too
     if not self.app:
         self.app = Event._get_app_from_request(request)
     self.save()
     return self
Beispiel #4
0
    def create_id_token(self, user: User, request: HttpRequest) -> IDToken:
        """Creates the id_token.
        See: http://openid.net/specs/openid-connect-core-1_0.html#IDToken"""
        sub = ""
        if self.provider.sub_mode == SubModes.HASHED_USER_ID:
            sub = sha256(f"{user.id}-{settings.SECRET_KEY}".encode(
                "ascii")).hexdigest()
        elif self.provider.sub_mode == SubModes.USER_EMAIL:
            sub = user.email
        elif self.provider.sub_mode == SubModes.USER_USERNAME:
            sub = user.username
        elif self.provider.sub_mode == SubModes.USER_UPN:
            sub = user.attributes["upn"]
        else:
            raise ValueError((f"Provider {self.provider} has invalid sub_mode "
                              f"selected: {self.provider.sub_mode}"))

        # Convert datetimes into timestamps.
        now = int(time.time())
        iat_time = now
        exp_time = int(
            now + timedelta_from_string(self.provider.token_validity).seconds)
        # We use the timestamp of the user's last successful login (EventAction.LOGIN) for auth_time
        auth_events = Event.objects.filter(
            action=EventAction.LOGIN, user=get_user(user)).order_by("-created")
        # Fallback in case we can't find any login events
        auth_time = datetime.now()
        if auth_events.exists():
            auth_time = auth_events.first().created
        auth_time = int(dateformat.format(auth_time, "U"))

        token = IDToken(
            iss=self.provider.get_issuer(request),
            sub=sub,
            aud=self.provider.client_id,
            exp=exp_time,
            iat=iat_time,
            auth_time=auth_time,
        )

        # Include (or not) user standard claims in the id_token.
        if self.provider.include_claims_in_id_token:
            from authentik.providers.oauth2.views.userinfo import UserInfoView

            user_info = UserInfoView()
            user_info.request = request
            claims = user_info.get_claims(self)
            token.claims = claims

        return token
Beispiel #5
0
 def test(self, request: Request, pk=None) -> Response:
     """Send example notification using selected transport. Requires
     Modify permissions."""
     transport: NotificationTransport = self.get_object()
     notification = Notification(
         severity=NotificationSeverity.NOTICE,
         body=f"Test Notification from transport {transport.name}",
         user=request.user,
         event=Event(
             action="Test",
             user=get_user(request.user),
             app=self.__class__.__module__,
             context={"foo": "bar"},
         ),
     )
     try:
         response = NotificationTransportTestSerializer(
             data={"messages": transport.send(notification)})
         response.is_valid()
         return Response(response.data)
     except NotificationTransportError as exc:
         return Response(str(exc.__cause__ or None), status=500)
Beispiel #6
0
 def set_user(self, user: User) -> "Event":
     """Set `.user` based on user, ensuring the correct attributes are copied.
     This should only be used when self.from_http is *not* used."""
     self.user = get_user(user)
     return self