mirror of
https://github.com/logto-io/logto.git
synced 2025-01-20 21:32:31 -05:00
refactor(core,schemas,console): refactor log key types and sso-connector authn-url api name (#4798)
* refactor(core,schemas,console): refactor log key types and sso-connector authn-url api name refactor log key types and sso-connector authn-url api name * feat(schemas): add user sso identities table (#4801) * feat(schemas): add user sso identities table add user sso identities table * fix(schemas): fix alterations fix alterations * refactor(schemas): use unique constrain use unique constrain
This commit is contained in:
parent
afde091582
commit
e515c04d44
8 changed files with 110 additions and 20 deletions
|
@ -9,10 +9,6 @@ export const auditLogEventTitle: Record<string, Optional<string>> &
|
|||
'ExchangeTokenBy.Unknown': undefined,
|
||||
'Interaction.Create': 'Interaction started',
|
||||
'Interaction.End': 'Interaction ended',
|
||||
'Interaction.ForgotPassword.Identifier.Password.Submit':
|
||||
'Submit forgot-password identifier with password',
|
||||
'Interaction.ForgotPassword.Identifier.Social.Create': undefined,
|
||||
'Interaction.ForgotPassword.Identifier.Social.Submit': undefined,
|
||||
'Interaction.ForgotPassword.Identifier.VerificationCode.Create':
|
||||
'Create and send forgot-password verification code',
|
||||
'Interaction.ForgotPassword.Identifier.VerificationCode.Submit':
|
||||
|
@ -72,8 +68,12 @@ export const auditLogEventTitle: Record<string, Optional<string>> &
|
|||
'Interaction.SignIn.Mfa.BackupCode.Submit': undefined,
|
||||
'Interaction.SignIn.Mfa.WebAuthn.Create': undefined,
|
||||
'Interaction.SignIn.Mfa.WebAuthn.Submit': undefined,
|
||||
'Interaction.SignIn.SingleSignOn.Create': 'Create single-sign-on authentication session',
|
||||
'Interaction.SignIn.SingleSignOn.Submit': 'Submit single-sign-on authentication interaction',
|
||||
'Interaction.SignIn.Identifier.SingleSignOn.Create':
|
||||
'Create single-sign-on authentication session',
|
||||
'Interaction.SignIn.Identifier.SingleSignOn.Submit':
|
||||
'Submit single-sign-on authentication interaction',
|
||||
'Interaction.Register.Identifier.SingleSignOn.Create': undefined,
|
||||
'Interaction.Register.Identifier.SingleSignOn.Submit': undefined,
|
||||
RevokeToken: undefined,
|
||||
Unknown: undefined,
|
||||
});
|
||||
|
|
|
@ -66,6 +66,12 @@ export default function additionalRoutes<T extends IRouterParamContext>(
|
|||
async (ctx, next) => {
|
||||
// Check interaction exists
|
||||
const { event } = getInteractionStorage(ctx.interactionDetails.result);
|
||||
|
||||
assertThat(
|
||||
event !== InteractionEvent.ForgotPassword,
|
||||
'session.not_supported_for_forgot_password'
|
||||
);
|
||||
|
||||
const log = ctx.createLog(`Interaction.${event}.Identifier.Social.Create`);
|
||||
|
||||
const { body: payload } = ctx.guard;
|
||||
|
|
|
@ -28,7 +28,7 @@ export default function singleSignOnRoutes<T extends IRouterParamContext>(
|
|||
|
||||
// Create SSO authorization url for user interaction
|
||||
router.post(
|
||||
`${interactionPrefix}/${ssoPath}/:connectorId/authentication`,
|
||||
`${interactionPrefix}/${ssoPath}/:connectorId/authorization-url`,
|
||||
koaGuard({
|
||||
params: z.object({
|
||||
connectorId: z.string(),
|
||||
|
@ -53,7 +53,7 @@ export default function singleSignOnRoutes<T extends IRouterParamContext>(
|
|||
'session.not_supported_for_forgot_password'
|
||||
);
|
||||
|
||||
const log = createLog(`Interaction.${event}.SingleSignOn.Create`);
|
||||
const log = createLog(`Interaction.${event}.Identifier.SingleSignOn.Create`);
|
||||
|
||||
const {
|
||||
params: { connectorId },
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import {
|
||||
type InteractionEvent,
|
||||
InteractionEvent,
|
||||
type IdentifierPayload,
|
||||
type SocialConnectorPayload,
|
||||
type VerifyVerificationCodePayload,
|
||||
|
@ -45,6 +45,11 @@ const verifyPasswordIdentifier = async (
|
|||
): Promise<AccountIdIdentifier> => {
|
||||
const { password, ...identity } = identifier;
|
||||
|
||||
assertThat(
|
||||
event !== InteractionEvent.ForgotPassword,
|
||||
'session.not_supported_for_forgot_password'
|
||||
);
|
||||
|
||||
const log = ctx.createLog(`Interaction.${event}.Identifier.Password.Submit`);
|
||||
log.append({ ...identity });
|
||||
|
||||
|
|
|
@ -12,7 +12,7 @@ export const getSsoAuthorizationUrl = async (
|
|||
) => {
|
||||
const { connectorId, ...payload } = data;
|
||||
return api
|
||||
.post(`interaction/${ssoPath}/${connectorId}/authentication`, {
|
||||
.post(`interaction/${ssoPath}/${connectorId}/authorization-url`, {
|
||||
headers: { cookie },
|
||||
json: payload,
|
||||
followRedirect: false,
|
||||
|
|
|
@ -0,0 +1,61 @@
|
|||
import { type CommonQueryMethods, sql } from 'slonik';
|
||||
|
||||
import type { AlterationScript } from '../lib/types/alteration.js';
|
||||
|
||||
const getId = (value: string) => sql.identifier([value]);
|
||||
|
||||
const getDatabaseName = async (pool: CommonQueryMethods) => {
|
||||
const { currentDatabase } = await pool.one<{ currentDatabase: string }>(sql`
|
||||
select current_database();
|
||||
`);
|
||||
|
||||
return currentDatabase.replaceAll('-', '_');
|
||||
};
|
||||
|
||||
/** The alteration script for adding `sso_identities` column to the users table. */
|
||||
const alteration: AlterationScript = {
|
||||
up: async (pool) => {
|
||||
const database = await getDatabaseName(pool);
|
||||
const baseRoleId = getId(`logto_tenant_${database}`);
|
||||
|
||||
await pool.query(sql`
|
||||
create table user_sso_identities (
|
||||
tenant_id varchar(21) not null
|
||||
references tenants (id) on update cascade on delete cascade,
|
||||
id varchar(21) not null,
|
||||
user_id varchar(12) not null
|
||||
references users (id) on update cascade on delete cascade,
|
||||
issuer varchar(256) not null,
|
||||
identity_id varchar(128) not null,
|
||||
detail jsonb not null default '{}'::jsonb,
|
||||
created_at timestamp not null default(now()),
|
||||
primary key (id),
|
||||
constraint user_sso_identities__issuer__identity_id
|
||||
unique (tenant_id, issuer, identity_id)
|
||||
);
|
||||
|
||||
create trigger set_tenant_id before insert on user_sso_identities
|
||||
for each row execute procedure set_tenant_id();
|
||||
|
||||
alter table user_sso_identities enable row level security;
|
||||
|
||||
create policy user_sso_identities_tenant_id on user_sso_identities
|
||||
as restrictive
|
||||
using (tenant_id = (select id from tenants where db_user = current_user));
|
||||
|
||||
create policy user_sso_identities_modification on user_sso_identities
|
||||
using (true);
|
||||
|
||||
grant select, insert, update, delete on user_sso_identities to ${baseRoleId};
|
||||
`);
|
||||
},
|
||||
down: async (pool) => {
|
||||
await pool.query(sql`
|
||||
drop policy user_sso_identities_modification on user_sso_identities;
|
||||
drop policy user_sso_identities_tenant_id on user_sso_identities;
|
||||
drop table user_sso_identities;
|
||||
`);
|
||||
},
|
||||
};
|
||||
|
||||
export default alteration;
|
|
@ -11,7 +11,6 @@ export enum Field {
|
|||
Identifier = 'Identifier',
|
||||
Profile = 'Profile',
|
||||
BindMfa = 'BindMfa',
|
||||
SingleSignOn = 'SingleSignOn',
|
||||
Mfa = 'Mfa',
|
||||
}
|
||||
|
||||
|
@ -20,6 +19,7 @@ export enum Method {
|
|||
Password = 'Password',
|
||||
VerificationCode = 'VerificationCode',
|
||||
Social = 'Social',
|
||||
SingleSignOn = 'SingleSignOn',
|
||||
}
|
||||
|
||||
export enum Action {
|
||||
|
@ -79,17 +79,18 @@ export type LogKey =
|
|||
| Action.Update // PATCH profile
|
||||
| Action.Create // PUT profile
|
||||
| Action.Delete}`
|
||||
| `${Prefix}.${InteractionEvent}.${Field.Identifier}.${Method.VerificationCode | Method.Social}.${
|
||||
| `${Prefix}.${Exclude<
|
||||
InteractionEvent,
|
||||
InteractionEvent.ForgotPassword
|
||||
>}.${Field.Identifier}.${Exclude<Method, Method.Password>}.${Action.Create | Action.Submit}`
|
||||
| `${Prefix}.${Exclude<
|
||||
InteractionEvent,
|
||||
InteractionEvent.ForgotPassword
|
||||
>}.${Field.Identifier}.${Method.Password}.${Action.Submit}`
|
||||
| `${Prefix}.${InteractionEvent.ForgotPassword}.${Field.Identifier}.${Method.VerificationCode}.${
|
||||
| Action.Create
|
||||
| Action.Submit}`
|
||||
| `${Prefix}.${InteractionEvent}.${Field.Identifier}.${Exclude<
|
||||
Method,
|
||||
Method.VerificationCode | Method.Social
|
||||
>}.${Action.Submit}`
|
||||
| `${Prefix}.${InteractionEvent}.${Field.BindMfa}.${MfaFactor}.${Action.Submit | Action.Create}`
|
||||
| `${Prefix}.${InteractionEvent.SignIn}.${Field.Mfa}.${MfaFactor}.${
|
||||
| Action.Submit
|
||||
| Action.Create}`
|
||||
| `${Prefix}.${InteractionEvent.SignIn | InteractionEvent.Register}.${Field.SingleSignOn}.${
|
||||
| Action.Create
|
||||
| Action.Submit}`;
|
||||
| Action.Create}`;
|
||||
|
|
17
packages/schemas/tables/user_sso_identities.sql
Normal file
17
packages/schemas/tables/user_sso_identities.sql
Normal file
|
@ -0,0 +1,17 @@
|
|||
/* init_order = 2 */
|
||||
|
||||
create table user_sso_identities (
|
||||
tenant_id varchar(21) not null
|
||||
references tenants (id) on update cascade on delete cascade,
|
||||
id varchar(21) not null,
|
||||
user_id varchar(12) not null references users (id) on update cascade on delete cascade,
|
||||
/** Unique provider identifier. Issuer of the OIDC connectors, entityId of the SAML providers */
|
||||
issuer varchar(256) not null,
|
||||
/** Provider user identity id*/
|
||||
identity_id varchar(128) not null,
|
||||
detail jsonb /* @use JsonObject */ not null default '{}'::jsonb,
|
||||
created_at timestamp not null default(now()),
|
||||
primary key (id),
|
||||
constraint user_sso_identities__issuer__identity_id
|
||||
unique (tenant_id, issuer, identity_id)
|
||||
);
|
Loading…
Add table
Reference in a new issue