fix: backend bugs (#1449)

* i18n of compliance problems

* fix: return iam member roles

* remove u2f/passwordless

* u2f/passwordless

* fix rest path GetMachineKeyByIDs

* fix rest path GetMachineKeyByIDs

* fix email mime-type

* fix: member preferred login name

* machine users in notify

* fix api key query

* fix: todos grpc api

* fix: handle user init state

* fix: tests

Co-authored-by: fabi <fabienne.gerschwiler@gmail.com>
This commit is contained in:
Livio Amstutz 2021-03-22 14:40:25 +01:00 committed by GitHub
parent 6b1f7ba333
commit bd1a3bb6d7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
52 changed files with 639 additions and 224 deletions

View File

@ -2,8 +2,14 @@ package handler
import (
"context"
"github.com/caos/zitadel/internal/domain"
caos_errs "github.com/caos/zitadel/internal/errors"
"github.com/caos/zitadel/internal/eventstore/v1"
es_sdk "github.com/caos/zitadel/internal/eventstore/v1/sdk"
iam_view "github.com/caos/zitadel/internal/iam/repository/view"
org_model "github.com/caos/zitadel/internal/org/model"
org_es_model "github.com/caos/zitadel/internal/org/repository/eventsourcing/model"
org_view "github.com/caos/zitadel/internal/org/repository/view"
"github.com/caos/zitadel/internal/user/repository/view"
view_model "github.com/caos/zitadel/internal/user/repository/view/model"
@ -11,8 +17,10 @@ import (
es_models "github.com/caos/zitadel/internal/eventstore/v1/models"
"github.com/caos/zitadel/internal/eventstore/v1/query"
"github.com/caos/zitadel/internal/eventstore/v1/spooler"
iam_model "github.com/caos/zitadel/internal/iam/model"
"github.com/caos/zitadel/internal/iam/repository/eventsourcing/model"
iam_model "github.com/caos/zitadel/internal/iam/repository/view/model"
iam_es_model "github.com/caos/zitadel/internal/iam/repository/eventsourcing/model"
iam_view_model "github.com/caos/zitadel/internal/iam/repository/view/model"
usr_model "github.com/caos/zitadel/internal/user/model"
usr_es_model "github.com/caos/zitadel/internal/user/repository/eventsourcing/model"
)
@ -84,7 +92,7 @@ func (m *IAMMember) Reduce(event *es_models.Event) (err error) {
}
func (m *IAMMember) processIAMMember(event *es_models.Event) (err error) {
member := new(iam_model.IAMMemberView)
member := new(iam_view_model.IAMMemberView)
switch event.Type {
case model.IAMMemberAdded:
err = member.AppendEvent(event)
@ -146,17 +154,25 @@ func (m *IAMMember) processUser(event *es_models.Event) (err error) {
}
}
func (m *IAMMember) fillData(member *iam_model.IAMMemberView) (err error) {
func (m *IAMMember) fillData(member *iam_view_model.IAMMemberView) (err error) {
user, err := m.getUserByID(member.UserID)
if err != nil {
return err
}
m.fillUserData(member, user)
return nil
return m.fillUserData(member, user)
}
func (m *IAMMember) fillUserData(member *iam_model.IAMMemberView, user *view_model.UserView) {
func (m *IAMMember) fillUserData(member *iam_view_model.IAMMemberView, user *view_model.UserView) error {
org, err := m.getOrgByID(context.Background(), user.ResourceOwner)
policy := org.OrgIamPolicy
if policy == nil {
policy, err = m.getDefaultOrgIAMPolicy(context.TODO())
if err != nil {
return err
}
}
member.UserName = user.UserName
member.PreferredLoginName = user.GenerateLoginName(org.GetPrimaryDomain().Domain, policy.UserLoginMustBeDomain)
if user.HumanView != nil {
member.FirstName = user.FirstName
member.LastName = user.LastName
@ -166,7 +182,9 @@ func (m *IAMMember) fillUserData(member *iam_model.IAMMemberView, user *view_mod
if user.MachineView != nil {
member.DisplayName = user.MachineView.Name
}
return nil
}
func (m *IAMMember) OnError(event *es_models.Event, err error) error {
logging.LogWithFields("SPOOL-Ld9ow", "id", event.AggregateID).WithError(err).Warn("something went wrong in iammember handler")
return spooler.HandleError(event, err, m.view.GetLatestIAMMemberFailedEvent, m.view.ProcessedIAMMemberFailedEvent, m.view.ProcessedIAMMemberSequence, m.errorCountUntilSkip)
@ -208,3 +226,53 @@ func (m *IAMMember) getUserEvents(userID string, sequence uint64) ([]*es_models.
return m.es.FilterEvents(context.Background(), query)
}
func (u *IAMMember) getOrgByID(ctx context.Context, orgID string) (*org_model.Org, error) {
query, err := org_view.OrgByIDQuery(orgID, 0)
if err != nil {
return nil, err
}
esOrg := &org_es_model.Org{
ObjectRoot: es_models.ObjectRoot{
AggregateID: orgID,
},
}
err = es_sdk.Filter(ctx, u.Eventstore().FilterEvents, esOrg.AppendEvents, query)
if err != nil && !caos_errs.IsNotFound(err) {
return nil, err
}
if esOrg.Sequence == 0 {
return nil, caos_errs.ThrowNotFound(nil, "EVENT-3nd7s", "Errors.Org.NotFound")
}
return org_es_model.OrgToModel(esOrg), nil
}
func (u *IAMMember) getDefaultOrgIAMPolicy(ctx context.Context) (*iam_model.OrgIAMPolicy, error) {
existingIAM, err := u.getIAMByID(ctx)
if err != nil {
return nil, err
}
if existingIAM.DefaultOrgIAMPolicy == nil {
return nil, caos_errs.ThrowNotFound(nil, "EVENT-3Bf7s", "Errors.IAM.OrgIAMPolicy.NotExisting")
}
return existingIAM.DefaultOrgIAMPolicy, nil
}
func (u *IAMMember) getIAMByID(ctx context.Context) (*iam_model.IAM, error) {
query, err := iam_view.IAMByIDQuery(domain.IAMID, 0)
if err != nil {
return nil, err
}
iam := &iam_es_model.IAM{
ObjectRoot: es_models.ObjectRoot{
AggregateID: domain.IAMID,
},
}
err = es_sdk.Filter(ctx, u.Eventstore().FilterEvents, iam.AppendEvents, query)
if err != nil && caos_errs.IsNotFound(err) && iam.Sequence == 0 {
return nil, err
}
return iam_es_model.IAMToModel(iam), nil
}

View File

@ -12,6 +12,7 @@ import (
func (s *Server) ListIAMMemberRoles(ctx context.Context, req *admin_pb.ListIAMMemberRolesRequest) (*admin_pb.ListIAMMemberRolesResponse, error) {
roles := s.iam.GetIAMMemberRoles()
return &admin_pb.ListIAMMemberRolesResponse{
Roles: roles,
Details: object.ToListDetails(uint64(len(roles)), 0, time.Now()),
}, nil
}

View File

@ -67,7 +67,6 @@ func (s *Server) AddMyAuthFactorU2F(ctx context.Context, _ *auth_pb.AddMyAuthFac
}
return &auth_pb.AddMyAuthFactorU2FResponse{
Key: &user_pb.WebAuthNKey{
Id: u2f.WebAuthNTokenID,
PublicKey: u2f.CredentialCreationData,
},
Details: object.AddToDetailsPb(
@ -91,7 +90,7 @@ func (s *Server) VerifyMyAuthFactorU2F(ctx context.Context, req *auth_pb.VerifyM
func (s *Server) RemoveMyAuthFactorU2F(ctx context.Context, req *auth_pb.RemoveMyAuthFactorU2FRequest) (*auth_pb.RemoveMyAuthFactorU2FResponse, error) {
ctxData := authz.GetCtxData(ctx)
objectDetails, err := s.command.HumanRemovePasswordless(ctx, ctxData.UserID, req.TokenId, ctxData.ResourceOwner)
objectDetails, err := s.command.HumanRemoveU2F(ctx, ctxData.UserID, req.TokenId, ctxData.ResourceOwner)
if err != nil {
return nil, err
}

View File

@ -41,14 +41,13 @@ func (s *Server) SetMyPhone(ctx context.Context, req *auth_pb.SetMyPhoneRequest)
func (s *Server) VerifyMyPhone(ctx context.Context, req *auth_pb.VerifyMyPhoneRequest) (*auth_pb.VerifyMyPhoneResponse, error) {
ctxData := authz.GetCtxData(ctx)
_, err := s.command.VerifyHumanPhone(ctx, ctxData.UserID, req.Code, ctxData.ResourceOwner)
objectDetails, err := s.command.VerifyHumanPhone(ctx, ctxData.UserID, req.Code, ctxData.ResourceOwner)
if err != nil {
return nil, err
}
//TODO: response from business
return &auth_pb.VerifyMyPhoneResponse{
//Details: object.DomainToChangeDetailsPb(objectDetails),
Details: object.DomainToChangeDetailsPb(objectDetails),
}, nil
}

View File

@ -245,7 +245,7 @@ func IDPProviderTypeModelFromPb(typ idp_pb.IDPOwnerType) iam_model.IDPProviderTy
func IDPIDQueryToModel(query *idp_pb.IDPIDQuery) *iam_model.IDPConfigSearchQuery {
return &iam_model.IDPConfigSearchQuery{
Key: iam_model.IDPConfigSearchKeyIdpConfigID, //TODO: whats the difference between idpconfigid and aggregateid search key?
Key: iam_model.IDPConfigSearchKeyIdpConfigID,
Method: domain.SearchMethodEquals,
Value: query.Id,
}

View File

@ -139,7 +139,6 @@ func (s *Server) GenerateOrgDomainValidation(ctx context.Context, req *mgmt_pb.G
return &mgmt_pb.GenerateOrgDomainValidationResponse{
Token: token,
Url: url,
//TODO: remove details from proto
}, nil
}

View File

@ -121,7 +121,7 @@ func AddAPIClientKeyRequestToDomain(key *mgmt_pb.AddAppKeyRequest) *domain.Appli
func ListAPIClientKeysRequestToModel(req *mgmt_pb.ListAppKeysRequest) (*key_model.AuthNKeySearchRequest, error) {
offset, limit, asc := object.ListQueryToModel(req.Query)
queries := make([]*key_model.AuthNKeySearchQuery, 2)
queries := make([]*key_model.AuthNKeySearchQuery, 0)
queries = append(queries, &key_model.AuthNKeySearchQuery{
Key: key_model.AuthNKeyObjectID,
Method: domain.SearchMethodEquals,

View File

@ -2,6 +2,7 @@ package management
import (
"context"
"time"
"github.com/caos/zitadel/internal/api/authz"
member_grpc "github.com/caos/zitadel/internal/api/grpc/member"
@ -106,8 +107,8 @@ func (s *Server) RemoveProjectGrant(ctx context.Context, req *mgmt_pb.RemoveProj
func (s *Server) ListProjectGrantMemberRoles(ctx context.Context, req *mgmt_pb.ListProjectGrantMemberRolesRequest) (*mgmt_pb.ListProjectGrantMemberRolesResponse, error) {
roles := s.project.GetProjectGrantMemberRoles()
return &mgmt_pb.ListProjectGrantMemberRolesResponse{
Result: roles,
//TODO: metadata
Result: roles,
Details: object_grpc.ToListDetails(uint64(len(roles)), 0, time.Now()),
}, nil
}

View File

@ -100,7 +100,5 @@ func (s *Server) BulkRemoveUserGrant(ctx context.Context, req *mgmt_pb.BulkRemov
if err != nil {
return nil, err
}
return &mgmt_pb.BulkRemoveUserGrantResponse{
//TODO: Do we need details here?
}, nil
return &mgmt_pb.BulkRemoveUserGrantResponse{}, nil
}

View File

@ -17,13 +17,13 @@ func IAMMembersToPb(members []*iam_model.IAMMemberView) []*member_pb.Member {
func IAMMemberToPb(m *iam_model.IAMMemberView) *member_pb.Member {
return &member_pb.Member{
UserId: m.UserID,
Roles: m.Roles,
// PreferredLoginName: //TODO: not implemented in be
Email: m.Email,
FirstName: m.FirstName,
LastName: m.LastName,
DisplayName: m.DisplayName,
UserId: m.UserID,
Roles: m.Roles,
PreferredLoginName: m.PreferredLoginName,
Email: m.Email,
FirstName: m.FirstName,
LastName: m.LastName,
DisplayName: m.DisplayName,
Details: object.ToViewDetailsPb(
m.Sequence,
m.CreationDate,

View File

@ -17,13 +17,13 @@ func OrgMembersToPb(members []*org_model.OrgMemberView) []*member_pb.Member {
func OrgMemberToPb(m *org_model.OrgMemberView) *member_pb.Member {
return &member_pb.Member{
UserId: m.UserID,
Roles: m.Roles,
// PreferredLoginName: //TODO: not implemented in be
Email: m.Email,
FirstName: m.FirstName,
LastName: m.LastName,
DisplayName: m.DisplayName,
UserId: m.UserID,
Roles: m.Roles,
PreferredLoginName: m.PreferredLoginName,
Email: m.Email,
FirstName: m.FirstName,
LastName: m.LastName,
DisplayName: m.DisplayName,
Details: object.ToViewDetailsPb(
m.Sequence,
m.CreationDate,

View File

@ -17,13 +17,13 @@ func ProjectGrantMembersToPb(members []*proj_model.ProjectGrantMemberView) []*me
func ProjectGrantMemberToPb(m *proj_model.ProjectGrantMemberView) *member_pb.Member {
return &member_pb.Member{
UserId: m.UserID,
Roles: m.Roles,
// PreferredLoginName: //TODO: not implemented in be
Email: m.Email,
FirstName: m.FirstName,
LastName: m.LastName,
DisplayName: m.DisplayName,
UserId: m.UserID,
Roles: m.Roles,
PreferredLoginName: m.PreferredLoginName,
Email: m.Email,
FirstName: m.FirstName,
LastName: m.LastName,
DisplayName: m.DisplayName,
Details: object.ToViewDetailsPb(
m.Sequence,
m.CreationDate,

View File

@ -17,13 +17,13 @@ func ProjectMembersToPb(members []*proj_model.ProjectMemberView) []*member_pb.Me
func ProjectMemberToPb(m *proj_model.ProjectMemberView) *member_pb.Member {
return &member_pb.Member{
UserId: m.UserID,
Roles: m.Roles,
// PreferredLoginName: //TODO: not implemented in be
Email: m.Email,
FirstName: m.FirstName,
LastName: m.LastName,
DisplayName: m.DisplayName,
UserId: m.UserID,
Roles: m.Roles,
PreferredLoginName: m.PreferredLoginName,
Email: m.Email,
FirstName: m.FirstName,
LastName: m.LastName,
DisplayName: m.DisplayName,
Details: object.ToViewDetailsPb(
m.Sequence,
m.CreationDate,

View File

@ -29,8 +29,11 @@ func OrgQueryToModel(query *org_pb.OrgQuery) (*org_model.OrgSearchQuery, error)
Value: q.DomainQuery.Domain,
}, nil
case *org_pb.OrgQuery_NameQuery:
//TODO: implement name in backend
return nil, errors.ThrowUnimplemented(nil, "ADMIN-KGXnX", "name query not implemented")
return &org_model.OrgSearchQuery{
Key: org_model.OrgSearchKeyOrgName,
Method: object.TextMethodToModel(q.NameQuery.Method),
Value: q.NameQuery.Name,
}, nil
default:
return nil, errors.ThrowInvalidArgument(nil, "ADMIN-vR9nC", "List.Query.Invalid")
}

View File

@ -7,7 +7,8 @@ import (
func MultiFactorTypeToDomain(multiFactorType policy_pb.MultiFactorType) domain.MultiFactorType {
switch multiFactorType {
//TODO: gap between proto and backend
case policy_pb.MultiFactorType_MULTI_FACTOR_TYPE_U2F_WITH_VERIFICATION:
return domain.MultiFactorTypeU2FWithPIN
default:
return domain.MultiFactorTypeUnspecified
}

View File

@ -244,7 +244,6 @@ func WebAuthNTokenViewToPb(token *model.WebAuthNView) *user_pb.WebAuthNToken {
func WebAuthNTokenToWebAuthNKeyPb(token *domain.WebAuthNToken) *user_pb.WebAuthNKey {
return &user_pb.WebAuthNKey{
Id: string(token.KeyID), //TODO: ask if it's the correct id?
PublicKey: token.PublicKey,
}
}

View File

@ -37,10 +37,14 @@ func (wm *HumanEmailWriteModel) Reduce() error {
switch e := event.(type) {
case *user.HumanAddedEvent:
wm.Email = e.EmailAddress
wm.UserState = domain.UserStateInitial
wm.UserState = domain.UserStateActive
case *user.HumanRegisteredEvent:
wm.Email = e.EmailAddress
wm.UserState = domain.UserStateActive
case *user.HumanInitialCodeAddedEvent:
wm.UserState = domain.UserStateInitial
case *user.HumanInitializedCheckSucceededEvent:
wm.UserState = domain.UserStateActive
case *user.HumanEmailChangedEvent:
wm.Email = e.EmailAddress
wm.IsEmailVerified = false
@ -52,9 +56,6 @@ func (wm *HumanEmailWriteModel) Reduce() error {
case *user.HumanEmailVerifiedEvent:
wm.IsEmailVerified = true
wm.Code = nil
if wm.UserState == domain.UserStateInitial {
wm.UserState = domain.UserStateActive
}
case *user.UserRemovedEvent:
wm.UserState = domain.UserStateDeleted
}

View File

@ -572,6 +572,12 @@ func TestCommandSide_CreateVerificationCodeHumanEmail(t *testing.T) {
true,
),
),
eventFromEventPusher(
user.NewHumanInitialCodeAddedEvent(context.Background(),
&user.NewAggregate("user1", "org1").Aggregate,
nil, time.Hour*1,
),
),
),
),
},

View File

@ -37,10 +37,10 @@ func (wm *HumanInitCodeWriteModel) Reduce() error {
switch e := event.(type) {
case *user.HumanAddedEvent:
wm.Email = e.EmailAddress
wm.UserState = domain.UserStateInitial
wm.UserState = domain.UserStateActive
case *user.HumanRegisteredEvent:
wm.Email = e.EmailAddress
wm.UserState = domain.UserStateInitial
wm.UserState = domain.UserStateActive
case *user.HumanEmailChangedEvent:
wm.Email = e.EmailAddress
wm.IsEmailVerified = false
@ -54,8 +54,10 @@ func (wm *HumanInitCodeWriteModel) Reduce() error {
wm.Code = e.Code
wm.CodeCreationDate = e.CreationDate()
wm.CodeExpiry = e.Expiry
wm.UserState = domain.UserStateInitial
case *user.HumanInitializedCheckSucceededEvent:
wm.Code = nil
wm.UserState = domain.UserStateActive
case *user.UserRemovedEvent:
wm.UserState = domain.UserStateDeleted
}

View File

@ -126,6 +126,12 @@ func TestCommandSide_ResendInitialMail(t *testing.T) {
true,
),
),
eventFromEventPusher(
user.NewHumanInitialCodeAddedEvent(context.Background(),
&user.NewAggregate("user1", "org1").Aggregate,
nil, time.Hour*1,
),
),
),
expectPush(
[]*repository.Event{
@ -178,6 +184,12 @@ func TestCommandSide_ResendInitialMail(t *testing.T) {
true,
),
),
eventFromEventPusher(
user.NewHumanInitialCodeAddedEvent(context.Background(),
&user.NewAggregate("user1", "org1").Aggregate,
nil, time.Hour*1,
),
),
),
expectPush(
[]*repository.Event{
@ -229,6 +241,12 @@ func TestCommandSide_ResendInitialMail(t *testing.T) {
true,
),
),
eventFromEventPusher(
user.NewHumanInitialCodeAddedEvent(context.Background(),
&user.NewAggregate("user1", "org1").Aggregate,
nil, time.Hour*1,
),
),
),
expectPush(
[]*repository.Event{

View File

@ -54,6 +54,10 @@ func (wm *HumanWriteModel) Reduce() error {
wm.reduceHumanAddedEvent(e)
case *user.HumanRegisteredEvent:
wm.reduceHumanRegisteredEvent(e)
case *user.HumanInitialCodeAddedEvent:
wm.UserState = domain.UserStateInitial
case *user.HumanInitializedCheckSucceededEvent:
wm.UserState = domain.UserStateActive
case *user.UsernameChangedEvent:
wm.UserName = e.UserName
case *user.HumanProfileChangedEvent:
@ -128,7 +132,7 @@ func (wm *HumanWriteModel) reduceHumanAddedEvent(e *user.HumanAddedEvent) {
wm.StreetAddress = e.StreetAddress
wm.Secret = e.Secret
wm.SecretChangeRequired = e.ChangeRequired
wm.UserState = domain.UserStateInitial
wm.UserState = domain.UserStateActive
}
func (wm *HumanWriteModel) reduceHumanRegisteredEvent(e *user.HumanRegisteredEvent) {
@ -148,7 +152,7 @@ func (wm *HumanWriteModel) reduceHumanRegisteredEvent(e *user.HumanRegisteredEve
wm.StreetAddress = e.StreetAddress
wm.Secret = e.Secret
wm.SecretChangeRequired = e.ChangeRequired
wm.UserState = domain.UserStateInitial
wm.UserState = domain.UserStateActive
}
func (wm *HumanWriteModel) reduceHumanProfileChangedEvent(e *user.HumanProfileChangedEvent) {

View File

@ -37,11 +37,15 @@ func (wm *HumanPasswordWriteModel) Reduce() error {
case *user.HumanAddedEvent:
wm.Secret = e.Secret
wm.SecretChangeRequired = e.ChangeRequired
wm.UserState = domain.UserStateInitial
wm.UserState = domain.UserStateActive
case *user.HumanRegisteredEvent:
wm.Secret = e.Secret
wm.SecretChangeRequired = e.ChangeRequired
wm.UserState = domain.UserStateActive
case *user.HumanInitialCodeAddedEvent:
wm.UserState = domain.UserStateInitial
case *user.HumanInitializedCheckSucceededEvent:
wm.UserState = domain.UserStateActive
case *user.HumanPasswordChangedEvent:
wm.Secret = e.Secret
wm.SecretChangeRequired = e.ChangeRequired

View File

@ -757,7 +757,7 @@ func TestCommandSide_RequestSetPassword(t *testing.T) {
},
},
{
name: "phone already verified, precondition error",
name: "user initial, precondition error",
fields: fields{
eventstore: eventstoreExpect(
t,
@ -776,6 +776,12 @@ func TestCommandSide_RequestSetPassword(t *testing.T) {
true,
),
),
eventFromEventPusher(
user.NewHumanInitialCodeAddedEvent(context.Background(),
&user.NewAggregate("user1", "org1").Aggregate,
nil, time.Hour*1,
),
),
eventFromEventPusher(
user.NewHumanPhoneChangedEvent(context.Background(),
&user.NewAggregate("user1", "org1").Aggregate,

View File

@ -48,6 +48,10 @@ func (wm *HumanPhoneWriteModel) Reduce() error {
wm.State = domain.PhoneStateActive
}
wm.UserState = domain.UserStateActive
case *user.HumanInitialCodeAddedEvent:
wm.UserState = domain.UserStateInitial
case *user.HumanInitializedCheckSucceededEvent:
wm.UserState = domain.UserStateActive
case *user.HumanPhoneChangedEvent:
wm.Phone = e.PhoneNumber
wm.IsPhoneVerified = false

View File

@ -474,7 +474,7 @@ func TestCommandSide_AddHuman(t *testing.T) {
EmailAddress: "email@test.ch",
IsEmailVerified: true,
},
State: domain.UserStateInitial,
State: domain.UserStateActive,
},
},
},
@ -1048,7 +1048,7 @@ func TestCommandSide_RegisterHuman(t *testing.T) {
EmailAddress: "email@test.ch",
IsEmailVerified: true,
},
State: domain.UserStateInitial,
State: domain.UserStateActive,
},
},
},

View File

@ -173,6 +173,7 @@ func (c *Commands) HumanVerifyU2FSetup(ctx context.Context, userID, resourceowne
webAuthN.PublicKey,
webAuthN.AAGUID,
webAuthN.SignCount,
userAgentID,
),
)
if err != nil {
@ -206,6 +207,7 @@ func (c *Commands) HumanHumanPasswordlessSetup(ctx context.Context, userID, reso
webAuthN.PublicKey,
webAuthN.AAGUID,
webAuthN.SignCount,
userAgentID,
),
)
if err != nil {
@ -436,7 +438,7 @@ func (c *Commands) removeHumanWebAuthN(ctx context.Context, userID, webAuthNID,
return nil, err
}
if existingWebAuthN.State == domain.MFAStateUnspecified || existingWebAuthN.State == domain.MFAStateRemoved {
return nil, caos_errs.ThrowNotFound(nil, "COMMAND-2M9ds", "Errors.User.ExternalIDP.NotFound")
return nil, caos_errs.ThrowNotFound(nil, "COMMAND-DAfb2", "Errors.User.WebAuthN.NotFound")
}
userAgg := UserAggregateFromWriteModel(&existingWebAuthN.WriteModel)

View File

@ -39,18 +39,50 @@ func (wm *HumanWebAuthNWriteModel) AppendEvents(events ...eventstore.EventReader
if wm.WebauthNTokenID == e.WebAuthNTokenID {
wm.WriteModel.AppendEvents(e)
}
case *user.HumanPasswordlessAddedEvent:
if wm.WebauthNTokenID == e.WebAuthNTokenID {
wm.WriteModel.AppendEvents(&e.HumanWebAuthNAddedEvent)
}
case *user.HumanU2FAddedEvent:
if wm.WebauthNTokenID == e.WebAuthNTokenID {
wm.WriteModel.AppendEvents(&e.HumanWebAuthNAddedEvent)
}
case *user.HumanWebAuthNVerifiedEvent:
if wm.WebauthNTokenID == e.WebAuthNTokenID {
wm.WriteModel.AppendEvents(e)
}
case *user.HumanPasswordlessVerifiedEvent:
if wm.WebauthNTokenID == e.WebAuthNTokenID {
wm.WriteModel.AppendEvents(e)
}
case *user.HumanU2FVerifiedEvent:
if wm.WebauthNTokenID == e.WebAuthNTokenID {
wm.WriteModel.AppendEvents(e)
}
case *user.HumanWebAuthNSignCountChangedEvent:
if wm.WebauthNTokenID == e.WebAuthNTokenID {
wm.WriteModel.AppendEvents(e)
}
case *user.HumanPasswordlessSignCountChangedEvent:
if wm.WebauthNTokenID == e.WebAuthNTokenID {
wm.WriteModel.AppendEvents(e)
}
case *user.HumanU2FSignCountChangedEvent:
if wm.WebauthNTokenID == e.WebAuthNTokenID {
wm.WriteModel.AppendEvents(e)
}
case *user.HumanWebAuthNRemovedEvent:
if wm.WebauthNTokenID == e.WebAuthNTokenID {
wm.WriteModel.AppendEvents(e)
}
case *user.HumanPasswordlessRemovedEvent:
if wm.WebauthNTokenID == e.WebAuthNTokenID {
wm.WriteModel.AppendEvents(e)
}
case *user.HumanU2FRemovedEvent:
if wm.WebauthNTokenID == e.WebAuthNTokenID {
wm.WriteModel.AppendEvents(e)
}
case *user.UserRemovedEvent:
wm.WriteModel.AppendEvents(e)
}

View File

@ -30,9 +30,11 @@ func (wm *UserWriteModel) Reduce() error {
switch e := event.(type) {
case *user.HumanAddedEvent:
wm.UserName = e.UserName
wm.UserState = domain.UserStateInitial
wm.UserState = domain.UserStateActive
case *user.HumanRegisteredEvent:
wm.UserName = e.UserName
wm.UserState = domain.UserStateActive
case *user.HumanInitialCodeAddedEvent:
wm.UserState = domain.UserStateInitial
case *user.HumanInitializedCheckSucceededEvent:
wm.UserState = domain.UserStateActive

View File

@ -6,17 +6,18 @@ import (
)
type IAMMemberView struct {
UserID string
IAMID string
UserName string
Email string
FirstName string
LastName string
DisplayName string
Roles []string
CreationDate time.Time
ChangeDate time.Time
Sequence uint64
UserID string
IAMID string
UserName string
Email string
FirstName string
LastName string
DisplayName string
PreferredLoginName string
Roles []string
CreationDate time.Time
ChangeDate time.Time
Sequence uint64
}
type IAMMemberSearchRequest struct {

View File

@ -23,15 +23,16 @@ const (
)
type IAMMemberView struct {
UserID string `json:"userId" gorm:"column:user_id;primary_key"`
IAMID string `json:"-" gorm:"column:iam_id"`
UserName string `json:"-" gorm:"column:user_name"`
Email string `json:"-" gorm:"column:email_address"`
FirstName string `json:"-" gorm:"column:first_name"`
LastName string `json:"-" gorm:"column:last_name"`
DisplayName string `json:"-" gorm:"column:display_name"`
Roles pq.StringArray `json:"roles" gorm:"column:roles"`
Sequence uint64 `json:"-" gorm:"column:sequence"`
UserID string `json:"userId" gorm:"column:user_id;primary_key"`
IAMID string `json:"-" gorm:"column:iam_id"`
UserName string `json:"-" gorm:"column:user_name"`
Email string `json:"-" gorm:"column:email_address"`
FirstName string `json:"-" gorm:"column:first_name"`
LastName string `json:"-" gorm:"column:last_name"`
DisplayName string `json:"-" gorm:"column:display_name"`
Roles pq.StringArray `json:"roles" gorm:"column:roles"`
Sequence uint64 `json:"-" gorm:"column:sequence"`
PreferredLoginName string `json:"-" gorm:"column:preferred_login_name"`
CreationDate time.Time `json:"-" gorm:"column:creation_date"`
ChangeDate time.Time `json:"-" gorm:"column:change_date"`
@ -55,17 +56,18 @@ func IAMMemberViewFromModel(member *model.IAMMemberView) *IAMMemberView {
func IAMMemberToModel(member *IAMMemberView) *model.IAMMemberView {
return &model.IAMMemberView{
UserID: member.UserID,
IAMID: member.IAMID,
UserName: member.UserName,
Email: member.Email,
FirstName: member.FirstName,
LastName: member.LastName,
DisplayName: member.DisplayName,
Roles: member.Roles,
Sequence: member.Sequence,
CreationDate: member.CreationDate,
ChangeDate: member.ChangeDate,
UserID: member.UserID,
IAMID: member.IAMID,
UserName: member.UserName,
Email: member.Email,
FirstName: member.FirstName,
LastName: member.LastName,
DisplayName: member.DisplayName,
PreferredLoginName: member.PreferredLoginName,
Roles: member.Roles,
Sequence: member.Sequence,
CreationDate: member.CreationDate,
ChangeDate: member.ChangeDate,
}
}

View File

@ -2,16 +2,23 @@ package handler
import (
"context"
"github.com/caos/zitadel/internal/domain"
caos_errs "github.com/caos/zitadel/internal/errors"
"github.com/caos/zitadel/internal/eventstore/v1"
es_sdk "github.com/caos/zitadel/internal/eventstore/v1/sdk"
iam_model "github.com/caos/zitadel/internal/iam/model"
iam_view "github.com/caos/zitadel/internal/iam/repository/view"
org_view "github.com/caos/zitadel/internal/org/repository/view"
"github.com/caos/zitadel/internal/user/repository/view"
"github.com/caos/logging"
es_models "github.com/caos/zitadel/internal/eventstore/v1/models"
"github.com/caos/zitadel/internal/eventstore/v1/query"
"github.com/caos/zitadel/internal/eventstore/v1/spooler"
iam_es_model "github.com/caos/zitadel/internal/iam/repository/eventsourcing/model"
org_model "github.com/caos/zitadel/internal/org/model"
"github.com/caos/zitadel/internal/org/repository/eventsourcing/model"
org_model "github.com/caos/zitadel/internal/org/repository/view/model"
org_view_model "github.com/caos/zitadel/internal/org/repository/view/model"
usr_model "github.com/caos/zitadel/internal/user/model"
usr_es_model "github.com/caos/zitadel/internal/user/repository/eventsourcing/model"
usr_view_model "github.com/caos/zitadel/internal/user/repository/view/model"
@ -84,7 +91,7 @@ func (m *OrgMember) Reduce(event *es_models.Event) (err error) {
}
func (m *OrgMember) processOrgMember(event *es_models.Event) (err error) {
member := new(org_model.OrgMemberView)
member := new(org_view_model.OrgMemberView)
switch event.Type {
case model.OrgMemberAdded:
err = member.AppendEvent(event)
@ -146,17 +153,25 @@ func (m *OrgMember) processUser(event *es_models.Event) (err error) {
}
}
func (m *OrgMember) fillData(member *org_model.OrgMemberView) (err error) {
func (m *OrgMember) fillData(member *org_view_model.OrgMemberView) (err error) {
user, err := m.getUserByID(member.UserID)
if err != nil {
return err
}
m.fillUserData(member, user)
return nil
return m.fillUserData(member, user)
}
func (m *OrgMember) fillUserData(member *org_model.OrgMemberView, user *usr_view_model.UserView) {
func (m *OrgMember) fillUserData(member *org_view_model.OrgMemberView, user *usr_view_model.UserView) error {
org, err := m.getOrgByID(context.Background(), user.ResourceOwner)
policy := org.OrgIamPolicy
if policy == nil {
policy, err = m.getDefaultOrgIAMPolicy(context.TODO())
if err != nil {
return err
}
}
member.UserName = user.UserName
member.PreferredLoginName = user.GenerateLoginName(org.GetPrimaryDomain().Domain, policy.UserLoginMustBeDomain)
if user.HumanView != nil {
member.FirstName = user.FirstName
member.LastName = user.LastName
@ -166,7 +181,9 @@ func (m *OrgMember) fillUserData(member *org_model.OrgMemberView, user *usr_view
if user.MachineView != nil {
member.DisplayName = user.MachineView.Name
}
return nil
}
func (m *OrgMember) OnError(event *es_models.Event, err error) error {
logging.LogWithFields("SPOOL-u73es", "id", event.AggregateID).WithError(err).Warn("something went wrong in orgmember handler")
return spooler.HandleError(event, err, m.view.GetLatestOrgMemberFailedEvent, m.view.ProcessedOrgMemberFailedEvent, m.view.ProcessedOrgMemberSequence, m.errorCountUntilSkip)
@ -208,3 +225,53 @@ func (u *OrgMember) getUserEvents(userID string, sequence uint64) ([]*es_models.
return u.es.FilterEvents(context.Background(), query)
}
func (u *OrgMember) getOrgByID(ctx context.Context, orgID string) (*org_model.Org, error) {
query, err := org_view.OrgByIDQuery(orgID, 0)
if err != nil {
return nil, err
}
esOrg := &model.Org{
ObjectRoot: es_models.ObjectRoot{
AggregateID: orgID,
},
}
err = es_sdk.Filter(ctx, u.Eventstore().FilterEvents, esOrg.AppendEvents, query)
if err != nil && !caos_errs.IsNotFound(err) {
return nil, err
}
if esOrg.Sequence == 0 {
return nil, caos_errs.ThrowNotFound(nil, "EVENT-kVLb2", "Errors.Org.NotFound")
}
return model.OrgToModel(esOrg), nil
}
func (u *OrgMember) getDefaultOrgIAMPolicy(ctx context.Context) (*iam_model.OrgIAMPolicy, error) {
existingIAM, err := u.getIAMByID(ctx)
if err != nil {
return nil, err
}
if existingIAM.DefaultOrgIAMPolicy == nil {
return nil, caos_errs.ThrowNotFound(nil, "EVENT-2Fj8s", "Errors.IAM.OrgIAMPolicy.NotExisting")
}
return existingIAM.DefaultOrgIAMPolicy, nil
}
func (u *OrgMember) getIAMByID(ctx context.Context) (*iam_model.IAM, error) {
query, err := iam_view.IAMByIDQuery(domain.IAMID, 0)
if err != nil {
return nil, err
}
iam := &iam_es_model.IAM{
ObjectRoot: es_models.ObjectRoot{
AggregateID: domain.IAMID,
},
}
err = es_sdk.Filter(ctx, u.Eventstore().FilterEvents, iam.AppendEvents, query)
if err != nil && caos_errs.IsNotFound(err) && iam.Sequence == 0 {
return nil, err
}
return iam_es_model.IAMToModel(iam), nil
}

View File

@ -2,8 +2,16 @@ package handler
import (
"context"
"github.com/caos/zitadel/internal/domain"
caos_errs "github.com/caos/zitadel/internal/errors"
"github.com/caos/zitadel/internal/eventstore/v1"
es_sdk "github.com/caos/zitadel/internal/eventstore/v1/sdk"
iam_model "github.com/caos/zitadel/internal/iam/model"
iam_es_model "github.com/caos/zitadel/internal/iam/repository/eventsourcing/model"
iam_view "github.com/caos/zitadel/internal/iam/repository/view"
org_model "github.com/caos/zitadel/internal/org/model"
org_es_model "github.com/caos/zitadel/internal/org/repository/eventsourcing/model"
org_view "github.com/caos/zitadel/internal/org/repository/view"
"github.com/caos/zitadel/internal/user/repository/view"
usr_view_model "github.com/caos/zitadel/internal/user/repository/view/model"
@ -160,8 +168,17 @@ func (p *ProjectGrantMember) fillData(member *view_model.ProjectGrantMemberView)
return nil
}
func (p *ProjectGrantMember) fillUserData(member *view_model.ProjectGrantMemberView, user *usr_view_model.UserView) {
func (p *ProjectGrantMember) fillUserData(member *view_model.ProjectGrantMemberView, user *usr_view_model.UserView) error {
org, err := p.getOrgByID(context.Background(), user.ResourceOwner)
policy := org.OrgIamPolicy
if policy == nil {
policy, err = p.getDefaultOrgIAMPolicy(context.TODO())
if err != nil {
return err
}
}
member.UserName = user.UserName
member.PreferredLoginName = user.GenerateLoginName(org.GetPrimaryDomain().Domain, policy.UserLoginMustBeDomain)
if user.HumanView != nil {
member.FirstName = user.FirstName
member.LastName = user.LastName
@ -171,6 +188,7 @@ func (p *ProjectGrantMember) fillUserData(member *view_model.ProjectGrantMemberV
if user.MachineView != nil {
member.DisplayName = user.MachineView.Name
}
return nil
}
func (p *ProjectGrantMember) OnError(event *es_models.Event, err error) error {
@ -214,3 +232,53 @@ func (u *ProjectGrantMember) getUserEvents(userID string, sequence uint64) ([]*e
return u.es.FilterEvents(context.Background(), query)
}
func (u *ProjectGrantMember) getOrgByID(ctx context.Context, orgID string) (*org_model.Org, error) {
query, err := org_view.OrgByIDQuery(orgID, 0)
if err != nil {
return nil, err
}
esOrg := &org_es_model.Org{
ObjectRoot: es_models.ObjectRoot{
AggregateID: orgID,
},
}
err = es_sdk.Filter(ctx, u.Eventstore().FilterEvents, esOrg.AppendEvents, query)
if err != nil && !caos_errs.IsNotFound(err) {
return nil, err
}
if esOrg.Sequence == 0 {
return nil, caos_errs.ThrowNotFound(nil, "EVENT-3nd7s", "Errors.Org.NotFound")
}
return org_es_model.OrgToModel(esOrg), nil
}
func (u *ProjectGrantMember) getDefaultOrgIAMPolicy(ctx context.Context) (*iam_model.OrgIAMPolicy, error) {
existingIAM, err := u.getIAMByID(ctx)
if err != nil {
return nil, err
}
if existingIAM.DefaultOrgIAMPolicy == nil {
return nil, caos_errs.ThrowNotFound(nil, "EVENT-3Bf7s", "Errors.IAM.OrgIAMPolicy.NotExisting")
}
return existingIAM.DefaultOrgIAMPolicy, nil
}
func (u *ProjectGrantMember) getIAMByID(ctx context.Context) (*iam_model.IAM, error) {
query, err := iam_view.IAMByIDQuery(domain.IAMID, 0)
if err != nil {
return nil, err
}
iam := &iam_es_model.IAM{
ObjectRoot: es_models.ObjectRoot{
AggregateID: domain.IAMID,
},
}
err = es_sdk.Filter(ctx, u.Eventstore().FilterEvents, iam.AppendEvents, query)
if err != nil && caos_errs.IsNotFound(err) && iam.Sequence == 0 {
return nil, err
}
return iam_es_model.IAMToModel(iam), nil
}

View File

@ -2,8 +2,15 @@ package handler
import (
"context"
"github.com/caos/zitadel/internal/domain"
caos_errs "github.com/caos/zitadel/internal/errors"
"github.com/caos/zitadel/internal/eventstore/v1"
es_sdk "github.com/caos/zitadel/internal/eventstore/v1/sdk"
iam_model "github.com/caos/zitadel/internal/iam/model"
iam_es_model "github.com/caos/zitadel/internal/iam/repository/eventsourcing/model"
iam_view "github.com/caos/zitadel/internal/iam/repository/view"
org_model "github.com/caos/zitadel/internal/org/model"
org_view "github.com/caos/zitadel/internal/org/repository/view"
"github.com/caos/zitadel/internal/user/repository/view"
"github.com/caos/logging"
@ -11,6 +18,7 @@ import (
es_models "github.com/caos/zitadel/internal/eventstore/v1/models"
"github.com/caos/zitadel/internal/eventstore/v1/query"
"github.com/caos/zitadel/internal/eventstore/v1/spooler"
org_es_model "github.com/caos/zitadel/internal/org/repository/eventsourcing/model"
proj_es_model "github.com/caos/zitadel/internal/project/repository/eventsourcing/model"
view_model "github.com/caos/zitadel/internal/project/repository/view/model"
usr_model "github.com/caos/zitadel/internal/user/model"
@ -153,12 +161,20 @@ func (p *ProjectMember) fillData(member *view_model.ProjectMemberView) (err erro
if err != nil {
return err
}
p.fillUserData(member, user)
return nil
return p.fillUserData(member, user)
}
func (p *ProjectMember) fillUserData(member *view_model.ProjectMemberView, user *usr_view_model.UserView) {
func (p *ProjectMember) fillUserData(member *view_model.ProjectMemberView, user *usr_view_model.UserView) error {
org, err := p.getOrgByID(context.Background(), user.ResourceOwner)
policy := org.OrgIamPolicy
if policy == nil {
policy, err = p.getDefaultOrgIAMPolicy(context.TODO())
if err != nil {
return err
}
}
member.UserName = user.UserName
member.PreferredLoginName = user.GenerateLoginName(org.GetPrimaryDomain().Domain, policy.UserLoginMustBeDomain)
if user.HumanView != nil {
member.FirstName = user.FirstName
member.LastName = user.LastName
@ -168,7 +184,9 @@ func (p *ProjectMember) fillUserData(member *view_model.ProjectMemberView, user
if user.MachineView != nil {
member.DisplayName = user.MachineView.Name
}
return nil
}
func (p *ProjectMember) OnError(event *es_models.Event, err error) error {
logging.LogWithFields("SPOOL-u73es", "id", event.AggregateID).WithError(err).Warn("something went wrong in projectmember handler")
return spooler.HandleError(event, err, p.view.GetLatestProjectMemberFailedEvent, p.view.ProcessedProjectMemberFailedEvent, p.view.ProcessedProjectMemberSequence, p.errorCountUntilSkip)
@ -210,3 +228,53 @@ func (u *ProjectMember) getUserEvents(userID string, sequence uint64) ([]*es_mod
return u.es.FilterEvents(context.Background(), query)
}
func (u *ProjectMember) getOrgByID(ctx context.Context, orgID string) (*org_model.Org, error) {
query, err := org_view.OrgByIDQuery(orgID, 0)
if err != nil {
return nil, err
}
esOrg := &org_es_model.Org{
ObjectRoot: es_models.ObjectRoot{
AggregateID: orgID,
},
}
err = es_sdk.Filter(ctx, u.Eventstore().FilterEvents, esOrg.AppendEvents, query)
if err != nil && !caos_errs.IsNotFound(err) {
return nil, err
}
if esOrg.Sequence == 0 {
return nil, caos_errs.ThrowNotFound(nil, "EVENT-3N8fs", "Errors.Org.NotFound")
}
return org_es_model.OrgToModel(esOrg), nil
}
func (u *ProjectMember) getDefaultOrgIAMPolicy(ctx context.Context) (*iam_model.OrgIAMPolicy, error) {
existingIAM, err := u.getIAMByID(ctx)
if err != nil {
return nil, err
}
if existingIAM.DefaultOrgIAMPolicy == nil {
return nil, caos_errs.ThrowNotFound(nil, "EVENT-5M9sd", "Errors.IAM.OrgIAMPolicy.NotExisting")
}
return existingIAM.DefaultOrgIAMPolicy, nil
}
func (u *ProjectMember) getIAMByID(ctx context.Context) (*iam_model.IAM, error) {
query, err := iam_view.IAMByIDQuery(domain.IAMID, 0)
if err != nil {
return nil, err
}
iam := &iam_es_model.IAM{
ObjectRoot: es_models.ObjectRoot{
AggregateID: domain.IAMID,
},
}
err = es_sdk.Filter(ctx, u.Eventstore().FilterEvents, iam.AppendEvents, query)
if err != nil && caos_errs.IsNotFound(err) && iam.Sequence == 0 {
return nil, err
}
return iam_es_model.IAMToModel(iam), nil
}

View File

@ -32,9 +32,9 @@ func (msg *EmailMessage) GetContent() string {
}
//default mime-type is html
mime := "MIME-version: 1.0;" + lineBreak + "Content-KeyType: text/html; charset=\"UTF-8\";" + lineBreak + lineBreak
mime := "MIME-version: 1.0;" + lineBreak + "Content-Type: text/html; charset=\"UTF-8\";" + lineBreak + lineBreak
if !isHTML(msg.Content) {
mime = "MIME-version: 1.0;" + lineBreak + "Content-KeyType: text/plain; charset=\"UTF-8\";" + lineBreak + lineBreak
mime = "MIME-version: 1.0;" + lineBreak + "Content-Type: text/plain; charset=\"UTF-8\";" + lineBreak + lineBreak
}
subject := "Subject: " + msg.Subject + lineBreak
message += subject + mime + lineBreak + msg.Content

View File

@ -2,6 +2,7 @@ package handler
import (
"context"
"github.com/caos/zitadel/internal/domain"
caos_errs "github.com/caos/zitadel/internal/errors"
"github.com/caos/zitadel/internal/eventstore/v1"
@ -12,6 +13,7 @@ import (
org_view "github.com/caos/zitadel/internal/org/repository/view"
"github.com/caos/logging"
es_models "github.com/caos/zitadel/internal/eventstore/v1/models"
"github.com/caos/zitadel/internal/eventstore/v1/query"
"github.com/caos/zitadel/internal/eventstore/v1/spooler"
@ -97,9 +99,13 @@ func (u *NotifyUser) ProcessUser(event *es_models.Event) (err error) {
case es_model.UserAdded,
es_model.UserRegistered,
es_model.HumanRegistered,
es_model.HumanAdded:
user.AppendEvent(event)
u.fillLoginNames(user)
es_model.HumanAdded,
es_model.MachineAdded:
err := user.AppendEvent(event)
if err != nil {
return err
}
err = u.fillLoginNames(user)
case es_model.UserProfileChanged,
es_model.UserEmailChanged,
es_model.UserEmailVerified,
@ -128,7 +134,7 @@ func (u *NotifyUser) ProcessUser(event *es_models.Event) (err error) {
if err != nil {
return err
}
u.fillLoginNames(user)
err = u.fillLoginNames(user)
case es_model.UserRemoved:
return u.view.DeleteNotifyUser(event.AggregateID, event)
default:

View File

@ -1,22 +1,24 @@
package model
import (
"github.com/caos/zitadel/internal/domain"
"time"
"github.com/caos/zitadel/internal/domain"
)
type OrgMemberView struct {
UserID string
OrgID string
UserName string
Email string
FirstName string
LastName string
DisplayName string
Roles []string
CreationDate time.Time
ChangeDate time.Time
Sequence uint64
UserID string
OrgID string
UserName string
Email string
FirstName string
LastName string
DisplayName string
PreferredLoginName string
Roles []string
CreationDate time.Time
ChangeDate time.Time
Sequence uint64
}
type OrgMemberSearchRequest struct {

View File

@ -23,15 +23,16 @@ const (
)
type OrgMemberView struct {
UserID string `json:"userId" gorm:"column:user_id;primary_key"`
OrgID string `json:"-" gorm:"column:org_id;primary_key"`
UserName string `json:"-" gorm:"column:user_name"`
Email string `json:"-" gorm:"column:email_address"`
FirstName string `json:"-" gorm:"column:first_name"`
LastName string `json:"-" gorm:"column:last_name"`
DisplayName string `json:"-" gorm:"column:display_name"`
Roles pq.StringArray `json:"roles" gorm:"column:roles"`
Sequence uint64 `json:"-" gorm:"column:sequence"`
UserID string `json:"userId" gorm:"column:user_id;primary_key"`
OrgID string `json:"-" gorm:"column:org_id;primary_key"`
UserName string `json:"-" gorm:"column:user_name"`
Email string `json:"-" gorm:"column:email_address"`
FirstName string `json:"-" gorm:"column:first_name"`
LastName string `json:"-" gorm:"column:last_name"`
DisplayName string `json:"-" gorm:"column:display_name"`
Roles pq.StringArray `json:"roles" gorm:"column:roles"`
Sequence uint64 `json:"-" gorm:"column:sequence"`
PreferredLoginName string `json:"-" gorm:"column:preferred_login_name"`
CreationDate time.Time `json:"-" gorm:"column:creation_date"`
ChangeDate time.Time `json:"-" gorm:"column:change_date"`
@ -39,17 +40,18 @@ type OrgMemberView struct {
func OrgMemberToModel(member *OrgMemberView) *model.OrgMemberView {
return &model.OrgMemberView{
UserID: member.UserID,
OrgID: member.OrgID,
UserName: member.UserName,
Email: member.Email,
FirstName: member.FirstName,
LastName: member.LastName,
DisplayName: member.DisplayName,
Roles: member.Roles,
Sequence: member.Sequence,
CreationDate: member.CreationDate,
ChangeDate: member.ChangeDate,
UserID: member.UserID,
OrgID: member.OrgID,
UserName: member.UserName,
Email: member.Email,
FirstName: member.FirstName,
LastName: member.LastName,
DisplayName: member.DisplayName,
PreferredLoginName: member.PreferredLoginName,
Roles: member.Roles,
Sequence: member.Sequence,
CreationDate: member.CreationDate,
ChangeDate: member.ChangeDate,
}
}

View File

@ -6,18 +6,19 @@ import (
)
type ProjectGrantMemberView struct {
UserID string
GrantID string
ProjectID string
UserName string
Email string
FirstName string
LastName string
DisplayName string
Roles []string
CreationDate time.Time
ChangeDate time.Time
Sequence uint64
UserID string
GrantID string
ProjectID string
UserName string
Email string
FirstName string
LastName string
DisplayName string
PreferredLoginName string
Roles []string
CreationDate time.Time
ChangeDate time.Time
Sequence uint64
}
type ProjectGrantMemberSearchRequest struct {

View File

@ -6,17 +6,18 @@ import (
)
type ProjectMemberView struct {
UserID string
ProjectID string
UserName string
Email string
FirstName string
LastName string
DisplayName string
Roles []string
CreationDate time.Time
ChangeDate time.Time
Sequence uint64
UserID string
ProjectID string
UserName string
Email string
FirstName string
LastName string
DisplayName string
PreferredLoginName string
Roles []string
CreationDate time.Time
ChangeDate time.Time
Sequence uint64
}
type ProjectMemberSearchRequest struct {

View File

@ -5,11 +5,12 @@ import (
"time"
"github.com/caos/logging"
"github.com/lib/pq"
caos_errs "github.com/caos/zitadel/internal/errors"
"github.com/caos/zitadel/internal/eventstore/v1/models"
"github.com/caos/zitadel/internal/project/model"
es_model "github.com/caos/zitadel/internal/project/repository/eventsourcing/model"
"github.com/lib/pq"
)
const (
@ -23,16 +24,17 @@ const (
)
type ProjectGrantMemberView struct {
UserID string `json:"userId" gorm:"column:user_id;primary_key"`
GrantID string `json:"grantId" gorm:"column:grant_id;primary_key"`
ProjectID string `json:"-" gorm:"column:project_id"`
UserName string `json:"-" gorm:"column:user_name"`
Email string `json:"-" gorm:"column:email_address"`
FirstName string `json:"-" gorm:"column:first_name"`
LastName string `json:"-" gorm:"column:last_name"`
DisplayName string `json:"-" gorm:"column:display_name"`
Roles pq.StringArray `json:"roles" gorm:"column:roles"`
Sequence uint64 `json:"-" gorm:"column:sequence"`
UserID string `json:"userId" gorm:"column:user_id;primary_key"`
GrantID string `json:"grantId" gorm:"column:grant_id;primary_key"`
ProjectID string `json:"-" gorm:"column:project_id"`
UserName string `json:"-" gorm:"column:user_name"`
Email string `json:"-" gorm:"column:email_address"`
FirstName string `json:"-" gorm:"column:first_name"`
LastName string `json:"-" gorm:"column:last_name"`
DisplayName string `json:"-" gorm:"column:display_name"`
Roles pq.StringArray `json:"roles" gorm:"column:roles"`
Sequence uint64 `json:"-" gorm:"column:sequence"`
PreferredLoginName string `json:"-" gorm:"column:preferred_login_name"`
CreationDate time.Time `json:"-" gorm:"column:creation_date"`
ChangeDate time.Time `json:"-" gorm:"column:change_date"`
@ -40,18 +42,19 @@ type ProjectGrantMemberView struct {
func ProjectGrantMemberToModel(member *ProjectGrantMemberView) *model.ProjectGrantMemberView {
return &model.ProjectGrantMemberView{
UserID: member.UserID,
GrantID: member.GrantID,
ProjectID: member.ProjectID,
UserName: member.UserName,
Email: member.Email,
FirstName: member.FirstName,
LastName: member.LastName,
DisplayName: member.DisplayName,
Roles: member.Roles,
Sequence: member.Sequence,
CreationDate: member.CreationDate,
ChangeDate: member.ChangeDate,
UserID: member.UserID,
GrantID: member.GrantID,
ProjectID: member.ProjectID,
UserName: member.UserName,
Email: member.Email,
FirstName: member.FirstName,
LastName: member.LastName,
DisplayName: member.DisplayName,
PreferredLoginName: member.PreferredLoginName,
Roles: member.Roles,
Sequence: member.Sequence,
CreationDate: member.CreationDate,
ChangeDate: member.ChangeDate,
}
}

View File

@ -22,15 +22,16 @@ const (
)
type ProjectMemberView struct {
UserID string `json:"userId" gorm:"column:user_id;primary_key"`
ProjectID string `json:"-" gorm:"column:project_id;primary_key"`
UserName string `json:"-" gorm:"column:user_name"`
Email string `json:"-" gorm:"column:email_address"`
FirstName string `json:"-" gorm:"column:first_name"`
LastName string `json:"-" gorm:"column:last_name"`
DisplayName string `json:"-" gorm:"column:display_name"`
Roles pq.StringArray `json:"roles" gorm:"column:roles"`
Sequence uint64 `json:"-" gorm:"column:sequence"`
UserID string `json:"userId" gorm:"column:user_id;primary_key"`
ProjectID string `json:"-" gorm:"column:project_id;primary_key"`
UserName string `json:"-" gorm:"column:user_name"`
Email string `json:"-" gorm:"column:email_address"`
FirstName string `json:"-" gorm:"column:first_name"`
LastName string `json:"-" gorm:"column:last_name"`
DisplayName string `json:"-" gorm:"column:display_name"`
Roles pq.StringArray `json:"roles" gorm:"column:roles"`
Sequence uint64 `json:"-" gorm:"column:sequence"`
PreferredLoginName string `json:"-" gorm:"column:preferred_login_name"`
CreationDate time.Time `json:"-" gorm:"column:creation_date"`
ChangeDate time.Time `json:"-" gorm:"column:change_date"`

View File

@ -64,6 +64,7 @@ func NewHumanPasswordlessVerifiedEvent(
publicKey,
aaguid []byte,
signCount uint32,
userAgentID string,
) *HumanPasswordlessVerifiedEvent {
return &HumanPasswordlessVerifiedEvent{
HumanWebAuthNVerifiedEvent: *NewHumanWebAuthNVerifiedEvent(
@ -79,6 +80,7 @@ func NewHumanPasswordlessVerifiedEvent(
publicKey,
aaguid,
signCount,
userAgentID,
),
}
}

View File

@ -64,6 +64,7 @@ func NewHumanU2FVerifiedEvent(
publicKey,
aaguid []byte,
signCount uint32,
userAgentID string,
) *HumanU2FVerifiedEvent {
return &HumanU2FVerifiedEvent{
HumanWebAuthNVerifiedEvent: *NewHumanWebAuthNVerifiedEvent(
@ -79,6 +80,7 @@ func NewHumanU2FVerifiedEvent(
publicKey,
aaguid,
signCount,
userAgentID,
),
}
}

View File

@ -2,6 +2,7 @@ package user
import (
"encoding/json"
"github.com/caos/zitadel/internal/domain"
"github.com/caos/zitadel/internal/errors"
"github.com/caos/zitadel/internal/eventstore"
@ -56,6 +57,7 @@ type HumanWebAuthNVerifiedEvent struct {
AAGUID []byte `json:"aaguid"`
SignCount uint32 `json:"signCount"`
WebAuthNTokenName string `json:"webAuthNTokenName"`
UserAgentID string `json:"userAgentID,omitempty"`
}
func (e *HumanWebAuthNVerifiedEvent) Data() interface{} {
@ -75,6 +77,7 @@ func NewHumanWebAuthNVerifiedEvent(
publicKey,
aaguid []byte,
signCount uint32,
userAgentID string,
) *HumanWebAuthNVerifiedEvent {
return &HumanWebAuthNVerifiedEvent{
BaseEvent: *base,
@ -85,6 +88,7 @@ func NewHumanWebAuthNVerifiedEvent(
AAGUID: aaguid,
SignCount: signCount,
WebAuthNTokenName: webAuthNTokenName,
UserAgentID: userAgentID,
}
}

View File

@ -69,8 +69,6 @@ func MachineAddedEventMapper(event *repository.Event) (eventstore.EventReader, e
type MachineChangedEvent struct {
eventstore.BaseEvent `json:"-"`
UserName string `json:"userName"`
Name *string `json:"name,omitempty"`
Description *string `json:"description,omitempty"`
}

View File

@ -2,16 +2,18 @@ package model
import (
"encoding/json"
iam_model "github.com/caos/zitadel/internal/iam/model"
"time"
iam_model "github.com/caos/zitadel/internal/iam/model"
"github.com/caos/logging"
"github.com/lib/pq"
caos_errs "github.com/caos/zitadel/internal/errors"
"github.com/caos/zitadel/internal/eventstore/v1/models"
org_model "github.com/caos/zitadel/internal/org/model"
"github.com/caos/zitadel/internal/user/model"
es_model "github.com/caos/zitadel/internal/user/repository/eventsourcing/model"
"github.com/lib/pq"
)
const (
@ -117,7 +119,8 @@ func (u *NotifyUser) AppendEvent(event *models.Event) (err error) {
case es_model.UserAdded,
es_model.UserRegistered,
es_model.HumanRegistered,
es_model.HumanAdded:
es_model.HumanAdded,
es_model.MachineAdded:
u.CreationDate = event.CreationDate
u.setRootData(event)
err = u.setData(event)
@ -130,7 +133,8 @@ func (u *NotifyUser) AppendEvent(event *models.Event) (err error) {
es_model.UserPhoneChanged,
es_model.HumanProfileChanged,
es_model.HumanEmailChanged,
es_model.HumanPhoneChanged:
es_model.HumanPhoneChanged,
es_model.UserUserNameChanged:
err = u.setData(event)
case es_model.UserEmailVerified,
es_model.HumanEmailVerified:

View File

@ -0,0 +1,5 @@
ALTER TABLE management.org_members ADD COLUMN preferred_login_name TEXT;
ALTER TABLE management.project_members ADD COLUMN preferred_login_name TEXT;
ALTER TABLE management.project_grant_members ADD COLUMN preferred_login_name TEXT;
ALTER TABLE adminapi.iam_members ADD COLUMN preferred_login_name TEXT;

View File

@ -11,16 +11,24 @@ func (a *App) Localizers() []middleware.Localizer {
switch configType := a.Config.(type) {
case *App_OidcConfig:
if !configType.OidcConfig.NoneCompliant {
return nil
}
localizers := make([]middleware.Localizer, len(configType.OidcConfig.ComplianceProblems))
for i, problem := range configType.OidcConfig.ComplianceProblems {
localizers[i] = problem
}
return localizers
return configType.ComplianceLocalizers()
}
return nil
}
func (o *App_OidcConfig) ComplianceLocalizers() []middleware.Localizer {
if o.OidcConfig == nil {
return nil
}
if !o.OidcConfig.NoneCompliant {
return nil
}
localizers := make([]middleware.Localizer, len(o.OidcConfig.ComplianceProblems))
for i, problem := range o.OidcConfig.ComplianceProblems {
localizers[i] = problem
}
return localizers
}
type AppConfig = isApp_Config

View File

@ -1,6 +1,28 @@
package management
import "github.com/caos/zitadel/internal/api/grpc/server/middleware"
import (
"github.com/caos/zitadel/internal/api/grpc/server/middleware"
)
func (a *ListAppsResponse) Localizers() []middleware.Localizer {
if a == nil {
return nil
}
localizers := make([]middleware.Localizer, 0)
for _, a := range a.Result {
localizers = append(localizers, a.Localizers()...)
}
return localizers
}
func (a *GetAppByIDResponse) Localizers() []middleware.Localizer {
if a == nil || (a != nil && a.App == nil) {
return nil
}
return a.App.Localizers()
}
func (a *AddOIDCAppResponse) Localizers() []middleware.Localizer {
if a == nil {

View File

@ -515,7 +515,9 @@ message VerifyMyPhoneRequest {
string code = 1 [(validate.rules).string = {min_len: 1, max_len: 200}];
}
message VerifyMyPhoneResponse {}
message VerifyMyPhoneResponse {
zitadel.v1.ObjectDetails details = 1;
}
message ResendMyPhoneVerificationRequest {}

View File

@ -388,7 +388,7 @@ service ManagementService {
rpc RemoveHumanAuthFactorU2F(RemoveHumanAuthFactorU2FRequest) returns (RemoveHumanAuthFactorU2FResponse) {
option (google.api.http) = {
delete: "/users/{user_id}/auth_factors/u2f"
delete: "/users/{user_id}/auth_factors/u2f/{token_id}"
};
option (zitadel.v1.auth_option) = {
@ -408,7 +408,7 @@ service ManagementService {
rpc RemoveHumanPasswordless(RemoveHumanPasswordlessRequest) returns (RemoveHumanPasswordlessResponse) {
option (google.api.http) = {
delete: "/users/{user_id}/passwordless"
delete: "/users/{user_id}/passwordless/{token_id}"
};
option (zitadel.v1.auth_option) = {
@ -429,8 +429,7 @@ service ManagementService {
rpc GetMachineKeyByIDs(GetMachineKeyByIDsRequest) returns (GetMachineKeyByIDsResponse) {
option (google.api.http) = {
post: "/users/{user_id}/keys/{key_id}"
body: "*"
get: "/users/{user_id}/keys/{key_id}"
};
option (zitadel.v1.auth_option) = {
@ -2206,9 +2205,8 @@ message GenerateOrgDomainValidationRequest {
}
message GenerateOrgDomainValidationResponse {
zitadel.v1.ObjectDetails details = 1;
string token = 2;
string url = 3;
string token = 1;
string url = 2;
}
message ValidateOrgDomainRequest {

View File

@ -172,8 +172,7 @@ message AuthFactorU2F {
}
message WebAuthNKey {
string id = 1;
bytes public_key = 2;
bytes public_key = 1;
}
message WebAuthNVerification {