Skip to content

Commit

Permalink
Get all API keys as list via admin get_all_apikeys REST API.
Browse files Browse the repository at this point in the history
  • Loading branch information
vmdocua committed Sep 19, 2023
1 parent f2c3081 commit 3a36ecc
Show file tree
Hide file tree
Showing 4 changed files with 76 additions and 20 deletions.
9 changes: 9 additions & 0 deletions repromon_app/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,15 @@ class BasePydantic(BaseModel, BaseDTO):
pass


class ApiKeyInfoDTO(BasePydantic):
"""API key info
"""

username: str = None
apikey: str = None
issued_on: datetime.datetime = None


class LoginInfoDTO(BasePydantic):
"""Logged user info
"""
Expand Down
32 changes: 23 additions & 9 deletions repromon_app/router/api_v1.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@
from fastapi import (APIRouter, Depends, Query, Request, WebSocket,
WebSocketDisconnect, WebSocketException)

from repromon_app.model import (DataProviderId, DeviceEntity, LoginInfoDTO,
MessageCategoryId, MessageLevelId,
MessageLogEntity, MessageLogInfoDTO,
PushMessageDTO, RoleEntity, Rolename,
StudyInfoDTO, UserEntity)
from repromon_app.model import (ApiKeyInfoDTO, DataProviderId, DeviceEntity,
LoginInfoDTO, MessageCategoryId,
MessageLevelId, MessageLogEntity,
MessageLogInfoDTO, PushMessageDTO, RoleEntity,
Rolename, StudyInfoDTO, UserEntity)
from repromon_app.security import (ApiKey, SecurityContext, SecurityManager,
Token, security_check, security_context,
web_oauth2_apikey_context,
Expand Down Expand Up @@ -428,6 +428,21 @@ def secsys_create_apikey(request: Request,
svc: SecSysService = SecSysService()
return svc.create_apikey()

# @security: admin
@api_v1_router.get("/secsys/get_all_apikeys",
response_model=list[ApiKeyInfoDTO],
tags=["SecSysService"],
summary="get_all_apikeys",
description="Get all API keys as list")
def secsys_get_all_apikeys(request: Request,
sec_ctx:
Annotated[SecurityContext, Depends(web_oauth2_context)],
) -> list[ApiKeyInfoDTO]:
logger.debug("secsys_get_all_apikeys()")
security_check(rolename=Rolename.ADMIN)
svc: SecSysService = SecSysService()
return svc.get_all_apikeys()

# @security: admin
@api_v1_router.get("/secsys/get_apikey_hash",
response_model=object,
Expand Down Expand Up @@ -468,7 +483,7 @@ def secsys_get_password_hash(request: Request,

# @security: admin
@api_v1_router.get("/secsys/get_user_apikey",
response_model=object,
response_model=ApiKeyInfoDTO,
tags=["SecSysService"],
summary="get_user_apikey",
description="Get user current API key if any")
Expand All @@ -478,12 +493,11 @@ def secsys_get_user_apikey(request: Request,
username: str =
Query(...,
description="Specify username"),
) -> UserEntity:
) -> ApiKeyInfoDTO:
logger.debug(f"secsys_get_user_apikey(username={username})")
security_check(rolename=Rolename.ADMIN)
svc: SecSysService = SecSysService()
key: ApiKey = svc.get_user_apikey(username)
return {"username": username, "apikey": key.key}
return svc.get_user_apikey(username)

# @security: admin
@api_v1_router.get("/secsys/get_user_devices",
Expand Down
22 changes: 16 additions & 6 deletions repromon_app/security.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ class ApiKey(BaseModel):
prefix: str
body: str
data: str
issued_on: datetime = None


# class representing current security context
Expand Down Expand Up @@ -146,7 +147,8 @@ def calculate_apikey(self, apikey_data: str) -> ApiKey:
# create key as prefix.body
key = f"{prefix}.{body}"
# logger.debug(f"key={key}")
return ApiKey(key=key, prefix=prefix, body=body, data=apikey_data)
return ApiKey(key=key, prefix=prefix, body=body,
data=apikey_data, issued_on=None)

def create_apikey(self) -> ApiKey:
logger.debug("create_apikey()")
Expand Down Expand Up @@ -201,19 +203,27 @@ def create_context_by_username(self, username: str) -> SecurityContext:
self.__context_cache[username] = ctx
return ctx

def get_apikey_by_user(self, username: str) -> ApiKey:
u: UserEntity = self._get_cached_user(username)

def get_apikey_by_entity(self, u: UserEntity) -> ApiKey:
if not u:
raise Exception(f"User not found: {username}")
raise Exception("User is null")

if not u.apikey_data:
raise Exception("User doesn't have API key")

if len(u.apikey_data) < 16:
raise Exception("User doesn't have valid API key")

return self.calculate_apikey(u.apikey_data)
key: ApiKey = self.calculate_apikey(u.apikey_data)
key.issued_on = u.apikey_issued_on
return key

def get_apikey_by_user(self, username: str) -> ApiKey:
u: UserEntity = self._get_cached_user(username)

if not u:
raise Exception(f"User not found: {username}")

return self.get_apikey_by_entity(u)

def get_apikey_hash(self, apikey: str) -> str:
if not apikey:
Expand Down
33 changes: 28 additions & 5 deletions repromon_app/service.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@

from repromon_app.config import app_settings
from repromon_app.dao import DAO
from repromon_app.model import (DeviceEntity, LoginInfoDTO, MessageLevelId,
MessageLogEntity, MessageLogInfoDTO,
PushMessageDTO, RoleEntity,
from repromon_app.model import (ApiKeyInfoDTO, DeviceEntity, LoginInfoDTO,
MessageLevelId, MessageLogEntity,
MessageLogInfoDTO, PushMessageDTO, RoleEntity,
SecUserDeviceEntity, SecUserRoleEntity,
StudyDataEntity, StudyInfoDTO, UserEntity)
from repromon_app.security import (ApiKey, SecurityManager, Token,
Expand Down Expand Up @@ -242,6 +242,12 @@ class SecSysService(BaseService):
def __init__(self):
super().__init__()

def _apikey_info(self, username: str, key: ApiKey) -> ApiKeyInfoDTO:
o: ApiKeyInfoDTO = ApiKeyInfoDTO(username=username,
apikey=key.key,
issued_on=key.issued_on)
return o

def calculate_apikey(self, apikey_data: str) -> str:
logger.debug(f"calculate_apikey(apikey_data={apikey_data})")
apikey: ApiKey = SecurityManager.instance().calculate_apikey(apikey_data)
Expand All @@ -263,6 +269,17 @@ def create_apikey(self) -> ApiKey:
logger.debug("create_apikey()")
return SecurityManager.instance().create_apikey()

def get_all_apikeys(self) -> list[ApiKeyInfoDTO]:
lst: list[UserEntity] = DAO.account.get_users()
lst = [u for u in lst if u.apikey_data and len(u.apikey_data) > 1]
lst2 = []
for u in lst:
try:
lst2.append(self.get_user_entity_apikey(u))
except BaseException as e:
logger.error(f"Failed calculate apikey for u={u}. {str(e)}")
return lst2

def get_apikey_hash(self, apikey: str) -> str:
logger.debug("get_apikey_hash(...)")
return SecurityManager.instance().get_apikey_hash(apikey)
Expand All @@ -271,9 +288,15 @@ def get_password_hash(self, pwd: str) -> str:
logger.debug("get_password_hash(...)")
return SecurityManager.instance().get_password_hash(pwd)

def get_user_apikey(self, username: str) -> ApiKey:
def get_user_apikey(self, username: str) -> ApiKeyInfoDTO:
logger.debug(f"get_user_apikey(username={username})")
return SecurityManager.instance().get_apikey_by_user(username)
key: ApiKey = SecurityManager.instance().get_apikey_by_user(username)
return self._apikey_info(username, key)

def get_user_entity_apikey(self, u: UserEntity) -> ApiKeyInfoDTO:
logger.debug("get_user_entity_apikey(...)")
key: ApiKey = SecurityManager.instance().get_apikey_by_entity(u)
return self._apikey_info(u.username, key)

def get_user_devices(self, username: str) -> list[str]:
logger.debug(f"get_user_devices(username={username})")
Expand Down

0 comments on commit 3a36ecc

Please sign in to comment.