Skip to content
Snippets Groups Projects
Commit 2c55176c authored by Tim Repke's avatar Tim Repke
Browse files

improved permission handling

parent 977e4194
No related branches found
No related tags found
1 merge request!109improved permission handling
Pipeline #3806 canceled
import mimetypes
from contextlib import asynccontextmanager
from fastapi import FastAPI
from fastapi.staticfiles import StaticFiles
......@@ -8,6 +9,7 @@ from fastapi.middleware.trustedhost import TrustedHostMiddleware
from .util.middlewares import TimingMiddleware, ErrorHandlingMiddleware
from .util.config import settings
from .util.security import auth_helper
from .data import db_engine
from .util.logging import get_logger
from .api import router as api_router
......@@ -20,10 +22,25 @@ mimetypes.init()
logger = get_logger('nacsos.server')
app = FastAPI(openapi_url=settings.SERVER.OPENAPI_FILE,
openapi_prefix=settings.SERVER.OPENAPI_PREFIX,
root_path=settings.SERVER.ROOT_PATH,
separate_input_output_schemas=False)
@asynccontextmanager
async def lifespan(app: FastAPI):
# Following code executed on startup
await db_engine.startup()
await auth_helper
yield # running server
# Following code executed after shutdown
app = FastAPI(
openapi_url=settings.SERVER.OPENAPI_FILE,
openapi_prefix=settings.SERVER.OPENAPI_PREFIX,
root_path=settings.SERVER.ROOT_PATH,
separate_input_output_schemas=False,
lifespan=lifespan
)
logger.debug('Setting up server and middlewares')
mimetypes.add_type('application/javascript', '.js')
......@@ -46,8 +63,3 @@ logger.debug('Setup routers')
app.include_router(api_router, prefix='/api')
app.mount('/', StaticFiles(directory=settings.SERVER.STATIC_FILES, html=True), name='static')
@app.on_event("startup")
async def on_startup():
await db_engine.startup()
......@@ -502,10 +502,9 @@ async def get_assignment_scopes_for_scheme(scheme_id: str,
permissions=Depends(UserPermissionChecker('annotations_read'))) \
-> list[AssignmentScopeModel]:
async with db_engine.session() as session: # type: AsyncSession
return [AssignmentScopeModel.model_validate(scope.__dict__)
for scope in (await session.execute(select(AssignmentScope)
.where(AssignmentScope.annotation_scheme_id == scheme_id))
).scalars().all()]
scopes = await session.execute(select(AssignmentScope)
.where(AssignmentScope.annotation_scheme_id == scheme_id))
return [AssignmentScopeModel.model_validate(scope) for scope in scopes.mappings().all()]
@router.get('/config/annotators/{scheme_id}', response_model=list[UserModel])
......
......@@ -6,13 +6,13 @@ from sqlalchemy.orm import selectinload
from nacsos_data.models.users import UserBaseModel
from nacsos_data.models.projects import ProjectPermissionsModel
from nacsos_data.db.schemas import ProjectPermissions
from nacsos_data.db.crud.projects import \
read_project_permissions_for_project, \
read_project_permissions_by_id, \
from nacsos_data.db.crud.projects import (
read_project_permissions_for_project,
read_project_permissions_by_id,
delete_project_permissions
)
from server.data import db_engine
from server.util.security import UserPermissionChecker, UserPermissions, InsufficientPermissions
from server.util.security import UserPermissionChecker, UserPermissions, InsufficientPermissions, auth_helper
from server.util.logging import get_logger
logger = get_logger('nacsos.api.route.project')
......@@ -83,6 +83,7 @@ async def save_project_permission(project_permission: ProjectPermissionsModel,
# Save
await session.commit()
await auth_helper.cache.reload_permissions()
return str(project_permission.project_permission_id)
# Create new permission
......@@ -97,13 +98,19 @@ async def save_project_permission(project_permission: ProjectPermissionsModel,
pp_orm = ProjectPermissions(**project_permission.model_dump())
session.add(pp_orm)
await session.commit()
return str(project_permission.project_permission_id)
new_id = str(project_permission.project_permission_id)
await auth_helper.cache.reload_permissions()
return new_id
@router.delete('/permission')
async def remove_project_permission(project_permission_id: str,
permission=Depends(UserPermissionChecker('owner'))):
await delete_project_permissions(project_permission_id=project_permission_id, engine=db_engine)
await auth_helper.cache.reload_permissions()
@router.get('/{project_permission_id}', response_model=ProjectPermissionsModel)
......
......@@ -17,7 +17,7 @@ from nacsos_data.db.crud.users import (
from server.data import db_engine
from server.api.errors import DataNotFoundWarning, UserNotFoundError, UserPermissionError
from server.util.logging import get_logger
from server.util.security import UserPermissionChecker, get_current_active_user
from server.util.security import UserPermissionChecker, get_current_active_user, auth_helper
if TYPE_CHECKING:
from sqlalchemy.ext.asyncio import AsyncSession # noqa F401
......@@ -102,7 +102,9 @@ async def save_user(user: UserInDBModel | UserModel, current_user: UserModel = D
if user.user_id != current_user.user_id and not current_user.is_superuser:
raise UserPermissionError('You do not have permission to perform this action.')
return await create_or_update_user(user, engine=db_engine)
new_user_id = await create_or_update_user(user, engine=db_engine)
await auth_helper.cache.reload_users()
return new_user_id
@router.put('/my-details', response_model=str)
......@@ -134,4 +136,5 @@ async def save_user_self(user: UserInDBModel | UserModel,
# save changes
await session.commit()
return user_id
await auth_helper.cache.reload_users()
return user_id
from fastapi import Depends, status as http_status, Header
from fastapi.security import OAuth2PasswordBearer
from nacsos_data.models.users import UserModel, UserInDBModel
from nacsos_data.models.users import UserModel
from nacsos_data.models.projects import ProjectPermission
from nacsos_data.util.auth import Authentication, InsufficientPermissionError, InvalidCredentialsError, UserPermissions
......@@ -29,9 +29,9 @@ auth_helper = Authentication(engine=db_engine,
oauth2_scheme = OAuth2PasswordBearer(tokenUrl='api/login/token', auto_error=False)
async def get_current_user(token: str = Depends(oauth2_scheme)) -> UserInDBModel:
async def get_current_user(token: str = Depends(oauth2_scheme)) -> UserModel:
try:
return await auth_helper.get_current_user(token_id=token)
return auth_helper.get_current_user(token_id=token)
except InvalidCredentialsError as e:
raise NotAuthenticated(str(e))
except InsufficientPermissionError as e:
......@@ -77,10 +77,10 @@ class UserPermissionChecker:
:raises HTTPException if permissions are not fulfilled
"""
try:
return await auth_helper.check_permissions(project_id=x_project_id,
user=current_user,
required_permissions=self.permissions,
fulfill_all=self.fulfill_all)
return auth_helper.check_permissions(project_id=x_project_id,
user=current_user,
required_permissions=self.permissions,
fulfill_all=self.fulfill_all)
except (InvalidCredentialsError, InsufficientPermissionError) as e:
raise InsufficientPermissions(repr(e))
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment