Exemplo n.º 1
0
    async def validate_token_request(self):
        client = await self.authenticate_token_endpoint_client()

        log.debug("Validate token request of %r", client)
        if not client.check_grant_type(self.GRANT_TYPE):
            raise UnauthorizedClientError()

        code = self.request.form.get("code")
        if code is None:
            raise InvalidRequestError('Missing "code" in request.')

        # ensure that the authorization code was issued to the authenticated
        # confidential client, or if the client is public, ensure that the
        # code was issued to "client_id" in the request
        authorization_code = await self.query_authorization_code(code, client)
        if not authorization_code:
            raise InvalidRequestError('Invalid "code" in request.')

        # validate redirect_uri parameter
        log.debug("Validate token redirect_uri of %r", client)
        redirect_uri = self.request.redirect_uri
        original_redirect_uri = authorization_code.get_redirect_uri()
        if original_redirect_uri and redirect_uri != original_redirect_uri:
            raise InvalidRequestError('Invalid "redirect_uri" in request.')

        # save for create_token_response
        self.request.client = client
        self.request.credential = authorization_code
        await self.execute_hook("after_validate_token_request")
Exemplo n.º 2
0
 def authenticate_user(self, username, password):
     user = User.query.filter_by(username=username).first()
     if not user:
         raise InvalidRequestError("Username {} not found".format(username))
     if not user.check_password(password):
         raise InvalidRequestError("Password not valid!")
     return user
Exemplo n.º 3
0
def validate_nonce(request, exists_nonce, required=False):
    nonce = request.data.get('nonce')
    if not nonce:
        if required:
            raise InvalidRequestError('Missing "nonce" in request.')
        return True

    if exists_nonce(nonce, request):
        raise InvalidRequestError('Replay attack')
Exemplo n.º 4
0
    async def _validate_request_token(self, client=None):
        refresh_token = self.request.form.get("refresh_token")
        if refresh_token is None:
            raise InvalidRequestError('Missing "refresh_token" in request.', )

        token = await self.authenticate_refresh_token(refresh_token)
        if not token or token.get_client_id() != client.get_client_id():
            raise InvalidRequestError('Invalid "refresh_token" in request.', )
        return token
Exemplo n.º 5
0
async def validate_nonce(request, exists_nonce, required):
    nonce = request.data.get("nonce")
    if not nonce:
        if required:
            raise InvalidRequestError('Missing "nonce" in request.')
        return True

    if await exists_nonce(nonce, request):
        raise InvalidRequestError("Replay attack")
Exemplo n.º 6
0
def create_response_mode_response(redirect_uri, params, response_mode=None):
    if response_mode is None:
        response_mode = os.getenv('AUTHLIB_DEFAULT_RESPONSE_CODE', 'fragment')

    if response_mode == 'form_post':
        tpl = (
            '<html><head><title>Authlib</title></head>'
            '<body onload="javascript:document.forms[0].submit()">'
            '<form method="post" action="{}">{}</form></body></html>'
        )
        inputs = ''.join([
            '<input type="hidden" name="{}" value="{}"/>'.format(
                quote_url(k), quote_url(v))
            for k, v in params
        ])
        body = tpl.format(quote_url(redirect_uri), inputs)
        return 200, body, [('Content-Type', 'text/html; charset=utf-8')]

    if response_mode == 'query':
        uri = add_params_to_uri(redirect_uri, params, fragment=False)
    elif response_mode == 'fragment':
        uri = add_params_to_uri(redirect_uri, params, fragment=True)
    else:
        raise InvalidRequestError('Invalid "response_mode" value')

    return 302, '', [('Location', uri)]
Exemplo n.º 7
0
    def create_token_response(self):
        client = self.request.client
        authorization_code = self.request.credential

        user = self.authenticate_user(authorization_code)
        if not user:
            raise InvalidRequestError('There is no "user" for this code.')

        scope = authorization_code.scope
        nonce = authorization_code.nonce
        refresh_token_expires_in = authorization_code.refresh_token_expires_in

        token = self.generate_token(
            client,
            self.GRANT_TYPE,
            user=user,
            scope=scope,
            include_refresh_token=client.has_client_secret(),
            nonce=nonce,
            refresh_token_expires_in=refresh_token_expires_in,
        )

        self.request.user = user
        self.server.save_token(token, self.request)
        self.execute_hook("process_token", token=token)
        self.delete_authorization_code(authorization_code)
        return 200, token, self.TOKEN_RESPONSE_HEADER
Exemplo n.º 8
0
    def validate_request_prompt(self, end_user):
        """
        Override method in authlib to fix behavior with login prompt.
        """
        prompt = self.request.data.get("prompt")
        if not prompt:
            if not end_user:
                self.prompt = "login"
            return self

        if prompt == "none" and not end_user:
            raise LoginRequiredError()

        prompts = prompt.split()
        if "none" in prompts and len(prompts) > 1:
            # If this parameter contains none with any other value,
            # an error is returned
            raise InvalidRequestError('Invalid "prompt" parameter.')
        if "login" in prompts:
            prompt = "login"
        if "consent" in prompts:
            if not end_user:
                raise ConsentRequiredError()
            prompt = "consent"
        elif "select_account" in prompts:
            if not end_user:
                raise AccountSelectionRequiredError()
            prompt = "select_account"

        if prompt:
            self.prompt = prompt

        return self
Exemplo n.º 9
0
def validate_request_prompt(grant, redirect_uri, redirect_fragment=False):
    prompt = grant.request.data.get('prompt')
    end_user = grant.request.user
    if not prompt:
        if not end_user:
            grant.prompt = 'login'
        return grant

    if prompt == 'none' and not end_user:
        raise LoginRequiredError(
            redirect_uri=redirect_uri,
            redirect_fragment=redirect_fragment)

    prompts = prompt.split()
    if 'none' in prompts and len(prompts) > 1:
        # If this parameter contains none with any other value,
        # an error is returned
        raise InvalidRequestError(
            'Invalid "prompt" parameter.',
            redirect_uri=redirect_uri,
            redirect_fragment=redirect_fragment)

    prompt = _guess_prompt_value(
        end_user, prompts, redirect_uri, redirect_fragment=redirect_fragment)
    if prompt:
        grant.prompt = prompt
    return grant
Exemplo n.º 10
0
    def create_token_response(self):
        client = self.request.client
        authorization_code = self.request.credential

        user = self.authenticate_user(authorization_code)
        if not user:
            raise InvalidRequestError('There is no "user" for this code.')

        scope = authorization_code.get_scope()

        query_args = dict(self.request.query_params)
        code = self.request.body.get("code") or query_args.get("code")
        with flask.current_app.db.session as session:
            authorization_code = (session.query(AuthorizationCode).filter_by(
                code=code, client_id=client.client_id).first())
            nonce = authorization_code.nonce

        token = self.generate_token(
            client,
            self.GRANT_TYPE,
            user=user,
            scope=scope,
            include_refresh_token=client.has_client_secret(),
            nonce=nonce,
        )

        self.request.user = user
        self.server.save_token(token, self.request)
        self.execute_hook("process_token", token=token)
        self.delete_authorization_code(authorization_code)
        return 200, token, self.TOKEN_RESPONSE_HEADER
Exemplo n.º 11
0
    async def create_token_response(self):
        credential = self.request.credential
        user = await self.authenticate_user(credential)
        if not user:
            raise InvalidRequestError('There is no "user" for this token.')

        client = self.request.client
        token = await self.issue_token(client, user, credential)
        log.debug("Issue token %r to %r", token, client)

        self.request.user = user
        await self.save_token(token)
        await self.execute_hook("process_token", token=token)
        await self.revoke_old_credential(credential)
        return 200, token, self.TOKEN_RESPONSE_HEADER
Exemplo n.º 12
0
    async def create_token_response(self):
        client = self.request.client
        authorization_code = self.request.credential

        user = await self.authenticate_user(authorization_code)
        if not user:
            raise InvalidRequestError('There is no "user" for this code.')

        scope = authorization_code.get_scope()
        token = await self.generate_token(
            client,
            self.GRANT_TYPE,
            user=user,
            scope=client.get_allowed_scope(scope),
            include_refresh_token=client.check_grant_type("refresh_token"),
        )
        log.debug("Issue token %r to %r", token, client)

        self.request.user = user
        await self.save_token(token)
        await self.execute_hook("process_token", token=token)
        await self.delete_authorization_code(authorization_code)
        return 200, token, self.TOKEN_RESPONSE_HEADER
Exemplo n.º 13
0
def _get_auth_response_for_prompts(prompts, grant, user, client, scope):
    """
    Get response based on prompt parameter. TODO: not completely conforming yet

    FIXME: To conform to spec, some of the prompt params should be handled
    before AuthN or if it fails (so adequate and useful errors are provided).

    Right now the behavior is that the endpoint will just continue to
    redirect the user to log in without checking these params....

    Args:
        prompts (TYPE): Description
        grant (TYPE): Description
        user (TYPE): Description
        client (TYPE): Description
        scope (TYPE): Description

    Returns:
        TYPE: Description
    """
    show_consent_screen = True

    if prompts:
        prompts = prompts.split(" ")
        if "none" in prompts:
            # don't auth or consent, error if user not logged in
            show_consent_screen = False

            # if none is here, there shouldn't be others
            if len(prompts) != 1:
                error = InvalidRequestError(state=grant.params.get("state"),
                                            uri=grant.params.get("uri"))
                return _get_authorize_error_response(
                    error, grant.params.get("redirect_uri"))

            try:
                get_current_user()
                response = server.create_authorization_response(user)
            except Unauthorized:
                error = AccessDeniedError(state=grant.params.get("state"),
                                          uri=grant.params.get("uri"))
                return _get_authorize_error_response(
                    error, grant.params.get("redirect_uri"))

        if "login" in prompts:
            show_consent_screen = True
            try:
                # Re-AuthN user (kind of).
                # TODO (RR 2018-03-16): this could also include removing active
                # refresh tokens.
                flask.session.clear()

                # For a POST, return the redirect in JSON instead of headers.
                if flask.request.method == "POST":
                    redirect_response = flask.make_response(
                        flask.jsonify(
                            {"redirect": response.headers["Location"]}))
                else:
                    redirect_response = flask.make_response(
                        flask.redirect(flask.url_for(".authorize")))

                clear_cookies(redirect_response)
                return redirect_response
            except Unauthorized:
                error = AccessDeniedError(state=grant.params.get("state"),
                                          uri=grant.params.get("uri"))
                return _get_authorize_error_response(
                    error, grant.params.get("redirect_uri"))

        if "consent" in prompts:
            # show consent screen (which is default behavior so pass)
            pass

        if "select_account" in prompts:
            # allow user to select one of their accounts, we
            # don't support this at the moment
            pass

    if show_consent_screen:
        shown_scopes = [] if not scope else scope.split(" ")
        if "openid" in shown_scopes:
            shown_scopes.remove("openid")

        enabled_idps = config.get("OPENID_CONNECT", {})
        idp_names = []
        for idp, info in enabled_idps.items():
            # prefer name if its there, then just use the key for the provider
            idp_name = info.get("name") or idp.title()
            idp_names.append(idp_name)

        resource_description = [
            SCOPE_DESCRIPTION[s].format(idp_names=" and ".join(idp_names))
            for s in shown_scopes
        ]

        privacy_policy = config.get("BASE_URL").rstrip("/") + "/privacy-policy"

        response = flask.render_template(
            "oauthorize.html",
            grant=grant,
            user=user,
            client=client,
            app_name=config.get("APP_NAME"),
            resource_description=resource_description,
            privacy_policy=privacy_policy,
        )

    return response