mirror of
https://github.com/zitadel/zitadel.git
synced 2025-10-21 10:11:39 +00:00
feat: mfa policy (#913)
* feat: add mfa to login policy * feat: add mfa to login policy * feat: add mfa to login policy * feat: add mfa to login policy * feat: add mfa to login policy on org * feat: add mfa to login policy on org * feat: append events on policy views * feat: iam login policy mfa definition * feat: login policies on orgs * feat: configured mfas in login process * feat: configured mfas in login process * Update internal/ui/login/static/i18n/en.yaml Co-authored-by: Livio Amstutz <livio.a@gmail.com> * fix: rename software and hardware mfas * fix: pr requests * fix user mfa * fix: test * fix: oidc version * fix: oidc version * fix: proto gen Co-authored-by: Livio Amstutz <livio.a@gmail.com> Co-authored-by: Max Peintner <max@caos.ch>
This commit is contained in:
@@ -48,8 +48,8 @@ type AuthRequestRepo struct {
|
||||
PasswordCheckLifeTime time.Duration
|
||||
ExternalLoginCheckLifeTime time.Duration
|
||||
MfaInitSkippedLifeTime time.Duration
|
||||
MfaSoftwareCheckLifeTime time.Duration
|
||||
MfaHardwareCheckLifeTime time.Duration
|
||||
SecondFactorCheckLifeTime time.Duration
|
||||
MultiFactorCheckLifeTime time.Duration
|
||||
|
||||
IAMID string
|
||||
}
|
||||
@@ -150,6 +150,10 @@ func (repo *AuthRequestRepo) AuthRequestByCode(ctx context.Context, code string)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = repo.fillLoginPolicy(ctx, request)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
steps, err := repo.nextSteps(ctx, request, true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -559,7 +563,11 @@ func (repo *AuthRequestRepo) nextSteps(ctx context.Context, request *model.AuthR
|
||||
request.AuthTime = userSession.PasswordVerification
|
||||
}
|
||||
|
||||
if step, ok := repo.mfaChecked(userSession, request, user); !ok {
|
||||
step, ok, err := repo.mfaChecked(userSession, request, user)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !ok {
|
||||
return append(steps, step), nil
|
||||
}
|
||||
|
||||
@@ -611,44 +619,48 @@ func (repo *AuthRequestRepo) usersForUserSelection(request *model.AuthRequest) (
|
||||
return users, nil
|
||||
}
|
||||
|
||||
func (repo *AuthRequestRepo) mfaChecked(userSession *user_model.UserSessionView, request *model.AuthRequest, user *user_model.UserView) (model.NextStep, bool) {
|
||||
func (repo *AuthRequestRepo) mfaChecked(userSession *user_model.UserSessionView, request *model.AuthRequest, user *user_model.UserView) (model.NextStep, bool, error) {
|
||||
mfaLevel := request.MfaLevel()
|
||||
promptRequired := user.MfaMaxSetUp < mfaLevel
|
||||
if promptRequired || !repo.mfaSkippedOrSetUp(user) {
|
||||
promptRequired := (user.MfaMaxSetUp < mfaLevel) || !user.HasRequiredOrgMFALevel(request.LoginPolicy)
|
||||
if promptRequired || !repo.mfaSkippedOrSetUp(user, request.LoginPolicy) {
|
||||
types := user.MfaTypesSetupPossible(mfaLevel, request.LoginPolicy)
|
||||
if promptRequired && len(types) == 0 {
|
||||
return nil, false, errors.ThrowPreconditionFailed(nil, "LOGIN-5Hm8s", "Errors.Login.LoginPolicy.MFA.ForceAndNotConfigured")
|
||||
}
|
||||
return &model.MfaPromptStep{
|
||||
Required: promptRequired,
|
||||
MfaProviders: user.MfaTypesSetupPossible(mfaLevel),
|
||||
}, false
|
||||
MfaProviders: types,
|
||||
}, false, nil
|
||||
}
|
||||
switch mfaLevel {
|
||||
default:
|
||||
fallthrough
|
||||
case model.MfaLevelNotSetUp:
|
||||
if user.MfaMaxSetUp == model.MfaLevelNotSetUp {
|
||||
return nil, true
|
||||
case model.MFALevelNotSetUp:
|
||||
if user.MfaMaxSetUp == model.MFALevelNotSetUp {
|
||||
return nil, true, nil
|
||||
}
|
||||
fallthrough
|
||||
case model.MfaLevelSoftware:
|
||||
if checkVerificationTime(userSession.MfaSoftwareVerification, repo.MfaSoftwareCheckLifeTime) {
|
||||
request.MfasVerified = append(request.MfasVerified, userSession.MfaSoftwareVerificationType)
|
||||
request.AuthTime = userSession.MfaSoftwareVerification
|
||||
return nil, true
|
||||
case model.MFALevelSecondFactor:
|
||||
if checkVerificationTime(userSession.SecondFactorVerification, repo.SecondFactorCheckLifeTime) {
|
||||
request.MfasVerified = append(request.MfasVerified, userSession.SecondFactorVerificationType)
|
||||
request.AuthTime = userSession.SecondFactorVerification
|
||||
return nil, true, nil
|
||||
}
|
||||
fallthrough
|
||||
case model.MfaLevelHardware:
|
||||
if checkVerificationTime(userSession.MfaHardwareVerification, repo.MfaHardwareCheckLifeTime) {
|
||||
request.MfasVerified = append(request.MfasVerified, userSession.MfaHardwareVerificationType)
|
||||
request.AuthTime = userSession.MfaHardwareVerification
|
||||
return nil, true
|
||||
case model.MFALevelMultiFactor:
|
||||
if checkVerificationTime(userSession.MultiFactorVerification, repo.MultiFactorCheckLifeTime) {
|
||||
request.MfasVerified = append(request.MfasVerified, userSession.MultiFactorVerificationType)
|
||||
request.AuthTime = userSession.MultiFactorVerification
|
||||
return nil, true, nil
|
||||
}
|
||||
}
|
||||
return &model.MfaVerificationStep{
|
||||
MfaProviders: user.MfaTypesAllowed(mfaLevel),
|
||||
}, false
|
||||
MfaProviders: user.MfaTypesAllowed(mfaLevel, request.LoginPolicy),
|
||||
}, false, nil
|
||||
}
|
||||
|
||||
func (repo *AuthRequestRepo) mfaSkippedOrSetUp(user *user_model.UserView) bool {
|
||||
if user.MfaMaxSetUp > model.MfaLevelNotSetUp {
|
||||
func (repo *AuthRequestRepo) mfaSkippedOrSetUp(user *user_model.UserView, policy *iam_model.LoginPolicyView) bool {
|
||||
if user.MfaMaxSetUp > model.MFALevelNotSetUp {
|
||||
return true
|
||||
}
|
||||
return checkVerificationTime(user.MfaInitSkipped, repo.MfaInitSkippedLifeTime)
|
||||
|
Reference in New Issue
Block a user