0
Fork 0
mirror of https://github.com/logto-io/logto.git synced 2025-01-20 21:32:31 -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:
simeng-li 2024-08-05 09:05:08 +08:00 committed by GitHub
parent 902e620e84
commit 5024182986
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 64 additions and 4 deletions

View file

@ -247,10 +247,17 @@ export default class ExperienceInteraction {
* 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.
*
* @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
*/
public async guardMfaVerificationStatus() {
if (this.hasVerifiedSsoIdentity) {
return;
}
const user = await this.getIdentifiedUser();
const mfaSettings = await this.signInExperienceValidator.getMfaSettings();
const mfaValidator = new MfaValidator(mfaSettings, user);
@ -338,13 +345,17 @@ export default class ExperienceInteraction {
await this.profile.validateAvailability();
// Profile fulfilled
if (!this.hasVerifiedSsoIdentity) {
await this.profile.assertUserMandatoryProfileFulfilled();
}
// Revalidate the new MFA data if any
await this.mfa.checkAvailability();
// MFA fulfilled
if (!this.hasVerifiedSsoIdentity) {
await this.mfa.assertUserMandatoryMfaFulfilled();
}
const { socialIdentity, enterpriseSsoIdentity, ...rest } = this.profile.data;
const { mfaSkipped, mfaVerifications } = this.mfa.toUserMfaVerifications();
@ -534,6 +545,12 @@ export default class ExperienceInteraction {
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.
*/

View file

@ -1,9 +1,11 @@
import { MfaFactor, SignInIdentifier } from '@logto/schemas';
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 { SsoConnectorApi } from '#src/api/sso-connector.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 { devFeatureTest, generateEmail } from '#src/utils.js';
@ -78,4 +80,45 @@ devFeatureTest.describe('enterprise sso sign-in and sign-up', () => {
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);
});
});
});