feat: add WebAuthN support for passwordless login and 2fa (#966)

* at least registration prompt works

* in memory test for login

* buttons to start webauthn process

* begin eventstore impl

* begin eventstore impl

* serialize into bytes

* fix: u2f, passwordless types

* fix for localhost

* fix script

* fix: u2f, passwordless types

* fix: add u2f

* fix: verify u2f

* fix: session data in event store

* fix: u2f credentials in eventstore

* fix: webauthn pkg handles business models

* feat: tests

* feat: append events

* fix: test

* fix: check only ready webauthn creds

* fix: move u2f methods to authrepo

* frontend improvements

* fix return

* feat: add passwordless

* feat: add passwordless

* improve ui / error handling

* separate call for login

* fix login

* js

* feat: u2f login methods

* feat: remove unused session id

* feat: error handling

* feat: error handling

* feat: refactor user eventstore

* feat: finish webauthn

* feat: u2f and passwordlss in auth.proto

* u2f step

* passwordless step

* cleanup js

* EndpointPasswordLessLogin

* migration

* update mfaChecked test

* next step test

* token name

* cleanup

* attribute

* passwordless as tokens

* remove sms as otp type

* add "user" to amr for webauthn

* error handling

* fixes

* fix tests

* naming

* naming

* fixes

* session handler

* i18n

* error handling in login

* Update internal/ui/login/static/i18n/de.yaml

Co-authored-by: Fabi <38692350+fgerschwiler@users.noreply.github.com>

* Update internal/ui/login/static/i18n/en.yaml

Co-authored-by: Fabi <38692350+fgerschwiler@users.noreply.github.com>

* improvements

* merge fixes

* fixes

* fixes

Co-authored-by: Fabiennne <fabienne.gerschwiler@gmail.com>
Co-authored-by: Fabi <38692350+fgerschwiler@users.noreply.github.com>
This commit is contained in:
Livio Amstutz
2020-12-02 17:00:04 +01:00
committed by GitHub
parent 184e79be97
commit 300ade66a7
115 changed files with 3383 additions and 740 deletions

View File

@@ -18,12 +18,27 @@ type AuthRequest struct {
}
func AuthRequestFromModel(request *model.AuthRequest) *AuthRequest {
return &AuthRequest{
req := &AuthRequest{
ID: request.ID,
UserAgentID: request.AgentID,
BrowserInfo: BrowserInfoFromModel(request.BrowserInfo),
SelectedIDPConfigID: request.SelectedIDPConfigID,
}
if request.BrowserInfo != nil {
req.BrowserInfo = BrowserInfoFromModel(request.BrowserInfo)
}
return req
}
func AuthRequestToModel(request *AuthRequest) *model.AuthRequest {
req := &model.AuthRequest{
ID: request.ID,
AgentID: request.UserAgentID,
SelectedIDPConfigID: request.SelectedIDPConfigID,
}
if request.BrowserInfo != nil {
req.BrowserInfo = BrowserInfoToModel(request.BrowserInfo)
}
return req
}
type BrowserInfo struct {
@@ -40,6 +55,13 @@ func BrowserInfoFromModel(info *model.BrowserInfo) *BrowserInfo {
}
}
func BrowserInfoToModel(info *BrowserInfo) *model.BrowserInfo {
return &model.BrowserInfo{
UserAgent: info.UserAgent,
AcceptLanguage: info.AcceptLanguage,
RemoteIP: info.RemoteIP,
}
}
func (a *AuthRequest) SetData(event *es_models.Event) error {
if err := json.Unmarshal(event.Data, a); err != nil {
logging.Log("EVEN-T5df6").WithError(err).Error("could not unmarshal event data")

View File

@@ -2,7 +2,6 @@ package model
import (
"encoding/json"
"github.com/caos/logging"
"github.com/caos/zitadel/internal/crypto"
caos_errs "github.com/caos/zitadel/internal/errors"
@@ -29,19 +28,19 @@ func OTPToModel(otp *OTP) *model.OTP {
return &model.OTP{
ObjectRoot: otp.ObjectRoot,
Secret: otp.Secret,
State: model.MfaState(otp.State),
State: model.MFAState(otp.State),
}
}
func (u *Human) appendOTPAddedEvent(event *es_models.Event) error {
u.OTP = &OTP{
State: int32(model.MfaStateNotReady),
State: int32(model.MFAStateNotReady),
}
return u.OTP.setData(event)
}
func (u *Human) appendOTPVerifiedEvent() {
u.OTP.State = int32(model.MfaStateReady)
u.OTP.State = int32(model.MFAStateReady)
}
func (u *Human) appendOTPRemovedEvent() {

View File

@@ -9,7 +9,7 @@ import (
"github.com/caos/zitadel/internal/user/model"
)
func TestAppendMfaOTPAddedEvent(t *testing.T) {
func TestAppendMFAOTPAddedEvent(t *testing.T) {
type args struct {
user *Human
otp *OTP
@@ -27,7 +27,7 @@ func TestAppendMfaOTPAddedEvent(t *testing.T) {
otp: &OTP{Secret: &crypto.CryptoValue{KeyID: "KeyID"}},
event: &es_models.Event{},
},
result: &Human{OTP: &OTP{Secret: &crypto.CryptoValue{KeyID: "KeyID"}, State: int32(model.MfaStateNotReady)}},
result: &Human{OTP: &OTP{Secret: &crypto.CryptoValue{KeyID: "KeyID"}, State: int32(model.MFAStateNotReady)}},
},
}
for _, tt := range tests {
@@ -44,7 +44,7 @@ func TestAppendMfaOTPAddedEvent(t *testing.T) {
}
}
func TestAppendMfaOTPVerifyEvent(t *testing.T) {
func TestAppendMFAOTPVerifyEvent(t *testing.T) {
type args struct {
user *Human
otp *OTP
@@ -62,7 +62,7 @@ func TestAppendMfaOTPVerifyEvent(t *testing.T) {
otp: &OTP{Secret: &crypto.CryptoValue{KeyID: "KeyID"}},
event: &es_models.Event{},
},
result: &Human{OTP: &OTP{Secret: &crypto.CryptoValue{KeyID: "KeyID"}, State: int32(model.MfaStateReady)}},
result: &Human{OTP: &OTP{Secret: &crypto.CryptoValue{KeyID: "KeyID"}, State: int32(model.MFAStateReady)}},
},
}
for _, tt := range tests {
@@ -79,7 +79,7 @@ func TestAppendMfaOTPVerifyEvent(t *testing.T) {
}
}
func TestAppendMfaOTPRemoveEvent(t *testing.T) {
func TestAppendMFAOTPRemoveEvent(t *testing.T) {
type args struct {
user *Human
otp *OTP

View File

@@ -118,6 +118,22 @@ const (
HumanMFAOTPCheckFailed models.EventType = "user.human.mfa.otp.check.failed"
HumanMFAInitSkipped models.EventType = "user.human.mfa.init.skipped"
HumanMFAU2FTokenAdded models.EventType = "user.human.mfa.u2f.token.added"
HumanMFAU2FTokenVerified models.EventType = "user.human.mfa.u2f.token.verified"
HumanMFAU2FTokenSignCountChanged models.EventType = "user.human.mfa.u2f.token.signcount.changed"
HumanMFAU2FTokenRemoved models.EventType = "user.human.mfa.u2f.token.removed"
HumanMFAU2FTokenBeginLogin models.EventType = "user.human.mfa.u2f.token.begin.login"
HumanMFAU2FTokenCheckSucceeded models.EventType = "user.human.mfa.u2f.token.check.succeeded"
HumanMFAU2FTokenCheckFailed models.EventType = "user.human.mfa.u2f.token.check.failed"
HumanPasswordlessTokenAdded models.EventType = "user.human.passwordless.token.added"
HumanPasswordlessTokenVerified models.EventType = "user.human.passwordless.token.verified"
HumanPasswordlessTokenChangeSignCount models.EventType = "user.human.passwordless.token.signcount.changed"
HumanPasswordlessTokenRemoved models.EventType = "user.human.passwordless.token.removed"
HumanPasswordlessTokenBeginLogin models.EventType = "user.human.passwordless.token.begin.login"
HumanPasswordlessTokenCheckSucceeded models.EventType = "user.human.passwordless.token.check.succeeded"
HumanPasswordlessTokenCheckFailed models.EventType = "user.human.passwordless.token.check.failed"
HumanSignedOut models.EventType = "user.human.signed.out"
)

View File

@@ -19,12 +19,16 @@ type Human struct {
*Email
*Phone
*Address
ExternalIDPs []*ExternalIDP `json:"-"`
InitCode *InitUserCode `json:"-"`
EmailCode *EmailCode `json:"-"`
PhoneCode *PhoneCode `json:"-"`
PasswordCode *PasswordCode `json:"-"`
OTP *OTP `json:"-"`
ExternalIDPs []*ExternalIDP `json:"-"`
InitCode *InitUserCode `json:"-"`
EmailCode *EmailCode `json:"-"`
PhoneCode *PhoneCode `json:"-"`
PasswordCode *PasswordCode `json:"-"`
OTP *OTP `json:"-"`
U2FTokens []*WebAuthNToken `json:"-"`
PasswordlessTokens []*WebAuthNToken `json:"-"`
U2FLogins []*WebAuthNLogin `json:"-"`
PasswordlessLogins []*WebAuthNLogin `json:"-"`
}
type InitUserCode struct {
@@ -56,6 +60,15 @@ func HumanFromModel(user *model.Human) *Human {
if user.ExternalIDPs != nil {
human.ExternalIDPs = ExternalIDPsFromModel(user.ExternalIDPs)
}
if user.U2FTokens != nil {
human.U2FTokens = WebAuthNsFromModel(user.U2FTokens)
}
if user.PasswordlessTokens != nil {
human.PasswordlessTokens = WebAuthNsFromModel(user.PasswordlessTokens)
}
if user.U2FLogins != nil {
human.U2FLogins = WebAuthNLoginsFromModel(user.U2FLogins)
}
return human
}
@@ -94,6 +107,15 @@ func HumanToModel(user *Human) *model.Human {
if user.OTP != nil {
human.OTP = OTPToModel(user.OTP)
}
if user.U2FTokens != nil {
human.U2FTokens = WebAuthNsToModel(user.U2FTokens)
}
if user.PasswordlessTokens != nil {
human.PasswordlessTokens = WebAuthNsToModel(user.PasswordlessTokens)
}
if user.U2FLogins != nil {
human.U2FLogins = WebAuthNLoginsToModel(user.U2FLogins)
}
return human
}
@@ -133,10 +155,10 @@ func (h *Human) AppendEvent(event *es_models.Event) (err error) {
HumanAdded,
HumanRegistered,
HumanProfileChanged:
h.setData(event)
err = h.setData(event)
case InitializedUserCodeAdded,
InitializedHumanCodeAdded:
h.appendInitUsercodeCreatedEvent(event)
err = h.appendInitUsercodeCreatedEvent(event)
case UserPasswordChanged,
HumanPasswordChanged:
err = h.appendUserPasswordChangedEvent(event)
@@ -180,6 +202,26 @@ func (h *Human) AppendEvent(event *es_models.Event) (err error) {
err = h.appendExternalIDPAddedEvent(event)
case HumanExternalIDPRemoved, HumanExternalIDPCascadeRemoved:
err = h.appendExternalIDPRemovedEvent(event)
case HumanMFAU2FTokenAdded:
err = h.appendU2FAddedEvent(event)
case HumanMFAU2FTokenVerified:
err = h.appendU2FVerifiedEvent(event)
case HumanMFAU2FTokenSignCountChanged:
err = h.appendU2FChangeSignCountEvent(event)
case HumanMFAU2FTokenRemoved:
err = h.appendU2FRemovedEvent(event)
case HumanPasswordlessTokenAdded:
err = h.appendPasswordlessAddedEvent(event)
case HumanPasswordlessTokenVerified:
err = h.appendPasswordlessVerifiedEvent(event)
case HumanPasswordlessTokenChangeSignCount:
err = h.appendPasswordlessChangeSignCountEvent(event)
case HumanPasswordlessTokenRemoved:
err = h.appendPasswordlessRemovedEvent(event)
case HumanMFAU2FTokenBeginLogin:
err = h.appendU2FLoginEvent(event)
case HumanPasswordlessTokenBeginLogin:
err = h.appendPasswordlessLoginEvent(event)
}
if err != nil {
return err

View File

@@ -0,0 +1,336 @@
package model
import (
"encoding/json"
"github.com/caos/logging"
caos_errs "github.com/caos/zitadel/internal/errors"
es_models "github.com/caos/zitadel/internal/eventstore/models"
"github.com/caos/zitadel/internal/user/model"
)
type WebAuthNToken struct {
es_models.ObjectRoot
WebauthNTokenID string `json:"webAuthNTokenId"`
Challenge string `json:"challenge"`
State int32 `json:"-"`
KeyID []byte `json:"keyId"`
PublicKey []byte `json:"publicKey"`
AttestationType string `json:"attestationType"`
AAGUID []byte `json:"aaguid"`
SignCount uint32 `json:"signCount"`
}
type WebAuthNVerify struct {
WebAuthNTokenID string `json:"webAuthNTokenId"`
KeyID []byte `json:"keyId"`
PublicKey []byte `json:"publicKey"`
AttestationType string `json:"attestationType"`
AAGUID []byte `json:"aaguid"`
SignCount uint32 `json:"signCount"`
WebAuthNTokenName string `json:"webAuthNTokenName"`
}
type WebAuthNSignCount struct {
WebauthNTokenID string `json:"webAuthNTokenId"`
SignCount uint32 `json:"signCount"`
}
type WebAuthNTokenID struct {
WebauthNTokenID string `json:"webAuthNTokenId"`
}
type WebAuthNLogin struct {
es_models.ObjectRoot
WebauthNTokenID string `json:"webAuthNTokenId"`
Challenge string `json:"challenge"`
*AuthRequest
}
func GetWebauthn(webauthnTokens []*WebAuthNToken, id string) (int, *WebAuthNToken) {
for i, webauthn := range webauthnTokens {
if webauthn.WebauthNTokenID == id {
return i, webauthn
}
}
return -1, nil
}
func WebAuthNsToModel(u2fs []*WebAuthNToken) []*model.WebAuthNToken {
convertedIDPs := make([]*model.WebAuthNToken, len(u2fs))
for i, m := range u2fs {
convertedIDPs[i] = WebAuthNToModel(m)
}
return convertedIDPs
}
func WebAuthNsFromModel(u2fs []*model.WebAuthNToken) []*WebAuthNToken {
convertedIDPs := make([]*WebAuthNToken, len(u2fs))
for i, m := range u2fs {
convertedIDPs[i] = WebAuthNFromModel(m)
}
return convertedIDPs
}
func WebAuthNFromModel(webAuthN *model.WebAuthNToken) *WebAuthNToken {
return &WebAuthNToken{
ObjectRoot: webAuthN.ObjectRoot,
WebauthNTokenID: webAuthN.WebAuthNTokenID,
Challenge: webAuthN.Challenge,
State: int32(webAuthN.State),
KeyID: webAuthN.KeyID,
PublicKey: webAuthN.PublicKey,
AAGUID: webAuthN.AAGUID,
SignCount: webAuthN.SignCount,
AttestationType: webAuthN.AttestationType,
}
}
func WebAuthNToModel(webAuthN *WebAuthNToken) *model.WebAuthNToken {
return &model.WebAuthNToken{
ObjectRoot: webAuthN.ObjectRoot,
WebAuthNTokenID: webAuthN.WebauthNTokenID,
Challenge: webAuthN.Challenge,
State: model.MFAState(webAuthN.State),
KeyID: webAuthN.KeyID,
PublicKey: webAuthN.PublicKey,
AAGUID: webAuthN.AAGUID,
SignCount: webAuthN.SignCount,
AttestationType: webAuthN.AttestationType,
}
}
func WebAuthNVerifyFromModel(webAuthN *model.WebAuthNToken) *WebAuthNVerify {
return &WebAuthNVerify{
WebAuthNTokenID: webAuthN.WebAuthNTokenID,
KeyID: webAuthN.KeyID,
PublicKey: webAuthN.PublicKey,
AAGUID: webAuthN.AAGUID,
SignCount: webAuthN.SignCount,
AttestationType: webAuthN.AttestationType,
WebAuthNTokenName: webAuthN.WebAuthNTokenName,
}
}
func WebAuthNLoginsToModel(u2fs []*WebAuthNLogin) []*model.WebAuthNLogin {
convertedIDPs := make([]*model.WebAuthNLogin, len(u2fs))
for i, m := range u2fs {
convertedIDPs[i] = WebAuthNLoginToModel(m)
}
return convertedIDPs
}
func WebAuthNLoginsFromModel(u2fs []*model.WebAuthNLogin) []*WebAuthNLogin {
convertedIDPs := make([]*WebAuthNLogin, len(u2fs))
for i, m := range u2fs {
convertedIDPs[i] = WebAuthNLoginFromModel(m)
}
return convertedIDPs
}
func WebAuthNLoginFromModel(webAuthN *model.WebAuthNLogin) *WebAuthNLogin {
return &WebAuthNLogin{
ObjectRoot: webAuthN.ObjectRoot,
Challenge: webAuthN.Challenge,
AuthRequest: AuthRequestFromModel(webAuthN.AuthRequest),
}
}
func WebAuthNLoginToModel(webAuthN *WebAuthNLogin) *model.WebAuthNLogin {
return &model.WebAuthNLogin{
ObjectRoot: webAuthN.ObjectRoot,
Challenge: webAuthN.Challenge,
AuthRequest: AuthRequestToModel(webAuthN.AuthRequest),
}
}
func (u *Human) appendU2FAddedEvent(event *es_models.Event) error {
webauthn := new(WebAuthNToken)
err := webauthn.setData(event)
if err != nil {
return err
}
webauthn.ObjectRoot.CreationDate = event.CreationDate
webauthn.State = int32(model.MFAStateNotReady)
for i, token := range u.U2FTokens {
if token.State == int32(model.MFAStateNotReady) {
u.U2FTokens[i] = webauthn
return nil
}
}
u.U2FTokens = append(u.U2FTokens, webauthn)
return nil
}
func (u *Human) appendU2FVerifiedEvent(event *es_models.Event) error {
webauthn := new(WebAuthNToken)
err := webauthn.setData(event)
if err != nil {
return err
}
if _, token := GetWebauthn(u.U2FTokens, webauthn.WebauthNTokenID); token != nil {
err := token.setData(event)
if err != nil {
return err
}
token.State = int32(model.MFAStateReady)
return nil
}
return caos_errs.ThrowPreconditionFailed(nil, "MODEL-4hu9s", "Errors.Users.MFA.U2F.NotExisting")
}
func (u *Human) appendU2FChangeSignCountEvent(event *es_models.Event) error {
webauthn := new(WebAuthNToken)
err := webauthn.setData(event)
if err != nil {
return err
}
if _, token := GetWebauthn(u.U2FTokens, webauthn.WebauthNTokenID); token != nil {
token.setData(event)
return nil
}
return caos_errs.ThrowPreconditionFailed(nil, "MODEL-5Ms8h", "Errors.Users.MFA.U2F.NotExisting")
}
func (u *Human) appendU2FRemovedEvent(event *es_models.Event) error {
webauthn := new(WebAuthNToken)
err := webauthn.setData(event)
if err != nil {
return err
}
for i := len(u.U2FTokens) - 1; i >= 0; i-- {
if u.U2FTokens[i].WebauthNTokenID == webauthn.WebauthNTokenID {
copy(u.U2FTokens[i:], u.U2FTokens[i+1:])
u.U2FTokens[len(u.U2FTokens)-1] = nil
u.U2FTokens = u.U2FTokens[:len(u.U2FTokens)-1]
return nil
}
}
return nil
}
func (u *Human) appendPasswordlessAddedEvent(event *es_models.Event) error {
webauthn := new(WebAuthNToken)
err := webauthn.setData(event)
if err != nil {
return err
}
webauthn.ObjectRoot.CreationDate = event.CreationDate
webauthn.State = int32(model.MFAStateNotReady)
for i, token := range u.PasswordlessTokens {
if token.State == int32(model.MFAStateNotReady) {
u.PasswordlessTokens[i] = webauthn
return nil
}
}
u.PasswordlessTokens = append(u.PasswordlessTokens, webauthn)
return nil
}
func (u *Human) appendPasswordlessVerifiedEvent(event *es_models.Event) error {
webauthn := new(WebAuthNToken)
err := webauthn.setData(event)
if err != nil {
return err
}
if _, token := GetWebauthn(u.PasswordlessTokens, webauthn.WebauthNTokenID); token != nil {
err := token.setData(event)
if err != nil {
return err
}
token.State = int32(model.MFAStateReady)
return nil
}
return caos_errs.ThrowPreconditionFailed(nil, "MODEL-mKns8", "Errors.Users.MFA.Passwordless.NotExisting")
}
func (u *Human) appendPasswordlessChangeSignCountEvent(event *es_models.Event) error {
webauthn := new(WebAuthNToken)
err := webauthn.setData(event)
if err != nil {
return err
}
if _, token := GetWebauthn(u.PasswordlessTokens, webauthn.WebauthNTokenID); token != nil {
err := token.setData(event)
if err != nil {
return err
}
return nil
}
return caos_errs.ThrowPreconditionFailed(nil, "MODEL-2Mv9s", "Errors.Users.MFA.Passwordless.NotExisting")
}
func (u *Human) appendPasswordlessRemovedEvent(event *es_models.Event) error {
webauthn := new(WebAuthNToken)
err := webauthn.setData(event)
if err != nil {
return err
}
for i := len(u.PasswordlessTokens) - 1; i >= 0; i-- {
if u.PasswordlessTokens[i].WebauthNTokenID == webauthn.WebauthNTokenID {
copy(u.PasswordlessTokens[i:], u.PasswordlessTokens[i+1:])
u.PasswordlessTokens[len(u.PasswordlessTokens)-1] = nil
u.PasswordlessTokens = u.PasswordlessTokens[:len(u.PasswordlessTokens)-1]
return nil
}
}
return nil
}
func (w *WebAuthNToken) setData(event *es_models.Event) error {
w.ObjectRoot.AppendEvent(event)
if err := json.Unmarshal(event.Data, w); err != nil {
logging.Log("EVEN-4M9is").WithError(err).Error("could not unmarshal event data")
return caos_errs.ThrowInternal(err, "MODEL-lo023", "could not unmarshal event")
}
return nil
}
func (u *Human) appendU2FLoginEvent(event *es_models.Event) error {
webauthn := new(WebAuthNLogin)
webauthn.ObjectRoot.AppendEvent(event)
err := webauthn.setData(event)
if err != nil {
return err
}
webauthn.ObjectRoot.CreationDate = event.CreationDate
for i, token := range u.U2FLogins {
if token.AuthRequest.ID == webauthn.AuthRequest.ID {
u.U2FLogins[i] = webauthn
return nil
}
}
u.U2FLogins = append(u.U2FLogins, webauthn)
return nil
}
func (u *Human) appendPasswordlessLoginEvent(event *es_models.Event) error {
webauthn := new(WebAuthNLogin)
webauthn.ObjectRoot.AppendEvent(event)
err := webauthn.setData(event)
if err != nil {
return err
}
webauthn.ObjectRoot.CreationDate = event.CreationDate
for i, token := range u.PasswordlessLogins {
if token.AuthRequest.ID == webauthn.AuthRequest.ID {
u.PasswordlessLogins[i] = webauthn
return nil
}
}
u.PasswordlessLogins = append(u.PasswordlessLogins, webauthn)
return nil
}
func (w *WebAuthNLogin) setData(event *es_models.Event) error {
w.ObjectRoot.AppendEvent(event)
if err := json.Unmarshal(event.Data, w); err != nil {
logging.Log("EVEN-hmSlo").WithError(err).Error("could not unmarshal event data")
return caos_errs.ThrowInternal(err, "MODEL-lo023", "could not unmarshal event")
}
return nil
}

View File

@@ -0,0 +1,151 @@
package model
import (
"encoding/json"
"github.com/caos/zitadel/pkg/grpc/auth"
"testing"
es_models "github.com/caos/zitadel/internal/eventstore/models"
)
func TestAppendMFAU2FAddedEvent(t *testing.T) {
type args struct {
user *Human
u2f *WebAuthNToken
event *es_models.Event
}
tests := []struct {
name string
args args
result *Human
}{
{
name: "append user u2f event",
args: args{
user: &Human{},
u2f: &WebAuthNToken{WebauthNTokenID: "WebauthNTokenID", Challenge: "Challenge"},
event: &es_models.Event{},
},
result: &Human{
U2FTokens: []*WebAuthNToken{
{WebauthNTokenID: "WebauthNTokenID", Challenge: "Challenge", State: int32(auth.MFAState_MFASTATE_NOT_READY)},
},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if tt.args.u2f != nil {
data, _ := json.Marshal(tt.args.u2f)
tt.args.event.Data = data
}
tt.args.user.appendU2FAddedEvent(tt.args.event)
if tt.args.user.U2FTokens[0].State != tt.result.U2FTokens[0].State {
t.Errorf("got wrong result: expected: %v, actual: %v ", tt.result.U2FTokens[0].State, tt.args.user.U2FTokens[0].State)
}
})
}
}
func TestAppendMFAU2FVerifyEvent(t *testing.T) {
type args struct {
user *Human
u2f *WebAuthNVerify
event *es_models.Event
}
tests := []struct {
name string
args args
result *Human
}{
{
name: "append u2f verify event",
args: args{
user: &Human{
U2FTokens: []*WebAuthNToken{
{WebauthNTokenID: "WebauthNTokenID", Challenge: "Challenge", State: int32(auth.MFAState_MFASTATE_NOT_READY)},
},
},
u2f: &WebAuthNVerify{WebAuthNTokenID: "WebauthNTokenID", KeyID: []byte("KeyID"), PublicKey: []byte("PublicKey"), AttestationType: "AttestationType", AAGUID: []byte("AAGUID"), SignCount: 1},
event: &es_models.Event{},
},
result: &Human{
U2FTokens: []*WebAuthNToken{
{
WebauthNTokenID: "WebauthNTokenID",
Challenge: "Challenge",
State: int32(auth.MFAState_MFASTATE_READY),
KeyID: []byte("KeyID"),
PublicKey: []byte("PublicKey"),
AttestationType: "AttestationType",
AAGUID: []byte("AAGUID"),
SignCount: 1,
},
},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if tt.args.u2f != nil {
data, _ := json.Marshal(tt.args.u2f)
tt.args.event.Data = data
}
tt.args.user.appendU2FVerifiedEvent(tt.args.event)
if tt.args.user.U2FTokens[0].State != tt.result.U2FTokens[0].State {
t.Errorf("got wrong result: expected: %v, actual: %v ", tt.result.U2FTokens[0].State, tt.args.user.U2FTokens[0].State)
}
if tt.args.user.U2FTokens[0].AttestationType != tt.result.U2FTokens[0].AttestationType {
t.Errorf("got wrong result: expected: %v, actual: %v ", tt.result.U2FTokens[0].AttestationType, tt.args.user.U2FTokens[0].AttestationType)
}
})
}
}
func TestAppendMFAU2FRemoveEvent(t *testing.T) {
type args struct {
user *Human
u2f *WebAuthNTokenID
event *es_models.Event
}
tests := []struct {
name string
args args
result *Human
}{
{
name: "append u2f remove event",
args: args{
user: &Human{
U2FTokens: []*WebAuthNToken{
{
WebauthNTokenID: "WebauthNTokenID",
Challenge: "Challenge",
State: int32(auth.MFAState_MFASTATE_NOT_READY),
KeyID: []byte("KeyID"),
PublicKey: []byte("PublicKey"),
AttestationType: "AttestationType",
AAGUID: []byte("AAGUID"),
SignCount: 1,
},
},
},
u2f: &WebAuthNTokenID{WebauthNTokenID: "WebauthNTokenID"},
event: &es_models.Event{},
},
result: &Human{},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if tt.args.u2f != nil {
data, _ := json.Marshal(tt.args.u2f)
tt.args.event.Data = data
}
tt.args.user.appendU2FRemovedEvent(tt.args.event)
if len(tt.args.user.U2FTokens) != 0 {
t.Errorf("got wrong result: actual: %v ", tt.result.U2FTokens)
}
})
}
}