mirror of
https://github.com/logto-io/logto.git
synced 2025-01-27 21:39:16 -05:00
refactor(core): should not guard sso authentication flow (#6394)
should not guard mfa and profile fulfillment for the sso authentication flow
This commit is contained in:
parent
902e620e84
commit
5024182986
2 changed files with 64 additions and 4 deletions
|
@ -247,10 +247,17 @@ export default class ExperienceInteraction {
|
||||||
* Validate the interaction verification records against the sign-in experience and user MFA settings.
|
* Validate the interaction verification records against the sign-in experience and user MFA settings.
|
||||||
* The interaction is verified if at least one user enabled MFA verification record is present and verified.
|
* The interaction is verified if at least one user enabled MFA verification record is present and verified.
|
||||||
*
|
*
|
||||||
* @throws — RequestError with 404 if the if the user is not identified or not found
|
* @remarks
|
||||||
|
* - EnterpriseSso verified interaction does not require MFA verification.
|
||||||
|
*
|
||||||
|
* @throws {RequestError} with 404 if the if the user is not identified or not found
|
||||||
* @throws {RequestError} with 403 if the mfa verification is required but not verified
|
* @throws {RequestError} with 403 if the mfa verification is required but not verified
|
||||||
*/
|
*/
|
||||||
public async guardMfaVerificationStatus() {
|
public async guardMfaVerificationStatus() {
|
||||||
|
if (this.hasVerifiedSsoIdentity) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const user = await this.getIdentifiedUser();
|
const user = await this.getIdentifiedUser();
|
||||||
const mfaSettings = await this.signInExperienceValidator.getMfaSettings();
|
const mfaSettings = await this.signInExperienceValidator.getMfaSettings();
|
||||||
const mfaValidator = new MfaValidator(mfaSettings, user);
|
const mfaValidator = new MfaValidator(mfaSettings, user);
|
||||||
|
@ -338,13 +345,17 @@ export default class ExperienceInteraction {
|
||||||
await this.profile.validateAvailability();
|
await this.profile.validateAvailability();
|
||||||
|
|
||||||
// Profile fulfilled
|
// Profile fulfilled
|
||||||
|
if (!this.hasVerifiedSsoIdentity) {
|
||||||
await this.profile.assertUserMandatoryProfileFulfilled();
|
await this.profile.assertUserMandatoryProfileFulfilled();
|
||||||
|
}
|
||||||
|
|
||||||
// Revalidate the new MFA data if any
|
// Revalidate the new MFA data if any
|
||||||
await this.mfa.checkAvailability();
|
await this.mfa.checkAvailability();
|
||||||
|
|
||||||
// MFA fulfilled
|
// MFA fulfilled
|
||||||
|
if (!this.hasVerifiedSsoIdentity) {
|
||||||
await this.mfa.assertUserMandatoryMfaFulfilled();
|
await this.mfa.assertUserMandatoryMfaFulfilled();
|
||||||
|
}
|
||||||
|
|
||||||
const { socialIdentity, enterpriseSsoIdentity, ...rest } = this.profile.data;
|
const { socialIdentity, enterpriseSsoIdentity, ...rest } = this.profile.data;
|
||||||
const { mfaSkipped, mfaVerifications } = this.mfa.toUserMfaVerifications();
|
const { mfaSkipped, mfaVerifications } = this.mfa.toUserMfaVerifications();
|
||||||
|
@ -534,6 +545,12 @@ export default class ExperienceInteraction {
|
||||||
return verificationRecord?.identifier.value === value && verificationRecord.isVerified;
|
return verificationRecord?.identifier.value === value && verificationRecord.isVerified;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private get hasVerifiedSsoIdentity() {
|
||||||
|
const ssoVerificationRecord = this.verificationRecords.get(VerificationType.EnterpriseSso);
|
||||||
|
|
||||||
|
return Boolean(ssoVerificationRecord?.isVerified);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clean up the interaction storage.
|
* Clean up the interaction storage.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
|
import { MfaFactor, SignInIdentifier } from '@logto/schemas';
|
||||||
import { generateStandardId } from '@logto/shared';
|
import { generateStandardId } from '@logto/shared';
|
||||||
|
|
||||||
import { deleteUser, getUser } from '#src/api/admin-user.js';
|
import { createUserMfaVerification, deleteUser, getUser } from '#src/api/admin-user.js';
|
||||||
import { updateSignInExperience } from '#src/api/sign-in-experience.js';
|
import { updateSignInExperience } from '#src/api/sign-in-experience.js';
|
||||||
import { SsoConnectorApi } from '#src/api/sso-connector.js';
|
import { SsoConnectorApi } from '#src/api/sso-connector.js';
|
||||||
import { signInWithEnterpriseSso } from '#src/helpers/experience/index.js';
|
import { signInWithEnterpriseSso } from '#src/helpers/experience/index.js';
|
||||||
|
import { enableMandatoryMfaWithTotp } from '#src/helpers/sign-in-experience.js';
|
||||||
import { generateNewUser } from '#src/helpers/user.js';
|
import { generateNewUser } from '#src/helpers/user.js';
|
||||||
import { devFeatureTest, generateEmail } from '#src/utils.js';
|
import { devFeatureTest, generateEmail } from '#src/utils.js';
|
||||||
|
|
||||||
|
@ -78,4 +80,45 @@ devFeatureTest.describe('enterprise sso sign-in and sign-up', () => {
|
||||||
|
|
||||||
await deleteUser(userId);
|
await deleteUser(userId);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('should not check mfa and profile fulfillment for the enterprise sso authentication flow', () => {
|
||||||
|
const email = generateEmail(domain);
|
||||||
|
const enterpriseSsoIdentityId = generateStandardId();
|
||||||
|
const userIdMap = new Map<string, string>();
|
||||||
|
|
||||||
|
beforeAll(async () => {
|
||||||
|
await updateSignInExperience({
|
||||||
|
signUp: { identifiers: [SignInIdentifier.Username], password: true, verify: false },
|
||||||
|
});
|
||||||
|
await enableMandatoryMfaWithTotp();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should successfully sign-up with enterprise sso without profile and mfa fulfillment', async () => {
|
||||||
|
const userId = await signInWithEnterpriseSso(
|
||||||
|
ssoConnectorApi.firstConnectorId!,
|
||||||
|
{
|
||||||
|
sub: enterpriseSsoIdentityId,
|
||||||
|
email,
|
||||||
|
email_verified: true,
|
||||||
|
},
|
||||||
|
true
|
||||||
|
);
|
||||||
|
|
||||||
|
userIdMap.set('ssoUser', userId);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should successfully sign-in with enterprise sso without mfa validation', async () => {
|
||||||
|
const userId = userIdMap.get('ssoUser')!;
|
||||||
|
|
||||||
|
await createUserMfaVerification(userId, MfaFactor.TOTP);
|
||||||
|
|
||||||
|
await signInWithEnterpriseSso(ssoConnectorApi.firstConnectorId!, {
|
||||||
|
sub: enterpriseSsoIdentityId,
|
||||||
|
email,
|
||||||
|
email_verified: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
await deleteUser(userId);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
Loading…
Add table
Reference in a new issue