Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(core,schemas): add CRUD for consent organization resource scopes #5804

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,11 @@
title: 'application_details.permissions.api_resource',
key: ApplicationUserConsentScopeType.ResourceScopes,
},
[ApplicationUserConsentScopeType.OrganizationResourceScopes]: {
// TODO @xiaoyijun: update the title

Check warning on line 14 in packages/console/src/pages/ApplicationDetails/ApplicationDetailsContent/Permissions/ApplicationScopesAssignmentModal/constants.ts

View workflow job for this annotation

GitHub Actions / ESLint Report Analysis

packages/console/src/pages/ApplicationDetails/ApplicationDetailsContent/Permissions/ApplicationScopesAssignmentModal/constants.ts#L14

[no-warning-comments] Unexpected 'todo' comment: 'TODO @xiaoyijun: update the title'.
title: 'application_details.permissions.api_resource',
key: ApplicationUserConsentScopeType.OrganizationResourceScopes,
},
[ApplicationUserConsentScopeType.OrganizationScopes]: {
title: 'application_details.permissions.organization',
key: ApplicationUserConsentScopeType.OrganizationScopes,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,8 @@
[ApplicationUserConsentScopeType.UserScopes]: userScopesAssignment,
[ApplicationUserConsentScopeType.OrganizationScopes]: organizationScopesAssignment,
[ApplicationUserConsentScopeType.ResourceScopes]: resourceScopesAssignment,
// TODO @xiaoyijun: Replace with correct scopes

Check warning on line 75 in packages/console/src/pages/ApplicationDetails/ApplicationDetailsContent/Permissions/ApplicationScopesAssignmentModal/use-application-scopes-assignment.ts

View workflow job for this annotation

GitHub Actions / ESLint Report Analysis

packages/console/src/pages/ApplicationDetails/ApplicationDetailsContent/Permissions/ApplicationScopesAssignmentModal/use-application-scopes-assignment.ts#L75

[no-warning-comments] Unexpected 'todo' comment: 'TODO @xiaoyijun: Replace with correct...'.
[ApplicationUserConsentScopeType.OrganizationResourceScopes]: resourceScopesAssignment,
}),
[organizationScopesAssignment, resourceScopesAssignment, userScopesAssignment]
);
Expand Down
53 changes: 46 additions & 7 deletions packages/core/src/libraries/application.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
applications: {
findApplicationById,
userConsentOrganizationScopes,
userConsentOrganizationResourceScopes,
userConsentResourceScopes,
userConsentUserScopes,
},
Expand Down Expand Up @@ -76,16 +77,20 @@
{
organizationScopes = [],
resourceScopes = [],
organizationResourceScopes = [],

Check warning on line 80 in packages/core/src/libraries/application.ts

View check run for this annotation

Codecov / codecov/patch

packages/core/src/libraries/application.ts#L80

Added line #L80 was not covered by tests
}: {
organizationScopes?: string[];
resourceScopes?: string[];
organizationResourceScopes?: string[];

Check warning on line 84 in packages/core/src/libraries/application.ts

View check run for this annotation

Codecov / codecov/patch

packages/core/src/libraries/application.ts#L84

Added line #L84 was not covered by tests
},
tenantId: string
) => {
const [organizationScopesData, resourceScopesData] = await Promise.all([
organizationScopesQuery.findByIds(organizationScopes),
findScopesByIds(resourceScopes),
]);
const [organizationScopesData, resourceScopesData, organizationResourceScopesData] =
await Promise.all([
organizationScopesQuery.findByIds(organizationScopes),
findScopesByIds(resourceScopes),
findScopesByIds(organizationResourceScopes),
]);

Check warning on line 93 in packages/core/src/libraries/application.ts

View check run for this annotation

Codecov / codecov/patch

packages/core/src/libraries/application.ts#L88-L93

Added lines #L88 - L93 were not covered by tests

const invalidOrganizationScopes = organizationScopes.filter(
(scope) => !organizationScopesData.some(({ id }) => id === scope)
Expand All @@ -95,22 +100,28 @@
(scope) => !resourceScopesData.some(({ id }) => id === scope)
);

const invalidOrganizationResourceScopes = organizationResourceScopes.filter(
(scope) => !organizationResourceScopesData.some(({ id }) => id === scope)
);

Check warning on line 106 in packages/core/src/libraries/application.ts

View check run for this annotation

Codecov / codecov/patch

packages/core/src/libraries/application.ts#L103-L106

Added lines #L103 - L106 were not covered by tests
// Assert that all scopes exist, return the missing ones
assertThat(
invalidOrganizationScopes.length === 0 && invalidResourceScopes.length === 0,
invalidOrganizationScopes.length === 0 &&
invalidResourceScopes.length === 0 &&
invalidOrganizationResourceScopes.length === 0,

Check warning on line 111 in packages/core/src/libraries/application.ts

View check run for this annotation

Codecov / codecov/patch

packages/core/src/libraries/application.ts#L109-L111

Added lines #L109 - L111 were not covered by tests
new RequestError(
{
code: 'application.user_consent_scopes_not_found',
status: 422,
},
{ invalidOrganizationScopes, invalidResourceScopes }
{ invalidOrganizationScopes, invalidResourceScopes, invalidOrganizationResourceScopes }

Check warning on line 117 in packages/core/src/libraries/application.ts

View check run for this annotation

Codecov / codecov/patch

packages/core/src/libraries/application.ts#L117

Added line #L117 was not covered by tests
)
);

const managementApiResourceIndicator = getManagementApiResourceIndicator(tenantId);

const managementApiScopes = await findScopesByIdsAndResourceIndicator(
resourceScopes,
[...resourceScopes, ...organizationResourceScopes],

Check warning on line 124 in packages/core/src/libraries/application.ts

View check run for this annotation

Codecov / codecov/patch

packages/core/src/libraries/application.ts#L124

Added line #L124 was not covered by tests
managementApiResourceIndicator
);

Expand All @@ -129,10 +140,12 @@
{
organizationScopes,
resourceScopes,
organizationResourceScopes,

Check warning on line 143 in packages/core/src/libraries/application.ts

View check run for this annotation

Codecov / codecov/patch

packages/core/src/libraries/application.ts#L143

Added line #L143 was not covered by tests
userScopes,
}: {
organizationScopes?: string[];
resourceScopes?: string[];
organizationResourceScopes?: string[];

Check warning on line 148 in packages/core/src/libraries/application.ts

View check run for this annotation

Codecov / codecov/patch

packages/core/src/libraries/application.ts#L148

Added line #L148 was not covered by tests
userScopes?: string[];
}
) => {
Expand All @@ -148,6 +161,12 @@
);
}

if (organizationResourceScopes) {
await userConsentOrganizationResourceScopes.insert(
...organizationResourceScopes.map<[string, string]>((scope) => [applicationId, scope])
);
}

Check warning on line 169 in packages/core/src/libraries/application.ts

View check run for this annotation

Codecov / codecov/patch

packages/core/src/libraries/application.ts#L164-L169

Added lines #L164 - L169 were not covered by tests
if (userScopes) {
await Promise.all(
userScopes.map(async (userScope) =>
Expand Down Expand Up @@ -181,6 +200,21 @@
);
};

const getApplicationUserConsentOrganizationResourceScopes = async (applicationId: string) => {
const [, scopes] = await userConsentOrganizationResourceScopes.getEntities(Scopes, {
applicationId,
});

const groupedScopes = groupResourceScopesByResourceId(scopes);

return Promise.all(
groupedScopes.map(async ({ resourceId, scopes }) => ({
resource: await findResourceById(resourceId),
scopes,
}))
);

Check warning on line 215 in packages/core/src/libraries/application.ts

View check run for this annotation

Codecov / codecov/patch

packages/core/src/libraries/application.ts#L204-L215

Added lines #L204 - L215 were not covered by tests
};

const getApplicationUserConsentScopes = async (applicationId: string) =>
userConsentUserScopes.findAllByApplicationId(applicationId);

Expand All @@ -198,6 +232,10 @@
await userConsentResourceScopes.delete({ applicationId, scopeId });
break;
}
case ApplicationUserConsentScopeType.OrganizationResourceScopes: {
await userConsentOrganizationResourceScopes.delete({ applicationId, scopeId });
break;
}

Check warning on line 238 in packages/core/src/libraries/application.ts

View check run for this annotation

Codecov / codecov/patch

packages/core/src/libraries/application.ts#L235-L238

Added lines #L235 - L238 were not covered by tests
case ApplicationUserConsentScopeType.UserScopes: {
await userConsentUserScopes.deleteByApplicationIdAndScopeId(applicationId, scopeId);
break;
Expand Down Expand Up @@ -250,6 +288,7 @@
assignApplicationUserConsentScopes,
getApplicationUserConsentOrganizationScopes,
getApplicationUserConsentResourceScopes,
getApplicationUserConsentOrganizationResourceScopes,
getApplicationUserConsentScopes,
deleteApplicationUserConsentScopesByTypeAndScopeId,
validateUserConsentOrganizationMembership,
Expand Down
10 changes: 10 additions & 0 deletions packages/core/src/queries/application-user-consent-scopes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { type UserScope } from '@logto/core-kit';
import {
ApplicationUserConsentOrganizationScopes,
ApplicationUserConsentResourceScopes,
ApplicationUserConsentOrganizationResourceScopes,
ApplicationUserConsentUserScopes,
Applications,
OrganizationScopes,
Expand Down Expand Up @@ -32,6 +33,15 @@ export class ApplicationUserConsentResourceScopeQueries extends TwoRelationsQuer
}
}

export class ApplicationUserConsentOrganizationResourceScopeQueries extends TwoRelationsQueries<
typeof Applications,
typeof Scopes
> {
constructor(pool: CommonQueryMethods) {
super(pool, ApplicationUserConsentOrganizationResourceScopes.table, Applications, Scopes);
}
}

export const createApplicationUserConsentUserScopeQueries = (pool: CommonQueryMethods) => {
const insert = buildInsertIntoWithPool(pool)(ApplicationUserConsentUserScopes, {
onConflict: { ignore: true },
Expand Down
3 changes: 3 additions & 0 deletions packages/core/src/queries/application.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import type { OmitAutoSetFields } from '#src/utils/sql.js';

import ApplicationUserConsentOrganizationsQuery from './application-user-consent-organizations.js';
import {
ApplicationUserConsentOrganizationResourceScopeQueries,
ApplicationUserConsentOrganizationScopeQueries,
ApplicationUserConsentResourceScopeQueries,
createApplicationUserConsentUserScopeQueries,
Expand Down Expand Up @@ -253,6 +254,8 @@ export const createApplicationQueries = (pool: CommonQueryMethods) => {
deleteApplicationById,
userConsentOrganizationScopes: new ApplicationUserConsentOrganizationScopeQueries(pool),
userConsentResourceScopes: new ApplicationUserConsentResourceScopeQueries(pool),
userConsentOrganizationResourceScopes:
new ApplicationUserConsentOrganizationResourceScopeQueries(pool),
userConsentUserScopes: createApplicationUserConsentUserScopeQueries(pool),
userConsentOrganizations: new ApplicationUserConsentOrganizationsQuery(pool),
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@
"resourceScopes": {
"description": "A list of resource scope id to assign to the application. Throws error if any given resource scope is not found."
},
"organizationResourceScopes": {
"description": "A list of organization resource scope id to assign to the application. Throws error if any given resource scope is not found."
},
"userScopes": {
"description": "A list of user scope enum value to assign to the application."
}
Expand Down Expand Up @@ -51,6 +54,9 @@
"resourceScopes": {
"description": "A list of resource scope details grouped by resource id assigned to the application."
},
"organizationResourceScopes": {
"description": "A list of organization resource scope details grouped by resource id assigned to the application."
},
"userScopes": {
"description": "A list of user scope enum value assigned to the application."
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
} from '@logto/schemas';
import { object, string, nativeEnum } from 'zod';

import { EnvSet } from '#src/env-set/index.js';
import koaGuard from '#src/middleware/koa-guard.js';

import type { ManagementApiRouter, RouterInitArgs } from '../types.js';
Expand All @@ -24,6 +25,7 @@
assignApplicationUserConsentScopes,
getApplicationUserConsentOrganizationScopes,
getApplicationUserConsentResourceScopes,
getApplicationUserConsentOrganizationResourceScopes,
getApplicationUserConsentScopes,
deleteApplicationUserConsentScopesByTypeAndScopeId,
},
Expand All @@ -40,6 +42,7 @@
body: object({
organizationScopes: string().array().optional(),
resourceScopes: string().array().optional(),
organizationResourceScopes: string().array().optional(),
userScopes: nativeEnum(UserScope).array().optional(),
}),
status: [201, 404, 422],
Expand All @@ -50,11 +53,15 @@
body,
} = ctx.guard;

// TODO @wangsijie: Remove this when feature is enabled in production

Check warning on line 56 in packages/core/src/routes/applications/application-user-consent-scope.ts

View workflow job for this annotation

GitHub Actions / ESLint Report Analysis

packages/core/src/routes/applications/application-user-consent-scope.ts#L56

[no-warning-comments] Unexpected 'todo' comment: 'TODO @wangsijie: Remove this when...'.
const { organizationResourceScopes, ...rest } = body;
const theBody = EnvSet.values.isDevFeaturesEnabled ? body : rest;

Check warning on line 59 in packages/core/src/routes/applications/application-user-consent-scope.ts

View check run for this annotation

Codecov / codecov/patch

packages/core/src/routes/applications/application-user-consent-scope.ts#L56-L59

Added lines #L56 - L59 were not covered by tests
await validateThirdPartyApplicationById(applicationId);

await validateApplicationUserConsentScopes(body, tenantId);
await validateApplicationUserConsentScopes(theBody, tenantId);

Check warning on line 62 in packages/core/src/routes/applications/application-user-consent-scope.ts

View check run for this annotation

Codecov / codecov/patch

packages/core/src/routes/applications/application-user-consent-scope.ts#L62

Added line #L62 was not covered by tests

await assignApplicationUserConsentScopes(applicationId, body);
await assignApplicationUserConsentScopes(applicationId, theBody);

Check warning on line 64 in packages/core/src/routes/applications/application-user-consent-scope.ts

View check run for this annotation

Codecov / codecov/patch

packages/core/src/routes/applications/application-user-consent-scope.ts#L64

Added line #L64 was not covered by tests

ctx.status = 201;

Expand All @@ -68,7 +75,9 @@
params: object({
applicationId: string(),
}),
response: applicationUserConsentScopesResponseGuard,
response: EnvSet.values.isDevFeaturesEnabled
? applicationUserConsentScopesResponseGuard
: applicationUserConsentScopesResponseGuard.omit({ organizationResourceScopes: true }),
status: [200, 404],
}),
async (ctx, next) => {
Expand All @@ -77,17 +86,26 @@
await findApplicationById(applicationId);

// Note: The following queries will return full data schema, we rely on the response guard to filter out the fields we don't need.
const [organizationScopes, resourceScopes, userScopes] = await Promise.all([
getApplicationUserConsentOrganizationScopes(applicationId),
getApplicationUserConsentResourceScopes(applicationId),
getApplicationUserConsentScopes(applicationId),
]);

ctx.body = {
organizationScopes,
resourceScopes,
userScopes,
};
const [organizationScopes, resourceScopes, organizationResourceScopes, userScopes] =
await Promise.all([
getApplicationUserConsentOrganizationScopes(applicationId),
getApplicationUserConsentResourceScopes(applicationId),
getApplicationUserConsentOrganizationResourceScopes(applicationId),
getApplicationUserConsentScopes(applicationId),
]);

ctx.body = EnvSet.values.isDevFeaturesEnabled
? {
organizationScopes,
resourceScopes,
organizationResourceScopes,
userScopes,
}
: {
organizationScopes,
resourceScopes,
userScopes,
};

Check warning on line 108 in packages/core/src/routes/applications/application-user-consent-scope.ts

View check run for this annotation

Codecov / codecov/patch

packages/core/src/routes/applications/application-user-consent-scope.ts#L89-L108

Added lines #L89 - L108 were not covered by tests

return next();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export const assignUserConsentScopes = async (
payload: {
organizationScopes?: string[];
resourceScopes?: string[];
organizationResourceScopes?: string[];
userScopes?: UserScope[];
}
) => authedAdminApi.post(`applications/${applicationId}/user-consent-scopes`, { json: payload });
Expand Down
Loading
Loading