Skip to content

Commit

Permalink
refactor(core,schemas,console): refactor log key types and sso-connec…
Browse files Browse the repository at this point in the history
…tor 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
  • Loading branch information
simeng-li authored Nov 2, 2023
1 parent afde091 commit e515c04
Show file tree
Hide file tree
Showing 8 changed files with 110 additions and 20 deletions.
12 changes: 6 additions & 6 deletions packages/console/src/consts/logs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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':
Expand Down Expand Up @@ -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,
});
Expand Down
6 changes: 6 additions & 0 deletions packages/core/src/routes/interaction/additional.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
4 changes: 2 additions & 2 deletions packages/core/src/routes/interaction/single-sign-on.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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(),
Expand All @@ -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 },
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {
type InteractionEvent,
InteractionEvent,
type IdentifierPayload,
type SocialConnectorPayload,
type VerifyVerificationCodePayload,
Expand Down Expand Up @@ -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 });

Expand Down
2 changes: 1 addition & 1 deletion packages/integration-tests/src/api/interaction-sso.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
Original file line number Diff line number Diff line change
@@ -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;
21 changes: 11 additions & 10 deletions packages/schemas/src/types/log/interaction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ export enum Field {
Identifier = 'Identifier',
Profile = 'Profile',
BindMfa = 'BindMfa',
SingleSignOn = 'SingleSignOn',
Mfa = 'Mfa',
}

Expand All @@ -20,6 +19,7 @@ export enum Method {
Password = 'Password',
VerificationCode = 'VerificationCode',
Social = 'Social',
SingleSignOn = 'SingleSignOn',
}

export enum Action {
Expand Down Expand Up @@ -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 changes: 17 additions & 0 deletions packages/schemas/tables/user_sso_identities.sql
Original file line number Diff line number Diff line change
@@ -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)
);

0 comments on commit e515c04

Please sign in to comment.