diff --git a/app/database.py b/app/database.py index b67e276..c547c36 100644 --- a/app/database.py +++ b/app/database.py @@ -5,9 +5,12 @@ def get_session(): # Initialize config_file = 'config.global.py' + db_params = configParser.getConfig('database_parameters', config_file) - url = configParser.getConfig('database_parameters', config_file)['database_url'] - engine = create_engine(url) + url = db_params['database_url'] + pool_size = int(db_params.get('pool_size', 25)) + max_overflow = int(db_params.get('max_overflow', 5)) + engine = create_engine(url, pool_size=pool_size, max_overflow=max_overflow) with Session(engine) as session: yield session diff --git a/app/logger/log.py b/app/logger/log.py index d38b485..1a10ae7 100644 --- a/app/logger/log.py +++ b/app/logger/log.py @@ -3,8 +3,7 @@ from app.utils import configParser from logging.handlers import TimedRotatingFileHandler -FORMATTER = logging.Formatter("""%(asctime)s - %(name)s - %(levelname)s - - %(message)s""") +FORMATTER = logging.Formatter("""%(asctime)s - %(name)s - %(levelname)s - %(message)s""") LOG_FILE = "{0}/{1}".format(configParser.getConfig('logging', 'config.global.py')['folder'], configParser.getConfig('logging', 'config.global.py')['file']) LEVEL = configParser.getConfig('logging', 'config.global.py')['level'] diff --git a/app/routers/authenticate.py b/app/routers/authenticate.py index bc4474b..1f3f072 100644 --- a/app/routers/authenticate.py +++ b/app/routers/authenticate.py @@ -1,4 +1,5 @@ from pprint import pprint +from app.logger import log from typing import Annotated, Any from fastapi import APIRouter, Depends, HTTPException, status, Security, Request @@ -18,13 +19,15 @@ # responses={404: {"description": "Not found"}}, ) +logger = log.get_logger("authenticate") + def initializeAuthOb(): config_file = 'config.' + g.tenant + '.' + g.environment + '.py' oidc_config = configParser.getConfig('oidc_client', config_file) oauth = OAuth() oauth.register( - 'rciam', + g.tenant + '.' + g.environment + '.rciam', client_id=oidc_config['client_id'], client_secret=oidc_config['client_secret'], server_metadata_url=oidc_config['issuer'] + "/.well-known/openid-configuration", @@ -43,7 +46,7 @@ async def login_endpoint( request: Request, oauth_ob= Depends(initializeAuthOb), server_config= Depends(getServerConfig)): - rciam = oauth_ob.create_client('rciam') + rciam = oauth_ob.create_client(g.tenant + '.' + g.environment + '.rciam') redirect_uri = server_config['protocol'] + "://" + server_config['host'] + server_config['api_path'] + "/auth" return await rciam.authorize_redirect(request, redirect_uri) @@ -68,7 +71,7 @@ async def authorize_rciam( response = RedirectResponse(url=urllib.parse.unquote(login_start_url)) response.delete_cookie("login_start") - rciam = oauth_ob.create_client('rciam') + rciam = oauth_ob.create_client(g.tenant + '.' + g.environment + '.rciam') try: token = await rciam.authorize_access_token(request) except OAuthError as error: @@ -119,7 +122,7 @@ async def authorize_rciam( # Authorization authorize_file = 'authorize.' + g.tenant + '.' + g.environment + '.py' - permissions = permissionsCalculation(authorize_file, user_info_data) + permissions = permissionsCalculation(logger, authorize_file, user_info_data) permissions_json = json.dumps(permissions).replace(" ", "").replace("\n", "") # Set the permissions cookie. @@ -145,7 +148,7 @@ async def logout( oauth_ob= Depends(initializeAuthOb), server_config=Depends(getServerConfig) ): - rciam = oauth_ob.create_client('rciam') + rciam = oauth_ob.create_client(g.tenant + '.' + g.environment + '.rciam') metadata = await rciam.load_server_metadata() # todo: Fix this after we complete the multitenacy redirect_uri = server_config['protocol'] + "://" + server_config['client'] +"/metrics" diff --git a/app/routers/communities.py b/app/routers/communities.py index 83047e9..27c6fac 100644 --- a/app/routers/communities.py +++ b/app/routers/communities.py @@ -43,7 +43,7 @@ async def read_min_date_communities( WHERE tenenv_id={0} """.format(tenenv_id)).one() return min_date -@router.get("/members_bystatus/") +@router.get("/members_bystatus") async def read_members_bystatus( *, session: Session = Depends(get_session), @@ -107,7 +107,7 @@ async def read_communities( return communities -@router.get("/communities/") +@router.get("/communities") async def read_community( *, session: Session = Depends(get_session), @@ -117,7 +117,7 @@ async def read_community( if community_id: sql_subquery = 'id={0} and'.format(community_id) community = session.exec(""" - SELECT * FROM community_info WHERE {0} tenenv_id={1} + SELECT * FROM community_info WHERE {0} tenenv_id={1} ORDER BY name ASC """.format(sql_subquery, tenenv_id)).all() # statement = select(Community).options(selectinload(Community.community_info)) # result = session.exec(statement) @@ -127,7 +127,7 @@ async def read_community( return community -@router.get("/communities_info/", response_model=List[Community_InfoRead]) +@router.get("/communities_info", response_model=List[Community_InfoRead]) async def read_communities_info( *, session: Session = Depends(get_session), diff --git a/app/utils/globalMethods.py b/app/utils/globalMethods.py index 6e4c202..d0b234f 100644 --- a/app/utils/globalMethods.py +++ b/app/utils/globalMethods.py @@ -1,4 +1,4 @@ -from pprint import pprint +from app.logger import log import requests as reqs from fastapi import Depends, FastAPI, HTTPException, Query, Request, HTTPException, status, Response import json, jwt @@ -10,19 +10,28 @@ # https://www.fastapitutorial.com/blog/class-based-dependency-injection/ class AuthNZCheck: + logger = log.get_logger("AuthNZCheck") + def __init__(self, tag: str = "", skip: bool = False): self.skip = skip self.tag = tag self.oauth = OAuth() async def __call__(self, request: Request, response: Response): + self.logger.debug("""=============== Request Context =================""") + self.logger.debug("""{0}.{1}: Request Url: {2}""" . format(g.tenant, g.environment, request.url)) + self.logger.debug("""{0}.{1}: Request Headers: {2}""" . format(g.tenant, g.environment, request.headers)) + # config authorize_file = 'authorize.' + g.tenant + '.' + g.environment + '.py' config_file = 'config.' + g.tenant + '.' + g.environment + '.py' oidc_config = configParser.getConfig('oidc_client', config_file) + self.logger.debug("""{0}.{1}: Authorize Config File Name: {2}""".format(g.tenant, g.environment, authorize_file)) + self.logger.debug("""{0}.{1}: Config File Name: {2}""".format(g.tenant, g.environment, config_file)) + self.oauth.register( - 'rciam', + g.tenant + '.' + g.environment + '.rciam', client_id=oidc_config['client_id'], client_secret=oidc_config['client_secret'], server_metadata_url=oidc_config['issuer'] + "/.well-known/openid-configuration", @@ -33,17 +42,19 @@ async def __call__(self, request: Request, response: Response): # permissions calculation access_token = request.headers.get('x-access-token') - rciam = self.oauth.create_client('rciam') + rciam = self.oauth.create_client(g.tenant + '.' + g.environment + '.rciam') metadata = await rciam.load_server_metadata() headers = {'Authorization': f'Bearer {access_token}'} + resp = reqs.get(metadata['userinfo_endpoint'], headers=headers) + self.logger.debug("""{0}.{1}: User Info Endpoint Response: {2}""" . format(g.tenant, g.environment, resp)) # Authentication if resp.status_code == 401: # For now we skip logins and dashboard routes if (self.tag == 'logins' or self.tag == 'dashboard') and self.skip: - permissions = permissionsCalculation(authorize_file) + permissions = permissionsCalculation(self.logger, authorize_file) permissions_json = json.dumps(permissions).replace(" ", "").replace("\n", "") # pprint(permissions_json) response.headers["X-Permissions"] = permissions_json @@ -51,6 +62,9 @@ async def __call__(self, request: Request, response: Response): response.headers["X-Redirect"] = "false" return + self.logger.debug("""{0}.{1}: Unauthorized request to User Info endpoint""") + self.logger.debug("""{0}.{1}: Response headers: {2}""" . format(g.tenant, g.environment, resp.headers)) + self.logger.debug("""{0}.{1}: Response body: {2}""" . format(g.tenant, g.environment, resp.json())) raise HTTPException( status_code=401, detail="Authentication failed", @@ -66,10 +80,13 @@ async def __call__(self, request: Request, response: Response): data = resp.json() except Exception as er: # TODO: Log here + self.logger.error("""{0}.{1}: error: {2}""".format(g.tenant, g.environment, er)) raise HTTPException(status_code=500) + self.logger.debug("""{0}.{1}: User Info Response: {2}""" . format(g.tenant, g.environment, data)) # Authorization - permissions = permissionsCalculation(authorize_file, data) + permissions = permissionsCalculation(self.logger, authorize_file, data) + self.logger.debug("""{0}.{1}: permissions: {2}""".format(g.tenant, g.environment, permissions)) permissions_json = json.dumps(permissions).replace(" ", "").replace("\n", "") # Add the permission to a custom header field @@ -82,7 +99,7 @@ async def __call__(self, request: Request, response: Response): HTTPException(status_code=403) -def permissionsCalculation(authorize_file, user_info=None): +def permissionsCalculation(logger, authorize_file, user_info=None): entitlements_config = configParser.getConfig('entitlements', authorize_file) user_entitlements = {} if user_info is not None: @@ -94,6 +111,9 @@ def permissionsCalculation(authorize_file, user_info=None): 'administrator': False } + logger.debug("""{0}.{1}: Entitlements Config: {2}""".format(g.tenant, g.environment, entitlements_config)) + logger.debug("""{0}.{1}: User Entitlements Config: {2}""".format(g.tenant, g.environment, user_entitlements)) + for ent, role in entitlements_config.items(): if user_entitlements is not None and ent in user_entitlements: # Reset the default anonymous role @@ -103,7 +123,7 @@ def permissionsCalculation(authorize_file, user_info=None): for item_role in role.split(","): roles[item_role] = True - # pprint(roles) + logger.debug("""{0}.{1}: roles: {2}""".format(g.tenant, g.environment, roles)) actions = { 'dashboard': { diff --git a/javascript/src/Pages/Communities/index.js b/javascript/src/Pages/Communities/index.js index e9e43f7..cf6fd93 100644 --- a/javascript/src/Pages/Communities/index.js +++ b/javascript/src/Pages/Communities/index.js @@ -25,6 +25,7 @@ const Communities = () => { [tenenvKey, {tenantId: tenant, environment: environment}], getTenenv, { retry: 0, + refetchOnWindowFocus: false }) useEffect(() => { diff --git a/javascript/src/components/Communities/communitiesDataTable.js b/javascript/src/components/Communities/communitiesDataTable.js index 2cfc371..c6e8b16 100644 --- a/javascript/src/components/Communities/communitiesDataTable.js +++ b/javascript/src/components/Communities/communitiesDataTable.js @@ -101,7 +101,6 @@ const CommunitiesDataTable = ({tenenvId}) => { // We only keep the first date because the backend returns the dataset sorted and we only care about the // min of the min dates. if (minDate == undefined || minDate == "") { - console.log(minDateCommunities?.data?.min_date) setMinDate(!!minDateCommunities?.data?.min_date ? new Date(minDateCommunities?.data?.min_date) : null) } $("#table-community").DataTable().destroy() diff --git a/javascript/src/components/Users/registeredUsersDataTable.js b/javascript/src/components/Users/registeredUsersDataTable.js index 511e43d..a003360 100644 --- a/javascript/src/components/Users/registeredUsersDataTable.js +++ b/javascript/src/components/Users/registeredUsersDataTable.js @@ -81,7 +81,6 @@ const RegisteredUsersDataTable = ({ params: params }]) queryClient.refetchQueries([minDateRegisteredUsersKey, {params:{tenenv_id: tenenvId}}]) - console.log(params) } catch (error) { // todo: Here we can handle any authentication or authorization errors console.log(error) @@ -90,7 +89,6 @@ const RegisteredUsersDataTable = ({ // Construct the data required for the datatable useEffect(() => { - console.log(registeredUsersPerCountryGroup) const perPeriod = registeredUsersPerCountryGroup?.data?.map(user => ({ "Date": !!user?.range_date ? convertDateByGroup(new Date(user?.range_date), groupBy): null, "Number of Registered Users": user?.count, diff --git a/javascript/src/utils/api/index.js b/javascript/src/utils/api/index.js index 9af0b94..504afec 100644 --- a/javascript/src/utils/api/index.js +++ b/javascript/src/utils/api/index.js @@ -33,7 +33,6 @@ const deleteCookie = (name, path, domain) => { const handleError = (error) => { console.log('error', error) - // debugger if (error?.response?.status == 401 && error?.response?.headers?.['x-authenticated'] == "false" && error?.response?.headers?.['x-redirect'] == "true" @@ -54,7 +53,7 @@ const client = axios.create({ "Content-type": "application/json", 'x-access-token': `${getCookie('atoken')}`, 'x-tenant': `${config.tenant}`, - 'x-environment': `${config.environment}`, + 'x-environment': `${config.environment}` }, validateStatus: function (status) { return status >= 200 && status < 300; // default diff --git a/javascript/src/utils/queries/index.js b/javascript/src/utils/queries/index.js index 2cfd5f9..72381e2 100644 --- a/javascript/src/utils/queries/index.js +++ b/javascript/src/utils/queries/index.js @@ -13,6 +13,7 @@ export const getTenenv = async ({queryKey}) => { return response.data } catch (error) { console.log('error', error) + console.log('queryKeys', queryKey) handleError(error) return error.response } @@ -26,6 +27,7 @@ export const getLoginsPerSP = async ({queryKey}) => { return response.data } catch (error) { console.log('error', error) + console.log('queryKeys', queryKey) handleError(error) return error.response } @@ -38,6 +40,7 @@ export const getLoginsPerIdp = async ({queryKey}) => { return response.data } catch (error) { console.log('error', error) + console.log('queryKeys', queryKey) handleError(error) return error.response } @@ -50,6 +53,7 @@ export const getLoginsPerCountry = async ({queryKey}) => { return response.data } catch (error) { console.log('error', error) + console.log('queryKeys', queryKey) handleError(error) return error.response } @@ -62,6 +66,7 @@ export const getMinDateLogins = async ({queryKey}) => { return response.data } catch (error) { console.log('error', error) + console.log('queryKeys', queryKey) handleError(error) return error.response } @@ -74,6 +79,7 @@ export const getMinDateCommunities = async ({queryKey}) => { return response.data } catch (error) { console.log('error', error) + console.log('queryKeys', queryKey) handleError(error) return error.response } @@ -86,6 +92,7 @@ export const getMinDateRegisteredUsers = async ({queryKey}) => { return response.data } catch (error) { console.log('error', error) + console.log('queryKeys', queryKey) handleError(error) return error.response } @@ -98,6 +105,7 @@ export const getLoginsGroupByDay = async ({queryKey}) => { return response.data } catch (error) { console.log('error', error) + console.log('queryKeys', queryKey) handleError(error) return error.response } @@ -110,6 +118,7 @@ export const getLoginsCountBy = async ({queryKey}) => { return response.data } catch (error) { console.log('error', error) + console.log('queryKeys', queryKey) handleError(error) return error.response } @@ -123,6 +132,7 @@ export const getIdps = async ({queryKey}) => { return response.data } catch (error) { console.log('error', error) + console.log('queryKeys', queryKey) handleError(error) return error.response } @@ -135,6 +145,7 @@ export const getSps = async ({queryKey}) => { return response.data } catch (error) { console.log('error', error) + console.log('queryKeys', queryKey) handleError(error) return error.response } @@ -148,6 +159,7 @@ export const getRegisteredUsersCountby = async ({queryKey}) => { return response.data } catch (error) { console.log('error', error) + console.log('queryKeys', queryKey) handleError(error) return error.response } @@ -160,6 +172,7 @@ export const getRegisteredUsersByCountry = async ({queryKey}) => { return response.data } catch (error) { console.log('error', error) + console.log('queryKeys', queryKey) handleError(error) return error.response } @@ -173,6 +186,7 @@ export const getCommunities = async ({queryKey}) => { return response.data } catch (error) { console.log('error', error) + console.log('queryKeys', queryKey) handleError(error) return error.response } @@ -185,6 +199,7 @@ export const getCommunityMembersByStatus = async ({queryKey}) => { return response.data } catch (error) { console.log('error', error) + console.log('queryKeys', queryKey) handleError(error) return error.response } @@ -197,6 +212,7 @@ export const getCountryStatsByVo = async ({queryKey}) => { return response.data } catch (error) { console.log('error', error) + console.log('queryKeys', queryKey) handleError(error) return error.response } @@ -211,6 +227,7 @@ export const getCommunitiesGroupBy = async ({queryKey}) => { return response.data } catch (error) { console.log('error', error) + console.log('queryKeys', queryKey) handleError(error) return error.response } @@ -225,6 +242,7 @@ export const getRegisteredUsersPerCountryGroupBy = async ({queryKey}) => { return response.data } catch (error) { console.log('error', error) + console.log('queryKeys', queryKey) handleError(error) return error.response } @@ -239,6 +257,7 @@ export const getRegisteredUsersGroupBy = async ({queryKey}) => { return response.data } catch (error) { console.log('error', error) + console.log('queryKeys', queryKey) handleError(error) return error.response }