mirror of
https://github.com/logto-io/logto.git
synced 2025-03-10 22:22:45 -05:00
Merge pull request #5494 from logto-io/yemq-log-8395-update-logto-schemas
chore(schemas): add cloud scope, service log type and API guard
This commit is contained in:
commit
2c7acb2cdf
6 changed files with 124 additions and 3 deletions
|
@ -168,7 +168,12 @@ export const seedTables = async (
|
||||||
adminTenantId,
|
adminTenantId,
|
||||||
applicationRole.id,
|
applicationRole.id,
|
||||||
...cloudAdditionalScopes
|
...cloudAdditionalScopes
|
||||||
.filter(({ name }) => name === CloudScope.SendSms || name === CloudScope.SendEmail)
|
.filter(
|
||||||
|
({ name }) =>
|
||||||
|
name === CloudScope.SendSms ||
|
||||||
|
name === CloudScope.SendEmail ||
|
||||||
|
name === CloudScope.FetchCustomJwt
|
||||||
|
)
|
||||||
.map(({ id }) => id)
|
.map(({ id }) => id)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,92 @@
|
||||||
|
import { generateStandardId } from '@logto/shared/universal';
|
||||||
|
import { sql } from 'slonik';
|
||||||
|
|
||||||
|
import type { AlterationScript } from '../lib/types/alteration.js';
|
||||||
|
|
||||||
|
type Resource = {
|
||||||
|
tenantId: string;
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
indicator: string;
|
||||||
|
isDefault: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
type Scope = {
|
||||||
|
tenantId: string;
|
||||||
|
id: string;
|
||||||
|
resourceId: string;
|
||||||
|
name: string;
|
||||||
|
description: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
type Role = {
|
||||||
|
tenantId: string;
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
description: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
const cloudApiIndicator = 'https://cloud.logto.io/api';
|
||||||
|
|
||||||
|
const cloudConnectionAppRoleName = 'tenantApplication';
|
||||||
|
|
||||||
|
const adminTenantId = 'admin';
|
||||||
|
|
||||||
|
const fetchCustomJwtCloudScopeName = 'fetch:custom:jwt';
|
||||||
|
const fetchCustomJwtCloudScopeDescription =
|
||||||
|
'Allow accessing external resource to execute JWT payload customizer script and fetch the parsed token payload.';
|
||||||
|
|
||||||
|
const alteration: AlterationScript = {
|
||||||
|
up: async (pool) => {
|
||||||
|
// Get the Cloud API resource
|
||||||
|
const cloudApiResource = await pool.one<Resource>(sql`
|
||||||
|
select * from resources
|
||||||
|
where tenant_id = ${adminTenantId}
|
||||||
|
and indicator = ${cloudApiIndicator}
|
||||||
|
`);
|
||||||
|
|
||||||
|
// Get cloud connection application role
|
||||||
|
const tenantApplicationRole = await pool.one<Role>(sql`
|
||||||
|
select * from roles
|
||||||
|
where tenant_id = ${adminTenantId}
|
||||||
|
and name = ${cloudConnectionAppRoleName} and type = 'MachineToMachine'
|
||||||
|
`);
|
||||||
|
|
||||||
|
// Create the `custom:jwt` scope
|
||||||
|
const customJwtCloudScope = await pool.one<Scope>(sql`
|
||||||
|
insert into scopes (id, tenant_id, resource_id, name, description)
|
||||||
|
values (${generateStandardId()}, ${adminTenantId}, ${
|
||||||
|
cloudApiResource.id
|
||||||
|
}, ${fetchCustomJwtCloudScopeName}, ${fetchCustomJwtCloudScopeDescription})
|
||||||
|
returning *;
|
||||||
|
`);
|
||||||
|
|
||||||
|
// Assign the `custom:jwt` scope to cloud connection application role
|
||||||
|
await pool.query(sql`
|
||||||
|
insert into roles_scopes (id, tenant_id, role_id, scope_id)
|
||||||
|
values (${generateStandardId()}, ${adminTenantId}, ${tenantApplicationRole.id}, ${
|
||||||
|
customJwtCloudScope.id
|
||||||
|
});
|
||||||
|
`);
|
||||||
|
},
|
||||||
|
down: async (pool) => {
|
||||||
|
// Get the Cloud API resource
|
||||||
|
const cloudApiResource = await pool.one<Resource>(sql`
|
||||||
|
select * from resources
|
||||||
|
where tenant_id = ${adminTenantId}
|
||||||
|
and indicator = ${cloudApiIndicator}
|
||||||
|
`);
|
||||||
|
|
||||||
|
// Remove the `custom:jwt` scope
|
||||||
|
await pool.query(sql`
|
||||||
|
delete from scopes
|
||||||
|
where
|
||||||
|
tenant_id = ${adminTenantId} and
|
||||||
|
name = ${fetchCustomJwtCloudScopeName} and
|
||||||
|
description = ${fetchCustomJwtCloudScopeDescription} and
|
||||||
|
resource_id = ${cloudApiResource.id}
|
||||||
|
`);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export default alteration;
|
|
@ -17,6 +17,11 @@ export enum CloudScope {
|
||||||
ManageTenantSelf = 'manage:tenant:self',
|
ManageTenantSelf = 'manage:tenant:self',
|
||||||
SendSms = 'send:sms',
|
SendSms = 'send:sms',
|
||||||
SendEmail = 'send:email',
|
SendEmail = 'send:email',
|
||||||
|
/**
|
||||||
|
* The user can access external (independent from Logto instance) resource to run JWT payload customizer
|
||||||
|
* scripts and fetch the parsed token payload.
|
||||||
|
*/
|
||||||
|
FetchCustomJwt = 'fetch:custom:jwt',
|
||||||
/** The user can see and manage affiliates, including create, update, and delete. */
|
/** The user can see and manage affiliates, including create, update, and delete. */
|
||||||
ManageAffiliate = 'manage:affiliate',
|
ManageAffiliate = 'manage:affiliate',
|
||||||
/** The user can create new affiliates and logs. */
|
/** The user can create new affiliates and logs. */
|
||||||
|
@ -63,6 +68,10 @@ export const createCloudApi = (): Readonly<[UpdateAdminData, ...CreateScope[]]>
|
||||||
CloudScope.SendSms,
|
CloudScope.SendSms,
|
||||||
'Allow sending SMS. This scope is only available to M2M application.'
|
'Allow sending SMS. This scope is only available to M2M application.'
|
||||||
),
|
),
|
||||||
|
buildScope(
|
||||||
|
CloudScope.FetchCustomJwt,
|
||||||
|
'Allow accessing external resource to execute JWT payload customizer script and fetch the parsed token payload.'
|
||||||
|
),
|
||||||
buildScope(CloudScope.CreateAffiliate, 'Allow creating new affiliates and logs.'),
|
buildScope(CloudScope.CreateAffiliate, 'Allow creating new affiliates and logs.'),
|
||||||
buildScope(
|
buildScope(
|
||||||
CloudScope.ManageAffiliate,
|
CloudScope.ManageAffiliate,
|
||||||
|
|
|
@ -8,8 +8,9 @@ import {
|
||||||
Scopes,
|
Scopes,
|
||||||
UserSsoIdentities,
|
UserSsoIdentities,
|
||||||
} from '../db-entries/index.js';
|
} from '../db-entries/index.js';
|
||||||
import { mfaFactorsGuard } from '../foundations/index.js';
|
import { mfaFactorsGuard, jsonObjectGuard } from '../foundations/index.js';
|
||||||
|
|
||||||
|
import { jwtCustomizerGuard } from './logto-config/index.js';
|
||||||
import { userInfoGuard } from './user.js';
|
import { userInfoGuard } from './user.js';
|
||||||
|
|
||||||
const organizationDetailGuard = z.object({
|
const organizationDetailGuard = z.object({
|
||||||
|
@ -40,3 +41,16 @@ export const jwtCustomizerUserContextGuard = userInfoGuard.extend({
|
||||||
});
|
});
|
||||||
|
|
||||||
export type JwtCustomizerUserContext = z.infer<typeof jwtCustomizerUserContextGuard>;
|
export type JwtCustomizerUserContext = z.infer<typeof jwtCustomizerUserContextGuard>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This guard is for cloud API use (request body guard).
|
||||||
|
* Since the cloud API will be use by both testing and production, should keep the fields as general as possible.
|
||||||
|
* The response guard for the cloud API is `jsonObjectGuard` since it extends the `token` with extra claims.
|
||||||
|
*/
|
||||||
|
export const customJwtFetcherGuard = jwtCustomizerGuard
|
||||||
|
.pick({ script: true, envVars: true })
|
||||||
|
.required({ script: true })
|
||||||
|
.extend({
|
||||||
|
token: jsonObjectGuard,
|
||||||
|
context: jsonObjectGuard.optional(),
|
||||||
|
});
|
||||||
|
|
|
@ -56,7 +56,7 @@ export enum LogtoJwtTokenKey {
|
||||||
ClientCredentials = 'jwt.clientCredentials',
|
ClientCredentials = 'jwt.clientCredentials',
|
||||||
}
|
}
|
||||||
|
|
||||||
const jwtCustomizerGuard = z
|
export const jwtCustomizerGuard = z
|
||||||
.object({
|
.object({
|
||||||
script: z.string(),
|
script: z.string(),
|
||||||
envVars: z.record(z.string()),
|
envVars: z.record(z.string()),
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
export enum ServiceLogType {
|
export enum ServiceLogType {
|
||||||
SendEmail = 'sendEmail',
|
SendEmail = 'sendEmail',
|
||||||
SendSms = 'sendSms',
|
SendSms = 'sendSms',
|
||||||
|
FetchCustomJwt = 'fetchCustomJwt',
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue