mirror of
https://github.com/zitadel/zitadel.git
synced 2025-08-11 15:49:35 +00:00
fix(import/export): fix for deactivated user/organization being imported as active (#9992)
This commit is contained in:
@@ -8,7 +8,9 @@ import (
|
|||||||
"google.golang.org/protobuf/types/known/timestamppb"
|
"google.golang.org/protobuf/types/known/timestamppb"
|
||||||
|
|
||||||
authn_grpc "github.com/zitadel/zitadel/internal/api/grpc/authn"
|
authn_grpc "github.com/zitadel/zitadel/internal/api/grpc/authn"
|
||||||
|
"github.com/zitadel/zitadel/internal/api/grpc/org"
|
||||||
text_grpc "github.com/zitadel/zitadel/internal/api/grpc/text"
|
text_grpc "github.com/zitadel/zitadel/internal/api/grpc/text"
|
||||||
|
user_converter "github.com/zitadel/zitadel/internal/api/grpc/user"
|
||||||
"github.com/zitadel/zitadel/internal/domain"
|
"github.com/zitadel/zitadel/internal/domain"
|
||||||
"github.com/zitadel/zitadel/internal/query"
|
"github.com/zitadel/zitadel/internal/query"
|
||||||
"github.com/zitadel/zitadel/internal/telemetry/tracing"
|
"github.com/zitadel/zitadel/internal/telemetry/tracing"
|
||||||
@@ -65,7 +67,7 @@ func (s *Server) ExportData(ctx context.Context, req *admin_pb.ExportDataRequest
|
|||||||
/******************************************************************************************************************
|
/******************************************************************************************************************
|
||||||
Organization
|
Organization
|
||||||
******************************************************************************************************************/
|
******************************************************************************************************************/
|
||||||
org := &admin_pb.DataOrg{OrgId: queriedOrg.ID, Org: &management_pb.AddOrgRequest{Name: queriedOrg.Name}}
|
org := &admin_pb.DataOrg{OrgId: queriedOrg.ID, OrgState: org.OrgStateToPb(queriedOrg.State), Org: &management_pb.AddOrgRequest{Name: queriedOrg.Name}}
|
||||||
orgs[i] = org
|
orgs[i] = org
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -567,6 +569,7 @@ func (s *Server) getUsers(ctx context.Context, org string, withPasswords bool, w
|
|||||||
case domain.UserTypeHuman:
|
case domain.UserTypeHuman:
|
||||||
dataUser := &v1_pb.DataHumanUser{
|
dataUser := &v1_pb.DataHumanUser{
|
||||||
UserId: user.ID,
|
UserId: user.ID,
|
||||||
|
State: user_converter.UserStateToPb(user.State),
|
||||||
User: &management_pb.ImportHumanUserRequest{
|
User: &management_pb.ImportHumanUserRequest{
|
||||||
UserName: user.Username,
|
UserName: user.Username,
|
||||||
Profile: &management_pb.ImportHumanUserRequest_Profile{
|
Profile: &management_pb.ImportHumanUserRequest_Profile{
|
||||||
@@ -620,6 +623,7 @@ func (s *Server) getUsers(ctx context.Context, org string, withPasswords bool, w
|
|||||||
case domain.UserTypeMachine:
|
case domain.UserTypeMachine:
|
||||||
machineUsers = append(machineUsers, &v1_pb.DataMachineUser{
|
machineUsers = append(machineUsers, &v1_pb.DataMachineUser{
|
||||||
UserId: user.ID,
|
UserId: user.ID,
|
||||||
|
State: user_converter.UserStateToPb(user.State),
|
||||||
User: &management_pb.AddMachineUserRequest{
|
User: &management_pb.AddMachineUserRequest{
|
||||||
UserName: user.Username,
|
UserName: user.Username,
|
||||||
Name: user.Machine.Name,
|
Name: user.Machine.Name,
|
||||||
@@ -647,7 +651,6 @@ func (s *Server) getUsers(ctx context.Context, org string, withPasswords bool, w
|
|||||||
ExpirationDate: timestamppb.New(key.Expiration),
|
ExpirationDate: timestamppb.New(key.Expiration),
|
||||||
PublicKey: key.PublicKey,
|
PublicKey: key.PublicKey,
|
||||||
})
|
})
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -888,7 +891,6 @@ func (s *Server) getNecessaryProjectGrantMembersForOrg(ctx context.Context, org
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -940,7 +942,6 @@ func (s *Server) getNecessaryOrgMembersForOrg(ctx context.Context, org string, p
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) getNecessaryProjectGrantsForOrg(ctx context.Context, org string, processedOrgs []string, processedProjects []string) ([]*v1_pb.DataProjectGrant, error) {
|
func (s *Server) getNecessaryProjectGrantsForOrg(ctx context.Context, org string, processedOrgs []string, processedProjects []string) ([]*v1_pb.DataProjectGrant, error) {
|
||||||
|
|
||||||
projectGrantSearchOrg, err := query.NewProjectGrantResourceOwnerSearchQuery(org)
|
projectGrantSearchOrg, err := query.NewProjectGrantResourceOwnerSearchQuery(org)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -991,7 +992,7 @@ func (s *Server) getNecessaryUserGrantsForOrg(ctx context.Context, org string, p
|
|||||||
for _, userGrant := range queriedUserGrants.UserGrants {
|
for _, userGrant := range queriedUserGrants.UserGrants {
|
||||||
for _, projectID := range processedProjects {
|
for _, projectID := range processedProjects {
|
||||||
if projectID == userGrant.ProjectID {
|
if projectID == userGrant.ProjectID {
|
||||||
//if usergrant is on a granted project
|
// if usergrant is on a granted project
|
||||||
if userGrant.GrantID != "" {
|
if userGrant.GrantID != "" {
|
||||||
for _, grantID := range processedGrants {
|
for _, grantID := range processedGrants {
|
||||||
if grantID == userGrant.GrantID {
|
if grantID == userGrant.GrantID {
|
||||||
@@ -1024,6 +1025,7 @@ func (s *Server) getNecessaryUserGrantsForOrg(ctx context.Context, org string, p
|
|||||||
}
|
}
|
||||||
return userGrants, nil
|
return userGrants, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) getCustomLoginTexts(ctx context.Context, org string, languages []string) ([]*management_pb.SetCustomLoginTextsRequest, error) {
|
func (s *Server) getCustomLoginTexts(ctx context.Context, org string, languages []string) ([]*management_pb.SetCustomLoginTextsRequest, error) {
|
||||||
customTexts := make([]*management_pb.SetCustomLoginTextsRequest, 0, len(languages))
|
customTexts := make([]*management_pb.SetCustomLoginTextsRequest, 0, len(languages))
|
||||||
for _, lang := range languages {
|
for _, lang := range languages {
|
||||||
|
@@ -22,6 +22,7 @@ import (
|
|||||||
action_grpc "github.com/zitadel/zitadel/internal/api/grpc/action"
|
action_grpc "github.com/zitadel/zitadel/internal/api/grpc/action"
|
||||||
"github.com/zitadel/zitadel/internal/api/grpc/authn"
|
"github.com/zitadel/zitadel/internal/api/grpc/authn"
|
||||||
"github.com/zitadel/zitadel/internal/api/grpc/management"
|
"github.com/zitadel/zitadel/internal/api/grpc/management"
|
||||||
|
org_converter "github.com/zitadel/zitadel/internal/api/grpc/org"
|
||||||
"github.com/zitadel/zitadel/internal/command"
|
"github.com/zitadel/zitadel/internal/command"
|
||||||
"github.com/zitadel/zitadel/internal/crypto"
|
"github.com/zitadel/zitadel/internal/crypto"
|
||||||
"github.com/zitadel/zitadel/internal/domain"
|
"github.com/zitadel/zitadel/internal/domain"
|
||||||
@@ -305,7 +306,8 @@ func importOrg1(ctx context.Context, s *Server, errors *[]*admin_pb.ImportDataEr
|
|||||||
ctx, span := tracing.NewSpan(ctx)
|
ctx, span := tracing.NewSpan(ctx)
|
||||||
defer func() { span.EndWithError(err) }()
|
defer func() { span.EndWithError(err) }()
|
||||||
|
|
||||||
_, err = s.command.AddOrgWithID(ctx, org.GetOrg().GetName(), ctxData.UserID, ctxData.ResourceOwner, org.GetOrgId(), []string{})
|
setOrgInactive := org_converter.OrgStateToDomain(org.OrgState) == domain.OrgStateInactive
|
||||||
|
_, err = s.command.AddOrgWithID(ctx, org.GetOrg().GetName(), ctxData.UserID, ctxData.ResourceOwner, org.GetOrgId(), setOrgInactive, []string{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
*errors = append(*errors, &admin_pb.ImportDataError{Type: "org", Id: org.GetOrgId(), Message: err.Error()})
|
*errors = append(*errors, &admin_pb.ImportDataError{Type: "org", Id: org.GetOrgId(), Message: err.Error()})
|
||||||
if _, err := s.query.OrgByID(ctx, true, org.OrgId); err != nil {
|
if _, err := s.query.OrgByID(ctx, true, org.OrgId); err != nil {
|
||||||
@@ -474,7 +476,10 @@ func importHumanUsers(ctx context.Context, s *Server, errors *[]*admin_pb.Import
|
|||||||
logging.Debugf("import user: %s", user.GetUserId())
|
logging.Debugf("import user: %s", user.GetUserId())
|
||||||
human, passwordless, links := management.ImportHumanUserRequestToDomain(user.User)
|
human, passwordless, links := management.ImportHumanUserRequestToDomain(user.User)
|
||||||
human.AggregateID = user.UserId
|
human.AggregateID = user.UserId
|
||||||
_, _, err := s.command.ImportHuman(ctx, org.GetOrgId(), human, passwordless, links, initCodeGenerator, emailCodeGenerator, phoneCodeGenerator, passwordlessInitCode)
|
userState := user.State.ToDomain()
|
||||||
|
|
||||||
|
//nolint:staticcheck
|
||||||
|
_, _, err := s.command.ImportHuman(ctx, org.GetOrgId(), human, passwordless, &userState, links, initCodeGenerator, emailCodeGenerator, phoneCodeGenerator, passwordlessInitCode)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
*errors = append(*errors, &admin_pb.ImportDataError{Type: "human_user", Id: user.GetUserId(), Message: err.Error()})
|
*errors = append(*errors, &admin_pb.ImportDataError{Type: "human_user", Id: user.GetUserId(), Message: err.Error()})
|
||||||
if isCtxTimeout(ctx) {
|
if isCtxTimeout(ctx) {
|
||||||
@@ -510,7 +515,8 @@ func importMachineUsers(ctx context.Context, s *Server, errors *[]*admin_pb.Impo
|
|||||||
}
|
}
|
||||||
for _, user := range org.GetMachineUsers() {
|
for _, user := range org.GetMachineUsers() {
|
||||||
logging.Debugf("import user: %s", user.GetUserId())
|
logging.Debugf("import user: %s", user.GetUserId())
|
||||||
_, err := s.command.AddMachine(ctx, management.AddMachineUserRequestToCommand(user.GetUser(), org.GetOrgId()), nil)
|
userState := user.State.ToDomain()
|
||||||
|
_, err := s.command.AddMachine(ctx, management.AddMachineUserRequestToCommand(user.GetUser(), org.GetOrgId()), &userState, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
*errors = append(*errors, &admin_pb.ImportDataError{Type: "machine_user", Id: user.GetUserId(), Message: err.Error()})
|
*errors = append(*errors, &admin_pb.ImportDataError{Type: "machine_user", Id: user.GetUserId(), Message: err.Error()})
|
||||||
if isCtxTimeout(ctx) {
|
if isCtxTimeout(ctx) {
|
||||||
@@ -609,7 +615,6 @@ func importUserLinks(ctx context.Context, s *Server, errors *[]*admin_pb.ImportD
|
|||||||
successOrg.UserLinks = append(successOrg.UserLinks, &admin_pb.ImportDataSuccessUserLinks{UserId: userLinks.GetUserId(), IdpId: userLinks.GetIdpId(), ExternalUserId: userLinks.GetProvidedUserId(), DisplayName: userLinks.GetProvidedUserName()})
|
successOrg.UserLinks = append(successOrg.UserLinks, &admin_pb.ImportDataSuccessUserLinks{UserId: userLinks.GetUserId(), IdpId: userLinks.GetIdpId(), ExternalUserId: userLinks.GetProvidedUserId(), DisplayName: userLinks.GetProvidedUserName()})
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func importProjects(ctx context.Context, s *Server, errors *[]*admin_pb.ImportDataError, successOrg *admin_pb.ImportDataSuccessOrg, org *admin_pb.DataOrg, count *counts) (err error) {
|
func importProjects(ctx context.Context, s *Server, errors *[]*admin_pb.ImportDataError, successOrg *admin_pb.ImportDataSuccessOrg, org *admin_pb.DataOrg, count *counts) (err error) {
|
||||||
@@ -750,6 +755,7 @@ func importActions(ctx context.Context, s *Server, errors *[]*admin_pb.ImportDat
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func importProjectRoles(ctx context.Context, s *Server, errors *[]*admin_pb.ImportDataError, successOrg *admin_pb.ImportDataSuccessOrg, org *admin_pb.DataOrg, count *counts) (err error) {
|
func importProjectRoles(ctx context.Context, s *Server, errors *[]*admin_pb.ImportDataError, successOrg *admin_pb.ImportDataSuccessOrg, org *admin_pb.DataOrg, count *counts) (err error) {
|
||||||
ctx, span := tracing.NewSpan(ctx)
|
ctx, span := tracing.NewSpan(ctx)
|
||||||
defer func() { span.EndWithError(err) }()
|
defer func() { span.EndWithError(err) }()
|
||||||
@@ -805,6 +811,7 @@ func importResources(ctx context.Context, s *Server, errors *[]*admin_pb.ImportD
|
|||||||
importDomainClaimedMessageTexts(ctx, s, errors, org)
|
importDomainClaimedMessageTexts(ctx, s, errors, org)
|
||||||
importPasswordlessRegistrationMessageTexts(ctx, s, errors, org)
|
importPasswordlessRegistrationMessageTexts(ctx, s, errors, org)
|
||||||
importInviteUserMessageTexts(ctx, s, errors, org)
|
importInviteUserMessageTexts(ctx, s, errors, org)
|
||||||
|
|
||||||
if err := importHumanUsers(ctx, s, errors, successOrg, org, count, initCodeGenerator, emailCodeGenerator, phoneCodeGenerator, passwordlessInitCode); err != nil {
|
if err := importHumanUsers(ctx, s, errors, successOrg, org, count, initCodeGenerator, emailCodeGenerator, phoneCodeGenerator, passwordlessInitCode); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@@ -273,7 +273,8 @@ func (s *Server) ImportHumanUser(ctx context.Context, req *mgmt_pb.ImportHumanUs
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
addedHuman, code, err := s.command.ImportHuman(ctx, authz.GetCtxData(ctx).OrgID, human, passwordless, links, initCodeGenerator, phoneCodeGenerator, emailCodeGenerator, passwordlessInitCode)
|
//nolint:staticcheck
|
||||||
|
addedHuman, code, err := s.command.ImportHuman(ctx, authz.GetCtxData(ctx).OrgID, human, passwordless, nil, links, initCodeGenerator, phoneCodeGenerator, emailCodeGenerator, passwordlessInitCode)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -297,7 +298,7 @@ func (s *Server) ImportHumanUser(ctx context.Context, req *mgmt_pb.ImportHumanUs
|
|||||||
|
|
||||||
func (s *Server) AddMachineUser(ctx context.Context, req *mgmt_pb.AddMachineUserRequest) (*mgmt_pb.AddMachineUserResponse, error) {
|
func (s *Server) AddMachineUser(ctx context.Context, req *mgmt_pb.AddMachineUserRequest) (*mgmt_pb.AddMachineUserResponse, error) {
|
||||||
machine := AddMachineUserRequestToCommand(req, authz.GetCtxData(ctx).OrgID)
|
machine := AddMachineUserRequestToCommand(req, authz.GetCtxData(ctx).OrgID)
|
||||||
objectDetails, err := s.command.AddMachine(ctx, machine, nil)
|
objectDetails, err := s.command.AddMachine(ctx, machine, nil, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@@ -25,6 +25,7 @@ func (s *Server) createUserTypeMachine(ctx context.Context, machinePb *user.Crea
|
|||||||
details, err := s.command.AddMachine(
|
details, err := s.command.AddMachine(
|
||||||
ctx,
|
ctx,
|
||||||
cmd,
|
cmd,
|
||||||
|
nil,
|
||||||
s.command.NewPermissionCheckUserWrite(ctx),
|
s.command.NewPermissionCheckUserWrite(ctx),
|
||||||
command.AddMachineWithUsernameToIDFallback(),
|
command.AddMachineWithUsernameToIDFallback(),
|
||||||
)
|
)
|
||||||
|
@@ -317,7 +317,7 @@ func (c *Commands) checkOrgExists(ctx context.Context, orgID string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Commands) AddOrgWithID(ctx context.Context, name, userID, resourceOwner, orgID string, claimedUserIDs []string) (_ *domain.Org, err error) {
|
func (c *Commands) AddOrgWithID(ctx context.Context, name, userID, resourceOwner, orgID string, setOrgInactive bool, claimedUserIDs []string) (_ *domain.Org, err error) {
|
||||||
ctx, span := tracing.NewSpan(ctx)
|
ctx, span := tracing.NewSpan(ctx)
|
||||||
defer func() { span.EndWithError(err) }()
|
defer func() { span.EndWithError(err) }()
|
||||||
|
|
||||||
@@ -329,7 +329,7 @@ func (c *Commands) AddOrgWithID(ctx context.Context, name, userID, resourceOwner
|
|||||||
return nil, zerrors.ThrowNotFound(nil, "ORG-lapo2m", "Errors.Org.AlreadyExisting")
|
return nil, zerrors.ThrowNotFound(nil, "ORG-lapo2m", "Errors.Org.AlreadyExisting")
|
||||||
}
|
}
|
||||||
|
|
||||||
return c.addOrgWithIDAndMember(ctx, name, userID, resourceOwner, orgID, claimedUserIDs)
|
return c.addOrgWithIDAndMember(ctx, name, userID, resourceOwner, orgID, setOrgInactive, claimedUserIDs)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Commands) AddOrg(ctx context.Context, name, userID, resourceOwner string, claimedUserIDs []string) (*domain.Org, error) {
|
func (c *Commands) AddOrg(ctx context.Context, name, userID, resourceOwner string, claimedUserIDs []string) (*domain.Org, error) {
|
||||||
@@ -342,10 +342,10 @@ func (c *Commands) AddOrg(ctx context.Context, name, userID, resourceOwner strin
|
|||||||
return nil, zerrors.ThrowInternal(err, "COMMA-OwciI", "Errors.Internal")
|
return nil, zerrors.ThrowInternal(err, "COMMA-OwciI", "Errors.Internal")
|
||||||
}
|
}
|
||||||
|
|
||||||
return c.addOrgWithIDAndMember(ctx, name, userID, resourceOwner, orgID, claimedUserIDs)
|
return c.addOrgWithIDAndMember(ctx, name, userID, resourceOwner, orgID, false, claimedUserIDs)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Commands) addOrgWithIDAndMember(ctx context.Context, name, userID, resourceOwner, orgID string, claimedUserIDs []string) (_ *domain.Org, err error) {
|
func (c *Commands) addOrgWithIDAndMember(ctx context.Context, name, userID, resourceOwner, orgID string, setOrgInactive bool, claimedUserIDs []string) (_ *domain.Org, err error) {
|
||||||
ctx, span := tracing.NewSpan(ctx)
|
ctx, span := tracing.NewSpan(ctx)
|
||||||
defer func() { span.EndWithError(err) }()
|
defer func() { span.EndWithError(err) }()
|
||||||
|
|
||||||
@@ -363,10 +363,15 @@ func (c *Commands) addOrgWithIDAndMember(ctx context.Context, name, userID, reso
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
events = append(events, orgMemberEvent)
|
events = append(events, orgMemberEvent)
|
||||||
|
if setOrgInactive {
|
||||||
|
deactivateOrgEvent := org.NewOrgDeactivatedEvent(ctx, orgAgg)
|
||||||
|
events = append(events, deactivateOrgEvent)
|
||||||
|
}
|
||||||
pushedEvents, err := c.eventstore.Push(ctx, events...)
|
pushedEvents, err := c.eventstore.Push(ctx, events...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = AppendAndReduce(addedOrg, pushedEvents...)
|
err = AppendAndReduce(addedOrg, pushedEvents...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@@ -428,7 +428,7 @@ func (h *AddHuman) shouldAddInitCode() bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Deprecated: use commands.AddUserHuman
|
// Deprecated: use commands.AddUserHuman
|
||||||
func (c *Commands) ImportHuman(ctx context.Context, orgID string, human *domain.Human, passwordless bool, links []*domain.UserIDPLink, initCodeGenerator, emailCodeGenerator, phoneCodeGenerator, passwordlessCodeGenerator crypto.Generator) (_ *domain.Human, passwordlessCode *domain.PasswordlessInitCode, err error) {
|
func (c *Commands) ImportHuman(ctx context.Context, orgID string, human *domain.Human, passwordless bool, state *domain.UserState, links []*domain.UserIDPLink, initCodeGenerator, emailCodeGenerator, phoneCodeGenerator, passwordlessCodeGenerator crypto.Generator) (_ *domain.Human, passwordlessCode *domain.PasswordlessInitCode, err error) {
|
||||||
ctx, span := tracing.NewSpan(ctx)
|
ctx, span := tracing.NewSpan(ctx)
|
||||||
defer func() { span.EndWithError(err) }()
|
defer func() { span.EndWithError(err) }()
|
||||||
|
|
||||||
@@ -455,10 +455,32 @@ func (c *Commands) ImportHuman(ctx context.Context, orgID string, human *domain.
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
events, addedHuman, addedCode, code, err := c.importHuman(ctx, orgID, human, passwordless, links, domainPolicy, pwPolicy, initCodeGenerator, emailCodeGenerator, phoneCodeGenerator, passwordlessCodeGenerator)
|
events, userAgg, addedHuman, addedCode, code, err := c.importHuman(ctx, orgID, human, passwordless, links, domainPolicy, pwPolicy, initCodeGenerator, emailCodeGenerator, phoneCodeGenerator, passwordlessCodeGenerator)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
if state != nil {
|
||||||
|
var event eventstore.Command
|
||||||
|
switch *state {
|
||||||
|
case domain.UserStateInactive:
|
||||||
|
event = user.NewUserDeactivatedEvent(ctx, userAgg)
|
||||||
|
case domain.UserStateLocked:
|
||||||
|
event = user.NewUserLockedEvent(ctx, userAgg)
|
||||||
|
case domain.UserStateDeleted:
|
||||||
|
// users are never imported if deleted
|
||||||
|
case domain.UserStateActive:
|
||||||
|
// added because of the linter
|
||||||
|
case domain.UserStateSuspend:
|
||||||
|
// added because of the linter
|
||||||
|
case domain.UserStateInitial:
|
||||||
|
// added because of the linter
|
||||||
|
case domain.UserStateUnspecified:
|
||||||
|
// added because of the linter
|
||||||
|
}
|
||||||
|
if event != nil {
|
||||||
|
events = append(events, event)
|
||||||
|
}
|
||||||
|
}
|
||||||
pushedEvents, err := c.eventstore.Push(ctx, events...)
|
pushedEvents, err := c.eventstore.Push(ctx, events...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
@@ -479,48 +501,48 @@ func (c *Commands) ImportHuman(ctx context.Context, orgID string, human *domain.
|
|||||||
return writeModelToHuman(addedHuman), passwordlessCode, nil
|
return writeModelToHuman(addedHuman), passwordlessCode, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Commands) importHuman(ctx context.Context, orgID string, human *domain.Human, passwordless bool, links []*domain.UserIDPLink, domainPolicy *domain.DomainPolicy, pwPolicy *domain.PasswordComplexityPolicy, initCodeGenerator, emailCodeGenerator, phoneCodeGenerator, passwordlessCodeGenerator crypto.Generator) (events []eventstore.Command, humanWriteModel *HumanWriteModel, passwordlessCodeWriteModel *HumanPasswordlessInitCodeWriteModel, code string, err error) {
|
func (c *Commands) importHuman(ctx context.Context, orgID string, human *domain.Human, passwordless bool, links []*domain.UserIDPLink, domainPolicy *domain.DomainPolicy, pwPolicy *domain.PasswordComplexityPolicy, initCodeGenerator, emailCodeGenerator, phoneCodeGenerator, passwordlessCodeGenerator crypto.Generator) (events []eventstore.Command, userAgg *eventstore.Aggregate, humanWriteModel *HumanWriteModel, passwordlessCodeWriteModel *HumanPasswordlessInitCodeWriteModel, code string, err error) {
|
||||||
ctx, span := tracing.NewSpan(ctx)
|
ctx, span := tracing.NewSpan(ctx)
|
||||||
defer func() { span.EndWithError(err) }()
|
defer func() { span.EndWithError(err) }()
|
||||||
|
|
||||||
if orgID == "" {
|
if orgID == "" {
|
||||||
return nil, nil, nil, "", zerrors.ThrowInvalidArgument(nil, "COMMAND-00p2b", "Errors.Org.Empty")
|
return nil, nil, nil, nil, "", zerrors.ThrowInvalidArgument(nil, "COMMAND-00p2b", "Errors.Org.Empty")
|
||||||
}
|
}
|
||||||
if err = human.Normalize(); err != nil {
|
if err = human.Normalize(); err != nil {
|
||||||
return nil, nil, nil, "", err
|
return nil, nil, nil, nil, "", err
|
||||||
}
|
}
|
||||||
events, humanWriteModel, err = c.createHuman(ctx, orgID, human, links, passwordless, domainPolicy, pwPolicy, initCodeGenerator, emailCodeGenerator, phoneCodeGenerator)
|
events, userAgg, humanWriteModel, err = c.createHuman(ctx, orgID, human, links, passwordless, domainPolicy, pwPolicy, initCodeGenerator, emailCodeGenerator, phoneCodeGenerator)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, nil, "", err
|
return nil, nil, nil, nil, "", err
|
||||||
}
|
}
|
||||||
if passwordless {
|
if passwordless {
|
||||||
var codeEvent eventstore.Command
|
var codeEvent eventstore.Command
|
||||||
codeEvent, passwordlessCodeWriteModel, code, err = c.humanAddPasswordlessInitCode(ctx, human.AggregateID, orgID, true, passwordlessCodeGenerator)
|
codeEvent, passwordlessCodeWriteModel, code, err = c.humanAddPasswordlessInitCode(ctx, human.AggregateID, orgID, true, passwordlessCodeGenerator)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, nil, "", err
|
return nil, nil, nil, nil, "", err
|
||||||
}
|
}
|
||||||
events = append(events, codeEvent)
|
events = append(events, codeEvent)
|
||||||
}
|
}
|
||||||
return events, humanWriteModel, passwordlessCodeWriteModel, code, nil
|
return events, userAgg, humanWriteModel, passwordlessCodeWriteModel, code, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Commands) createHuman(ctx context.Context, orgID string, human *domain.Human, links []*domain.UserIDPLink, passwordless bool, domainPolicy *domain.DomainPolicy, pwPolicy *domain.PasswordComplexityPolicy, initCodeGenerator, emailCodeGenerator, phoneCodeGenerator crypto.Generator) (events []eventstore.Command, addedHuman *HumanWriteModel, err error) {
|
func (c *Commands) createHuman(ctx context.Context, orgID string, human *domain.Human, links []*domain.UserIDPLink, passwordless bool, domainPolicy *domain.DomainPolicy, pwPolicy *domain.PasswordComplexityPolicy, initCodeGenerator, emailCodeGenerator, phoneCodeGenerator crypto.Generator) (events []eventstore.Command, userAgg *eventstore.Aggregate, addedHuman *HumanWriteModel, err error) {
|
||||||
ctx, span := tracing.NewSpan(ctx)
|
ctx, span := tracing.NewSpan(ctx)
|
||||||
defer func() { span.EndWithError(err) }()
|
defer func() { span.EndWithError(err) }()
|
||||||
|
|
||||||
if err = human.CheckDomainPolicy(domainPolicy); err != nil {
|
if err = human.CheckDomainPolicy(domainPolicy); err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, nil, err
|
||||||
}
|
}
|
||||||
human.Username = strings.TrimSpace(human.Username)
|
human.Username = strings.TrimSpace(human.Username)
|
||||||
human.EmailAddress = human.EmailAddress.Normalize()
|
human.EmailAddress = human.EmailAddress.Normalize()
|
||||||
if err = c.userValidateDomain(ctx, orgID, human.Username, domainPolicy.UserLoginMustBeDomain); err != nil {
|
if err = c.userValidateDomain(ctx, orgID, human.Username, domainPolicy.UserLoginMustBeDomain); err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if human.AggregateID == "" {
|
if human.AggregateID == "" {
|
||||||
userID, err := c.idGenerator.Next()
|
userID, err := c.idGenerator.Next()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, nil, err
|
||||||
}
|
}
|
||||||
human.AggregateID = userID
|
human.AggregateID = userID
|
||||||
}
|
}
|
||||||
@@ -528,20 +550,21 @@ func (c *Commands) createHuman(ctx context.Context, orgID string, human *domain.
|
|||||||
human.EnsureDisplayName()
|
human.EnsureDisplayName()
|
||||||
if human.Password != nil {
|
if human.Password != nil {
|
||||||
if err := human.HashPasswordIfExisting(ctx, pwPolicy, c.userPasswordHasher, human.Password.ChangeRequired); err != nil {
|
if err := human.HashPasswordIfExisting(ctx, pwPolicy, c.userPasswordHasher, human.Password.ChangeRequired); err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
addedHuman = NewHumanWriteModel(human.AggregateID, orgID)
|
addedHuman = NewHumanWriteModel(human.AggregateID, orgID)
|
||||||
//TODO: adlerhurst maybe we could simplify the code below
|
|
||||||
userAgg := UserAggregateFromWriteModel(&addedHuman.WriteModel)
|
// TODO: adlerhurst maybe we could simplify the code below
|
||||||
|
userAgg = UserAggregateFromWriteModelCtx(ctx, &addedHuman.WriteModel)
|
||||||
|
|
||||||
events = append(events, createAddHumanEvent(ctx, userAgg, human, domainPolicy.UserLoginMustBeDomain))
|
events = append(events, createAddHumanEvent(ctx, userAgg, human, domainPolicy.UserLoginMustBeDomain))
|
||||||
|
|
||||||
for _, link := range links {
|
for _, link := range links {
|
||||||
event, err := c.addUserIDPLink(ctx, userAgg, link, false)
|
event, err := c.addUserIDPLink(ctx, userAgg, link, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, nil, err
|
||||||
}
|
}
|
||||||
events = append(events, event)
|
events = append(events, event)
|
||||||
}
|
}
|
||||||
@@ -549,7 +572,7 @@ func (c *Commands) createHuman(ctx context.Context, orgID string, human *domain.
|
|||||||
if human.IsInitialState(passwordless, len(links) > 0) {
|
if human.IsInitialState(passwordless, len(links) > 0) {
|
||||||
initCode, err := domain.NewInitUserCode(initCodeGenerator)
|
initCode, err := domain.NewInitUserCode(initCodeGenerator)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, nil, err
|
||||||
}
|
}
|
||||||
events = append(events, user.NewHumanInitialCodeAddedEvent(ctx, userAgg, initCode.Code, initCode.Expiry, ""))
|
events = append(events, user.NewHumanInitialCodeAddedEvent(ctx, userAgg, initCode.Code, initCode.Expiry, ""))
|
||||||
} else {
|
} else {
|
||||||
@@ -558,7 +581,7 @@ func (c *Commands) createHuman(ctx context.Context, orgID string, human *domain.
|
|||||||
} else {
|
} else {
|
||||||
emailCode, _, err := domain.NewEmailCode(emailCodeGenerator)
|
emailCode, _, err := domain.NewEmailCode(emailCodeGenerator)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, nil, err
|
||||||
}
|
}
|
||||||
events = append(events, user.NewHumanEmailCodeAddedEvent(ctx, userAgg, emailCode.Code, emailCode.Expiry, ""))
|
events = append(events, user.NewHumanEmailCodeAddedEvent(ctx, userAgg, emailCode.Code, emailCode.Expiry, ""))
|
||||||
}
|
}
|
||||||
@@ -567,14 +590,14 @@ func (c *Commands) createHuman(ctx context.Context, orgID string, human *domain.
|
|||||||
if human.Phone != nil && human.PhoneNumber != "" && !human.IsPhoneVerified {
|
if human.Phone != nil && human.PhoneNumber != "" && !human.IsPhoneVerified {
|
||||||
phoneCode, generatorID, err := c.newPhoneCode(ctx, c.eventstore.Filter, domain.SecretGeneratorTypeVerifyPhoneCode, c.userEncryption, c.defaultSecretGenerators.PhoneVerificationCode) //nolint:staticcheck
|
phoneCode, generatorID, err := c.newPhoneCode(ctx, c.eventstore.Filter, domain.SecretGeneratorTypeVerifyPhoneCode, c.userEncryption, c.defaultSecretGenerators.PhoneVerificationCode) //nolint:staticcheck
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, nil, err
|
||||||
}
|
}
|
||||||
events = append(events, user.NewHumanPhoneCodeAddedEvent(ctx, userAgg, phoneCode.CryptedCode(), phoneCode.CodeExpiry(), generatorID))
|
events = append(events, user.NewHumanPhoneCodeAddedEvent(ctx, userAgg, phoneCode.CryptedCode(), phoneCode.CodeExpiry(), generatorID))
|
||||||
} else if human.Phone != nil && human.PhoneNumber != "" && human.IsPhoneVerified {
|
} else if human.Phone != nil && human.PhoneNumber != "" && human.IsPhoneVerified {
|
||||||
events = append(events, user.NewHumanPhoneVerifiedEvent(ctx, userAgg))
|
events = append(events, user.NewHumanPhoneVerifiedEvent(ctx, userAgg))
|
||||||
}
|
}
|
||||||
|
|
||||||
return events, addedHuman, nil
|
return events, userAgg, addedHuman, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Commands) HumanSkipMFAInit(ctx context.Context, userID, resourceowner string) (err error) {
|
func (c *Commands) HumanSkipMFAInit(ctx context.Context, userID, resourceowner string) (err error) {
|
||||||
|
@@ -1200,7 +1200,8 @@ func TestCommandSide_AddHuman(t *testing.T) {
|
|||||||
},
|
},
|
||||||
wantID: "user1",
|
wantID: "user1",
|
||||||
},
|
},
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
name: "add human (with return code), ok",
|
name: "add human (with return code), ok",
|
||||||
fields: fields{
|
fields: fields{
|
||||||
eventstore: expectEventstore(
|
eventstore: expectEventstore(
|
||||||
@@ -1432,6 +1433,7 @@ func TestCommandSide_ImportHuman(t *testing.T) {
|
|||||||
orgID string
|
orgID string
|
||||||
human *domain.Human
|
human *domain.Human
|
||||||
passwordless bool
|
passwordless bool
|
||||||
|
state *domain.UserState
|
||||||
links []*domain.UserIDPLink
|
links []*domain.UserIDPLink
|
||||||
secretGenerator crypto.Generator
|
secretGenerator crypto.Generator
|
||||||
passwordlessInitCode crypto.Generator
|
passwordlessInitCode crypto.Generator
|
||||||
@@ -1584,7 +1586,8 @@ func TestCommandSide_ImportHuman(t *testing.T) {
|
|||||||
res: res{
|
res: res{
|
||||||
err: zerrors.IsErrorInvalidArgument,
|
err: zerrors.IsErrorInvalidArgument,
|
||||||
},
|
},
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
name: "add human (with password and initial code), ok",
|
name: "add human (with password and initial code), ok",
|
||||||
given: func(t *testing.T) (fields, args) {
|
given: func(t *testing.T) (fields, args) {
|
||||||
return fields{
|
return fields{
|
||||||
@@ -2985,6 +2988,364 @@ func TestCommandSide_ImportHuman(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "add human (with idp, auto creation not allowed) + deactivated state, ok",
|
||||||
|
given: func(t *testing.T) (fields, args) {
|
||||||
|
return fields{
|
||||||
|
eventstore: expectEventstore(
|
||||||
|
expectFilter(
|
||||||
|
eventFromEventPusher(
|
||||||
|
org.NewDomainPolicyAddedEvent(context.Background(),
|
||||||
|
&user.NewAggregate("user1", "org1").Aggregate,
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
expectFilter(
|
||||||
|
eventFromEventPusher(
|
||||||
|
org.NewPasswordComplexityPolicyAddedEvent(context.Background(),
|
||||||
|
&user.NewAggregate("user1", "org1").Aggregate,
|
||||||
|
1,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
expectFilter(
|
||||||
|
eventFromEventPusher(
|
||||||
|
org.NewIDPConfigAddedEvent(context.Background(),
|
||||||
|
&org.NewAggregate("org1").Aggregate,
|
||||||
|
"idpID",
|
||||||
|
"name",
|
||||||
|
domain.IDPConfigTypeOIDC,
|
||||||
|
domain.IDPConfigStylingTypeUnspecified,
|
||||||
|
false,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
eventFromEventPusher(
|
||||||
|
org.NewIDPOIDCConfigAddedEvent(context.Background(),
|
||||||
|
&org.NewAggregate("org1").Aggregate,
|
||||||
|
"clientID",
|
||||||
|
"idpID",
|
||||||
|
"issuer",
|
||||||
|
"authEndpoint",
|
||||||
|
"tokenEndpoint",
|
||||||
|
nil,
|
||||||
|
domain.OIDCMappingFieldUnspecified,
|
||||||
|
domain.OIDCMappingFieldUnspecified,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
eventFromEventPusher(
|
||||||
|
func() eventstore.Command {
|
||||||
|
e, _ := org.NewOIDCIDPChangedEvent(context.Background(),
|
||||||
|
&org.NewAggregate("org1").Aggregate,
|
||||||
|
"config1",
|
||||||
|
[]idp.OIDCIDPChanges{
|
||||||
|
idp.ChangeOIDCOptions(idp.OptionChanges{IsCreationAllowed: gu.Ptr(false)}),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
return e
|
||||||
|
}(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
expectFilter(
|
||||||
|
eventFromEventPusher(
|
||||||
|
org.NewIDPConfigAddedEvent(context.Background(),
|
||||||
|
&org.NewAggregate("org1").Aggregate,
|
||||||
|
"idpID",
|
||||||
|
"name",
|
||||||
|
domain.IDPConfigTypeOIDC,
|
||||||
|
domain.IDPConfigStylingTypeUnspecified,
|
||||||
|
false,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
eventFromEventPusher(
|
||||||
|
org.NewIDPOIDCConfigAddedEvent(context.Background(),
|
||||||
|
&org.NewAggregate("org1").Aggregate,
|
||||||
|
"clientID",
|
||||||
|
"idpID",
|
||||||
|
"issuer",
|
||||||
|
"authEndpoint",
|
||||||
|
"tokenEndpoint",
|
||||||
|
nil,
|
||||||
|
domain.OIDCMappingFieldUnspecified,
|
||||||
|
domain.OIDCMappingFieldUnspecified,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
eventFromEventPusher(
|
||||||
|
func() eventstore.Command {
|
||||||
|
e, _ := org.NewOIDCIDPChangedEvent(context.Background(),
|
||||||
|
&org.NewAggregate("org1").Aggregate,
|
||||||
|
"config1",
|
||||||
|
[]idp.OIDCIDPChanges{
|
||||||
|
idp.ChangeOIDCOptions(idp.OptionChanges{
|
||||||
|
IsCreationAllowed: gu.Ptr(true),
|
||||||
|
IsAutoCreation: gu.Ptr(false),
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
return e
|
||||||
|
}(),
|
||||||
|
),
|
||||||
|
eventFromEventPusher(
|
||||||
|
org.NewIdentityProviderAddedEvent(context.Background(),
|
||||||
|
&org.NewAggregate("org1").Aggregate,
|
||||||
|
"idpID",
|
||||||
|
domain.IdentityProviderTypeOrg,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
expectPush(
|
||||||
|
newAddHumanEvent("", false, true, "", AllowedLanguage),
|
||||||
|
user.NewUserIDPLinkAddedEvent(context.Background(),
|
||||||
|
&user.NewAggregate("user1", "org1").Aggregate,
|
||||||
|
"idpID",
|
||||||
|
"name",
|
||||||
|
"externalID",
|
||||||
|
),
|
||||||
|
user.NewHumanEmailVerifiedEvent(context.Background(),
|
||||||
|
&user.NewAggregate("user1", "org1").Aggregate),
|
||||||
|
user.NewUserDeactivatedEvent(context.Background(),
|
||||||
|
&user.NewAggregate("user1", "org1").Aggregate,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "user1"),
|
||||||
|
userPasswordHasher: mockPasswordHasher("x"),
|
||||||
|
},
|
||||||
|
args{
|
||||||
|
ctx: context.Background(),
|
||||||
|
orgID: "org1",
|
||||||
|
state: func() *domain.UserState {
|
||||||
|
state := domain.UserStateInactive
|
||||||
|
return &state
|
||||||
|
}(),
|
||||||
|
human: &domain.Human{
|
||||||
|
Username: "username",
|
||||||
|
Profile: &domain.Profile{
|
||||||
|
FirstName: "firstname",
|
||||||
|
LastName: "lastname",
|
||||||
|
PreferredLanguage: AllowedLanguage,
|
||||||
|
},
|
||||||
|
Email: &domain.Email{
|
||||||
|
EmailAddress: "email@test.ch",
|
||||||
|
IsEmailVerified: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
links: []*domain.UserIDPLink{
|
||||||
|
{
|
||||||
|
IDPConfigID: "idpID",
|
||||||
|
ExternalUserID: "externalID",
|
||||||
|
DisplayName: "name",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
secretGenerator: GetMockSecretGenerator(t),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
res: res{
|
||||||
|
wantHuman: &domain.Human{
|
||||||
|
ObjectRoot: models.ObjectRoot{
|
||||||
|
AggregateID: "user1",
|
||||||
|
ResourceOwner: "org1",
|
||||||
|
},
|
||||||
|
Username: "username",
|
||||||
|
Profile: &domain.Profile{
|
||||||
|
FirstName: "firstname",
|
||||||
|
LastName: "lastname",
|
||||||
|
DisplayName: "firstname lastname",
|
||||||
|
PreferredLanguage: AllowedLanguage,
|
||||||
|
},
|
||||||
|
Email: &domain.Email{
|
||||||
|
EmailAddress: "email@test.ch",
|
||||||
|
IsEmailVerified: true,
|
||||||
|
},
|
||||||
|
State: domain.UserStateInactive,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "add human (with idp, auto creation not allowed) + locked state, ok",
|
||||||
|
given: func(t *testing.T) (fields, args) {
|
||||||
|
return fields{
|
||||||
|
eventstore: expectEventstore(
|
||||||
|
expectFilter(
|
||||||
|
eventFromEventPusher(
|
||||||
|
org.NewDomainPolicyAddedEvent(context.Background(),
|
||||||
|
&user.NewAggregate("user1", "org1").Aggregate,
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
expectFilter(
|
||||||
|
eventFromEventPusher(
|
||||||
|
org.NewPasswordComplexityPolicyAddedEvent(context.Background(),
|
||||||
|
&user.NewAggregate("user1", "org1").Aggregate,
|
||||||
|
1,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
expectFilter(
|
||||||
|
eventFromEventPusher(
|
||||||
|
org.NewIDPConfigAddedEvent(context.Background(),
|
||||||
|
&org.NewAggregate("org1").Aggregate,
|
||||||
|
"idpID",
|
||||||
|
"name",
|
||||||
|
domain.IDPConfigTypeOIDC,
|
||||||
|
domain.IDPConfigStylingTypeUnspecified,
|
||||||
|
false,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
eventFromEventPusher(
|
||||||
|
org.NewIDPOIDCConfigAddedEvent(context.Background(),
|
||||||
|
&org.NewAggregate("org1").Aggregate,
|
||||||
|
"clientID",
|
||||||
|
"idpID",
|
||||||
|
"issuer",
|
||||||
|
"authEndpoint",
|
||||||
|
"tokenEndpoint",
|
||||||
|
nil,
|
||||||
|
domain.OIDCMappingFieldUnspecified,
|
||||||
|
domain.OIDCMappingFieldUnspecified,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
eventFromEventPusher(
|
||||||
|
func() eventstore.Command {
|
||||||
|
e, _ := org.NewOIDCIDPChangedEvent(context.Background(),
|
||||||
|
&org.NewAggregate("org1").Aggregate,
|
||||||
|
"config1",
|
||||||
|
[]idp.OIDCIDPChanges{
|
||||||
|
idp.ChangeOIDCOptions(idp.OptionChanges{IsCreationAllowed: gu.Ptr(false)}),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
return e
|
||||||
|
}(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
expectFilter(
|
||||||
|
eventFromEventPusher(
|
||||||
|
org.NewIDPConfigAddedEvent(context.Background(),
|
||||||
|
&org.NewAggregate("org1").Aggregate,
|
||||||
|
"idpID",
|
||||||
|
"name",
|
||||||
|
domain.IDPConfigTypeOIDC,
|
||||||
|
domain.IDPConfigStylingTypeUnspecified,
|
||||||
|
false,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
eventFromEventPusher(
|
||||||
|
org.NewIDPOIDCConfigAddedEvent(context.Background(),
|
||||||
|
&org.NewAggregate("org1").Aggregate,
|
||||||
|
"clientID",
|
||||||
|
"idpID",
|
||||||
|
"issuer",
|
||||||
|
"authEndpoint",
|
||||||
|
"tokenEndpoint",
|
||||||
|
nil,
|
||||||
|
domain.OIDCMappingFieldUnspecified,
|
||||||
|
domain.OIDCMappingFieldUnspecified,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
eventFromEventPusher(
|
||||||
|
func() eventstore.Command {
|
||||||
|
e, _ := org.NewOIDCIDPChangedEvent(context.Background(),
|
||||||
|
&org.NewAggregate("org1").Aggregate,
|
||||||
|
"config1",
|
||||||
|
[]idp.OIDCIDPChanges{
|
||||||
|
idp.ChangeOIDCOptions(idp.OptionChanges{
|
||||||
|
IsCreationAllowed: gu.Ptr(true),
|
||||||
|
IsAutoCreation: gu.Ptr(false),
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
return e
|
||||||
|
}(),
|
||||||
|
),
|
||||||
|
eventFromEventPusher(
|
||||||
|
org.NewIdentityProviderAddedEvent(context.Background(),
|
||||||
|
&org.NewAggregate("org1").Aggregate,
|
||||||
|
"idpID",
|
||||||
|
domain.IdentityProviderTypeOrg,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
expectPush(
|
||||||
|
newAddHumanEvent("", false, true, "", AllowedLanguage),
|
||||||
|
user.NewUserIDPLinkAddedEvent(context.Background(),
|
||||||
|
&user.NewAggregate("user1", "org1").Aggregate,
|
||||||
|
"idpID",
|
||||||
|
"name",
|
||||||
|
"externalID",
|
||||||
|
),
|
||||||
|
user.NewHumanEmailVerifiedEvent(context.Background(),
|
||||||
|
&user.NewAggregate("user1", "org1").Aggregate),
|
||||||
|
user.NewUserLockedEvent(context.Background(),
|
||||||
|
&user.NewAggregate("user1", "org1").Aggregate,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "user1"),
|
||||||
|
userPasswordHasher: mockPasswordHasher("x"),
|
||||||
|
},
|
||||||
|
args{
|
||||||
|
ctx: context.Background(),
|
||||||
|
orgID: "org1",
|
||||||
|
state: func() *domain.UserState {
|
||||||
|
state := domain.UserStateLocked
|
||||||
|
return &state
|
||||||
|
}(),
|
||||||
|
human: &domain.Human{
|
||||||
|
Username: "username",
|
||||||
|
Profile: &domain.Profile{
|
||||||
|
FirstName: "firstname",
|
||||||
|
LastName: "lastname",
|
||||||
|
PreferredLanguage: AllowedLanguage,
|
||||||
|
},
|
||||||
|
Email: &domain.Email{
|
||||||
|
EmailAddress: "email@test.ch",
|
||||||
|
IsEmailVerified: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
links: []*domain.UserIDPLink{
|
||||||
|
{
|
||||||
|
IDPConfigID: "idpID",
|
||||||
|
ExternalUserID: "externalID",
|
||||||
|
DisplayName: "name",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
secretGenerator: GetMockSecretGenerator(t),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
res: res{
|
||||||
|
wantHuman: &domain.Human{
|
||||||
|
ObjectRoot: models.ObjectRoot{
|
||||||
|
AggregateID: "user1",
|
||||||
|
ResourceOwner: "org1",
|
||||||
|
},
|
||||||
|
Username: "username",
|
||||||
|
Profile: &domain.Profile{
|
||||||
|
FirstName: "firstname",
|
||||||
|
LastName: "lastname",
|
||||||
|
DisplayName: "firstname lastname",
|
||||||
|
PreferredLanguage: AllowedLanguage,
|
||||||
|
},
|
||||||
|
Email: &domain.Email{
|
||||||
|
EmailAddress: "email@test.ch",
|
||||||
|
IsEmailVerified: true,
|
||||||
|
},
|
||||||
|
State: domain.UserStateLocked,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
@@ -2996,7 +3357,7 @@ func TestCommandSide_ImportHuman(t *testing.T) {
|
|||||||
newEncryptedCodeWithDefault: f.newEncryptedCodeWithDefault,
|
newEncryptedCodeWithDefault: f.newEncryptedCodeWithDefault,
|
||||||
defaultSecretGenerators: f.defaultSecretGenerators,
|
defaultSecretGenerators: f.defaultSecretGenerators,
|
||||||
}
|
}
|
||||||
gotHuman, gotCode, err := r.ImportHuman(a.ctx, a.orgID, a.human, a.passwordless, a.links, a.secretGenerator, a.secretGenerator, a.secretGenerator, a.secretGenerator)
|
gotHuman, gotCode, err := r.ImportHuman(a.ctx, a.orgID, a.human, a.passwordless, a.state, a.links, a.secretGenerator, a.secretGenerator, a.secretGenerator, a.secretGenerator)
|
||||||
if tt.res.err == nil {
|
if tt.res.err == nil {
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
}
|
}
|
||||||
|
@@ -79,7 +79,7 @@ func AddMachineWithUsernameToIDFallback() addMachineOption {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Commands) AddMachine(ctx context.Context, machine *Machine, check PermissionCheck, options ...addMachineOption) (_ *domain.ObjectDetails, err error) {
|
func (c *Commands) AddMachine(ctx context.Context, machine *Machine, state *domain.UserState, check PermissionCheck, options ...addMachineOption) (_ *domain.ObjectDetails, err error) {
|
||||||
ctx, span := tracing.NewSpan(ctx)
|
ctx, span := tracing.NewSpan(ctx)
|
||||||
defer func() { span.EndWithError(err) }()
|
defer func() { span.EndWithError(err) }()
|
||||||
|
|
||||||
@@ -107,6 +107,29 @@ func (c *Commands) AddMachine(ctx context.Context, machine *Machine, check Permi
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if state != nil {
|
||||||
|
var cmd eventstore.Command
|
||||||
|
switch *state {
|
||||||
|
case domain.UserStateInactive:
|
||||||
|
cmd = user.NewUserDeactivatedEvent(ctx, &agg.Aggregate)
|
||||||
|
case domain.UserStateLocked:
|
||||||
|
cmd = user.NewUserLockedEvent(ctx, &agg.Aggregate)
|
||||||
|
case domain.UserStateDeleted:
|
||||||
|
// users are never imported if deleted
|
||||||
|
case domain.UserStateActive:
|
||||||
|
// added because of the linter
|
||||||
|
case domain.UserStateSuspend:
|
||||||
|
// added because of the linter
|
||||||
|
case domain.UserStateInitial:
|
||||||
|
// added because of the linter
|
||||||
|
case domain.UserStateUnspecified:
|
||||||
|
// added because of the linter
|
||||||
|
}
|
||||||
|
if cmd != nil {
|
||||||
|
cmds = append(cmds, cmd)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
events, err := c.eventstore.Push(ctx, cmds...)
|
events, err := c.eventstore.Push(ctx, cmds...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@@ -24,6 +24,7 @@ func TestCommandSide_AddMachine(t *testing.T) {
|
|||||||
type args struct {
|
type args struct {
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
machine *Machine
|
machine *Machine
|
||||||
|
state *domain.UserState
|
||||||
check PermissionCheck
|
check PermissionCheck
|
||||||
options func(*Commands) []addMachineOption
|
options func(*Commands) []addMachineOption
|
||||||
}
|
}
|
||||||
@@ -419,6 +420,112 @@ func TestCommandSide_AddMachine(t *testing.T) {
|
|||||||
err: zerrors.IsPermissionDenied,
|
err: zerrors.IsPermissionDenied,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "add machine, ok + deactive state",
|
||||||
|
fields: fields{
|
||||||
|
eventstore: eventstoreExpect(
|
||||||
|
t,
|
||||||
|
expectFilter(),
|
||||||
|
expectFilter(
|
||||||
|
eventFromEventPusher(
|
||||||
|
org.NewDomainPolicyAddedEvent(context.Background(),
|
||||||
|
&user.NewAggregate("user1", "org1").Aggregate,
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
expectPush(
|
||||||
|
user.NewMachineAddedEvent(context.Background(),
|
||||||
|
&user.NewAggregate("user1", "org1").Aggregate,
|
||||||
|
"username",
|
||||||
|
"name",
|
||||||
|
"description",
|
||||||
|
true,
|
||||||
|
domain.OIDCTokenTypeBearer,
|
||||||
|
),
|
||||||
|
user.NewUserDeactivatedEvent(context.Background(),
|
||||||
|
&user.NewAggregate("user1", "org1").Aggregate,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "user1"),
|
||||||
|
},
|
||||||
|
args: args{
|
||||||
|
ctx: context.Background(),
|
||||||
|
machine: &Machine{
|
||||||
|
ObjectRoot: models.ObjectRoot{
|
||||||
|
ResourceOwner: "org1",
|
||||||
|
},
|
||||||
|
Description: "description",
|
||||||
|
Name: "name",
|
||||||
|
Username: "username",
|
||||||
|
},
|
||||||
|
state: func() *domain.UserState {
|
||||||
|
state := domain.UserStateInactive
|
||||||
|
return &state
|
||||||
|
}(),
|
||||||
|
},
|
||||||
|
res: res{
|
||||||
|
want: &domain.ObjectDetails{
|
||||||
|
ResourceOwner: "org1",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "add machine, ok + locked state",
|
||||||
|
fields: fields{
|
||||||
|
eventstore: eventstoreExpect(
|
||||||
|
t,
|
||||||
|
expectFilter(),
|
||||||
|
expectFilter(
|
||||||
|
eventFromEventPusher(
|
||||||
|
org.NewDomainPolicyAddedEvent(context.Background(),
|
||||||
|
&user.NewAggregate("user1", "org1").Aggregate,
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
expectPush(
|
||||||
|
user.NewMachineAddedEvent(context.Background(),
|
||||||
|
&user.NewAggregate("user1", "org1").Aggregate,
|
||||||
|
"username",
|
||||||
|
"name",
|
||||||
|
"description",
|
||||||
|
true,
|
||||||
|
domain.OIDCTokenTypeBearer,
|
||||||
|
),
|
||||||
|
user.NewUserLockedEvent(context.Background(),
|
||||||
|
&user.NewAggregate("user1", "org1").Aggregate,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "user1"),
|
||||||
|
},
|
||||||
|
args: args{
|
||||||
|
ctx: context.Background(),
|
||||||
|
machine: &Machine{
|
||||||
|
ObjectRoot: models.ObjectRoot{
|
||||||
|
ResourceOwner: "org1",
|
||||||
|
},
|
||||||
|
Description: "description",
|
||||||
|
Name: "name",
|
||||||
|
Username: "username",
|
||||||
|
},
|
||||||
|
state: func() *domain.UserState {
|
||||||
|
state := domain.UserStateLocked
|
||||||
|
return &state
|
||||||
|
}(),
|
||||||
|
},
|
||||||
|
res: res{
|
||||||
|
want: &domain.ObjectDetails{
|
||||||
|
ResourceOwner: "org1",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
@@ -431,7 +538,7 @@ func TestCommandSide_AddMachine(t *testing.T) {
|
|||||||
if tt.args.options != nil {
|
if tt.args.options != nil {
|
||||||
options = tt.args.options(r)
|
options = tt.args.options(r)
|
||||||
}
|
}
|
||||||
got, err := r.AddMachine(tt.args.ctx, tt.args.machine, tt.args.check, options...)
|
got, err := r.AddMachine(tt.args.ctx, tt.args.machine, tt.args.state, tt.args.check, options...)
|
||||||
if tt.res.err == nil {
|
if tt.res.err == nil {
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
}
|
}
|
||||||
|
@@ -9005,6 +9005,7 @@ message DataOrg {
|
|||||||
repeated zitadel.management.v1.SetCustomVerifySMSOTPMessageTextRequest verify_sms_otp_messages = 37;
|
repeated zitadel.management.v1.SetCustomVerifySMSOTPMessageTextRequest verify_sms_otp_messages = 37;
|
||||||
repeated zitadel.management.v1.SetCustomVerifyEmailOTPMessageTextRequest verify_email_otp_messages = 38;
|
repeated zitadel.management.v1.SetCustomVerifyEmailOTPMessageTextRequest verify_email_otp_messages = 38;
|
||||||
repeated zitadel.management.v1.SetCustomInviteUserMessageTextRequest invite_user_messages = 39;
|
repeated zitadel.management.v1.SetCustomInviteUserMessageTextRequest invite_user_messages = 39;
|
||||||
|
zitadel.org.v1.OrgState org_state = 40;
|
||||||
}
|
}
|
||||||
|
|
||||||
message ImportDataResponse{
|
message ImportDataResponse{
|
||||||
|
@@ -172,10 +172,12 @@ message DataOIDCApplication {
|
|||||||
message DataHumanUser {
|
message DataHumanUser {
|
||||||
string user_id = 1;
|
string user_id = 1;
|
||||||
zitadel.management.v1.ImportHumanUserRequest user = 2;
|
zitadel.management.v1.ImportHumanUserRequest user = 2;
|
||||||
|
zitadel.user.v1.UserState state = 3;
|
||||||
}
|
}
|
||||||
message DataMachineUser {
|
message DataMachineUser {
|
||||||
string user_id = 1;
|
string user_id = 1;
|
||||||
zitadel.management.v1.AddMachineUserRequest user = 2;
|
zitadel.management.v1.AddMachineUserRequest user = 2;
|
||||||
|
zitadel.user.v1.UserState state = 3;
|
||||||
}
|
}
|
||||||
message DataAction {
|
message DataAction {
|
||||||
string action_id = 1;
|
string action_id = 1;
|
||||||
|
Reference in New Issue
Block a user