44 addToTenant ,
55 getEntraIdToken ,
66 getGroupMetadata ,
7+ getServicePrincipalOwnedGroups ,
78 listGroupMembers ,
89 modifyGroup ,
910 patchUserProfile ,
@@ -18,15 +19,17 @@ import {
1819 NotFoundError ,
1920} from "../../common/errors/index.js" ;
2021import { DynamoDBClient , PutItemCommand } from "@aws-sdk/client-dynamodb" ;
21- import { genericConfig , roleArns } from "../../common/config.js" ;
22+ import {
23+ GENERIC_CACHE_SECONDS ,
24+ genericConfig ,
25+ roleArns ,
26+ } from "../../common/config.js" ;
2227import { marshall } from "@aws-sdk/util-dynamodb" ;
2328import {
2429 invitePostRequestSchema ,
2530 groupMappingCreatePostSchema ,
26- entraActionResponseSchema ,
2731 groupModificationPatchSchema ,
2832 EntraGroupActions ,
29- entraGroupMembershipListResponse ,
3033 entraProfilePatchRequest ,
3134} from "../../common/types/iam.js" ;
3235import {
@@ -44,6 +47,7 @@ import { AvailableSQSFunctions, SQSPayload } from "common/types/sqsMessage.js";
4447import { SendMessageBatchCommand , SQSClient } from "@aws-sdk/client-sqs" ;
4548import { v4 as uuidv4 } from "uuid" ;
4649import { randomUUID } from "crypto" ;
50+ import { getRedisKey , setRedisKey } from "api/functions/redisCache.js" ;
4751
4852const iamRoutes : FastifyPluginAsync = async ( fastify , _options ) => {
4953 const getAuthorizedClients = async ( ) => {
@@ -560,6 +564,52 @@ No action is required from you at this time.
560564 reply . status ( 200 ) . send ( response ) ;
561565 } ,
562566 ) ;
567+ fastify . withTypeProvider < FastifyZodOpenApiTypeProvider > ( ) . get (
568+ "/groups" ,
569+ {
570+ schema : withRoles (
571+ [ AppRoles . IAM_ADMIN ] ,
572+ withTags ( [ "IAM" ] , {
573+ summary : "Get all manageable groups." , // This is all groups where the Core API service principal is an owner.
574+ } ) ,
575+ ) ,
576+ onRequest : fastify . authorizeFromSchema ,
577+ } ,
578+ async ( request , reply ) => {
579+ const entraIdToken = await getEntraIdToken (
580+ await getAuthorizedClients ( ) ,
581+ fastify . environmentConfig . AadValidClientId ,
582+ undefined ,
583+ genericConfig . EntraSecretName ,
584+ ) ;
585+ const { redisClient } = fastify ;
586+ const key = `entra_manageable_groups_${ fastify . environmentConfig . EntraServicePrincipalId } ` ;
587+ const redisResponse = await getRedisKey <
588+ { displayName : string ; id : string } [ ]
589+ > ( { redisClient, key, parseJson : true } ) ;
590+ if ( redisResponse ) {
591+ request . log . debug ( "Got manageable groups from Redis cache." ) ;
592+ return reply . status ( 200 ) . send ( redisResponse ) ;
593+ }
594+ // get groups, but don't show protected groups as manageable
595+ const freshData = (
596+ await getServicePrincipalOwnedGroups (
597+ entraIdToken ,
598+ fastify . environmentConfig . EntraServicePrincipalId ,
599+ )
600+ ) . filter ( ( x ) => ! genericConfig . ProtectedEntraIDGroups . includes ( x . id ) ) ;
601+ request . log . debug (
602+ "Got manageable groups from Entra ID, setting to cache." ,
603+ ) ;
604+ await setRedisKey ( {
605+ redisClient,
606+ key,
607+ value : JSON . stringify ( freshData ) ,
608+ expiresSec : GENERIC_CACHE_SECONDS ,
609+ } ) ;
610+ return reply . status ( 200 ) . send ( freshData ) ;
611+ } ,
612+ ) ;
563613} ;
564614
565615export default iamRoutes ;
0 commit comments