Ejemplo n.º 1
0
 def pre_permission_check(self):
     """Check prompt parameter before checking permission/authentication,
     see https://openid.net/specs/openid-connect-core-1_0.html#rfc.section.3.1.2.6"""
     try:
         self.params = OAuthAuthorizationParams.from_request(self.request)
     except AuthorizeError as error:
         error.to_event(redirect_uri=error.redirect_uri).from_http(self.request)
         raise RequestValidationError(HttpResponseRedirect(error.create_uri()))
     except OAuth2Error as error:
         error.to_event().from_http(self.request)
         raise RequestValidationError(
             bad_request_message(self.request, error.description, title=error.error)
         )
     except OAuth2Provider.DoesNotExist:
         raise Http404
     if PROMPT_NONE in self.params.prompt and not self.request.user.is_authenticated:
         # When "prompt" is set to "none" but the user is not logged in, show an error message
         error = AuthorizeError(
             self.params.redirect_uri,
             "login_required",
             self.params.grant_type,
             self.params.state,
         )
         error.to_event(redirect_uri=error.redirect_uri).from_http(self.request)
         raise RequestValidationError(HttpResponseRedirect(error.create_uri()))
Ejemplo n.º 2
0
 def check_code_challenge(self):
     """PKCE validation of the transformation method."""
     if self.code_challenge:
         if not (self.code_challenge_method in ["plain", "S256"]):
             raise AuthorizeError(
                 self.redirect_uri, "invalid_request", self.grant_type, self.state
             )
Ejemplo n.º 3
0
    def check_redirect_uri(self):
        """Redirect URI validation."""
        allowed_redirect_urls = self.provider.redirect_uris.split()
        if not self.redirect_uri:
            LOGGER.warning("Missing redirect uri.")
            raise RedirectUriError("", allowed_redirect_urls)

        if self.provider.redirect_uris == "":
            LOGGER.info("Setting redirect for blank redirect_uris",
                        redirect=self.redirect_uri)
            self.provider.redirect_uris = self.redirect_uri
            self.provider.save()
            allowed_redirect_urls = self.provider.redirect_uris.split()

        if self.provider.redirect_uris == "*":
            LOGGER.warning(
                "Provider has wildcard allowed redirect_uri set, allowing all.",
                allow=self.redirect_uri,
            )
            return
        if self.redirect_uri not in [x.lower() for x in allowed_redirect_urls]:
            LOGGER.warning(
                "Invalid redirect uri",
                redirect_uri=self.redirect_uri,
                excepted=allowed_redirect_urls,
            )
            raise RedirectUriError(self.redirect_uri, allowed_redirect_urls)
        if self.request:
            raise AuthorizeError(self.redirect_uri, "request_not_supported",
                                 self.grant_type, self.state)
Ejemplo n.º 4
0
 def check_scope(self):
     """Ensure openid scope is set in Hybrid flows, or when requesting an id_token"""
     if SCOPE_OPENID not in self.scope and (
             self.grant_type == GrantTypes.HYBRID or self.response_type
             in [ResponseTypes.ID_TOKEN, ResponseTypes.ID_TOKEN_TOKEN]):
         LOGGER.warning("Missing 'openid' scope.")
         raise AuthorizeError(self.redirect_uri, "invalid_scope",
                              self.grant_type, self.state)
Ejemplo n.º 5
0
 def check_nonce(self):
     """Nonce parameter validation."""
     if not self.nonce:
         self.nonce = self.state
         LOGGER.warning("Using state as nonce for OpenID Request")
     if not self.nonce:
         if SCOPE_OPENID in self.scope:
             LOGGER.warning("Missing nonce for OpenID Request")
             raise AuthorizeError(self.redirect_uri, "invalid_request",
                                  self.grant_type, self.state)
Ejemplo n.º 6
0
    def from_request(request: HttpRequest) -> "OAuthAuthorizationParams":
        """
        Get all the params used by the Authorization Code Flow
        (and also for the Implicit and Hybrid).

        See: http://openid.net/specs/openid-connect-core-1_0.html#AuthRequest
        """
        # Because in this endpoint we handle both GET
        # and POST request.
        query_dict = request.POST if request.method == "POST" else request.GET
        state = query_dict.get("state")
        redirect_uri = query_dict.get("redirect_uri", "")

        response_type = query_dict.get("response_type", "")
        grant_type = None
        # Determine which flow to use.
        if response_type in [ResponseTypes.CODE]:
            grant_type = GrantTypes.AUTHORIZATION_CODE
        elif response_type in [
            ResponseTypes.ID_TOKEN,
            ResponseTypes.ID_TOKEN_TOKEN,
        ]:
            grant_type = GrantTypes.IMPLICIT
        elif response_type in [
            ResponseTypes.CODE_TOKEN,
            ResponseTypes.CODE_ID_TOKEN,
            ResponseTypes.CODE_ID_TOKEN_TOKEN,
        ]:
            grant_type = GrantTypes.HYBRID

        # Grant type validation.
        if not grant_type:
            LOGGER.warning("Invalid response type", type=response_type)
            raise AuthorizeError(redirect_uri, "unsupported_response_type", "", state)

        max_age = query_dict.get("max_age")
        return OAuthAuthorizationParams(
            client_id=query_dict.get("client_id", ""),
            redirect_uri=redirect_uri,
            response_type=response_type,
            grant_type=grant_type,
            scope=query_dict.get("scope", "").split(),
            state=state,
            nonce=query_dict.get("nonce"),
            prompt=ALLOWED_PROMPT_PARAMS.intersection(
                set(query_dict.get("prompt", "").split())
            ),
            request=query_dict.get("request", None),
            max_age=int(max_age) if max_age else None,
            code_challenge=query_dict.get("code_challenge"),
            code_challenge_method=query_dict.get("code_challenge_method"),
        )
Ejemplo n.º 7
0
 def check_nonce(self):
     """Nonce parameter validation."""
     # https://openid.net/specs/openid-connect-core-1_0.html#ImplicitIDTValidation
     # Nonce is only required for Implicit flows
     if self.grant_type != GrantTypes.IMPLICIT:
         return
     if not self.nonce:
         self.nonce = self.state
         LOGGER.warning("Using state as nonce for OpenID Request")
     if not self.nonce:
         if SCOPE_OPENID in self.scope:
             LOGGER.warning("Missing nonce for OpenID Request")
             raise AuthorizeError(self.redirect_uri, "invalid_request",
                                  self.grant_type, self.state)
Ejemplo n.º 8
0
 def check_redirect_uri(self):
     """Redirect URI validation."""
     if not self.redirect_uri:
         LOGGER.warning("Missing redirect uri.")
         raise RedirectUriError("", self.provider.redirect_uris.split())
     if self.redirect_uri.lower() not in [
             x.lower() for x in self.provider.redirect_uris.split()
     ]:
         LOGGER.warning(
             "Invalid redirect uri",
             redirect_uri=self.redirect_uri,
             excepted=self.provider.redirect_uris.split(),
         )
         raise RedirectUriError(self.redirect_uri,
                                self.provider.redirect_uris.split())
     if self.request:
         raise AuthorizeError(self.redirect_uri, "request_not_supported",
                              self.grant_type, self.state)
Ejemplo n.º 9
0
    def create_response_uri(self) -> str:
        """Create a final Response URI the user is redirected to."""
        uri = urlsplit(self.params.redirect_uri)
        query_params = parse_qs(uri.query)

        try:
            code = None

            if self.params.grant_type in [
                    GrantTypes.AUTHORIZATION_CODE,
                    GrantTypes.HYBRID,
            ]:
                code = self.params.create_code(self.request)
                code.save(force_insert=True)

            if self.params.grant_type == GrantTypes.AUTHORIZATION_CODE:
                query_params["code"] = code.code
                query_params["state"] = [
                    str(self.params.state) if self.params.state else ""
                ]

                uri = uri._replace(query=urlencode(query_params, doseq=True))
                return urlunsplit(uri)
            if self.params.grant_type in [
                    GrantTypes.IMPLICIT, GrantTypes.HYBRID
            ]:
                query_fragment = self.create_implicit_response(code)

                uri = uri._replace(fragment=uri.fragment +
                                   urlencode(query_fragment, doseq=True), )
                return urlunsplit(uri)
            raise OAuth2Error()
        except OAuth2Error as error:
            LOGGER.warning("Error when trying to create response uri",
                           error=error)
            raise AuthorizeError(
                self.params.redirect_uri,
                "server_error",
                self.params.grant_type,
                self.params.state,
            )
Ejemplo n.º 10
0
 def get(self, request: HttpRequest, *args, **kwargs) -> HttpResponse:
     """final Stage of an OAuth2 Flow"""
     if PLAN_CONTEXT_PARAMS not in self.executor.plan.context:
         LOGGER.warning("Got to fulfillment stage with no pending context")
         return HttpResponseBadRequest()
     self.params: OAuthAuthorizationParams = self.executor.plan.context.pop(
         PLAN_CONTEXT_PARAMS)
     application: Application = self.executor.plan.context.pop(
         PLAN_CONTEXT_APPLICATION)
     self.provider = get_object_or_404(OAuth2Provider,
                                       pk=application.provider_id)
     try:
         # At this point we don't need to check permissions anymore
         if {PROMPT_NONE, PROMPT_CONSNET}.issubset(self.params.prompt):
             raise AuthorizeError(
                 self.params.redirect_uri,
                 "consent_required",
                 self.params.grant_type,
                 self.params.state,
             )
         Event.new(
             EventAction.AUTHORIZE_APPLICATION,
             authorized_application=application,
             flow=self.executor.plan.flow_pk,
             scopes=", ".join(self.params.scope),
         ).from_http(self.request)
         return self.redirect(self.create_response_uri())
     except (ClientIdError, RedirectUriError) as error:
         error.to_event(application=application).from_http(request)
         self.executor.stage_invalid()
         # pylint: disable=no-member
         return bad_request_message(request,
                                    error.description,
                                    title=error.error)
     except AuthorizeError as error:
         error.to_event(application=application).from_http(request)
         self.executor.stage_invalid()
         return self.redirect(error.create_uri())