mirror of
https://github.com/zitadel/zitadel.git
synced 2025-06-14 13:28:31 +00:00
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
This commit is contained in:
parent
12f8c7202c
commit
38478efefb
@ -86,9 +86,9 @@ SystemDefaults:
|
|||||||
FromName: $EMAIL_SENDER_NAME
|
FromName: $EMAIL_SENDER_NAME
|
||||||
Tls: $SMTP_TLS
|
Tls: $SMTP_TLS
|
||||||
Twilio:
|
Twilio:
|
||||||
SID: $TWILIO_SERVICE_SID
|
SID: $TWILIO_SERVICE_SID
|
||||||
Token: $TWILIO_TOKEN
|
Token: $TWILIO_TOKEN
|
||||||
From: $TWILIO_SENDER_NAME
|
From: $TWILIO_SENDER_NAME
|
||||||
TemplateData:
|
TemplateData:
|
||||||
InitCode:
|
InitCode:
|
||||||
Title: 'InitCode.Title'
|
Title: 'InitCode.Title'
|
||||||
@ -127,5 +127,6 @@ SystemDefaults:
|
|||||||
ButtonText: 'DomainClaimed.ButtonText'
|
ButtonText: 'DomainClaimed.ButtonText'
|
||||||
WebAuthN:
|
WebAuthN:
|
||||||
ID: $ZITADEL_COOKIE_DOMAIN
|
ID: $ZITADEL_COOKIE_DOMAIN
|
||||||
Origin: $ZITADEL_ACCOUNTS
|
OriginLogin: $ZITADEL_ACCOUNTS
|
||||||
|
OriginConsole: $ZITADEL_CONSOLE
|
||||||
DisplayName: ZITADEL
|
DisplayName: ZITADEL
|
@ -382,6 +382,7 @@ func mfaFromModel(mfa *usr_model.MultiFactor) *auth.MultiFactor {
|
|||||||
State: mfaStateFromModel(mfa.State),
|
State: mfaStateFromModel(mfa.State),
|
||||||
Type: mfaTypeFromModel(mfa.Type),
|
Type: mfaTypeFromModel(mfa.Type),
|
||||||
Attribute: mfa.Attribute,
|
Attribute: mfa.Attribute,
|
||||||
|
Id: mfa.ID,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -270,7 +270,7 @@ func (repo *AuthRequestRepo) BeginMFAU2FLogin(ctx context.Context, userID, authR
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
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) {
|
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 {
|
if err != nil {
|
||||||
return err
|
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) {
|
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 {
|
if err != nil {
|
||||||
return nil, err
|
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) {
|
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 {
|
if err != nil {
|
||||||
return err
|
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) {
|
func (repo *AuthRequestRepo) LinkExternalUsers(ctx context.Context, authReqID, userAgentID string, info *model.BrowserInfo) (err error) {
|
||||||
|
@ -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})
|
mfas = append(mfas, &model.MultiFactor{Type: model.MFATypeOTP, State: user.OTPState})
|
||||||
}
|
}
|
||||||
for _, u2f := range user.U2FTokens {
|
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
|
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) {
|
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) {
|
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 {
|
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) {
|
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) {
|
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 {
|
func (repo *UserRepo) VerifyPasswordlessSetup(ctx context.Context, userID, tokenName, userAgentID string, credentialData []byte) error {
|
||||||
|
@ -92,7 +92,8 @@ type TemplateData struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type WebAuthN struct {
|
type WebAuthN struct {
|
||||||
ID string
|
ID string
|
||||||
Origin string
|
OriginLogin string
|
||||||
DisplayName string
|
OriginConsole string
|
||||||
|
DisplayName string
|
||||||
}
|
}
|
||||||
|
@ -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})
|
mfas = append(mfas, &usr_model.MultiFactor{Type: usr_model.MFATypeOTP, State: user.OTPState})
|
||||||
}
|
}
|
||||||
for _, u2f := range user.U2FTokens {
|
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
|
return mfas, nil
|
||||||
}
|
}
|
||||||
|
@ -26,6 +26,7 @@ type MultiFactor struct {
|
|||||||
Type MFAType
|
Type MFAType
|
||||||
State MFAState
|
State MFAState
|
||||||
Attribute string
|
Attribute string
|
||||||
|
ID string
|
||||||
}
|
}
|
||||||
|
|
||||||
type MFAType int32
|
type MFAType int32
|
||||||
|
@ -70,7 +70,7 @@ func StartUser(conf UserConfig, systemDefaults sd.SystemDefaults) (*UserEventsto
|
|||||||
passwordVerificationCode := crypto.NewEncryptionGenerator(systemDefaults.SecretGenerators.PasswordVerificationCode, aesCrypto)
|
passwordVerificationCode := crypto.NewEncryptionGenerator(systemDefaults.SecretGenerators.PasswordVerificationCode, aesCrypto)
|
||||||
aesOTPCrypto, err := crypto.NewAESCrypto(systemDefaults.Multifactors.OTP.VerificationKey)
|
aesOTPCrypto, err := crypto.NewAESCrypto(systemDefaults.Multifactors.OTP.VerificationKey)
|
||||||
passwordAlg := crypto.NewBCrypt(systemDefaults.SecretGenerators.PasswordSaltCost)
|
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 {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -1302,12 +1302,12 @@ func (es *UserEventstore) verifyMFAOTP(otp *usr_model.OTP, code string) error {
|
|||||||
return nil
|
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)
|
user, err := es.HumanByID(ctx, userID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
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 {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -1333,7 +1333,7 @@ func (es *UserEventstore) VerifyU2FSetup(ctx context.Context, userID, tokenName,
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
_, token := user.Human.GetU2FToVerify()
|
_, 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 {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -1364,7 +1364,7 @@ func (es *UserEventstore) RemoveU2FToken(ctx context.Context, userID, webAuthNTo
|
|||||||
return nil
|
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)
|
user, err := es.HumanByID(ctx, userID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
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")
|
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 {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -1387,13 +1387,13 @@ func (es *UserEventstore) BeginU2FLogin(ctx context.Context, userID string, auth
|
|||||||
return webAuthNLogin, nil
|
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)
|
user, err := es.HumanByID(ctx, userID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
_, u2f := user.GetU2FLogin(authRequest.ID)
|
_, 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 {
|
if finishErr != nil && keyID == nil {
|
||||||
return finishErr
|
return finishErr
|
||||||
}
|
}
|
||||||
@ -1410,12 +1410,12 @@ func (es *UserEventstore) VerifyMFAU2F(ctx context.Context, userID string, crede
|
|||||||
return finishErr
|
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)
|
user, err := es.HumanByID(ctx, userID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
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 {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -1439,7 +1439,7 @@ func (es *UserEventstore) VerifyPasswordlessSetup(ctx context.Context, userID, t
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
_, token := user.Human.GetPasswordlessToVerify()
|
_, 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 {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -1470,7 +1470,7 @@ func (es *UserEventstore) RemovePasswordlessToken(ctx context.Context, userID, w
|
|||||||
return nil
|
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)
|
user, err := es.HumanByID(ctx, userID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -1478,7 +1478,7 @@ func (es *UserEventstore) BeginPasswordlessLogin(ctx context.Context, userID str
|
|||||||
if user.PasswordlessTokens == nil {
|
if user.PasswordlessTokens == nil {
|
||||||
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-5M9sd", "Errors.User.MFA.Passwordless.NotExisting")
|
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 {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -1492,13 +1492,13 @@ func (es *UserEventstore) BeginPasswordlessLogin(ctx context.Context, userID str
|
|||||||
return webAuthNLogin, nil
|
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)
|
user, err := es.HumanByID(ctx, userID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
_, passwordless := user.GetPasswordlessLogin(authRequest.ID)
|
_, 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 {
|
if finishErr != nil && keyID == nil {
|
||||||
return finishErr
|
return finishErr
|
||||||
}
|
}
|
||||||
|
@ -367,12 +367,13 @@ func (u *UserView) addPasswordlessToken(event *models.Event) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
for _, t := range u.PasswordlessTokens {
|
for i, t := range u.PasswordlessTokens {
|
||||||
if t.State == int32(model.MFAStateNotReady) {
|
if t.State == int32(model.MFAStateNotReady) {
|
||||||
t = token
|
u.PasswordlessTokens[i].ID = token.ID
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
token.State = int32(model.MFAStateNotReady)
|
||||||
u.U2FTokens = append(u.U2FTokens, token)
|
u.U2FTokens = append(u.U2FTokens, token)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -413,12 +414,13 @@ func (u *UserView) addU2FToken(event *models.Event) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
for _, t := range u.U2FTokens {
|
for i, t := range u.U2FTokens {
|
||||||
if t.State == int32(model.MFAStateNotReady) {
|
if t.State == int32(model.MFAStateNotReady) {
|
||||||
t = token
|
u.U2FTokens[i].ID = token.ID
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
token.State = int32(model.MFAStateNotReady)
|
||||||
u.U2FTokens = append(u.U2FTokens, token)
|
u.U2FTokens = append(u.U2FTokens, token)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -7,25 +7,36 @@ import (
|
|||||||
"github.com/duo-labs/webauthn/protocol"
|
"github.com/duo-labs/webauthn/protocol"
|
||||||
"github.com/duo-labs/webauthn/webauthn"
|
"github.com/duo-labs/webauthn/webauthn"
|
||||||
|
|
||||||
|
"github.com/caos/zitadel/internal/config/systemdefaults"
|
||||||
caos_errs "github.com/caos/zitadel/internal/errors"
|
caos_errs "github.com/caos/zitadel/internal/errors"
|
||||||
usr_model "github.com/caos/zitadel/internal/user/model"
|
usr_model "github.com/caos/zitadel/internal/user/model"
|
||||||
)
|
)
|
||||||
|
|
||||||
type WebAuthN struct {
|
type WebAuthN struct {
|
||||||
web *webauthn.WebAuthn
|
webLogin *webauthn.WebAuthn
|
||||||
|
webConsole *webauthn.WebAuthn
|
||||||
}
|
}
|
||||||
|
|
||||||
func StartServer(displayName, id, origin string) (*WebAuthN, error) {
|
func StartServer(sd systemdefaults.WebAuthN) (*WebAuthN, error) {
|
||||||
web, err := webauthn.New(&webauthn.Config{
|
webLogin, err := webauthn.New(&webauthn.Config{
|
||||||
RPDisplayName: displayName,
|
RPDisplayName: sd.DisplayName,
|
||||||
RPID: id,
|
RPID: sd.ID,
|
||||||
RPOrigin: origin,
|
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 {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return &WebAuthN{
|
return &WebAuthN{
|
||||||
web: web,
|
webLogin: webLogin,
|
||||||
|
webConsole: webConsole,
|
||||||
}, err
|
}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -54,7 +65,7 @@ func (u *webUser) WebAuthnCredentials() []webauthn.Credential {
|
|||||||
return u.credentials
|
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)
|
creds := WebAuthNsToCredentials(webAuthNs)
|
||||||
existing := make([]protocol.CredentialDescriptor, len(creds))
|
existing := make([]protocol.CredentialDescriptor, len(creds))
|
||||||
for i, cred := range 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,
|
CredentialID: cred.ID,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
credentialOptions, sessionData, err := w.web.BeginRegistration(
|
credentialOptions, sessionData, err := w.web(isLoginUI).BeginRegistration(
|
||||||
&webUser{
|
&webUser{
|
||||||
User: user,
|
User: user,
|
||||||
credentials: creds,
|
credentials: creds,
|
||||||
@ -90,7 +101,7 @@ func (w *WebAuthN) BeginRegistration(user *usr_model.User, authType usr_model.Au
|
|||||||
}, nil
|
}, 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 {
|
if webAuthN == nil {
|
||||||
return nil, caos_errs.ThrowInternal(nil, "WEBAU-5M9so", "Errors.User.WebAuthN.NotFound")
|
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")
|
return nil, caos_errs.ThrowInternal(err, "WEBAU-sEr8c", "Errors.User.WebAuthN.ErrorOnParseCredential")
|
||||||
}
|
}
|
||||||
sessionData := WebAuthNToSessionData(webAuthN)
|
sessionData := WebAuthNToSessionData(webAuthN)
|
||||||
credential, err := w.web.CreateCredential(
|
credential, err := w.web(isLoginUI).CreateCredential(
|
||||||
&webUser{
|
&webUser{
|
||||||
User: user,
|
User: user,
|
||||||
},
|
},
|
||||||
@ -117,8 +128,8 @@ func (w *WebAuthN) FinishRegistration(user *usr_model.User, webAuthN *usr_model.
|
|||||||
return webAuthN, nil
|
return webAuthN, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *WebAuthN) BeginLogin(user *usr_model.User, userVerification usr_model.UserVerificationRequirement, webAuthNs ...*usr_model.WebAuthNToken) (*usr_model.WebAuthNLogin, error) {
|
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.BeginLogin(&webUser{
|
assertion, sessionData, err := w.web(isLoginUI).BeginLogin(&webUser{
|
||||||
User: user,
|
User: user,
|
||||||
credentials: WebAuthNsToCredentials(webAuthNs),
|
credentials: WebAuthNsToCredentials(webAuthNs),
|
||||||
}, webauthn.WithUserVerification(UserVerificationFromModel(userVerification)))
|
}, webauthn.WithUserVerification(UserVerificationFromModel(userVerification)))
|
||||||
@ -137,7 +148,7 @@ func (w *WebAuthN) BeginLogin(user *usr_model.User, userVerification usr_model.U
|
|||||||
}, nil
|
}, 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))
|
assertionData, err := protocol.ParseCredentialRequestResponseBody(bytes.NewReader(credData))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, 0, caos_errs.ThrowInternal(err, "WEBAU-ADgv4", "Errors.User.WebAuthN.ValidateLoginFailed")
|
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,
|
User: user,
|
||||||
credentials: WebAuthNsToCredentials(webAuthNs),
|
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 {
|
if err != nil {
|
||||||
return nil, 0, caos_errs.ThrowInternal(err, "WEBAU-3M9si", "Errors.User.WebAuthN.ValidateLoginFailed")
|
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
|
return credential.ID, credential.Authenticator.SignCount, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (w *WebAuthN) web(isLoginUI bool) *webauthn.WebAuthn {
|
||||||
|
if isLoginUI {
|
||||||
|
return w.webLogin
|
||||||
|
}
|
||||||
|
return w.webConsole
|
||||||
|
}
|
||||||
|
@ -656,6 +656,7 @@ message MultiFactor {
|
|||||||
MfaType type = 1;
|
MfaType type = 1;
|
||||||
MFAState state = 2;
|
MFAState state = 2;
|
||||||
string attribute = 3;
|
string attribute = 3;
|
||||||
|
string id = 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
message MfaOtpResponse {
|
message MfaOtpResponse {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user