From 38478efefbfd91fa2ab15e63d4ae307dbb8c31d1 Mon Sep 17 00:00:00 2001 From: Livio Amstutz Date: Tue, 8 Dec 2020 15:39:58 +0100 Subject: [PATCH] fix: handle multiple webauthn origins (#1078) * fix(grpc): return CredentialCreationData in webauthn public key * return id of u2f tokens * handle separate origins in webauthn * param --- cmd/zitadel/system-defaults.yaml | 7 +-- internal/api/grpc/auth/user_converter.go | 1 + .../eventsourcing/eventstore/auth_request.go | 8 ++-- .../eventsourcing/eventstore/user.go | 10 ++-- .../config/systemdefaults/system_defaults.go | 7 +-- .../eventsourcing/eventstore/user.go | 2 +- internal/user/model/otp.go | 1 + .../repository/eventsourcing/eventstore.go | 30 ++++++------ internal/user/repository/view/model/user.go | 10 ++-- internal/webauthn/webauthn.go | 48 +++++++++++++------ pkg/grpc/auth/proto/auth.proto | 1 + 11 files changed, 75 insertions(+), 50 deletions(-) diff --git a/cmd/zitadel/system-defaults.yaml b/cmd/zitadel/system-defaults.yaml index 7f075bee3b..54a41bb068 100644 --- a/cmd/zitadel/system-defaults.yaml +++ b/cmd/zitadel/system-defaults.yaml @@ -86,9 +86,9 @@ SystemDefaults: FromName: $EMAIL_SENDER_NAME Tls: $SMTP_TLS Twilio: - SID: $TWILIO_SERVICE_SID + SID: $TWILIO_SERVICE_SID Token: $TWILIO_TOKEN - From: $TWILIO_SENDER_NAME + From: $TWILIO_SENDER_NAME TemplateData: InitCode: Title: 'InitCode.Title' @@ -127,5 +127,6 @@ SystemDefaults: ButtonText: 'DomainClaimed.ButtonText' WebAuthN: ID: $ZITADEL_COOKIE_DOMAIN - Origin: $ZITADEL_ACCOUNTS + OriginLogin: $ZITADEL_ACCOUNTS + OriginConsole: $ZITADEL_CONSOLE DisplayName: ZITADEL \ No newline at end of file diff --git a/internal/api/grpc/auth/user_converter.go b/internal/api/grpc/auth/user_converter.go index 0f1756854c..21e56f79fa 100644 --- a/internal/api/grpc/auth/user_converter.go +++ b/internal/api/grpc/auth/user_converter.go @@ -382,6 +382,7 @@ func mfaFromModel(mfa *usr_model.MultiFactor) *auth.MultiFactor { State: mfaStateFromModel(mfa.State), Type: mfaTypeFromModel(mfa.Type), Attribute: mfa.Attribute, + Id: mfa.ID, } } diff --git a/internal/auth/repository/eventsourcing/eventstore/auth_request.go b/internal/auth/repository/eventsourcing/eventstore/auth_request.go index cd9bd0406e..68189e5890 100644 --- a/internal/auth/repository/eventsourcing/eventstore/auth_request.go +++ b/internal/auth/repository/eventsourcing/eventstore/auth_request.go @@ -270,7 +270,7 @@ func (repo *AuthRequestRepo) BeginMFAU2FLogin(ctx context.Context, userID, authR if err != nil { return nil, err } - return repo.UserEvents.BeginU2FLogin(ctx, userID, request) + return repo.UserEvents.BeginU2FLogin(ctx, userID, request, true) } func (repo *AuthRequestRepo) VerifyMFAU2F(ctx context.Context, userID, authRequestID, userAgentID string, credentialData []byte, info *model.BrowserInfo) (err error) { @@ -280,7 +280,7 @@ func (repo *AuthRequestRepo) VerifyMFAU2F(ctx context.Context, userID, authReque if err != nil { return err } - return repo.UserEvents.VerifyMFAU2F(ctx, userID, credentialData, request) + return repo.UserEvents.VerifyMFAU2F(ctx, userID, credentialData, request, true) } func (repo *AuthRequestRepo) BeginPasswordlessLogin(ctx context.Context, userID, authRequestID, userAgentID string) (login *user_model.WebAuthNLogin, err error) { @@ -290,7 +290,7 @@ func (repo *AuthRequestRepo) BeginPasswordlessLogin(ctx context.Context, userID, if err != nil { return nil, err } - return repo.UserEvents.BeginPasswordlessLogin(ctx, userID, request) + return repo.UserEvents.BeginPasswordlessLogin(ctx, userID, request, true) } func (repo *AuthRequestRepo) VerifyPasswordless(ctx context.Context, userID, authRequestID, userAgentID string, credentialData []byte, info *model.BrowserInfo) (err error) { @@ -300,7 +300,7 @@ func (repo *AuthRequestRepo) VerifyPasswordless(ctx context.Context, userID, aut if err != nil { return err } - return repo.UserEvents.VerifyPasswordless(ctx, userID, credentialData, request) + return repo.UserEvents.VerifyPasswordless(ctx, userID, credentialData, request, true) } func (repo *AuthRequestRepo) LinkExternalUsers(ctx context.Context, authReqID, userAgentID string, info *model.BrowserInfo) (err error) { diff --git a/internal/auth/repository/eventsourcing/eventstore/user.go b/internal/auth/repository/eventsourcing/eventstore/user.go index 50ce4a1127..7fffb728d8 100644 --- a/internal/auth/repository/eventsourcing/eventstore/user.go +++ b/internal/auth/repository/eventsourcing/eventstore/user.go @@ -263,7 +263,7 @@ func (repo *UserRepo) MyUserMFAs(ctx context.Context) ([]*model.MultiFactor, err mfas = append(mfas, &model.MultiFactor{Type: model.MFATypeOTP, State: user.OTPState}) } for _, u2f := range user.U2FTokens { - mfas = append(mfas, &model.MultiFactor{Type: model.MFATypeU2F, State: u2f.State, Attribute: u2f.Name}) + mfas = append(mfas, &model.MultiFactor{Type: model.MFATypeU2F, State: u2f.State, Attribute: u2f.Name, ID: u2f.TokenID}) } return mfas, nil } @@ -303,11 +303,11 @@ func (repo *UserRepo) RemoveMyMFAOTP(ctx context.Context) error { } func (repo *UserRepo) AddMFAU2F(ctx context.Context, userID string) (*model.WebAuthNToken, error) { - return repo.UserEvents.AddU2F(ctx, userID) + return repo.UserEvents.AddU2F(ctx, userID, true) } func (repo *UserRepo) AddMyMFAU2F(ctx context.Context) (*model.WebAuthNToken, error) { - return repo.UserEvents.AddU2F(ctx, authz.GetCtxData(ctx).UserID) + return repo.UserEvents.AddU2F(ctx, authz.GetCtxData(ctx).UserID, false) } func (repo *UserRepo) VerifyMFAU2FSetup(ctx context.Context, userID, tokenName, userAgentID string, credentialData []byte) error { @@ -327,11 +327,11 @@ func (repo *UserRepo) RemoveMyMFAU2F(ctx context.Context, webAuthNTokenID string } func (repo *UserRepo) AddPasswordless(ctx context.Context, userID string) (*model.WebAuthNToken, error) { - return repo.UserEvents.AddPasswordless(ctx, userID) + return repo.UserEvents.AddPasswordless(ctx, userID, true) } func (repo *UserRepo) AddMyPasswordless(ctx context.Context) (*model.WebAuthNToken, error) { - return repo.UserEvents.AddPasswordless(ctx, authz.GetCtxData(ctx).UserID) + return repo.UserEvents.AddPasswordless(ctx, authz.GetCtxData(ctx).UserID, false) } func (repo *UserRepo) VerifyPasswordlessSetup(ctx context.Context, userID, tokenName, userAgentID string, credentialData []byte) error { diff --git a/internal/config/systemdefaults/system_defaults.go b/internal/config/systemdefaults/system_defaults.go index c6b582b30d..1e6bab7a22 100644 --- a/internal/config/systemdefaults/system_defaults.go +++ b/internal/config/systemdefaults/system_defaults.go @@ -92,7 +92,8 @@ type TemplateData struct { } type WebAuthN struct { - ID string - Origin string - DisplayName string + ID string + OriginLogin string + OriginConsole string + DisplayName string } diff --git a/internal/management/repository/eventsourcing/eventstore/user.go b/internal/management/repository/eventsourcing/eventstore/user.go index 8eb7a1806b..a9c77c84b8 100644 --- a/internal/management/repository/eventsourcing/eventstore/user.go +++ b/internal/management/repository/eventsourcing/eventstore/user.go @@ -222,7 +222,7 @@ func (repo *UserRepo) UserMFAs(ctx context.Context, userID string) ([]*usr_model mfas = append(mfas, &usr_model.MultiFactor{Type: usr_model.MFATypeOTP, State: user.OTPState}) } for _, u2f := range user.U2FTokens { - mfas = append(mfas, &usr_model.MultiFactor{Type: usr_model.MFATypeU2F, State: u2f.State, Attribute: u2f.Name}) + mfas = append(mfas, &usr_model.MultiFactor{Type: usr_model.MFATypeU2F, State: u2f.State, Attribute: u2f.Name, ID: u2f.TokenID}) } return mfas, nil } diff --git a/internal/user/model/otp.go b/internal/user/model/otp.go index 3317ae6b99..78e4626297 100644 --- a/internal/user/model/otp.go +++ b/internal/user/model/otp.go @@ -26,6 +26,7 @@ type MultiFactor struct { Type MFAType State MFAState Attribute string + ID string } type MFAType int32 diff --git a/internal/user/repository/eventsourcing/eventstore.go b/internal/user/repository/eventsourcing/eventstore.go index 6d553a3492..447351435f 100644 --- a/internal/user/repository/eventsourcing/eventstore.go +++ b/internal/user/repository/eventsourcing/eventstore.go @@ -70,7 +70,7 @@ func StartUser(conf UserConfig, systemDefaults sd.SystemDefaults) (*UserEventsto passwordVerificationCode := crypto.NewEncryptionGenerator(systemDefaults.SecretGenerators.PasswordVerificationCode, aesCrypto) aesOTPCrypto, err := crypto.NewAESCrypto(systemDefaults.Multifactors.OTP.VerificationKey) passwordAlg := crypto.NewBCrypt(systemDefaults.SecretGenerators.PasswordSaltCost) - web, err := webauthn_helper.StartServer(systemDefaults.WebAuthN.DisplayName, systemDefaults.WebAuthN.ID, systemDefaults.WebAuthN.Origin) + web, err := webauthn_helper.StartServer(systemDefaults.WebAuthN) if err != nil { return nil, err } @@ -1302,12 +1302,12 @@ func (es *UserEventstore) verifyMFAOTP(otp *usr_model.OTP, code string) error { return nil } -func (es *UserEventstore) AddU2F(ctx context.Context, userID string) (*usr_model.WebAuthNToken, error) { +func (es *UserEventstore) AddU2F(ctx context.Context, userID string, isLoginUI bool) (*usr_model.WebAuthNToken, error) { user, err := es.HumanByID(ctx, userID) if err != nil { return nil, err } - webAuthN, err := es.webauthn.BeginRegistration(user, usr_model.AuthenticatorAttachmentUnspecified, usr_model.UserVerificationRequirementDiscouraged, user.U2FTokens...) + webAuthN, err := es.webauthn.BeginRegistration(user, usr_model.AuthenticatorAttachmentUnspecified, usr_model.UserVerificationRequirementDiscouraged, isLoginUI, user.U2FTokens...) if err != nil { return nil, err } @@ -1333,7 +1333,7 @@ func (es *UserEventstore) VerifyU2FSetup(ctx context.Context, userID, tokenName, return err } _, token := user.Human.GetU2FToVerify() - webAuthN, err := es.webauthn.FinishRegistration(user, token, tokenName, credentialData) + webAuthN, err := es.webauthn.FinishRegistration(user, token, tokenName, credentialData, userAgentID != "") if err != nil { return err } @@ -1364,7 +1364,7 @@ func (es *UserEventstore) RemoveU2FToken(ctx context.Context, userID, webAuthNTo return nil } -func (es *UserEventstore) BeginU2FLogin(ctx context.Context, userID string, authRequest *req_model.AuthRequest) (*usr_model.WebAuthNLogin, error) { +func (es *UserEventstore) BeginU2FLogin(ctx context.Context, userID string, authRequest *req_model.AuthRequest, isLoginUI bool) (*usr_model.WebAuthNLogin, error) { user, err := es.HumanByID(ctx, userID) if err != nil { return nil, err @@ -1373,7 +1373,7 @@ func (es *UserEventstore) BeginU2FLogin(ctx context.Context, userID string, auth return nil, errors.ThrowPreconditionFailed(nil, "EVENT-5Mk8s", "Errors.User.MFA.U2F.NotExisting") } - webAuthNLogin, err := es.webauthn.BeginLogin(user, usr_model.UserVerificationRequirementDiscouraged, user.U2FTokens...) + webAuthNLogin, err := es.webauthn.BeginLogin(user, usr_model.UserVerificationRequirementDiscouraged, isLoginUI, user.U2FTokens...) if err != nil { return nil, err } @@ -1387,13 +1387,13 @@ func (es *UserEventstore) BeginU2FLogin(ctx context.Context, userID string, auth return webAuthNLogin, nil } -func (es *UserEventstore) VerifyMFAU2F(ctx context.Context, userID string, credentialData []byte, authRequest *req_model.AuthRequest) error { +func (es *UserEventstore) VerifyMFAU2F(ctx context.Context, userID string, credentialData []byte, authRequest *req_model.AuthRequest, isLoginUI bool) error { user, err := es.HumanByID(ctx, userID) if err != nil { return err } _, u2f := user.GetU2FLogin(authRequest.ID) - keyID, signCount, finishErr := es.webauthn.FinishLogin(user, u2f, credentialData, user.U2FTokens...) + keyID, signCount, finishErr := es.webauthn.FinishLogin(user, u2f, credentialData, isLoginUI, user.U2FTokens...) if finishErr != nil && keyID == nil { return finishErr } @@ -1410,12 +1410,12 @@ func (es *UserEventstore) VerifyMFAU2F(ctx context.Context, userID string, crede return finishErr } -func (es *UserEventstore) AddPasswordless(ctx context.Context, userID string) (*usr_model.WebAuthNToken, error) { +func (es *UserEventstore) AddPasswordless(ctx context.Context, userID string, isLoginUI bool) (*usr_model.WebAuthNToken, error) { user, err := es.HumanByID(ctx, userID) if err != nil { return nil, err } - webAuthN, err := es.webauthn.BeginRegistration(user, usr_model.AuthenticatorAttachmentUnspecified, usr_model.UserVerificationRequirementRequired, user.PasswordlessTokens...) + webAuthN, err := es.webauthn.BeginRegistration(user, usr_model.AuthenticatorAttachmentUnspecified, usr_model.UserVerificationRequirementRequired, isLoginUI, user.PasswordlessTokens...) if err != nil { return nil, err } @@ -1439,7 +1439,7 @@ func (es *UserEventstore) VerifyPasswordlessSetup(ctx context.Context, userID, t return err } _, token := user.Human.GetPasswordlessToVerify() - webAuthN, err := es.webauthn.FinishRegistration(user, token, tokenName, credentialData) + webAuthN, err := es.webauthn.FinishRegistration(user, token, tokenName, credentialData, userAgentID != "") if err != nil { return err } @@ -1470,7 +1470,7 @@ func (es *UserEventstore) RemovePasswordlessToken(ctx context.Context, userID, w return nil } -func (es *UserEventstore) BeginPasswordlessLogin(ctx context.Context, userID string, authRequest *req_model.AuthRequest) (*usr_model.WebAuthNLogin, error) { +func (es *UserEventstore) BeginPasswordlessLogin(ctx context.Context, userID string, authRequest *req_model.AuthRequest, isLoginUI bool) (*usr_model.WebAuthNLogin, error) { user, err := es.HumanByID(ctx, userID) if err != nil { return nil, err @@ -1478,7 +1478,7 @@ func (es *UserEventstore) BeginPasswordlessLogin(ctx context.Context, userID str if user.PasswordlessTokens == nil { return nil, errors.ThrowPreconditionFailed(nil, "EVENT-5M9sd", "Errors.User.MFA.Passwordless.NotExisting") } - webAuthNLogin, err := es.webauthn.BeginLogin(user, usr_model.UserVerificationRequirementRequired, user.PasswordlessTokens...) + webAuthNLogin, err := es.webauthn.BeginLogin(user, usr_model.UserVerificationRequirementRequired, isLoginUI, user.PasswordlessTokens...) if err != nil { return nil, err } @@ -1492,13 +1492,13 @@ func (es *UserEventstore) BeginPasswordlessLogin(ctx context.Context, userID str return webAuthNLogin, nil } -func (es *UserEventstore) VerifyPasswordless(ctx context.Context, userID string, credentialData []byte, authRequest *req_model.AuthRequest) error { +func (es *UserEventstore) VerifyPasswordless(ctx context.Context, userID string, credentialData []byte, authRequest *req_model.AuthRequest, isLoginUI bool) error { user, err := es.HumanByID(ctx, userID) if err != nil { return err } _, passwordless := user.GetPasswordlessLogin(authRequest.ID) - keyID, signCount, finishErr := es.webauthn.FinishLogin(user, passwordless, credentialData, user.PasswordlessTokens...) + keyID, signCount, finishErr := es.webauthn.FinishLogin(user, passwordless, credentialData, isLoginUI, user.PasswordlessTokens...) if finishErr != nil && keyID == nil { return finishErr } diff --git a/internal/user/repository/view/model/user.go b/internal/user/repository/view/model/user.go index b13031bc5e..0d65bc108b 100644 --- a/internal/user/repository/view/model/user.go +++ b/internal/user/repository/view/model/user.go @@ -367,12 +367,13 @@ func (u *UserView) addPasswordlessToken(event *models.Event) error { if err != nil { return err } - for _, t := range u.PasswordlessTokens { + for i, t := range u.PasswordlessTokens { if t.State == int32(model.MFAStateNotReady) { - t = token + u.PasswordlessTokens[i].ID = token.ID return nil } } + token.State = int32(model.MFAStateNotReady) u.U2FTokens = append(u.U2FTokens, token) return nil } @@ -413,12 +414,13 @@ func (u *UserView) addU2FToken(event *models.Event) error { if err != nil { return err } - for _, t := range u.U2FTokens { + for i, t := range u.U2FTokens { if t.State == int32(model.MFAStateNotReady) { - t = token + u.U2FTokens[i].ID = token.ID return nil } } + token.State = int32(model.MFAStateNotReady) u.U2FTokens = append(u.U2FTokens, token) return nil } diff --git a/internal/webauthn/webauthn.go b/internal/webauthn/webauthn.go index 4a38ab1b58..8c1fa0093f 100644 --- a/internal/webauthn/webauthn.go +++ b/internal/webauthn/webauthn.go @@ -7,25 +7,36 @@ import ( "github.com/duo-labs/webauthn/protocol" "github.com/duo-labs/webauthn/webauthn" + "github.com/caos/zitadel/internal/config/systemdefaults" caos_errs "github.com/caos/zitadel/internal/errors" usr_model "github.com/caos/zitadel/internal/user/model" ) type WebAuthN struct { - web *webauthn.WebAuthn + webLogin *webauthn.WebAuthn + webConsole *webauthn.WebAuthn } -func StartServer(displayName, id, origin string) (*WebAuthN, error) { - web, err := webauthn.New(&webauthn.Config{ - RPDisplayName: displayName, - RPID: id, - RPOrigin: origin, +func StartServer(sd systemdefaults.WebAuthN) (*WebAuthN, error) { + webLogin, err := webauthn.New(&webauthn.Config{ + RPDisplayName: sd.DisplayName, + RPID: sd.ID, + RPOrigin: sd.OriginLogin, + }) + if err != nil { + return nil, err + } + webConsole, err := webauthn.New(&webauthn.Config{ + RPDisplayName: sd.DisplayName, + RPID: sd.ID, + RPOrigin: sd.OriginConsole, }) if err != nil { return nil, err } return &WebAuthN{ - web: web, + webLogin: webLogin, + webConsole: webConsole, }, err } @@ -54,7 +65,7 @@ func (u *webUser) WebAuthnCredentials() []webauthn.Credential { return u.credentials } -func (w *WebAuthN) BeginRegistration(user *usr_model.User, authType usr_model.AuthenticatorAttachment, userVerification usr_model.UserVerificationRequirement, webAuthNs ...*usr_model.WebAuthNToken) (*usr_model.WebAuthNToken, error) { +func (w *WebAuthN) BeginRegistration(user *usr_model.User, authType usr_model.AuthenticatorAttachment, userVerification usr_model.UserVerificationRequirement, isLoginUI bool, webAuthNs ...*usr_model.WebAuthNToken) (*usr_model.WebAuthNToken, error) { creds := WebAuthNsToCredentials(webAuthNs) existing := make([]protocol.CredentialDescriptor, len(creds)) for i, cred := range creds { @@ -63,7 +74,7 @@ func (w *WebAuthN) BeginRegistration(user *usr_model.User, authType usr_model.Au CredentialID: cred.ID, } } - credentialOptions, sessionData, err := w.web.BeginRegistration( + credentialOptions, sessionData, err := w.web(isLoginUI).BeginRegistration( &webUser{ User: user, credentials: creds, @@ -90,7 +101,7 @@ func (w *WebAuthN) BeginRegistration(user *usr_model.User, authType usr_model.Au }, nil } -func (w *WebAuthN) FinishRegistration(user *usr_model.User, webAuthN *usr_model.WebAuthNToken, tokenName string, credData []byte) (*usr_model.WebAuthNToken, error) { +func (w *WebAuthN) FinishRegistration(user *usr_model.User, webAuthN *usr_model.WebAuthNToken, tokenName string, credData []byte, isLoginUI bool) (*usr_model.WebAuthNToken, error) { if webAuthN == nil { return nil, caos_errs.ThrowInternal(nil, "WEBAU-5M9so", "Errors.User.WebAuthN.NotFound") } @@ -99,7 +110,7 @@ func (w *WebAuthN) FinishRegistration(user *usr_model.User, webAuthN *usr_model. return nil, caos_errs.ThrowInternal(err, "WEBAU-sEr8c", "Errors.User.WebAuthN.ErrorOnParseCredential") } sessionData := WebAuthNToSessionData(webAuthN) - credential, err := w.web.CreateCredential( + credential, err := w.web(isLoginUI).CreateCredential( &webUser{ User: user, }, @@ -117,8 +128,8 @@ func (w *WebAuthN) FinishRegistration(user *usr_model.User, webAuthN *usr_model. return webAuthN, nil } -func (w *WebAuthN) BeginLogin(user *usr_model.User, userVerification usr_model.UserVerificationRequirement, webAuthNs ...*usr_model.WebAuthNToken) (*usr_model.WebAuthNLogin, error) { - assertion, sessionData, err := w.web.BeginLogin(&webUser{ +func (w *WebAuthN) BeginLogin(user *usr_model.User, userVerification usr_model.UserVerificationRequirement, isLoginUI bool, webAuthNs ...*usr_model.WebAuthNToken) (*usr_model.WebAuthNLogin, error) { + assertion, sessionData, err := w.web(isLoginUI).BeginLogin(&webUser{ User: user, credentials: WebAuthNsToCredentials(webAuthNs), }, webauthn.WithUserVerification(UserVerificationFromModel(userVerification))) @@ -137,7 +148,7 @@ func (w *WebAuthN) BeginLogin(user *usr_model.User, userVerification usr_model.U }, nil } -func (w *WebAuthN) FinishLogin(user *usr_model.User, webAuthN *usr_model.WebAuthNLogin, credData []byte, webAuthNs ...*usr_model.WebAuthNToken) ([]byte, uint32, error) { +func (w *WebAuthN) FinishLogin(user *usr_model.User, webAuthN *usr_model.WebAuthNLogin, credData []byte, isLoginUI bool, webAuthNs ...*usr_model.WebAuthNToken) ([]byte, uint32, error) { assertionData, err := protocol.ParseCredentialRequestResponseBody(bytes.NewReader(credData)) if err != nil { return nil, 0, caos_errs.ThrowInternal(err, "WEBAU-ADgv4", "Errors.User.WebAuthN.ValidateLoginFailed") @@ -146,7 +157,7 @@ func (w *WebAuthN) FinishLogin(user *usr_model.User, webAuthN *usr_model.WebAuth User: user, credentials: WebAuthNsToCredentials(webAuthNs), } - credential, err := w.web.ValidateLogin(webUser, WebAuthNLoginToSessionData(webAuthN), assertionData) + credential, err := w.web(isLoginUI).ValidateLogin(webUser, WebAuthNLoginToSessionData(webAuthN), assertionData) if err != nil { return nil, 0, caos_errs.ThrowInternal(err, "WEBAU-3M9si", "Errors.User.WebAuthN.ValidateLoginFailed") } @@ -156,3 +167,10 @@ func (w *WebAuthN) FinishLogin(user *usr_model.User, webAuthN *usr_model.WebAuth } return credential.ID, credential.Authenticator.SignCount, nil } + +func (w *WebAuthN) web(isLoginUI bool) *webauthn.WebAuthn { + if isLoginUI { + return w.webLogin + } + return w.webConsole +} diff --git a/pkg/grpc/auth/proto/auth.proto b/pkg/grpc/auth/proto/auth.proto index fccedd0b55..70490f9f22 100644 --- a/pkg/grpc/auth/proto/auth.proto +++ b/pkg/grpc/auth/proto/auth.proto @@ -656,6 +656,7 @@ message MultiFactor { MfaType type = 1; MFAState state = 2; string attribute = 3; + string id = 4; } message MfaOtpResponse {