Ejemplo n.º 1
0
async def set_cookie(response: Response, key, value, expires, path, domain,
                     secure, http_only, same_site):
    response.delete_cookie(key)  # Delete earlier cookies
    if CookieConfig.get_instance().cookie_domain is not None:
        domain = CookieConfig.get_instance().cookie_domain
    if CookieConfig.get_instance().cookie_secure is not None:
        secure = CookieConfig.get_instance().cookie_secure
    if CookieConfig.get_instance().cookie_same_site is not None:
        same_site = CookieConfig.get_instance().cookie_same_site
    handshake_info = await HandshakeInfo.get_instance()
    if path in {
            handshake_info.refresh_token_path, handshake_info.access_token_path
    }:
        if path == handshake_info.access_token_path and CookieConfig.get_instance(
        ).access_token_path is not None:
            path = CookieConfig.get_instance().access_token_path
        elif path == handshake_info.refresh_token_path and CookieConfig.get_instance(
        ).refresh_token_path is not None:
            path = CookieConfig.get_instance().refresh_token_path
    response.set_cookie(key=key,
                        value=quote(value, encoding='utf-8'),
                        expires=((expires - get_timestamp_ms()) // 1000),
                        path=path,
                        domain=domain,
                        secure=secure,
                        httponly=http_only,
                        samesite=same_site)
Ejemplo n.º 2
0
def index_page(username: Optional[str] = Cookie(default=None)):
    with open('templates/login.html', 'r') as f:
        login_page = f.read()
    if not username:
        return Response(login_page, media_type='text/html')
    valid_username = get_username_from_sign(username)
    if not valid_username:
        response = Response(login_page, media_type='text/html')
        response.delete_cookie(key='username')
        return response
    try:
        user = users[valid_username]
    except KeyError:
        repsonse = Response(login_page, media_type='text/html')
        repsonse.delete_cookie(key='username')
        return repsonse
    return Response(
        f'Привет,{users[valid_username]["name"]}!<br />'
        f'Баланс: {users[valid_username]["balance"]}',
        media_type='text/html')
Ejemplo n.º 3
0
def index_page(username: Optional[str] = Cookie(default=None)):
    with open('templates/login.html', 'r') as f:
        login_page = f.read()
    if not username:
        return Response(login_page, media_type="text/html")
    valid_username = get_username_from_signed_string(username)
    if not valid_username:
        response = Response(login_page, media_type="text/html")
        response.delete_cookie(key="username")
        return response
    try:
        user = users[valid_username]
    except KeyError:
        response = Response(login_page, media_type="text/html")
        response.delete_cookie(key="username")
        return response

    return Response(
        f"Привет, {users[valid_username]['name']}<br />Баланс: {users[valid_username]['balance']}",
        media_type="text/html")
Ejemplo n.º 4
0
def logout(response: Response):
    response.delete_cookie(AUTH_COOKIE_NAME)
Ejemplo n.º 5
0
async def complete_authentication(request: Request, _state=Depends(webauthn_state)):
    try:
        # decode the request's body
        data = cbor.decode(await request.body())
        credential_id = data["credentialId"]
        client_data = ClientData(data["clientDataJSON"])
        auth_data = AuthenticatorData(data["authenticatorData"])
        signature = data["signature"]

        # the user uuid saved on the authenticator device
        user_uuid = uuid.UUID(data["userHandle"].decode("utf-8"))

        # try to get the user from the database
        user: User = await User.get(user_uuid)

        # if the user is not in the database, he does not exist.
        if not user:
            raise HTTPException(
                status_code=status.HTTP_401_UNAUTHORIZED,
                detail="User does not exist!",
            )
        try:
            # parse the state parameter and verify signature
            state = jwt.decode(
                _state,
                config.SESSION_SECRET.get_secret_value(),
                algorithms=["HS256"],
            )
        except jwt.PyJWTError:
            raise HTTPException(
                status_code=status.HTTP_401_UNAUTHORIZED,
                detail="Warning: Invalid state parameter!",
            )
        else:
            # give the parameters to the fido2 library to verify them
            fido2server.authenticate_complete(
                state,
                # get the registered credentials of the user
                User.get_webauthn_credentials(user.webauthn_credentials),
                credential_id,
                client_data,
                auth_data,
                signature,
            )
            # create a session token. Sessions are only validated by their signature
            token = jwt.encode(
                {
                    "sub": str(user.user_uuid),
                    "exp": datetime.utcnow() + timedelta(weeks=1),
                },
                key=config.SESSION_SECRET.get_secret_value(),
                algorithm="HS256",
            )
            response = Response(
                content=cbor.encode({"status": "OK"}),
                media_type="application/cbor",
            )
            # set the session token
            response.set_cookie("session", token)
            # remove the state parameter because it's not longer needed
            response.delete_cookie("_state")
            return response
    except (ValueError, KeyError):
        raise HTTPException(
            status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
            detail="Received invalid data!",
        )
Ejemplo n.º 6
0
async def complete_webauthn(
    request: Request,
    user_uuid: uuid.UUID = Depends(get_current_user),
    # the previous state parameter as a cookie
    _state=Depends(webauthn_state),
    # The key should have a nickname so it can be easier identified.
    # E.g. ``Yubikey Keychain``.
    security_key_nickname: str = Query(...),
):
    try:
        # decode the requests body using cbor
        data = cbor.decode(await request.body())
        client_data = ClientData(data["clientDataJSON"])
        att_obj = AttestationObject(data["attestationObject"])
    except ValueError:
        raise HTTPException(
            status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
            detail="Failed to parse request body!",
        )
    try:
        # parse the state parameter
        state = jwt.decode(
            _state, config.SESSION_SECRET.get_secret_value(), algorithms=["HS256"]
        )
    except jwt.PyJWTError:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="Warning: Invalid state parameter!",
        )
    try:
        # verify authentication data
        auth_data: AuthenticatorData = fido2server.register_complete(
            state,
            client_data,
            att_obj,
        )
    except ValueError:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="Invalid authentication data!",
        )

    # create the response with ``Content-Type`` ``application/cbor``.
    response = Response(
        content=cbor.encode({"status": "OK"}), media_type="application/cbor"
    )

    # Tell the client to delete the cookie used to store the state since it is not
    # needed anymore.
    response.delete_cookie("_state")

    # get the current user from the database
    user = await User.get(user_uuid)

    # Guess there should be some kind of mutable array for this tho
    # SQLAlchemy somehow has trouble with mutable arrays. Because of this we simply
    # replace the whole array with the current array and add the new credential to the
    # list before sending it to the database. It needs more traffic and is slower so
    # tell me if you have a better solution.
    await user.update(
        webauthn_credentials=user.webauthn_credentials
        # we store the credential data as binary data in the database so we have to make
        # it an bytearray.
        + [bytearray(auth_data.credential_data)]
    ).apply()

    # to safe the nickname we store the credential id in the database with the
    # associated user uuid.
    await WebAuthnEntry.create(
        credential_id=auth_data.credential_data.credential_id,
        nickname=security_key_nickname,
        user_uuid=user_uuid,
    )

    # return the response
    return response
Ejemplo n.º 7
0
async def Logout(response: Response) -> RedirectResponse:
    response = RedirectResponse("/", status_code=status.HTTP_302_FOUND)
    response.delete_cookie("user")
    return response
Ejemplo n.º 8
0
def logout():
    response = Response()
    response.status_code = 303
    response.headers["Location"] = "/"
    response.delete_cookie(key="session_token")
    return response