Skip to content

Commit

Permalink
fix: enable groups/teams auth via getIdentity (#4418)
Browse files Browse the repository at this point in the history
  • Loading branch information
adrians5j authored Nov 29, 2024
1 parent b205212 commit c597750
Show file tree
Hide file tree
Showing 3 changed files with 91 additions and 88 deletions.
28 changes: 23 additions & 5 deletions packages/api-security-cognito/src/createCognito.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import {
Config as CognitoConfig,
TokenData
} from "@webiny/api-cognito-authenticator";
import { createGroupAuthorizer } from "~/createGroupAuthorizer";
import { createGroupsTeamsAuthorizerHandler } from "@webiny/api-security";
import { CoreContext } from "~/types";
import { createAdminUsersHooks } from "./createAdminUsersHooks";
import adminUsersGqlPlugins from "./graphql/user.gql";
Expand All @@ -24,7 +24,9 @@ interface GetPermissionsParams<TContext> {

interface Config<TContext, TToken, TIdentity> extends CognitoConfig {
identityType: string;

getIdentity?(params: GetIdentityParams<TContext, TToken, TIdentity>): TIdentity;

getPermissions?(params: GetPermissionsParams<TContext>): Promise<SecurityPermission[] | null>;
}

Expand All @@ -33,9 +35,26 @@ export interface CognitoTokenData extends TokenData {
family_name: string;
email: string;
"custom:id": string;

[key: string]: any;
}

const mustAddGroupsTeamsAuthorizer = (identity: SecurityIdentity) => {
if ("group" in identity) {
return true;
}

if ("groups" in identity) {
return true;
}

if ("team" in identity) {
return true;
}

return "teams" in identity;
};

export const createCognito = <
TContext extends CoreContext = CoreContext,
TToken extends CognitoTokenData = CognitoTokenData,
Expand Down Expand Up @@ -77,10 +96,9 @@ export const createCognito = <
context
});

if (customIdentity.group) {
context.security.addAuthorizer(
createGroupAuthorizer(context, customIdentity.group)
);
if (mustAddGroupsTeamsAuthorizer(customIdentity)) {
const authorizer = createGroupsTeamsAuthorizerHandler(config, context);
context.security.addAuthorizer(authorizer);
}

return customIdentity;
Expand Down
25 changes: 0 additions & 25 deletions packages/api-security-cognito/src/createGroupAuthorizer.ts

This file was deleted.

126 changes: 68 additions & 58 deletions packages/api-security/src/utils/createGroupsTeamsAuthorizer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,78 +7,88 @@ import {

export type { GroupsTeamsAuthorizerConfig };

export const createGroupsTeamsAuthorizer = <TContext extends SecurityContext = SecurityContext>(
config: GroupsTeamsAuthorizerConfig<TContext>
export const createGroupsTeamsAuthorizerHandler = <
TContext extends SecurityContext = SecurityContext
>(
config: GroupsTeamsAuthorizerConfig<TContext>,
context: TContext
) => {
return new ContextPlugin<TContext>(context => {
return async () => {
const { security, tenancy } = context;
security.addAuthorizer(async () => {
const identity = security.getIdentity();
if (!identity) {
return null;
}
const identity = security.getIdentity();
if (!identity) {
return null;
}

// If `identityType` is specified, we'll only execute this authorizer for a matching identity.
if (config.identityType && identity.type !== config.identityType) {
return null;
}
// If `identityType` is specified, we'll only execute this authorizer for a matching identity.
if (config.identityType && identity.type !== config.identityType) {
return null;
}

// @ts-expect-error Check `packages/api-security/src/plugins/tenantLinkAuthorization.ts:23`.
const locale = context.i18n?.getContentLocale();
if (!locale) {
return null;
}
// @ts-expect-error Check `packages/api-security/src/plugins/tenantLinkAuthorization.ts:23`.
const locale = context.i18n?.getContentLocale();
if (!locale) {
return null;
}

if (config.canAccessTenant) {
const canAccessTenant = await config.canAccessTenant(context);
if (!canAccessTenant) {
return [];
}
if (config.canAccessTenant) {
const canAccessTenant = await config.canAccessTenant(context);
if (!canAccessTenant) {
return [];
}
}

const currentTenantPermissions = await listPermissionsFromGroupsAndTeams<TContext>({
config,
context,
identity,
localeCode: locale.code
});
const currentTenantPermissions = await listPermissionsFromGroupsAndTeams<TContext>({
config,
context,
identity,
localeCode: locale.code
});

if (Array.isArray(currentTenantPermissions)) {
return currentTenantPermissions;
}
if (Array.isArray(currentTenantPermissions)) {
return currentTenantPermissions;
}

// If no security groups were found, it could be due to an identity accessing a sub-tenant. In this case,
// let's try loading permissions from the parent tenant. Note that this will work well for flat tenant
// hierarchy where there's a `root` tenant and 1 level of sibling sub-tenants. For multi-level hierarchy,
// the best approach is to code a plugin with the desired permissions-fetching logic.
if (config.inheritGroupsFromParentTenant === false) {
return null;
}
// If no security groups were found, it could be due to an identity accessing a sub-tenant. In this case,
// let's try loading permissions from the parent tenant. Note that this will work well for flat tenant
// hierarchy where there's a `root` tenant and 1 level of sibling sub-tenants. For multi-level hierarchy,
// the best approach is to code a plugin with the desired permissions-fetching logic.
if (config.inheritGroupsFromParentTenant === false) {
return null;
}

const parentTenantId = context.tenancy.getCurrentTenant().parent;
if (!parentTenantId) {
return null;
}
const parentTenantId = context.tenancy.getCurrentTenant().parent;
if (!parentTenantId) {
return null;
}

const parentTenant = await tenancy.getTenantById(parentTenantId);
if (!parentTenant) {
return null;
}
const parentTenant = await tenancy.getTenantById(parentTenantId);
if (!parentTenant) {
return null;
}

const parentTenantPermissions = await tenancy.withTenant(parentTenant, async () => {
return listPermissionsFromGroupsAndTeams({
config,
context,
identity,
localeCode: locale.code
});
const parentTenantPermissions = await tenancy.withTenant(parentTenant, async () => {
return listPermissionsFromGroupsAndTeams({
config,
context,
identity,
localeCode: locale.code
});
});

if (Array.isArray(parentTenantPermissions)) {
return parentTenantPermissions;
}
if (Array.isArray(parentTenantPermissions)) {
return parentTenantPermissions;
}

return null;
});
return null;
};
};

export const createGroupsTeamsAuthorizer = <TContext extends SecurityContext = SecurityContext>(
config: GroupsTeamsAuthorizerConfig<TContext>
) => {
return new ContextPlugin<TContext>(context => {
const gcc = createGroupsTeamsAuthorizerHandler(config, context);
context.security.addAuthorizer(gcc);
});
};

0 comments on commit c597750

Please sign in to comment.