New way to check table and routes access

This commit is contained in:
Andrew 2023-04-29 01:09:01 +07:00
parent a5aad5b5ea
commit b799d1312b
2 changed files with 166 additions and 61 deletions

167
app.py
View file

@ -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
View file

@ -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: