From bfbd8fcc0f7520112fdfe6c6ca807488d68fa0c9 Mon Sep 17 00:00:00 2001 From: Teodora Vasic Date: Thu, 19 Sep 2024 16:30:51 +0200 Subject: [PATCH 1/2] try using flash for login or creation of users --- backend/src/appointment/database/models.py | 4 +- backend/src/appointment/dependencies/auth.py | 29 +++++ backend/src/appointment/routes/auth.py | 105 ++++++++++++++----- 3 files changed, 111 insertions(+), 27 deletions(-) diff --git a/backend/src/appointment/database/models.py b/backend/src/appointment/database/models.py index 2e4721697..361e58e07 100644 --- a/backend/src/appointment/database/models.py +++ b/backend/src/appointment/database/models.py @@ -124,11 +124,11 @@ class Subscriber(HasSoftDelete, Base): id = Column(Integer, primary_key=True, index=True) username = Column(encrypted_type(String), unique=True, index=True) # Encrypted (here) and hashed (by the associated hashing functions in routes/auth) - password = Column(encrypted_type(String), index=False) + # password = Column(encrypted_type(String), index=False) # Use subscriber.preferred_email for any email, or other user-facing presence. email = Column(encrypted_type(String), unique=True, index=True) - secondary_email = Column(encrypted_type(String), nullable=True, index=True) + # secondary_email = Column(encrypted_type(String), nullable=True, index=True) name = Column(encrypted_type(String), index=True) level = Column(Enum(SubscriberLevel), default=SubscriberLevel.basic, index=True) diff --git a/backend/src/appointment/dependencies/auth.py b/backend/src/appointment/dependencies/auth.py index 2dc4dddd5..36077e692 100644 --- a/backend/src/appointment/dependencies/auth.py +++ b/backend/src/appointment/dependencies/auth.py @@ -1,6 +1,9 @@ +import base64 import datetime +import json import os from typing import Annotated +from uuid import UUID import sentry_sdk from fastapi import Depends, Body, Request, HTTPException @@ -156,3 +159,29 @@ def get_subscriber_from_schedule_or_signed_url( raise validation.InvalidLinkException return subscriber + +def get_flash_user_data_from_token(request): + token = request.headers.get('Authorization', None) + if not token: + return "Missing Authorization Header" + + token = token.replace("Bearer ", "") + + _, payload, _ = token.split(".") + + # b64decode() requires the length of input to be a multiple of 4 + padded_payload = payload + "=" * (4 - len(payload) % 4) + decoded_payload = base64.b64decode(padded_payload).decode("utf-8") + + payload_json = json.loads(decoded_payload) + print("________________________________") + print(payload_json) + print("________________________________") + flash_user_data = { + "username": payload_json["preferred_username"], + "email": payload_json["email"], + "name": payload_json["given_name"] + " " + payload_json["family_name"] + } + + return flash_user_data + diff --git a/backend/src/appointment/routes/auth.py b/backend/src/appointment/routes/auth.py index 76677fa20..b197f5073 100644 --- a/backend/src/appointment/routes/auth.py +++ b/backend/src/appointment/routes/auth.py @@ -5,7 +5,7 @@ from datetime import timedelta, datetime, UTC from secrets import token_urlsafe from typing import Annotated - +from fastapi import Request import argon2.exceptions import jwt from fastapi.security import OAuth2PasswordRequestForm @@ -22,7 +22,7 @@ from ..defines import INVITES_TO_GIVE_OUT from ..dependencies.database import get_db -from ..dependencies.auth import get_subscriber, get_admin_subscriber, get_subscriber_from_onetime_token +from ..dependencies.auth import get_flash_user_data_from_token, get_subscriber, get_admin_subscriber, get_subscriber_from_onetime_token from ..controller import auth from ..controller.apis.fxa_client import FxaClient @@ -348,26 +348,81 @@ def permission_check(subscriber: Subscriber = Depends(get_admin_subscriber)): return True # Covered by get_admin_subscriber -# @router.get('/test-create-account') -# def test_create_account(email: str, password: str, timezone: str, db: Session = Depends(get_db)): -# """Used to create a test account""" -# if os.getenv('APP_ENV') != 'dev': -# raise HTTPException(status_code=405) -# if os.getenv('AUTH_SCHEME') != 'password': -# raise HTTPException(status_code=405) -# -# subscriber = repo.subscriber.create(db, schemas.SubscriberBase( -# email=email, -# username=email, -# name=email.split('@')[0], -# timezone=timezone -# )) -# -# # Update with password -# subscriber.password = get_password_hash(password) -# -# db.add(subscriber) -# db.commit() -# db.refresh(subscriber) -# -# return subscriber +@router.get('/create-account-no-waiting-list') +def create_account_no_waiting_list(email: str, password: str, timezone: str, db: Session = Depends(get_db)): + """Used to create a test account""" + if os.getenv('APP_ENV') != 'dev': + raise HTTPException(status_code=405) + if os.getenv('AUTH_SCHEME') != 'password': + raise HTTPException(status_code=405) + + subscriber = repo.subscriber.create(db, schemas.SubscriberBase( + email=email, + username=email, + name=email.split('@')[0], + timezone=timezone + )) + + # Update with password + subscriber.password = utils.get_password_hash(password) + + db.add(subscriber) + db.commit() + db.refresh(subscriber) + + return subscriber + +@router.get('/create-account-no-waiting-list') +def create_account_no_waiting_list(email: str, password: str, timezone: str, db: Session = Depends(get_db)): + """Used to create a test account""" + if os.getenv('APP_ENV') != 'dev': + raise HTTPException(status_code=405) + if os.getenv('AUTH_SCHEME') != 'password': + raise HTTPException(status_code=405) + + subscriber = repo.subscriber.create(db, schemas.SubscriberBase( + email=email, + username=email, + name=email.split('@')[0], + timezone=timezone + )) + + # Update with password + subscriber.password = utils.get_password_hash(password) + + db.add(subscriber) + db.commit() + db.refresh(subscriber) + + return subscriber + +@router.get('/login-or-create-user') +def login_or_create_user(request: Request, db: Session = Depends(get_db)): + """Used to create a test account""" + if os.getenv('APP_ENV') != 'dev': + raise HTTPException(status_code=405) + if os.getenv('AUTH_SCHEME') != 'password': + raise HTTPException(status_code=405) + + user_data = get_flash_user_data_from_token(request) + + if repo.subscriber.get_by_email(db, user_data["email"]): + return "Successfully logged in" + + else: + + subscriber = repo.subscriber.create(db, schemas.SubscriberBase( + email=user_data["email"], + username=user_data["username"], + name=user_data["name"], + timezone="UTC" + )) + + # Update with password + # subscriber.password = utils.get_password_hash(password) + + db.add(subscriber) + db.commit() + db.refresh(subscriber) + + return subscriber \ No newline at end of file From a7a4aa3826ed75b0aed89d53ba6b2b3dcccefc7f Mon Sep 17 00:00:00 2001 From: Teodora Vasic Date: Thu, 26 Sep 2024 08:01:38 +0200 Subject: [PATCH 2/2] fix --- .github/workflows/deploy-staging.yml | 34 +++++++++++----------- backend/src/appointment/database/models.py | 4 +-- backend/src/appointment/routes/auth.py | 3 ++ 3 files changed, 22 insertions(+), 19 deletions(-) diff --git a/.github/workflows/deploy-staging.yml b/.github/workflows/deploy-staging.yml index 0cc0db0fa..a797d08b0 100644 --- a/.github/workflows/deploy-staging.yml +++ b/.github/workflows/deploy-staging.yml @@ -50,7 +50,7 @@ jobs: environment: staging runs-on: ubuntu-latest env: - TF_VAR_region: ${{ vars.AWS_REGION }} + TF_VAR_region: us-east-1 TF_VAR_environment: ${{ vars.ENV_SHORT_NAME }} TF_VAR_name_prefix: "tb-${{ vars.PROJECT_SHORT_NAME }}-${{ vars.ENV_SHORT_NAME }}" TF_VAR_frontend_url: ${{ vars.FRONTEND_URL }} @@ -72,11 +72,11 @@ jobs: terragrunt -v - name: Configure AWS credentials - uses: aws-actions/configure-aws-credentials@v4 + uses: aws-actions/configure-aws-credentials@v1 with: - role-to-assume: ${{ secrets.IAM_ROLE }} - role-session-name: Appointment_GitHub_to_AWS_via_FederatedOIDC - aws-region: ${{ vars.AWS_REGION }} + aws-access-key-id: ${{ secrets.INSTALLER_DEV_AWS_ACCESS_KEY_ID }} + aws-secret-access-key: ${{ secrets.INSTALLER_DEV_AWS_SECRET_KEY }} + aws-region: us-east-1 - name: vpc working-directory: ./tofu/environments/stage/network/vpc @@ -170,11 +170,11 @@ jobs: arch: amd64 - name: Configure AWS credentials - uses: aws-actions/configure-aws-credentials@v4 + uses: aws-actions/configure-aws-credentials@v1 with: - role-to-assume: ${{ secrets.IAM_ROLE }} - role-session-name: Appointment_GitHub_to_AWS_via_FederatedOIDC - aws-region: ${{ vars.AWS_REGION }} + aws-access-key-id: ${{ secrets.INSTALLER_DEV_AWS_ACCESS_KEY_ID }} + aws-secret-access-key: ${{ secrets.INSTALLER_DEV_AWS_SECRET_KEY }} + aws-region: us-east-1 - name: Get frontend bucket & distribution id: get-frontend-resources @@ -199,11 +199,11 @@ jobs: - uses: actions/checkout@v4 - name: Configure AWS credentials - uses: aws-actions/configure-aws-credentials@v4 + uses: aws-actions/configure-aws-credentials@v1 with: - role-to-assume: ${{ secrets.IAM_ROLE }} - role-session-name: Appointment_GitHub_to_AWS_via_FederatedOIDC - aws-region: ${{ vars.AWS_REGION }} + aws-access-key-id: ${{ secrets.INSTALLER_DEV_AWS_ACCESS_KEY_ID }} + aws-secret-access-key: ${{ secrets.INSTALLER_DEV_AWS_SECRET_KEY }} + aws-region: us-east-1 - name: Login to Amazon ECR id: login-ecr @@ -289,11 +289,11 @@ jobs: echo ecr_tag=$output >> $GITHUB_OUTPUT - name: Configure AWS credentials - uses: aws-actions/configure-aws-credentials@v4 + uses: aws-actions/configure-aws-credentials@v1 with: - role-to-assume: ${{ secrets.IAM_ROLE }} - role-session-name: Appointment_GitHub_to_AWS_via_FederatedOIDC - aws-region: ${{ vars.AWS_REGION }} + aws-access-key-id: ${{ secrets.INSTALLER_DEV_AWS_ACCESS_KEY_ID }} + aws-secret-access-key: ${{ secrets.INSTALLER_DEV_AWS_SECRET_KEY }} + aws-region: us-east-1 - name: deploy backend-service working-directory: ./tofu/environments/stage/services/backend-service diff --git a/backend/src/appointment/database/models.py b/backend/src/appointment/database/models.py index 361e58e07..2e4721697 100644 --- a/backend/src/appointment/database/models.py +++ b/backend/src/appointment/database/models.py @@ -124,11 +124,11 @@ class Subscriber(HasSoftDelete, Base): id = Column(Integer, primary_key=True, index=True) username = Column(encrypted_type(String), unique=True, index=True) # Encrypted (here) and hashed (by the associated hashing functions in routes/auth) - # password = Column(encrypted_type(String), index=False) + password = Column(encrypted_type(String), index=False) # Use subscriber.preferred_email for any email, or other user-facing presence. email = Column(encrypted_type(String), unique=True, index=True) - # secondary_email = Column(encrypted_type(String), nullable=True, index=True) + secondary_email = Column(encrypted_type(String), nullable=True, index=True) name = Column(encrypted_type(String), index=True) level = Column(Enum(SubscriberLevel), default=SubscriberLevel.basic, index=True) diff --git a/backend/src/appointment/routes/auth.py b/backend/src/appointment/routes/auth.py index b197f5073..8e1c449a8 100644 --- a/backend/src/appointment/routes/auth.py +++ b/backend/src/appointment/routes/auth.py @@ -5,6 +5,7 @@ from datetime import timedelta, datetime, UTC from secrets import token_urlsafe from typing import Annotated +from ..routes.api import sync_remote_calendars from fastapi import Request import argon2.exceptions import jwt @@ -425,4 +426,6 @@ def login_or_create_user(request: Request, db: Session = Depends(get_db)): db.commit() db.refresh(subscriber) + sync_remote_calendars(db, subscriber) + return subscriber \ No newline at end of file