0
Fork 0
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:
simeng-li 2023-11-02 10:13:06 +08:00 committed by GitHub
parent afde091582
commit e515c04d44
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 110 additions and 20 deletions

View file

@ -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,
});

View file

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

View file

@ -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 },

View file

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

View file

@ -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,

View file

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

View file

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

View 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)
);