0
Fork 0
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:
simeng-li 2023-11-13 11:14:46 +08:00 committed by GitHub
parent a8b164ca54
commit eeb1928e57
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
15 changed files with 24 additions and 72 deletions

View file

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

View file

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

View file

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

View file

@ -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 = {

View file

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

View file

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

View file

@ -45,7 +45,6 @@ export const mockSsoConnectors: SsoConnectorMetadata[] = [
{
id: 'arbitrary-sso-connector',
connectorName: 'AzureAD',
ssoOnly: true,
logo: 'http://logto.dev/logto.png',
},
];

View file

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

View file

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

View file

@ -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 () => {

View file

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

View file

@ -72,7 +72,6 @@ describe('.well-known api', () => {
expect(newCreatedConnector).toMatchObject({
id,
connectorName,
ssoOnly: newOidcSsoConnectorPayload.ssoOnly,
logo: newOidcSsoConnectorPayload.branding.logo,
darkLogo: newOidcSsoConnectorPayload.branding.darkLogo,
});

View file

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

View file

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

View file

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