mirror of
https://github.com/logto-io/logto.git
synced 2025-04-07 23:01:25 -05:00
feat(core,schemas): remove the ssoOnly setting of the sso connectors (#4856)
feat(core,schemas): remove ssoOnly property remove the ssoOnly property from sso connectors
This commit is contained in:
parent
a8b164ca54
commit
eeb1928e57
15 changed files with 24 additions and 72 deletions
|
@ -11,7 +11,6 @@ export const mockSsoConnector = {
|
|||
domains: [],
|
||||
branding: {},
|
||||
syncProfile: true,
|
||||
ssoOnly: true,
|
||||
createdAt: Date.now(),
|
||||
} satisfies SsoConnector;
|
||||
|
||||
|
@ -28,6 +27,5 @@ export const wellConfiguredSsoConnector = {
|
|||
domains: ['foo.com'],
|
||||
branding: {},
|
||||
syncProfile: true,
|
||||
ssoOnly: true,
|
||||
createdAt: Date.now(),
|
||||
} satisfies SsoConnector;
|
||||
|
|
|
@ -160,7 +160,6 @@ describe('getFullSignInExperience()', () => {
|
|||
{
|
||||
id: wellConfiguredSsoConnector.id,
|
||||
connectorName: wellConfiguredSsoConnector.connectorName,
|
||||
ssoOnly: wellConfiguredSsoConnector.ssoOnly,
|
||||
logo: ssoConnectorFactories[wellConfiguredSsoConnector.providerName].logo,
|
||||
darkLogo: undefined,
|
||||
},
|
||||
|
@ -185,7 +184,6 @@ describe('get sso connectors', () => {
|
|||
{
|
||||
id: wellConfiguredSsoConnector.id,
|
||||
connectorName: wellConfiguredSsoConnector.connectorName,
|
||||
ssoOnly: wellConfiguredSsoConnector.ssoOnly,
|
||||
logo: ssoConnectorFactories[wellConfiguredSsoConnector.providerName].logo,
|
||||
darkLogo: undefined,
|
||||
},
|
||||
|
|
|
@ -72,13 +72,12 @@ export const createSignInExperienceLibrary = (
|
|||
const ssoConnectors = await getAvailableSsoConnectors();
|
||||
|
||||
return ssoConnectors.map(
|
||||
({ providerName, connectorName, id, branding, ssoOnly }): SsoConnectorMetadata => {
|
||||
({ providerName, connectorName, id, branding }): SsoConnectorMetadata => {
|
||||
const factory = ssoConnectorFactories[providerName];
|
||||
|
||||
return {
|
||||
id,
|
||||
connectorName,
|
||||
ssoOnly,
|
||||
logo: branding.logo ?? factory.logo,
|
||||
darkLogo: branding.darkLogo,
|
||||
};
|
||||
|
|
|
@ -14,7 +14,7 @@ const mockSsoConnectorLibrary: SsoConnectorLibrary = {
|
|||
getSsoConnectorById: jest.fn(),
|
||||
};
|
||||
|
||||
describe('verifySsoOnlyEmailIdentifier tests', () => {
|
||||
describe('verifyEmailIdentifier tests', () => {
|
||||
it('should return if the identifier is not an email', async () => {
|
||||
await expect(
|
||||
verifySsoOnlyEmailIdentifier(mockSsoConnectorLibrary, {
|
||||
|
@ -38,22 +38,6 @@ describe('verifySsoOnlyEmailIdentifier tests', () => {
|
|||
})
|
||||
).resolves.not.toThrow();
|
||||
});
|
||||
it('should return if the connector is not sso only', async () => {
|
||||
getAvailableSsoConnectorsMock.mockResolvedValueOnce([
|
||||
{
|
||||
...wellConfiguredSsoConnector,
|
||||
domains: ['example.com'],
|
||||
ssoOnly: false,
|
||||
},
|
||||
]);
|
||||
|
||||
await expect(
|
||||
verifySsoOnlyEmailIdentifier(mockSsoConnectorLibrary, {
|
||||
email: 'foo@example.com',
|
||||
password: 'bar',
|
||||
})
|
||||
).resolves.not.toThrow();
|
||||
});
|
||||
|
||||
it('should throw an error if multiple sso connectors found with the given email', async () => {
|
||||
const connector = {
|
||||
|
|
|
@ -24,8 +24,8 @@ export const verifySsoOnlyEmailIdentifier = async (
|
|||
return;
|
||||
}
|
||||
|
||||
const availableConnectors = availableSsoConnectors.filter(
|
||||
({ domains, ssoOnly }) => domains.includes(domain) && ssoOnly
|
||||
const availableConnectors = availableSsoConnectors.filter(({ domains }) =>
|
||||
domains.includes(domain)
|
||||
);
|
||||
|
||||
assertThat(
|
||||
|
|
|
@ -22,7 +22,6 @@ export const ssoConnectorCreateGuard = SsoConnectors.createGuard
|
|||
domains: true,
|
||||
branding: true,
|
||||
syncProfile: true,
|
||||
ssoOnly: true,
|
||||
})
|
||||
// Provider name and connector name are required for creating a connector
|
||||
.merge(SsoConnectors.guard.pick({ providerName: true, connectorName: true }));
|
||||
|
@ -42,7 +41,6 @@ export const ssoConnectorPatchGuard = SsoConnectors.guard
|
|||
domains: true,
|
||||
branding: true,
|
||||
syncProfile: true,
|
||||
ssoOnly: true,
|
||||
connectorName: true,
|
||||
})
|
||||
.partial();
|
||||
|
|
|
@ -45,7 +45,6 @@ export const mockSsoConnectors: SsoConnectorMetadata[] = [
|
|||
{
|
||||
id: 'arbitrary-sso-connector',
|
||||
connectorName: 'AzureAD',
|
||||
ssoOnly: true,
|
||||
logo: 'http://logto.dev/logto.png',
|
||||
},
|
||||
];
|
||||
|
|
|
@ -35,7 +35,6 @@ export const newOidcSsoConnectorPayload = {
|
|||
providerName: ProviderName.OIDC,
|
||||
connectorName: 'test-oidc',
|
||||
domains: ['example.io'], // Auto-generated email domain
|
||||
ssoOnly: true,
|
||||
branding: {
|
||||
logo: 'https://logto.io/oidc-logo.png',
|
||||
darkLogo: 'https://logto.io/oidc-dark-logo.png',
|
||||
|
|
|
@ -6,7 +6,6 @@ import {
|
|||
patchInteractionIdentifiers,
|
||||
putInteractionProfile,
|
||||
deleteUser,
|
||||
createUser,
|
||||
} from '#src/api/index.js';
|
||||
import { createSsoConnector } from '#src/api/sso-connector.js';
|
||||
import { newOidcSsoConnectorPayload } from '#src/constants.js';
|
||||
|
@ -22,7 +21,6 @@ import {
|
|||
enableAllVerificationCodeSignInMethods,
|
||||
} from '#src/helpers/sign-in-experience.js';
|
||||
import { generateNewUser, generateNewUserProfile } from '#src/helpers/user.js';
|
||||
import { generatePassword, generateEmail } from '#src/utils.js';
|
||||
|
||||
describe('Sign-in flow using password identifiers', () => {
|
||||
beforeAll(async () => {
|
||||
|
@ -99,34 +97,6 @@ describe('Sign-in flow using password identifiers', () => {
|
|||
await deleteUser(user.id);
|
||||
});
|
||||
|
||||
it('should allow sign-in with email and password with SSO connector settings ssoOnly to false', async () => {
|
||||
const password = generatePassword();
|
||||
const email = generateEmail('sso-email-password-sign-in-happy-path.io');
|
||||
const user = await createUser({ primaryEmail: email, password });
|
||||
const client = await initClient();
|
||||
|
||||
await createSsoConnector({
|
||||
...newOidcSsoConnectorPayload,
|
||||
domains: ['sso-email-password-sign-in-happy-path.io'],
|
||||
ssoOnly: false,
|
||||
});
|
||||
|
||||
await client.successSend(putInteraction, {
|
||||
event: InteractionEvent.SignIn,
|
||||
identifier: {
|
||||
email,
|
||||
password,
|
||||
},
|
||||
});
|
||||
|
||||
const { redirectTo } = await client.submitInteraction();
|
||||
|
||||
await processSession(client, redirectTo);
|
||||
await logoutClient(client);
|
||||
|
||||
await deleteUser(user.id);
|
||||
});
|
||||
|
||||
it('sign-in with phone and password', async () => {
|
||||
const { userProfile, user } = await generateNewUser({ primaryPhone: true, password: true });
|
||||
const client = await initClient();
|
||||
|
|
|
@ -13,7 +13,7 @@ describe('Single Sign On Happy Path', () => {
|
|||
const redirectUri = 'http://foo.dev/callback';
|
||||
|
||||
beforeAll(async () => {
|
||||
const { id, connectorName, ssoOnly } = await createSsoConnector({
|
||||
const { id, connectorName } = await createSsoConnector({
|
||||
providerName: ProviderName.OIDC,
|
||||
connectorName: 'test-oidc',
|
||||
domains: ['foo.com'],
|
||||
|
@ -24,7 +24,7 @@ describe('Single Sign On Happy Path', () => {
|
|||
},
|
||||
});
|
||||
|
||||
connectorIdMap.set(id, { id, connectorName, ssoOnly, logo: '' });
|
||||
connectorIdMap.set(id, { id, connectorName, logo: '' });
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
|
|
|
@ -68,7 +68,6 @@ describe('post sso-connectors', () => {
|
|||
expect(response).toHaveProperty('connectorName', 'test');
|
||||
expect(response).toHaveProperty('config', {});
|
||||
expect(response).toHaveProperty('domains', []);
|
||||
expect(response).toHaveProperty('ssoOnly', false);
|
||||
expect(response).toHaveProperty('syncProfile', false);
|
||||
|
||||
await deleteSsoConnectorById(response.id);
|
||||
|
@ -95,7 +94,6 @@ describe('post sso-connectors', () => {
|
|||
connectorName: 'test',
|
||||
config,
|
||||
domains: ['test.com'],
|
||||
ssoOnly: true,
|
||||
};
|
||||
|
||||
const response = await createSsoConnector(data);
|
||||
|
@ -105,7 +103,6 @@ describe('post sso-connectors', () => {
|
|||
expect(response).toHaveProperty('connectorName', 'test');
|
||||
expect(response).toHaveProperty('config', data.config);
|
||||
expect(response).toHaveProperty('domains', data.domains);
|
||||
expect(response).toHaveProperty('ssoOnly', data.ssoOnly);
|
||||
expect(response).toHaveProperty('syncProfile', false);
|
||||
|
||||
await deleteSsoConnectorById(response.id);
|
||||
|
@ -156,7 +153,6 @@ describe('get sso-connector by id', () => {
|
|||
expect(connector).toHaveProperty('connectorName', 'integration_test connector');
|
||||
expect(connector).toHaveProperty('config', {});
|
||||
expect(connector).toHaveProperty('domains', []);
|
||||
expect(connector).toHaveProperty('ssoOnly', false);
|
||||
expect(connector).toHaveProperty('syncProfile', false);
|
||||
|
||||
await deleteSsoConnectorById(id);
|
||||
|
@ -198,7 +194,6 @@ describe('patch sso-connector by id', () => {
|
|||
const connector = await patchSsoConnectorById(id, {
|
||||
connectorName: 'integration_test connector updated',
|
||||
domains: ['test.com'],
|
||||
ssoOnly: true,
|
||||
});
|
||||
|
||||
expect(connector).toHaveProperty('id', id);
|
||||
|
@ -206,7 +201,6 @@ describe('patch sso-connector by id', () => {
|
|||
expect(connector).toHaveProperty('connectorName', 'integration_test connector updated');
|
||||
expect(connector).toHaveProperty('config', {});
|
||||
expect(connector).toHaveProperty('domains', ['test.com']);
|
||||
expect(connector).toHaveProperty('ssoOnly', true);
|
||||
expect(connector).toHaveProperty('syncProfile', false);
|
||||
|
||||
await deleteSsoConnectorById(id);
|
||||
|
@ -227,7 +221,6 @@ describe('patch sso-connector by id', () => {
|
|||
expect(connector).toHaveProperty('connectorName', 'integration_test connector');
|
||||
expect(connector).toHaveProperty('config', {});
|
||||
expect(connector).toHaveProperty('domains', []);
|
||||
expect(connector).toHaveProperty('ssoOnly', false);
|
||||
expect(connector).toHaveProperty('syncProfile', false);
|
||||
|
||||
await deleteSsoConnectorById(id);
|
||||
|
|
|
@ -72,7 +72,6 @@ describe('.well-known api', () => {
|
|||
expect(newCreatedConnector).toMatchObject({
|
||||
id,
|
||||
connectorName,
|
||||
ssoOnly: newOidcSsoConnectorPayload.ssoOnly,
|
||||
logo: newOidcSsoConnectorPayload.branding.logo,
|
||||
darkLogo: newOidcSsoConnectorPayload.branding.darkLogo,
|
||||
});
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
import { sql } from 'slonik';
|
||||
|
||||
import type { AlterationScript } from '../lib/types/alteration.js';
|
||||
|
||||
const alteration: AlterationScript = {
|
||||
up: async (pool) => {
|
||||
await pool.query(sql`
|
||||
alter table sso_connectors drop column sso_only;
|
||||
`);
|
||||
},
|
||||
down: async (pool) => {
|
||||
await pool.query(sql`
|
||||
alter table sso_connectors add column sso_only boolean not null default FALSE;
|
||||
`);
|
||||
},
|
||||
};
|
||||
|
||||
export default alteration;
|
|
@ -7,7 +7,6 @@ export const ssoConnectorMetadataGuard = z.object({
|
|||
id: z.string(),
|
||||
connectorName: z.string(),
|
||||
logo: z.string(),
|
||||
ssoOnly: z.boolean(),
|
||||
darkLogo: z.string().optional(),
|
||||
});
|
||||
|
||||
|
|
|
@ -16,8 +16,6 @@ create table sso_connectors (
|
|||
branding jsonb /* @use SsoBranding */ not null default '{}'::jsonb,
|
||||
/** Determines whether to synchronize the user's profile on each login. */
|
||||
sync_profile boolean not null default FALSE,
|
||||
/** Determines whether SSO is the restricted sign-in method for users with the SSO registered email domains */
|
||||
sso_only boolean not null default FALSE,
|
||||
/** When the SSO connector was created. */
|
||||
created_at timestamptz not null default(now()),
|
||||
primary key (id)
|
||||
|
|
Loading…
Add table
Reference in a new issue