Skip to content

Commit

Permalink
Merge pull request #408 from uhh-lt/fix/file-content-auth
Browse files Browse the repository at this point in the history
fix file content auth
  • Loading branch information
floschne authored Aug 23, 2024
2 parents 172948e + 87964d8 commit 5a66f9c
Show file tree
Hide file tree
Showing 6 changed files with 82 additions and 14 deletions.
48 changes: 44 additions & 4 deletions backend/src/api/endpoints/authentication.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
from fastapi import APIRouter, Depends, HTTPException
from typing import Annotated

from fastapi import APIRouter, Depends, Header, HTTPException, Request, Response
from fastapi.security import OAuth2PasswordRequestForm
from sqlalchemy.orm import Session

from api.dependencies import get_db_session
from api.dependencies import get_current_user, get_db_session
from api.util import credentials_exception
from app.core.authorization.authz_user import AuthzUser
from app.core.data.crud.crud_base import NoSuchElementError
from app.core.data.crud.refresh_token import crud_refresh_token
from app.core.data.crud.user import crud_user
Expand All @@ -17,6 +20,9 @@
from app.core.mail.mail_service import MailService
from app.core.security import generate_jwt

CONTENT_PREFIX = "/content/projects/"
AUTHORIZATION = "Authorization"

router = APIRouter(prefix="/authentication", tags=["authentication"])


Expand Down Expand Up @@ -56,6 +62,7 @@ def login(
*,
db: Session = Depends(get_db_session),
user_login_form_data: OAuth2PasswordRequestForm = Depends(),
response: Response,
) -> UserAuthorizationHeaderData:
user_login = UserLogin(
username=user_login_form_data.username,
Expand All @@ -68,6 +75,15 @@ def login(
(access_token, access_token_expires) = generate_jwt(user)
refresh_token = crud_refresh_token.generate(db, user.id)

response.set_cookie(
AUTHORIZATION,
access_token,
expires=access_token_expires,
secure=True,
httponly=True,
samesite="strict",
)

return UserAuthorizationHeaderData(
access_token=access_token,
access_token_expires=access_token_expires,
Expand All @@ -82,10 +98,14 @@ def login(
summary="Revokes the refresh token associated with the given session.",
)
def logout(
*, db: Session = Depends(get_db_session), dto: RefreshAccessTokenData = Depends()
):
*,
db: Session = Depends(get_db_session),
dto: RefreshAccessTokenData = Depends(),
response: Response,
) -> None:
token = crud_refresh_token.read_and_verify(db, dto.refresh_token)
crud_refresh_token.revoke(db, token)
response.delete_cookie(AUTHORIZATION, secure=True, httponly=True, samesite="strict")


@router.post(
Expand All @@ -109,3 +129,23 @@ def refresh_access_token(
token_type="bearer",
refresh_token_expires=new_token.expires_at,
)


@router.get(
"/content",
summary="Returns success if the user can access the content",
)
async def auth_content(
request: Request,
db: Session = Depends(get_db_session),
x_original_uri: Annotated[str | None, Header()] = None,
) -> None:
# returns None on purpose
token = request.cookies[AUTHORIZATION]
a = AuthzUser(request, get_current_user(db, token), db)
if not x_original_uri.startswith(CONTENT_PREFIX):
return

index = x_original_uri.find("/", len(CONTENT_PREFIX))
project = int(x_original_uri[len(CONTENT_PREFIX) : index])
a.assert_in_project(project)
1 change: 1 addition & 0 deletions backend/src/test/api/endpoints/test_authentication.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ def test_authentication_required():
# This route requires authentication, but does so
# in a manner we couldn't easily verify in the test.
({"GET"}, "/user/me"),
({"GET"}, "/authentication/content"),
# FastAPI built-in routes
({"GET", "HEAD"}, "/openapi.json"),
({"GET", "HEAD"}, "/docs"),
Expand Down
3 changes: 2 additions & 1 deletion docker/.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ COMPOSE_PROJECT_NAME=demo
# If you're running the backend and frontend
# outside of containers,
# remove their profiles to disable their containers
# add `dev_frontend` if you run the frontend externally
COMPOSE_PROFILES=backend,frontend,background,ray

# Which user and group to use for running processes
Expand Down Expand Up @@ -123,7 +124,7 @@ SYSTEM_USER_PASSWORD="12SYSTEM34"

FRONTEND_EXPOSED=3000
API_EXPOSED=13120
CONTENT_SERVER_EXPOSED=13121
CONTENT_SERVER_EXPOSED=13121 # only required for frontend development

POSTGRES_EXPOSED=13122
RABBIT_EXPOSED=13123
Expand Down
8 changes: 5 additions & 3 deletions docker/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,8 @@ services:
tty: true
networks:
- dats_demo_network
profiles:
- dev_frontend

celery-background-jobs-worker:
image: uhhlt/dats_backend:${DATS_BACKEND_DOCKER_VERSION:-debian_dev_latest}
Expand Down Expand Up @@ -203,8 +205,8 @@ services:
reservations:
devices:
- driver: nvidia
device_ids: ["0"]
capabilities: [gpu]
device_ids: [ "0" ]
capabilities: [ gpu ]
profiles:
- ray

Expand Down Expand Up @@ -260,7 +262,6 @@ services:
- ./backend_repo:${SHARED_REPO_ROOT:-/tmp/dats}
depends_on:
- elasticsearch
- lighttpd
- postgres
- rabbitmq
- redis
Expand All @@ -287,6 +288,7 @@ services:
image: uhhlt/dats_frontend:${DATS_FRONTEND_DOCKER_VERSION:-latest}
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf
- ./backend_repo:/usr/share/nginx/content:ro
depends_on:
- dats-backend-api
ports:
Expand Down
19 changes: 13 additions & 6 deletions docker/nginx.conf
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,6 @@ http {
server dats-backend-api:5500;
}

upstream docker-dats-content {
# this port and name has to match the service name and service port of the dats-backend
server lighttpd:80;
}

server {

# this port has to match the ports defined in the docker-compose file!
Expand All @@ -29,7 +24,10 @@ http {
}

location /content/ {
proxy_pass http://docker-dats-content/;
root /usr/share/nginx;
auth_request /auth;
auth_request_set $auth_status $upstream_status;

}

location / {
Expand All @@ -38,6 +36,15 @@ http {
try_files $uri /index.html;
}

location = /auth {
internal;
proxy_pass http://docker-dats-backend/authentication/content;
proxy_pass_request_body off;
proxy_set_header Content-Length "";
proxy_set_header X-Original-URI $request_uri;
}


error_page 500 502 503 504 /50x.html;

location = /50x.html {
Expand Down
17 changes: 17 additions & 0 deletions frontend/src/api/openapi/services/AuthenticationService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,4 +84,21 @@ export class AuthenticationService {
},
});
}
/**
* Returns success if the user can access the content
* @returns any Successful Response
* @throws ApiError
*/
public static authContent({ xOriginalUri }: { xOriginalUri?: string | null }): CancelablePromise<any> {
return __request(OpenAPI, {
method: "GET",
url: "/authentication/content",
headers: {
"x-original-uri": xOriginalUri,
},
errors: {
422: `Validation Error`,
},
});
}
}

0 comments on commit 5a66f9c

Please sign in to comment.