Skip to content

Commit

Permalink
fix: improve groups/teams assignments (external IdPs) (#4349)
Browse files Browse the repository at this point in the history
  • Loading branch information
adrians5j authored Oct 23, 2024
1 parent 8ba6bab commit 7c018a1
Show file tree
Hide file tree
Showing 11 changed files with 262 additions and 181 deletions.
6 changes: 3 additions & 3 deletions packages/api-security-auth0/src/createAuth0.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import { createAuthenticator, AuthenticatorConfig } from "~/createAuthenticator";
import { createGroupAuthorizer, GroupAuthorizerConfig } from "~/createGroupAuthorizer";
import { createGroupsTeamsAuthorizer, GroupsTeamsAuthorizerConfig } from "@webiny/api-security";
import { createIdentityType } from "~/createIdentityType";
import { createAdminUsersHooks } from "./createAdminUsersHooks";
import { extendTenancy } from "./extendTenancy";
import { Context } from "~/types";

export interface CreateAuth0Config<TContext extends Context = Context>
extends AuthenticatorConfig,
GroupAuthorizerConfig<TContext> {
GroupsTeamsAuthorizerConfig<TContext> {
graphQLIdentityType?: string;
}

Expand All @@ -22,7 +22,7 @@ export const createAuth0 = <TContext extends Context = Context>(
domain: config.domain,
getIdentity: config.getIdentity
}),
createGroupAuthorizer<TContext>({
createGroupsTeamsAuthorizer<TContext>({
identityType,
getGroupSlug: config.getGroupSlug,
inheritGroupsFromParentTenant: config.inheritGroupsFromParentTenant,
Expand Down
94 changes: 0 additions & 94 deletions packages/api-security-auth0/src/createGroupAuthorizer.ts

This file was deleted.

18 changes: 16 additions & 2 deletions packages/api-security-auth0/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,20 @@
import {
createGroupsTeamsAuthorizer,
type GroupsTeamsAuthorizerConfig
} from "@webiny/api-security";

export { createIdentityType } from "./createIdentityType";
export { createAuthenticator } from "./createAuthenticator";
export type { AuthenticatorConfig } from "./createAuthenticator";
export { createGroupAuthorizer } from "./createGroupAuthorizer";
export type { GroupAuthorizerConfig } from "./createGroupAuthorizer";
export { createAuth0 } from "./createAuth0";

export { createGroupsTeamsAuthorizer, type GroupsTeamsAuthorizerConfig };

// Backwards compatibility.
// @deprecated Use `createGroupsTeamsAuthorizer` instead.
const createGroupAuthorizer = createGroupsTeamsAuthorizer;

// @deprecated Use `GroupsTeamsAuthorizerConfig` instead.
type GroupAuthorizerConfig = GroupsTeamsAuthorizerConfig;

export { createGroupAuthorizer, type GroupAuthorizerConfig };
77 changes: 0 additions & 77 deletions packages/api-security-okta/src/createGroupAuthorizer.ts

This file was deleted.

6 changes: 3 additions & 3 deletions packages/api-security-okta/src/createOkta.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import { createAuthenticator, AuthenticatorConfig } from "~/createAuthenticator";
import { createGroupAuthorizer, GroupAuthorizerConfig } from "~/createGroupAuthorizer";
import { createGroupsTeamsAuthorizer, GroupsTeamsAuthorizerConfig } from "@webiny/api-security";
import { createIdentityType } from "~/createIdentityType";
import { extendTenancy } from "./extendTenancy";
import { createAdminUsersHooks } from "./createAdminUsersHooks";
import { Context } from "~/types";

export interface CreateOktaConfig<TContext extends Context = Context>
extends AuthenticatorConfig,
GroupAuthorizerConfig<TContext> {
GroupsTeamsAuthorizerConfig<TContext> {
graphQLIdentityType?: string;
}

Expand All @@ -22,7 +22,7 @@ export const createOkta = <TContext extends Context = Context>(
issuer: config.issuer,
getIdentity: config.getIdentity
}),
createGroupAuthorizer<TContext>({
createGroupsTeamsAuthorizer<TContext>({
identityType,
getGroupSlug: config.getGroupSlug
}),
Expand Down
18 changes: 16 additions & 2 deletions packages/api-security-okta/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,20 @@
import {
createGroupsTeamsAuthorizer,
type GroupsTeamsAuthorizerConfig
} from "@webiny/api-security";

export { createIdentityType } from "./createIdentityType";
export { createAuthenticator } from "./createAuthenticator";
export type { AuthenticatorConfig } from "./createAuthenticator";
export { createGroupAuthorizer } from "./createGroupAuthorizer";
export type { GroupAuthorizerConfig } from "./createGroupAuthorizer";
export { createOkta } from "./createOkta";

export { createGroupsTeamsAuthorizer, type GroupsTeamsAuthorizerConfig };

// Backwards compatibility.
// @deprecated Use `createGroupsTeamsAuthorizer` instead.
const createGroupAuthorizer = createGroupsTeamsAuthorizer;

// @deprecated Use `GroupsTeamsAuthorizerConfig` instead.
type GroupAuthorizerConfig = GroupsTeamsAuthorizerConfig;

export { createGroupAuthorizer, type GroupAuthorizerConfig };
1 change: 1 addition & 0 deletions packages/api-security/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ export interface SecurityConfig extends MultiTenancyAppConfig {
export * from "./utils/AppPermissions";
export * from "./utils/getPermissionsFromSecurityGroupsForLocale";
export * from "./utils/IdentityValue";
export * from "./utils/createGroupsTeamsAuthorizer";

type Context = SecurityContext & TenancyContext & WcpContext;

Expand Down
84 changes: 84 additions & 0 deletions packages/api-security/src/utils/createGroupsTeamsAuthorizer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
import { ContextPlugin } from "@webiny/handler";
import { SecurityContext } from "~/types";
import {
GroupsTeamsAuthorizerConfig,
listPermissionsFromGroupsAndTeams
} from "./createGroupsTeamsAuthorizer/listPermissionsFromGroupsAndTeams";

export type { GroupsTeamsAuthorizerConfig };

export const createGroupsTeamsAuthorizer = <TContext extends SecurityContext = SecurityContext>(
config: GroupsTeamsAuthorizerConfig<TContext>
) => {
return new ContextPlugin<TContext>(context => {
const { security, tenancy } = context;
security.addAuthorizer(async () => {
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;
}

// @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 [];
}
}

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

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;
}

const parentTenantId = context.tenancy.getCurrentTenant().parent;
if (!parentTenantId) {
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
});
});

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

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

0 comments on commit 7c018a1

Please sign in to comment.