New way to check table and routes access
This commit is contained in:
parent
a5aad5b5ea
commit
b799d1312b
2 changed files with 166 additions and 61 deletions
167
app.py
167
app.py
|
|
@ -255,11 +255,16 @@ async def createUser(
|
||||||
user: CreateUserDefinition,
|
user: CreateUserDefinition,
|
||||||
access_token: str | None = Header(default=None),
|
access_token: str | None = Header(default=None),
|
||||||
):
|
):
|
||||||
is_admin = check_if_admin_access_token(connector, access_token)
|
try:
|
||||||
if not is_admin:
|
_user, _ = get_user_by_access_token(connector, access_token)
|
||||||
|
if not _user:
|
||||||
|
raise Exception("Not allowed")
|
||||||
|
acl = get_user_permissions_for_table(connector, "users", _user)
|
||||||
|
if acl != AccessType.READ and acl != AccessType.READ_WRITE:
|
||||||
|
raise Exception("Not allowed")
|
||||||
|
except Exception as e:
|
||||||
return JSONResponse(
|
return JSONResponse(
|
||||||
ErrorResponse(error="Not allowed").dict(),
|
ErrorResponse(error=str(e)).dict(), status_code=status.HTTP_403_FORBIDDEN
|
||||||
status_code=status.HTTP_403_FORBIDDEN,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
|
@ -300,11 +305,16 @@ async def updateUser(
|
||||||
user: UserUpdateDefinition,
|
user: UserUpdateDefinition,
|
||||||
access_token: str | None = Header(default=None),
|
access_token: str | None = Header(default=None),
|
||||||
):
|
):
|
||||||
is_admin = check_if_admin_access_token(connector, access_token)
|
try:
|
||||||
if not is_admin:
|
_user, _ = get_user_by_access_token(connector, access_token)
|
||||||
|
if not _user:
|
||||||
|
raise Exception("Not allowed")
|
||||||
|
acl = get_user_permissions_for_table(connector, "users", _user)
|
||||||
|
if acl != AccessType.WRITE and acl != AccessType.READ_WRITE:
|
||||||
|
raise Exception("Not allowed")
|
||||||
|
except Exception as e:
|
||||||
return JSONResponse(
|
return JSONResponse(
|
||||||
ErrorResponse(error="Not allowed").dict(),
|
ErrorResponse(error=str(e)).dict(), status_code=status.HTTP_403_FORBIDDEN
|
||||||
status_code=status.HTTP_403_FORBIDDEN,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
|
@ -344,11 +354,16 @@ async def removeUser(
|
||||||
user_id: int,
|
user_id: int,
|
||||||
access_token: str | None = Header(default=None),
|
access_token: str | None = Header(default=None),
|
||||||
):
|
):
|
||||||
is_admin = check_if_admin_access_token(connector, access_token)
|
try:
|
||||||
if not is_admin:
|
_user, _ = get_user_by_access_token(connector, access_token)
|
||||||
|
if not _user:
|
||||||
|
raise Exception("Not allowed")
|
||||||
|
acl = get_user_permissions_for_table(connector, "users", _user)
|
||||||
|
if acl != AccessType.WRITE and acl != AccessType.READ_WRITE:
|
||||||
|
raise Exception("Not allowed")
|
||||||
|
except Exception as e:
|
||||||
return JSONResponse(
|
return JSONResponse(
|
||||||
ErrorResponse(error="Not allowed").dict(),
|
ErrorResponse(error=str(e)).dict(), status_code=status.HTTP_403_FORBIDDEN
|
||||||
status_code=status.HTTP_403_FORBIDDEN,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
|
@ -408,11 +423,20 @@ async def items(
|
||||||
status_code=status.HTTP_404_NOT_FOUND,
|
status_code=status.HTTP_404_NOT_FOUND,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
try:
|
||||||
is_admin = check_if_admin_access_token(connector, access_token)
|
is_admin = check_if_admin_access_token(connector, access_token)
|
||||||
if table_info["system"] and not is_admin:
|
if table_info["system"] and not is_admin:
|
||||||
|
raise Exception("Not allowed")
|
||||||
|
|
||||||
|
user, group = get_user_by_access_token(connector, access_token)
|
||||||
|
if not user:
|
||||||
|
raise Exception("Not allowed")
|
||||||
|
acl = get_user_permissions_for_table(connector, tableName, user)
|
||||||
|
if acl != AccessType.READ and acl != AccessType.READ_WRITE:
|
||||||
|
raise Exception("Not allowed")
|
||||||
|
except Exception as e:
|
||||||
return JSONResponse(
|
return JSONResponse(
|
||||||
ErrorResponse(error="Not allowed").dict(),
|
ErrorResponse(error=str(e)).dict(), status_code=status.HTTP_403_FORBIDDEN
|
||||||
status_code=status.HTTP_403_FORBIDDEN,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
columns = parse_columns_from_definition(table_info["columns"])
|
columns = parse_columns_from_definition(table_info["columns"])
|
||||||
|
|
@ -514,14 +538,22 @@ async def itemsCreate(
|
||||||
status_code=status.HTTP_404_NOT_FOUND,
|
status_code=status.HTTP_404_NOT_FOUND,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
try:
|
||||||
is_admin = check_if_admin_access_token(connector, access_token)
|
is_admin = check_if_admin_access_token(connector, access_token)
|
||||||
if table_info["system"] and not is_admin:
|
if table_info["system"] and not is_admin:
|
||||||
return JSONResponse(
|
raise Exception("Not allowed")
|
||||||
ErrorResponse(error="Not allowed").dict(),
|
|
||||||
status_code=status.HTTP_403_FORBIDDEN,
|
|
||||||
)
|
|
||||||
|
|
||||||
user, group = get_user_by_access_token(connector, access_token)
|
user, group = get_user_by_access_token(connector, access_token)
|
||||||
|
if not user:
|
||||||
|
raise Exception("Not allowed")
|
||||||
|
acl = get_user_permissions_for_table(connector, tableName, user)
|
||||||
|
if acl != AccessType.WRITE and acl != AccessType.READ_WRITE:
|
||||||
|
raise Exception("Not allowed")
|
||||||
|
except Exception as e:
|
||||||
|
return JSONResponse(
|
||||||
|
ErrorResponse(error=str(e)).dict(), status_code=status.HTTP_403_FORBIDDEN
|
||||||
|
)
|
||||||
|
|
||||||
if not is_admin:
|
if not is_admin:
|
||||||
allowedColumns = get_allowed_columns_for_group(
|
allowedColumns = get_allowed_columns_for_group(
|
||||||
connector, tableName, group.id if group else -1
|
connector, tableName, group.id if group else -1
|
||||||
|
|
@ -597,14 +629,22 @@ async def itemsUpdate(
|
||||||
status_code=status.HTTP_404_NOT_FOUND,
|
status_code=status.HTTP_404_NOT_FOUND,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
try:
|
||||||
is_admin = check_if_admin_access_token(connector, access_token)
|
is_admin = check_if_admin_access_token(connector, access_token)
|
||||||
if table_info["system"] and not is_admin:
|
if table_info["system"] and not is_admin:
|
||||||
return JSONResponse(
|
raise Exception("Not allowed")
|
||||||
ErrorResponse(error="Not allowed").dict(),
|
|
||||||
status_code=status.HTTP_403_FORBIDDEN,
|
|
||||||
)
|
|
||||||
|
|
||||||
user, group = get_user_by_access_token(connector, access_token)
|
user, group = get_user_by_access_token(connector, access_token)
|
||||||
|
if not user:
|
||||||
|
raise Exception("Not allowed")
|
||||||
|
acl = get_user_permissions_for_table(connector, tableName, user)
|
||||||
|
if acl != AccessType.WRITE and acl != AccessType.READ_WRITE:
|
||||||
|
raise Exception("Not allowed")
|
||||||
|
except Exception as e:
|
||||||
|
return JSONResponse(
|
||||||
|
ErrorResponse(error=str(e)).dict(), status_code=status.HTTP_403_FORBIDDEN
|
||||||
|
)
|
||||||
|
|
||||||
if not is_admin:
|
if not is_admin:
|
||||||
allowedColumns = get_allowed_columns_for_group(
|
allowedColumns = get_allowed_columns_for_group(
|
||||||
connector, tableName, group.id if group else -1
|
connector, tableName, group.id if group else -1
|
||||||
|
|
@ -682,17 +722,25 @@ async def itemsDelete(
|
||||||
status_code=status.HTTP_404_NOT_FOUND,
|
status_code=status.HTTP_404_NOT_FOUND,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
try:
|
||||||
is_admin = check_if_admin_access_token(connector, access_token)
|
is_admin = check_if_admin_access_token(connector, access_token)
|
||||||
if table_info["system"] and not is_admin:
|
if table_info["system"] and not is_admin:
|
||||||
return JSONResponse(
|
raise Exception("Not allowed")
|
||||||
ErrorResponse(error="Not allowed").dict(),
|
|
||||||
status_code=status.HTTP_403_FORBIDDEN,
|
|
||||||
)
|
|
||||||
|
|
||||||
user, group = get_user_by_access_token(connector, access_token)
|
user, group = get_user_by_access_token(connector, access_token)
|
||||||
|
if not user:
|
||||||
|
raise Exception("Not allowed")
|
||||||
|
acl = get_user_permissions_for_table(connector, tableName, user)
|
||||||
|
if acl != AccessType.WRITE and acl != AccessType.READ_WRITE:
|
||||||
|
raise Exception("Not allowed")
|
||||||
|
except Exception as e:
|
||||||
|
return JSONResponse(
|
||||||
|
ErrorResponse(error=str(e)).dict(), status_code=status.HTTP_403_FORBIDDEN
|
||||||
|
)
|
||||||
|
|
||||||
if not is_admin:
|
if not is_admin:
|
||||||
allowedColumns = get_allowed_columns_for_group(
|
allowedColumns = get_allowed_columns_for_group(
|
||||||
connector, tableName, group.id if group else -1
|
connector, tableName, group.id if group else 1
|
||||||
)
|
)
|
||||||
if not allowedColumns:
|
if not allowedColumns:
|
||||||
return JSONResponse(
|
return JSONResponse(
|
||||||
|
|
@ -730,16 +778,21 @@ async def itemsDelete(
|
||||||
},
|
},
|
||||||
403: {
|
403: {
|
||||||
"model": ErrorResponse,
|
"model": ErrorResponse,
|
||||||
"description": "Requesting this endpoint requires admin access token",
|
"description": "Requesting this endpoint requires permissions",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
async def getAssets(access_token: str | None = Header(default=None)):
|
async def getAssets(access_token: str | None = Header(default=None)):
|
||||||
is_admin = check_if_admin_access_token(connector, access_token)
|
try:
|
||||||
if not is_admin:
|
user, _ = get_user_by_access_token(connector, access_token)
|
||||||
|
if not user:
|
||||||
|
raise Exception("Not allowed")
|
||||||
|
acl = get_user_permissions_for_table(connector, "assets", user)
|
||||||
|
if acl != AccessType.READ and acl != AccessType.READ_WRITE:
|
||||||
|
raise Exception("Not allowed")
|
||||||
|
except Exception as e:
|
||||||
return JSONResponse(
|
return JSONResponse(
|
||||||
ErrorResponse(error="Not allowed").dict(),
|
ErrorResponse(error=str(e)).dict(), status_code=status.HTTP_403_FORBIDDEN
|
||||||
status_code=status.HTTP_403_FORBIDDEN,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
assets = get_assets(connector)
|
assets = get_assets(connector)
|
||||||
|
|
@ -761,11 +814,16 @@ async def getAssets(access_token: str | None = Header(default=None)):
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
async def getAssetsTags(access_token: str | None = Header(default=None)):
|
async def getAssetsTags(access_token: str | None = Header(default=None)):
|
||||||
is_admin = check_if_admin_access_token(connector, access_token)
|
try:
|
||||||
if not is_admin:
|
user, _ = get_user_by_access_token(connector, access_token)
|
||||||
|
if not user:
|
||||||
|
raise Exception("Not allowed")
|
||||||
|
acl = get_user_permissions_for_table(connector, "assets", user)
|
||||||
|
if acl != AccessType.READ and acl != AccessType.READ_WRITE:
|
||||||
|
raise Exception("Not allowed")
|
||||||
|
except Exception as e:
|
||||||
return JSONResponse(
|
return JSONResponse(
|
||||||
ErrorResponse(error="Not allowed").dict(),
|
ErrorResponse(error=str(e)).dict(), status_code=status.HTTP_403_FORBIDDEN
|
||||||
status_code=status.HTTP_403_FORBIDDEN,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
assets = get_assets_tags(connector)
|
assets = get_assets_tags(connector)
|
||||||
|
|
@ -833,11 +891,16 @@ async def createAsset(
|
||||||
asset: UploadFile,
|
asset: UploadFile,
|
||||||
access_token: str | None = Header(default=None),
|
access_token: str | None = Header(default=None),
|
||||||
):
|
):
|
||||||
|
try:
|
||||||
user, _ = get_user_by_access_token(connector, access_token)
|
user, _ = get_user_by_access_token(connector, access_token)
|
||||||
if not user:
|
if not user:
|
||||||
|
raise Exception("Not allowed")
|
||||||
|
acl = get_user_permissions_for_table(connector, "assets", user)
|
||||||
|
if acl != AccessType.WRITE and acl != AccessType.READ_WRITE:
|
||||||
|
raise Exception("Not allowed")
|
||||||
|
except Exception as e:
|
||||||
return JSONResponse(
|
return JSONResponse(
|
||||||
ErrorResponse(error="Not allowed").dict(),
|
ErrorResponse(error=str(e)).dict(), status_code=status.HTTP_403_FORBIDDEN
|
||||||
status_code=status.HTTP_403_FORBIDDEN,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
filename = asset.filename
|
filename = asset.filename
|
||||||
|
|
@ -902,14 +965,21 @@ async def updateAsset(
|
||||||
asset_update: AssetUpdateDefinition,
|
asset_update: AssetUpdateDefinition,
|
||||||
access_token: str | None = Header(default=None),
|
access_token: str | None = Header(default=None),
|
||||||
):
|
):
|
||||||
user = get_user_by_access_token(connector, access_token)
|
try:
|
||||||
|
user, _ = get_user_by_access_token(connector, access_token)
|
||||||
if not user:
|
if not user:
|
||||||
|
raise Exception("Not allowed")
|
||||||
|
acl = get_user_permissions_for_table(connector, "assets", user)
|
||||||
|
if acl != AccessType.WRITE and acl != AccessType.READ_WRITE:
|
||||||
|
raise Exception("Not allowed")
|
||||||
|
except Exception as e:
|
||||||
return JSONResponse(
|
return JSONResponse(
|
||||||
ErrorResponse(error="Not allowed").dict(),
|
ErrorResponse(error=str(e)).dict(), status_code=status.HTTP_403_FORBIDDEN
|
||||||
status_code=status.HTTP_403_FORBIDDEN,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
ok, e = update_asset(connector, asset_id, asset_update.description, asset_update.tags)
|
ok, e = update_asset(
|
||||||
|
connector, asset_id, asset_update.description, asset_update.tags
|
||||||
|
)
|
||||||
if not ok:
|
if not ok:
|
||||||
if e:
|
if e:
|
||||||
return JSONResponse(
|
return JSONResponse(
|
||||||
|
|
@ -952,11 +1022,16 @@ async def removeAsset(
|
||||||
delete_referencing: bool = False,
|
delete_referencing: bool = False,
|
||||||
access_token: str | None = Header(default=None),
|
access_token: str | None = Header(default=None),
|
||||||
):
|
):
|
||||||
user = get_user_by_access_token(connector, access_token)
|
try:
|
||||||
|
user, _ = get_user_by_access_token(connector, access_token)
|
||||||
if not user:
|
if not user:
|
||||||
|
raise Exception("Not allowed")
|
||||||
|
acl = get_user_permissions_for_table(connector, "assets", user)
|
||||||
|
if acl != AccessType.WRITE and acl != AccessType.READ_WRITE:
|
||||||
|
raise Exception("Not allowed")
|
||||||
|
except Exception as e:
|
||||||
return JSONResponse(
|
return JSONResponse(
|
||||||
ErrorResponse(error="Not allowed").dict(),
|
ErrorResponse(error=str(e)).dict(), status_code=status.HTTP_403_FORBIDDEN
|
||||||
status_code=status.HTTP_403_FORBIDDEN,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
asset = get_asset_by_id(connector, asset_id)
|
asset = get_asset_by_id(connector, asset_id)
|
||||||
|
|
@ -967,7 +1042,7 @@ async def removeAsset(
|
||||||
)
|
)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
minioClient.remove_object(BUCKET_NAME, asset.fid)
|
minioClient.remove_object(BUCKET_NAME, asset.name)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"Failed to remove asset from storage: {e}")
|
logger.error(f"Failed to remove asset from storage: {e}")
|
||||||
return JSONResponse(
|
return JSONResponse(
|
||||||
|
|
|
||||||
42
dba.py
42
dba.py
|
|
@ -206,6 +206,20 @@ def get_user_by_access_token(conn: DBConnector, access_token: str | None):
|
||||||
return None, None
|
return None, None
|
||||||
|
|
||||||
|
|
||||||
|
def get_user_permissions_for_table(conn: DBConnector, table_name:str, user: User) -> AccessType:
|
||||||
|
try:
|
||||||
|
groups = get_user_groups(conn, user.id)
|
||||||
|
for g in groups:
|
||||||
|
acl = get_table_access_level(conn, table_name, g)
|
||||||
|
if acl is not None and acl != AccessType.NONE:
|
||||||
|
return acl
|
||||||
|
|
||||||
|
return AccessType.NONE
|
||||||
|
except Exception as e:
|
||||||
|
logger.exception(e)
|
||||||
|
return AccessType.NONE
|
||||||
|
|
||||||
|
|
||||||
def check_user(conn: DBConnector, username: str, password: str):
|
def check_user(conn: DBConnector, username: str, password: str):
|
||||||
try:
|
try:
|
||||||
hashedPwd = hash_password(password)
|
hashedPwd = hash_password(password)
|
||||||
|
|
@ -294,6 +308,25 @@ def set_user_group(conn: DBConnector, user_id: int, group_id: int):
|
||||||
return False, e
|
return False, e
|
||||||
|
|
||||||
|
|
||||||
|
def get_user_groups(conn: DBConnector, user_id: int) -> list[UserGroup]:
|
||||||
|
try:
|
||||||
|
_groups = conn.filterFromTable(
|
||||||
|
USER_IN_USER_GROUP_JOIN_TABLE_NAME,
|
||||||
|
["*"],
|
||||||
|
[ColumnCondition("user_id", "eq", user_id)],
|
||||||
|
)
|
||||||
|
if len(_groups) == 0:
|
||||||
|
logger.warning(f"User with id {user_id} not found, so no group")
|
||||||
|
return []
|
||||||
|
|
||||||
|
u_groups = [UserInUserGroup.parse_obj(group) for group in _groups]
|
||||||
|
groups = [get_group_by_id(conn, ug.user_group_id) for ug in u_groups]
|
||||||
|
return [group for group in groups if group is not None]
|
||||||
|
except Exception as e:
|
||||||
|
logger.exception(e)
|
||||||
|
return []
|
||||||
|
|
||||||
|
|
||||||
def get_user_group(conn: DBConnector, user_id: int):
|
def get_user_group(conn: DBConnector, user_id: int):
|
||||||
try:
|
try:
|
||||||
grp_usr_joint = conn.filterFromTable(
|
grp_usr_joint = conn.filterFromTable(
|
||||||
|
|
@ -353,13 +386,10 @@ def create_table(conn: DBConnector, table_name: str, schema: list[ColumnDefiniti
|
||||||
|
|
||||||
|
|
||||||
def get_table_access_level(
|
def get_table_access_level(
|
||||||
conn: DBConnector, table_name: str, user_id: int
|
conn: DBConnector, table_name: str, group: UserGroup
|
||||||
) -> AccessType:
|
) -> AccessType:
|
||||||
try:
|
try:
|
||||||
user_group = get_user_group(conn, user_id)
|
if group.id == 2 and group.name == "admin":
|
||||||
if not user_group:
|
|
||||||
return AccessType.NONE
|
|
||||||
elif user_group.name == "admin":
|
|
||||||
return AccessType.READ_WRITE
|
return AccessType.READ_WRITE
|
||||||
|
|
||||||
access = conn.filterFromTable(
|
access = conn.filterFromTable(
|
||||||
|
|
@ -367,7 +397,7 @@ def get_table_access_level(
|
||||||
["*"],
|
["*"],
|
||||||
[
|
[
|
||||||
ColumnCondition("table_name", "eq", table_name),
|
ColumnCondition("table_name", "eq", table_name),
|
||||||
ColumnCondition("user_group_id", "eq", user_group.id),
|
ColumnCondition("user_group_id", "eq", group.id),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
if not access:
|
if not access:
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue