mirror of
https://github.com/zitadel/zitadel.git
synced 2025-08-12 01:47:33 +00:00
Merge branch 'master' into new-eventstore
# Conflicts: # go.mod # internal/admin/repository/eventsourcing/eventstore/iam.go # internal/authz/repository/eventsourcing/repository.go # internal/eventstore/eventstore.go # internal/setup/config.go # pkg/grpc/management/mock/management.proto.mock.go
This commit is contained in:
@@ -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, isLoginUI bool) (*usr_model.WebAuthNToken, error) {
|
||||
func (es *UserEventstore) AddU2F(ctx context.Context, userID string, accountName 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, isLoginUI, user.U2FTokens...)
|
||||
webAuthN, err := es.webauthn.BeginRegistration(user, accountName, usr_model.AuthenticatorAttachmentUnspecified, usr_model.UserVerificationRequirementDiscouraged, isLoginUI, user.U2FTokens...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -1353,7 +1353,7 @@ func (es *UserEventstore) RemoveU2FToken(ctx context.Context, userID, webAuthNTo
|
||||
return err
|
||||
}
|
||||
if _, token := user.Human.GetU2F(webAuthNTokenID); token == nil {
|
||||
return errors.ThrowPreconditionFailed(nil, "EVENT-2M9ds", "Errors.User.NotHuman")
|
||||
return errors.ThrowPreconditionFailed(nil, "EVENT-2M9ds", "Errors.User.MFA.U2F.NotExisting")
|
||||
}
|
||||
repoUser := model.UserFromModel(user)
|
||||
err = es_sdk.Push(ctx, es.PushAggregates, repoUser.AppendEvents, MFAU2FRemoveAggregate(es.AggregateCreator(), repoUser, &model.WebAuthNTokenID{webAuthNTokenID}))
|
||||
@@ -1410,12 +1410,20 @@ func (es *UserEventstore) VerifyMFAU2F(ctx context.Context, userID string, crede
|
||||
return finishErr
|
||||
}
|
||||
|
||||
func (es *UserEventstore) AddPasswordless(ctx context.Context, userID string, isLoginUI bool) (*usr_model.WebAuthNToken, error) {
|
||||
func (es *UserEventstore) GetPasswordless(ctx context.Context, userID string) ([]*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, isLoginUI, user.PasswordlessTokens...)
|
||||
return user.PasswordlessTokens, nil
|
||||
}
|
||||
|
||||
func (es *UserEventstore) AddPasswordless(ctx context.Context, userID, accountName 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, accountName, usr_model.AuthenticatorAttachmentUnspecified, usr_model.UserVerificationRequirementRequired, isLoginUI, user.PasswordlessTokens...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -1616,11 +1624,10 @@ func (es *UserEventstore) AddMachineKey(ctx context.Context, key *usr_model.Mach
|
||||
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-5ROh4", "Errors.User.NotMachine")
|
||||
}
|
||||
|
||||
id, err := es.idGenerator.Next()
|
||||
key.KeyID, err = es.idGenerator.Next()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
key.KeyID = id
|
||||
|
||||
if key.ExpirationDate.IsZero() {
|
||||
key.ExpirationDate, err = time.Parse(yearLayout, defaultExpirationDate)
|
||||
|
@@ -16,8 +16,6 @@ type Email struct {
|
||||
|
||||
EmailAddress string `json:"email,omitempty"`
|
||||
IsEmailVerified bool `json:"-"`
|
||||
|
||||
isEmailUnique bool `json:"-"`
|
||||
}
|
||||
|
||||
type EmailCode struct {
|
||||
|
@@ -1,6 +1,8 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"golang.org/x/text/language"
|
||||
|
||||
es_models "github.com/caos/zitadel/internal/eventstore/models"
|
||||
@@ -10,14 +12,12 @@ import (
|
||||
type Profile struct {
|
||||
es_models.ObjectRoot
|
||||
|
||||
FirstName string `json:"firstName,omitempty"`
|
||||
LastName string `json:"lastName,omitempty"`
|
||||
NickName string `json:"nickName,omitempty"`
|
||||
DisplayName string `json:"displayName,omitempty"`
|
||||
PreferredLanguage language.Tag `json:"preferredLanguage,omitempty"`
|
||||
Gender int32 `json:"gender,omitempty"`
|
||||
|
||||
isUserNameUnique bool
|
||||
FirstName string `json:"firstName,omitempty"`
|
||||
LastName string `json:"lastName,omitempty"`
|
||||
NickName string `json:"nickName,omitempty"`
|
||||
DisplayName string `json:"displayName,omitempty"`
|
||||
PreferredLanguage LanguageTag `json:"preferredLanguage,omitempty"`
|
||||
Gender int32 `json:"gender,omitempty"`
|
||||
}
|
||||
|
||||
func (p *Profile) Changes(changed *Profile) map[string]interface{} {
|
||||
@@ -34,7 +34,7 @@ func (p *Profile) Changes(changed *Profile) map[string]interface{} {
|
||||
if changed.DisplayName != "" && p.DisplayName != changed.DisplayName {
|
||||
changes["displayName"] = changed.DisplayName
|
||||
}
|
||||
if changed.PreferredLanguage != language.Und && changed.PreferredLanguage != p.PreferredLanguage {
|
||||
if language.Tag(changed.PreferredLanguage) != language.Und && changed.PreferredLanguage != p.PreferredLanguage {
|
||||
changes["preferredLanguage"] = changed.PreferredLanguage
|
||||
}
|
||||
if changed.Gender != p.Gender {
|
||||
@@ -50,7 +50,7 @@ func ProfileFromModel(profile *model.Profile) *Profile {
|
||||
LastName: profile.LastName,
|
||||
NickName: profile.NickName,
|
||||
DisplayName: profile.DisplayName,
|
||||
PreferredLanguage: profile.PreferredLanguage,
|
||||
PreferredLanguage: LanguageTag(profile.PreferredLanguage),
|
||||
Gender: int32(profile.Gender),
|
||||
}
|
||||
}
|
||||
@@ -62,7 +62,37 @@ func ProfileToModel(profile *Profile) *model.Profile {
|
||||
LastName: profile.LastName,
|
||||
NickName: profile.NickName,
|
||||
DisplayName: profile.DisplayName,
|
||||
PreferredLanguage: profile.PreferredLanguage,
|
||||
PreferredLanguage: language.Tag(profile.PreferredLanguage),
|
||||
Gender: model.Gender(profile.Gender),
|
||||
}
|
||||
}
|
||||
|
||||
type LanguageTag language.Tag
|
||||
|
||||
func (t *LanguageTag) UnmarshalJSON(data []byte) error {
|
||||
var tag string
|
||||
err := json.Unmarshal(data, &tag)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*t = LanguageTag(language.Make(tag))
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t LanguageTag) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(language.Tag(t))
|
||||
}
|
||||
|
||||
func (t *LanguageTag) MarshalBinary() ([]byte, error) {
|
||||
if t == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
return []byte(language.Tag(*t).String()), nil
|
||||
}
|
||||
|
||||
// UnmarshalBinary modifies the receiver so it must take a pointer receiver.
|
||||
func (t *LanguageTag) UnmarshalBinary(data []byte) error {
|
||||
*t = LanguageTag(language.Make(string(data)))
|
||||
return nil
|
||||
}
|
||||
|
@@ -23,8 +23,8 @@ func TestProfileChanges(t *testing.T) {
|
||||
{
|
||||
name: "all attributes changed",
|
||||
args: args{
|
||||
existingProfile: &Profile{FirstName: "FirstName", LastName: "LastName", NickName: "NickName", DisplayName: "DisplayName", PreferredLanguage: language.German, Gender: int32(user_model.GenderFemale)},
|
||||
newProfile: &Profile{FirstName: "FirstNameChanged", LastName: "LastNameChanged", NickName: "NickNameChanged", DisplayName: "DisplayNameChanged", PreferredLanguage: language.English, Gender: int32(user_model.GenderMale)},
|
||||
existingProfile: &Profile{FirstName: "FirstName", LastName: "LastName", NickName: "NickName", DisplayName: "DisplayName", PreferredLanguage: LanguageTag(language.German), Gender: int32(user_model.GenderFemale)},
|
||||
newProfile: &Profile{FirstName: "FirstNameChanged", LastName: "LastNameChanged", NickName: "NickNameChanged", DisplayName: "DisplayNameChanged", PreferredLanguage: LanguageTag(language.English), Gender: int32(user_model.GenderMale)},
|
||||
},
|
||||
res: res{
|
||||
changesLen: 6,
|
||||
@@ -33,8 +33,8 @@ func TestProfileChanges(t *testing.T) {
|
||||
{
|
||||
name: "no changes",
|
||||
args: args{
|
||||
existingProfile: &Profile{FirstName: "FirstName", LastName: "LastName", NickName: "NickName", DisplayName: "DisplayName", PreferredLanguage: language.German, Gender: int32(user_model.GenderFemale)},
|
||||
newProfile: &Profile{FirstName: "FirstName", LastName: "LastName", NickName: "NickName", DisplayName: "DisplayName", PreferredLanguage: language.German, Gender: int32(user_model.GenderFemale)},
|
||||
existingProfile: &Profile{FirstName: "FirstName", LastName: "LastName", NickName: "NickName", DisplayName: "DisplayName", PreferredLanguage: LanguageTag(language.German), Gender: int32(user_model.GenderFemale)},
|
||||
newProfile: &Profile{FirstName: "FirstName", LastName: "LastName", NickName: "NickName", DisplayName: "DisplayName", PreferredLanguage: LanguageTag(language.German), Gender: int32(user_model.GenderFemale)},
|
||||
},
|
||||
res: res{
|
||||
changesLen: 0,
|
||||
@@ -43,8 +43,8 @@ func TestProfileChanges(t *testing.T) {
|
||||
{
|
||||
name: "empty names",
|
||||
args: args{
|
||||
existingProfile: &Profile{FirstName: "FirstName", LastName: "LastName", NickName: "NickName", DisplayName: "DisplayName", PreferredLanguage: language.German, Gender: int32(user_model.GenderFemale)},
|
||||
newProfile: &Profile{FirstName: "", LastName: "", NickName: "NickName", DisplayName: "DisplayName", PreferredLanguage: language.German, Gender: int32(user_model.GenderFemale)},
|
||||
existingProfile: &Profile{FirstName: "FirstName", LastName: "LastName", NickName: "NickName", DisplayName: "DisplayName", PreferredLanguage: LanguageTag(language.German), Gender: int32(user_model.GenderFemale)},
|
||||
newProfile: &Profile{FirstName: "", LastName: "", NickName: "NickName", DisplayName: "DisplayName", PreferredLanguage: LanguageTag(language.German), Gender: int32(user_model.GenderFemale)},
|
||||
},
|
||||
res: res{
|
||||
changesLen: 0,
|
||||
|
@@ -99,18 +99,18 @@ func (u *User) AppendEvent(event *es_models.Event) error {
|
||||
}
|
||||
|
||||
if u.Human != nil {
|
||||
u.Human.User = u
|
||||
u.Human.user = u
|
||||
return u.Human.AppendEvent(event)
|
||||
} else if u.Machine != nil {
|
||||
u.Machine.User = u
|
||||
u.Machine.user = u
|
||||
return u.Machine.AppendEvent(event)
|
||||
}
|
||||
if strings.HasPrefix(string(event.Type), "user.human") || event.AggregateVersion == "v1" {
|
||||
u.Human = &Human{User: u}
|
||||
u.Human = &Human{user: u}
|
||||
return u.Human.AppendEvent(event)
|
||||
}
|
||||
if strings.HasPrefix(string(event.Type), "user.machine") {
|
||||
u.Machine = &Machine{User: u}
|
||||
u.Machine = &Machine{user: u}
|
||||
return u.Machine.AppendEvent(event)
|
||||
}
|
||||
|
||||
|
@@ -12,7 +12,7 @@ import (
|
||||
)
|
||||
|
||||
type Human struct {
|
||||
*User `json:"-"`
|
||||
user *User `json:"-"`
|
||||
|
||||
*Password
|
||||
*Profile
|
||||
@@ -69,6 +69,9 @@ func HumanFromModel(user *model.Human) *Human {
|
||||
if user.U2FLogins != nil {
|
||||
human.U2FLogins = WebAuthNLoginsFromModel(user.U2FLogins)
|
||||
}
|
||||
if user.PasswordlessLogins != nil {
|
||||
human.PasswordlessLogins = WebAuthNLoginsFromModel(user.PasswordlessLogins)
|
||||
}
|
||||
return human
|
||||
}
|
||||
|
||||
@@ -116,6 +119,9 @@ func HumanToModel(user *Human) *model.Human {
|
||||
if user.U2FLogins != nil {
|
||||
human.U2FLogins = WebAuthNLoginsToModel(user.U2FLogins)
|
||||
}
|
||||
if user.PasswordlessLogins != nil {
|
||||
human.PasswordlessLogins = WebAuthNLoginsToModel(user.PasswordlessLogins)
|
||||
}
|
||||
return human
|
||||
}
|
||||
|
||||
@@ -231,27 +237,27 @@ func (h *Human) AppendEvent(event *es_models.Event) (err error) {
|
||||
}
|
||||
|
||||
func (h *Human) ComputeObject() {
|
||||
if h.State == int32(model.UserStateUnspecified) || h.State == int32(model.UserStateInitial) {
|
||||
if h.user.State == int32(model.UserStateUnspecified) || h.user.State == int32(model.UserStateInitial) {
|
||||
if h.Email != nil && h.IsEmailVerified {
|
||||
h.State = int32(model.UserStateActive)
|
||||
h.user.State = int32(model.UserStateActive)
|
||||
} else {
|
||||
h.State = int32(model.UserStateInitial)
|
||||
h.user.State = int32(model.UserStateInitial)
|
||||
}
|
||||
}
|
||||
if h.Password != nil && h.Password.ObjectRoot.IsZero() {
|
||||
h.Password.ObjectRoot = h.User.ObjectRoot
|
||||
h.Password.ObjectRoot = h.user.ObjectRoot
|
||||
}
|
||||
if h.Profile != nil && h.Profile.ObjectRoot.IsZero() {
|
||||
h.Profile.ObjectRoot = h.User.ObjectRoot
|
||||
h.Profile.ObjectRoot = h.user.ObjectRoot
|
||||
}
|
||||
if h.Email != nil && h.Email.ObjectRoot.IsZero() {
|
||||
h.Email.ObjectRoot = h.User.ObjectRoot
|
||||
h.Email.ObjectRoot = h.user.ObjectRoot
|
||||
}
|
||||
if h.Phone != nil && h.Phone.ObjectRoot.IsZero() {
|
||||
h.Phone.ObjectRoot = h.User.ObjectRoot
|
||||
h.Phone.ObjectRoot = h.user.ObjectRoot
|
||||
}
|
||||
if h.Address != nil && h.Address.ObjectRoot.IsZero() {
|
||||
h.Address.ObjectRoot = h.User.ObjectRoot
|
||||
h.Address.ObjectRoot = h.user.ObjectRoot
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -13,7 +13,7 @@ import (
|
||||
)
|
||||
|
||||
type Machine struct {
|
||||
*User `json:"-"`
|
||||
user *User `json:"-"`
|
||||
|
||||
Name string `json:"name,omitempty"`
|
||||
Description string `json:"description,omitempty"`
|
||||
|
@@ -17,11 +17,12 @@ type WebAuthNToken struct {
|
||||
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"`
|
||||
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 WebAuthNVerify struct {
|
||||
@@ -79,29 +80,31 @@ func WebAuthNsFromModel(u2fs []*model.WebAuthNToken) []*WebAuthNToken {
|
||||
|
||||
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,
|
||||
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,
|
||||
WebAuthNTokenName: webAuthN.WebAuthNTokenName,
|
||||
}
|
||||
}
|
||||
|
||||
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,
|
||||
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,
|
||||
WebAuthNTokenName: webAuthN.WebAuthNTokenName,
|
||||
}
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user