fix: commandside queries (#1313)

* fix: move user by id to query side

* fix: move get passwordless to query side

# Conflicts:
#	internal/user/repository/eventsourcing/eventstore.go

* fix: move get passwordless to query side

* remove user eventstore

* remove unused models

* org changes

* org changes

* fix: move org queries to query side

* fix: remove org eventstore

* fix: remove org eventstore

* fix: remove org eventstore

* remove project from es v1

* project cleanup

* project cleanup

* fix: remove org eventstore

* fix: remove iam eventstore

Co-authored-by: Livio Amstutz <livio.a@gmail.com>
This commit is contained in:
Fabi
2021-02-22 14:08:47 +01:00
committed by GitHub
parent 2ba56595b1
commit 428ef4acdb
106 changed files with 2301 additions and 2799 deletions

View File

@@ -1,19 +1,5 @@
package model
import (
"github.com/caos/zitadel/internal/crypto"
es_models "github.com/caos/zitadel/internal/eventstore/models"
)
type OTP struct {
es_models.ObjectRoot
Secret *crypto.CryptoValue
SecretString string
Url string
State MFAState
}
type MFAState int32
const (

View File

@@ -1,103 +0,0 @@
package model
import (
iam_model "github.com/caos/zitadel/internal/iam/model"
"strings"
caos_errors "github.com/caos/zitadel/internal/errors"
es_models "github.com/caos/zitadel/internal/eventstore/models"
"github.com/golang/protobuf/ptypes/timestamp"
)
type User struct {
es_models.ObjectRoot
State UserState
UserName string
*Human
*Machine
}
type UserState int32
const (
UserStateUnspecified UserState = iota
UserStateActive
UserStateInactive
UserStateDeleted
UserStateLocked
UserStateSuspend
UserStateInitial
)
func (u *User) CheckOrgIAMPolicy(policy *iam_model.OrgIAMPolicyView) error {
if policy == nil {
return caos_errors.ThrowPreconditionFailed(nil, "MODEL-zSH7j", "Errors.Users.OrgIamPolicyNil")
}
if policy.UserLoginMustBeDomain && strings.Contains(u.UserName, "@") {
return caos_errors.ThrowPreconditionFailed(nil, "MODEL-se4sJ", "Errors.User.EmailAsUsernameNotAllowed")
}
if !policy.UserLoginMustBeDomain && u.Profile != nil && u.UserName == "" && u.Email != nil {
u.UserName = u.EmailAddress
}
return nil
}
func (u *User) SetNamesAsDisplayname() {
if u.Profile != nil && u.DisplayName == "" && u.FirstName != "" && u.LastName != "" {
u.DisplayName = u.FirstName + " " + u.LastName
}
}
type UserChanges struct {
Changes []*UserChange
LastSequence uint64
}
type UserChange struct {
ChangeDate *timestamp.Timestamp `json:"changeDate,omitempty"`
EventType string `json:"eventType,omitempty"`
Sequence uint64 `json:"sequence,omitempty"`
ModifierID string `json:"modifierUser,omitempty"`
ModifierName string `json:"-"`
Data interface{} `json:"data,omitempty"`
}
func (u *User) IsActive() bool {
return u.State == UserStateActive
}
func (u *User) IsInitial() bool {
return u.State == UserStateInitial
}
func (u *User) IsInactive() bool {
return u.State == UserStateInactive
}
func (u *User) IsLocked() bool {
return u.State == UserStateLocked
}
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()
}
func (u *User) CheckOrgIamPolicy(policy *iam_model.OrgIAMPolicy) error {
if policy == nil {
return caos_errors.ThrowPreconditionFailed(nil, "MODEL-zSH7j", "Errors.Users.OrgIamPolicyNil")
}
if policy.UserLoginMustBeDomain && strings.Contains(u.UserName, "@") {
return caos_errors.ThrowPreconditionFailed(nil, "MODEL-se4sJ", "Errors.User.EmailAsUsernameNotAllowed")
}
if !policy.UserLoginMustBeDomain && u.Profile != nil && u.UserName == "" && u.Email != nil {
u.UserName = u.EmailAddress
}
return nil
}

View File

@@ -0,0 +1,19 @@
package model
import (
"github.com/golang/protobuf/ptypes/timestamp"
)
type UserChanges struct {
Changes []*UserChange
LastSequence uint64
}
type UserChange struct {
ChangeDate *timestamp.Timestamp `json:"changeDate,omitempty"`
EventType string `json:"eventType,omitempty"`
Sequence uint64 `json:"sequence,omitempty"`
ModifierID string `json:"modifierUser,omitempty"`
ModifierName string `json:"-"`
Data interface{} `json:"data,omitempty"`
}

View File

@@ -1,203 +0,0 @@
package model
import (
"bytes"
caos_errors "github.com/caos/zitadel/internal/errors"
"github.com/caos/zitadel/internal/v2/domain"
"strings"
"time"
iam_model "github.com/caos/zitadel/internal/iam/model"
"github.com/caos/zitadel/internal/crypto"
es_models "github.com/caos/zitadel/internal/eventstore/models"
)
type Human struct {
es_models.ObjectRoot
*Password
*Profile
*Email
*Phone
*Address
ExternalIDPs []*ExternalIDP
InitCode *InitUserCode
EmailCode *EmailCode
PhoneCode *PhoneCode
PasswordCode *PasswordCode
OTP *OTP
U2FTokens []*WebAuthNToken
PasswordlessTokens []*WebAuthNToken
U2FLogins []*WebAuthNLogin
PasswordlessLogins []*WebAuthNLogin
}
type InitUserCode struct {
es_models.ObjectRoot
Code *crypto.CryptoValue
Expiry time.Duration
}
type Gender int32
const (
GenderUnspecified Gender = iota
GenderFemale
GenderMale
GenderDiverse
)
func (u *Human) CheckOrgIAMPolicy(userName string, policy *domain.OrgIAMPolicy) error {
if policy == nil {
return caos_errors.ThrowPreconditionFailed(nil, "MODEL-zSH7j", "Errors.Users.OrgIamPolicyNil")
}
if policy.UserLoginMustBeDomain && strings.Contains(userName, "@") {
return caos_errors.ThrowPreconditionFailed(nil, "MODEL-se4sJ", "Errors.User.EmailAsUsernameNotAllowed")
}
if !policy.UserLoginMustBeDomain && u.Profile != nil && userName == "" && u.Email != nil {
userName = u.EmailAddress
}
return nil
}
func (u *Human) SetNamesAsDisplayname() {
if u.Profile != nil && u.DisplayName == "" && u.FirstName != "" && u.LastName != "" {
u.DisplayName = u.FirstName + " " + u.LastName
}
}
func (u *Human) IsValid() bool {
return u.Profile != nil && u.FirstName != "" && u.LastName != "" && u.Email != nil && u.Email.IsValid() && u.Phone == nil || (u.Phone != nil && u.Phone.PhoneNumber != "" && u.Phone.IsValid())
}
func (u *Human) IsInitialState() bool {
return u.Email == nil || !u.IsEmailVerified || (u.ExternalIDPs == nil || len(u.ExternalIDPs) == 0) && (u.Password == nil || u.SecretString == "")
}
func (u *Human) IsOTPReady() bool {
return u.OTP != nil && u.OTP.State == MFAStateReady
}
func (u *Human) HashPasswordIfExisting(policy *iam_model.PasswordComplexityPolicyView, passwordAlg crypto.HashAlgorithm, onetime bool) error {
if u.Password != nil {
return u.Password.HashPasswordIfExisting(policy, passwordAlg, onetime)
}
return nil
}
func (u *Human) GenerateInitCodeIfNeeded(initGenerator crypto.Generator) error {
if !u.IsInitialState() {
return nil
}
u.InitCode = new(InitUserCode)
return u.InitCode.GenerateInitUserCode(initGenerator)
}
func (u *Human) GeneratePhoneCodeIfNeeded(phoneGenerator crypto.Generator) error {
if u.Phone == nil || u.IsPhoneVerified {
return nil
}
u.PhoneCode = new(PhoneCode)
return u.PhoneCode.GeneratePhoneCode(phoneGenerator)
}
func (u *Human) GenerateEmailCodeIfNeeded(emailGenerator crypto.Generator) error {
if u.Email == nil || u.IsEmailVerified {
return nil
}
u.EmailCode = new(EmailCode)
return u.EmailCode.GenerateEmailCode(emailGenerator)
}
func (init *InitUserCode) GenerateInitUserCode(generator crypto.Generator) error {
initCodeCrypto, _, err := crypto.NewCode(generator)
if err != nil {
return err
}
init.Code = initCodeCrypto
init.Expiry = generator.Expiry()
return nil
}
func (u *Human) GetExternalIDP(externalIDP *ExternalIDP) (int, *ExternalIDP) {
for i, idp := range u.ExternalIDPs {
if idp.UserID == externalIDP.UserID {
return i, idp
}
}
return -1, nil
}
func (u *Human) GetU2F(webAuthNTokenID string) (int, *WebAuthNToken) {
for i, u2f := range u.U2FTokens {
if u2f.WebAuthNTokenID == webAuthNTokenID {
return i, u2f
}
}
return -1, nil
}
func (u *Human) GetU2FByKeyID(keyID []byte) (int, *WebAuthNToken) {
for i, u2f := range u.U2FTokens {
if bytes.Compare(u2f.KeyID, keyID) == 0 {
return i, u2f
}
}
return -1, nil
}
func (u *Human) GetU2FToVerify() (int, *WebAuthNToken) {
for i, u2f := range u.U2FTokens {
if u2f.State == MFAStateNotReady {
return i, u2f
}
}
return -1, nil
}
func (u *Human) GetPasswordless(webAuthNTokenID string) (int, *WebAuthNToken) {
for i, u2f := range u.PasswordlessTokens {
if u2f.WebAuthNTokenID == webAuthNTokenID {
return i, u2f
}
}
return -1, nil
}
func (u *Human) GetPasswordlessByKeyID(keyID []byte) (int, *WebAuthNToken) {
for i, pwl := range u.PasswordlessTokens {
if bytes.Compare(pwl.KeyID, keyID) == 0 {
return i, pwl
}
}
return -1, nil
}
func (u *Human) GetPasswordlessToVerify() (int, *WebAuthNToken) {
for i, u2f := range u.PasswordlessTokens {
if u2f.State == MFAStateNotReady {
return i, u2f
}
}
return -1, nil
}
func (u *Human) GetU2FLogin(authReqID string) (int, *WebAuthNLogin) {
for i, u2f := range u.U2FLogins {
if u2f.AuthRequest.ID == authReqID {
return i, u2f
}
}
return -1, nil
}
func (u *Human) GetPasswordlessLogin(authReqID string) (int, *WebAuthNLogin) {
for i, pw := range u.PasswordlessLogins {
if pw.AuthRequest.ID == authReqID {
return i, pw
}
}
return -1, nil
}

View File

@@ -1,105 +0,0 @@
package model
import (
"testing"
)
func TestIsUserValid(t *testing.T) {
type args struct {
user *Human
}
tests := []struct {
name string
args args
result bool
errFunc func(err error) bool
}{
{
name: "user with minimal data",
args: args{
user: &Human{
Profile: &Profile{
FirstName: "FirstName",
LastName: "LastName",
},
Email: &Email{
EmailAddress: "Email",
},
},
},
result: true,
},
{
name: "user with phone data",
args: args{
user: &Human{
Profile: &Profile{
FirstName: "FirstName",
LastName: "LastName",
},
Email: &Email{
EmailAddress: "Email",
},
Phone: &Phone{
PhoneNumber: "+41711234569",
},
},
},
result: true,
},
{
name: "user with address data",
args: args{
user: &Human{
Profile: &Profile{
FirstName: "FirstName",
LastName: "LastName",
},
Email: &Email{
EmailAddress: "Email",
},
Address: &Address{
StreetAddress: "Teufenerstrasse 19",
PostalCode: "9000",
Locality: "St. Gallen",
Country: "Switzerland",
},
},
},
result: true,
},
{
name: "user with all data",
args: args{
user: &Human{
Profile: &Profile{
FirstName: "FirstName",
LastName: "LastName",
},
Email: &Email{
EmailAddress: "Email",
},
Phone: &Phone{
PhoneNumber: "+41711234569",
},
Address: &Address{
StreetAddress: "Teufenerstrasse 19",
PostalCode: "9000",
Locality: "St. Gallen",
Country: "Switzerland",
},
},
},
result: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
isValid := tt.args.user.IsValid()
if tt.result != isValid {
t.Errorf("got wrong result: expected: %v, actual: %v ", tt.result, isValid)
}
})
}
}

View File

@@ -1,28 +0,0 @@
package model
import (
"time"
"github.com/caos/zitadel/internal/eventstore/models"
key_model "github.com/caos/zitadel/internal/key/model"
)
type Machine struct {
models.ObjectRoot
Name string
Description string
}
func (sa *Machine) IsValid() bool {
return sa.Name != ""
}
type MachineKey struct {
models.ObjectRoot
KeyID string
Type key_model.AuthNKeyType
ExpirationDate time.Time
PrivateKey []byte
}

View File

@@ -108,6 +108,27 @@ type UserSearchResponse struct {
Timestamp time.Time
}
type UserState int32
const (
UserStateUnspecified UserState = iota
UserStateActive
UserStateInactive
UserStateDeleted
UserStateLocked
UserStateSuspend
UserStateInitial
)
type Gender int32
const (
GenderUnspecified Gender = iota
GenderFemale
GenderMale
GenderDiverse
)
func (r *UserSearchRequest) EnsureLimit(limit uint64) {
if r.Limit == 0 || r.Limit > limit {
r.Limit = limit

View File

@@ -1,58 +0,0 @@
package model
import (
"github.com/caos/zitadel/internal/auth_request/model"
es_models "github.com/caos/zitadel/internal/eventstore/models"
)
type WebAuthNToken struct {
es_models.ObjectRoot
WebAuthNTokenID string
CredentialCreationData []byte
State MFAState
Challenge string
AllowedCredentialIDs [][]byte
UserVerification UserVerificationRequirement
KeyID []byte
PublicKey []byte
AttestationType string
AAGUID []byte
SignCount uint32
WebAuthNTokenName string
}
type WebAuthNLogin struct {
es_models.ObjectRoot
CredentialAssertionData []byte
Challenge string
AllowedCredentialIDs [][]byte
UserVerification UserVerificationRequirement
*model.AuthRequest
}
type WebAuthNMethod int32
const (
WebAuthNMethodUnspecified WebAuthNMethod = iota
WebAuthNMethodU2F
WebAuthNMethodPasswordless
)
type UserVerificationRequirement int32
const (
UserVerificationRequirementUnspecified UserVerificationRequirement = iota
UserVerificationRequirementRequired
UserVerificationRequirementPreferred
UserVerificationRequirementDiscouraged
)
type AuthenticatorAttachment int32
const (
AuthenticatorAttachmentUnspecified AuthenticatorAttachment = iota
AuthenticatorAttachmentPlattform
AuthenticatorAttachmentCrossPlattform
)