mirror of
https://github.com/logto-io/logto.git
synced 2025-02-03 21:48:55 -05:00
chore(schemas): add cloud scope, service log type and API guard
This commit is contained in:
parent
5a7204571a
commit
733f092e40
6 changed files with 124 additions and 3 deletions
|
@ -168,7 +168,12 @@ export const seedTables = async (
|
|||
adminTenantId,
|
||||
applicationRole.id,
|
||||
...cloudAdditionalScopes
|
||||
.filter(({ name }) => name === CloudScope.SendSms || name === CloudScope.SendEmail)
|
||||
.filter(
|
||||
({ name }) =>
|
||||
name === CloudScope.SendSms ||
|
||||
name === CloudScope.SendEmail ||
|
||||
name === CloudScope.FetchCustomJwt
|
||||
)
|
||||
.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',
|
||||
SendSms = 'send:sms',
|
||||
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. */
|
||||
ManageAffiliate = 'manage:affiliate',
|
||||
/** The user can create new affiliates and logs. */
|
||||
|
@ -63,6 +68,10 @@ export const createCloudApi = (): Readonly<[UpdateAdminData, ...CreateScope[]]>
|
|||
CloudScope.SendSms,
|
||||
'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.ManageAffiliate,
|
||||
|
|
|
@ -8,8 +8,9 @@ import {
|
|||
Scopes,
|
||||
UserSsoIdentities,
|
||||
} 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';
|
||||
|
||||
const organizationDetailGuard = z.object({
|
||||
|
@ -40,3 +41,16 @@ export const jwtCustomizerUserContextGuard = userInfoGuard.extend({
|
|||
});
|
||||
|
||||
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',
|
||||
}
|
||||
|
||||
const jwtCustomizerGuard = z
|
||||
export const jwtCustomizerGuard = z
|
||||
.object({
|
||||
script: z.string(),
|
||||
envVars: z.record(z.string()),
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
export enum ServiceLogType {
|
||||
SendEmail = 'sendEmail',
|
||||
SendSms = 'sendSms',
|
||||
FetchCustomJwt = 'fetchCustomJwt',
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue