feat: new user auth api (#1168)

* fix: correct selectors for extended writemodel

* fix: no previous checks in eventstore

* start check previous

* feat: auth user commands

* feat: auth user commands

* feat: auth user commands

* feat: otp

* feat: corrections from pr merge

* feat: webauthn

* feat: comment old webauthn

* feat: refactor user, human, machine

* feat: webauth command side

* feat: command and query side in login

* feat: fix user writemodel append events

* fix: remove creation dates on command side

* fix: remove previous sequence

* previous sequence

* fix: external idps

* Update internal/api/grpc/management/user.go

Co-authored-by: Livio Amstutz <livio.a@gmail.com>

* Update internal/v2/command/user_human_email.go

Co-authored-by: Livio Amstutz <livio.a@gmail.com>

* fix: pr changes

* fix: phone verification

Co-authored-by: adlerhurst <silvan.reusser@gmail.com>
Co-authored-by: Livio Amstutz <livio.a@gmail.com>
This commit is contained in:
Fabi
2021-01-15 09:32:59 +01:00
committed by GitHub
parent e5731b0d3b
commit 959530ddad
74 changed files with 1554 additions and 1519 deletions

View File

@@ -11,6 +11,8 @@ import (
type Human struct {
es_models.ObjectRoot
Username string
State UserState
*Password
*Profile
*Email
@@ -24,6 +26,14 @@ type Human struct {
PasswordlessLogins []*WebAuthNLogin
}
func (h Human) GetUsername() string {
return h.Username
}
func (h Human) GetState() UserState {
return h.State
}
type InitUserCode struct {
es_models.ObjectRoot
@@ -91,3 +101,10 @@ func NewInitUserCode(generator crypto.Generator) (*InitUserCode, error) {
Expiry: generator.Expiry(),
}, nil
}
func GenerateLoginName(username, domain string, appendDomain bool) string {
if !appendDomain {
return username
}
return username + "@" + domain
}

View File

@@ -2,7 +2,10 @@ package domain
import (
"github.com/caos/zitadel/internal/crypto"
caos_errs "github.com/caos/zitadel/internal/errors"
es_models "github.com/caos/zitadel/internal/eventstore/models"
"github.com/pquerna/otp"
"github.com/pquerna/otp/totp"
)
type OTP struct {
@@ -14,16 +17,27 @@ type OTP struct {
State MFAState
}
type OTPState int32
const (
OTPStateUnspecified OTPState = iota
OTPStateActive
OTPStateRemoved
otpStateCount
)
func (s OTPState) Valid() bool {
return s >= 0 && s < otpStateCount
func NewOTPKey(issuer, accountName string, cryptoAlg crypto.EncryptionAlgorithm) (*otp.Key, *crypto.CryptoValue, error) {
key, err := totp.Generate(totp.GenerateOpts{Issuer: issuer, AccountName: accountName})
if err != nil {
return nil, nil, err
}
encryptedSecret, err := crypto.Encrypt([]byte(key.Secret()), cryptoAlg)
if err != nil {
return nil, nil, err
}
return key, encryptedSecret, nil
}
func VerifyMFAOTP(code string, secret *crypto.CryptoValue, cryptoAlg crypto.EncryptionAlgorithm) error {
decrypt, err := crypto.DecryptString(secret, cryptoAlg)
if err != nil {
return err
}
valid := totp.Validate(code, decrypt)
if !valid {
return caos_errs.ThrowInvalidArgument(nil, "EVENT-8isk2", "Errors.User.MFA.OTP.InvalidCode")
}
return nil
}

View File

@@ -39,16 +39,19 @@ const (
UserVerificationRequirementDiscouraged
)
type WebAuthNState int32
type AuthenticatorAttachment int32
const (
WebAuthNStateUnspecified WebAuthNState = iota
WebAuthNStateActive
WebAuthNStateRemoved
webAuthNStateCount
AuthenticatorAttachmentUnspecified AuthenticatorAttachment = iota
AuthenticatorAttachmentPlattform
AuthenticatorAttachmentCrossPlattform
)
func (s WebAuthNState) Valid() bool {
return s >= 0 && s < webAuthNStateCount
func GetTokenToVerify(tokens []*WebAuthNToken) (int, *WebAuthNToken) {
for i, u2f := range tokens {
if u2f.State == MFAStateNotReady {
return i, u2f
}
}
return -1, nil
}

View File

@@ -5,10 +5,20 @@ import "github.com/caos/zitadel/internal/eventstore/models"
type Machine struct {
models.ObjectRoot
Username string
State UserState
Name string
Description string
}
func (m Machine) GetUsername() string {
return m.Username
}
func (m Machine) GetState() UserState {
return m.State
}
func (sa *Machine) IsValid() bool {
return sa.Name != ""
}

View File

@@ -6,6 +6,7 @@ const (
MFAStateUnspecified MFAState = iota
MFAStateNotReady
MFAStateReady
MFAStateRemoved
stateCount
)

View File

@@ -12,6 +12,7 @@ type Org struct {
State OrgState
Name string
PrimaryDomain string
Domains []*OrgDomain
Members []*Member
OrgIamPolicy *OrgIAMPolicy
@@ -38,6 +39,7 @@ func (o *Org) nameForDomain(iamDomain string) string {
type OrgState int32
const (
OrgStateActive OrgState = iota
OrgStateUnspecified OrgState = iota
OrgStateActive
OrgStateInactive
)

View File

@@ -1,14 +1,8 @@
package domain
import es_models "github.com/caos/zitadel/internal/eventstore/models"
type User struct {
es_models.ObjectRoot
State UserState
UserName string
*Human
*Machine
type User interface {
GetUsername() string
GetState() UserState
}
type UserState int32
@@ -28,13 +22,3 @@ const (
func (f UserState) Valid() bool {
return f >= 0 && f < userStateCount
}
func (u *User) IsValid() bool {
if u.Human == nil && u.Machine == nil || u.UserName == "" {
return false
}
if u.Human != nil {
return u.Human.IsValid()
}
return u.Machine.IsValid()
}