mirror of
https://github.com/zitadel/zitadel.git
synced 2025-02-28 20:17:23 +00:00
feat: allow import of federated users in ImportHumanUser (#4675)
Co-authored-by: Fabi <38692350+hifabienne@users.noreply.github.com>
This commit is contained in:
parent
a4ddedb5f4
commit
eba602e064
@ -5408,6 +5408,7 @@ This is an empty response
|
|||||||
| password_change_required | bool | - | |
|
| password_change_required | bool | - | |
|
||||||
| request_passwordless_registration | bool | - | |
|
| request_passwordless_registration | bool | - | |
|
||||||
| otp_code | string | - | |
|
| otp_code | string | - | |
|
||||||
|
| idps | repeated ImportHumanUserRequest.IDP | - | |
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -5436,6 +5437,19 @@ This is an empty response
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### ImportHumanUserRequest.IDP
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
| Field | Type | Description | Validation |
|
||||||
|
| ----- | ---- | ----------- | ----------- |
|
||||||
|
| config_id | string | internal id of the IDP in ZITADEL | string.min_len: 1<br /> string.max_len: 200<br /> |
|
||||||
|
| external_user_id | string | id of the user on the IDP | string.min_len: 1<br /> string.max_len: 200<br /> |
|
||||||
|
| display_name | string | (display) name of the user on the IDP | string.max_len: 200<br /> |
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### ImportHumanUserRequest.Phone
|
### ImportHumanUserRequest.Phone
|
||||||
|
|
||||||
|
|
||||||
|
@ -535,9 +535,9 @@ func (s *Server) importData(ctx context.Context, orgs []*admin_pb.DataOrg) (*adm
|
|||||||
if org.HumanUsers != nil {
|
if org.HumanUsers != nil {
|
||||||
for _, user := range org.GetHumanUsers() {
|
for _, user := range org.GetHumanUsers() {
|
||||||
logging.Debugf("import user: %s", user.GetUserId())
|
logging.Debugf("import user: %s", user.GetUserId())
|
||||||
human, passwordless := 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, initCodeGenerator, emailCodeGenerator, phoneCodeGenerator, passwordlessInitCode)
|
_, _, err := s.command.ImportHuman(ctx, org.GetOrgId(), human, passwordless, 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) {
|
||||||
|
@ -230,7 +230,7 @@ func AddHumanUserRequestToAddHuman(req *mgmt_pb.AddHumanUserRequest) *command.Ad
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) ImportHumanUser(ctx context.Context, req *mgmt_pb.ImportHumanUserRequest) (*mgmt_pb.ImportHumanUserResponse, error) {
|
func (s *Server) ImportHumanUser(ctx context.Context, req *mgmt_pb.ImportHumanUserRequest) (*mgmt_pb.ImportHumanUserResponse, error) {
|
||||||
human, passwordless := ImportHumanUserRequestToDomain(req)
|
human, passwordless, links := ImportHumanUserRequestToDomain(req)
|
||||||
initCodeGenerator, err := s.query.InitEncryptionGenerator(ctx, domain.SecretGeneratorTypeInitCode, s.userCodeAlg)
|
initCodeGenerator, err := s.query.InitEncryptionGenerator(ctx, domain.SecretGeneratorTypeInitCode, s.userCodeAlg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -247,7 +247,7 @@ 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, initCodeGenerator, phoneCodeGenerator, emailCodeGenerator, passwordlessInitCode)
|
addedHuman, code, err := s.command.ImportHuman(ctx, authz.GetCtxData(ctx).OrgID, human, passwordless, links, initCodeGenerator, phoneCodeGenerator, emailCodeGenerator, passwordlessInitCode)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -120,7 +120,7 @@ func AddHumanUserRequestToDomain(req *mgmt_pb.AddHumanUserRequest) *domain.Human
|
|||||||
return h
|
return h
|
||||||
}
|
}
|
||||||
|
|
||||||
func ImportHumanUserRequestToDomain(req *mgmt_pb.ImportHumanUserRequest) (human *domain.Human, passwordless bool) {
|
func ImportHumanUserRequestToDomain(req *mgmt_pb.ImportHumanUserRequest) (human *domain.Human, passwordless bool, links []*domain.UserIDPLink) {
|
||||||
human = &domain.Human{
|
human = &domain.Human{
|
||||||
Username: req.UserName,
|
Username: req.UserName,
|
||||||
}
|
}
|
||||||
@ -153,8 +153,16 @@ func ImportHumanUserRequestToDomain(req *mgmt_pb.ImportHumanUserRequest) (human
|
|||||||
if req.HashedPassword != nil && req.HashedPassword.Value != "" && req.HashedPassword.Algorithm != "" {
|
if req.HashedPassword != nil && req.HashedPassword.Value != "" && req.HashedPassword.Algorithm != "" {
|
||||||
human.HashedPassword = domain.NewHashedPassword(req.HashedPassword.Value, req.HashedPassword.Algorithm)
|
human.HashedPassword = domain.NewHashedPassword(req.HashedPassword.Value, req.HashedPassword.Algorithm)
|
||||||
}
|
}
|
||||||
|
links = make([]*domain.UserIDPLink, len(req.Idps))
|
||||||
|
for i, idp := range req.Idps {
|
||||||
|
links[i] = &domain.UserIDPLink{
|
||||||
|
IDPConfigID: idp.ConfigId,
|
||||||
|
ExternalUserID: idp.ExternalUserId,
|
||||||
|
DisplayName: idp.DisplayName,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return human, req.RequestPasswordlessRegistration
|
return human, req.RequestPasswordlessRegistration, links
|
||||||
}
|
}
|
||||||
|
|
||||||
func AddMachineUserRequestToCommand(req *mgmt_pb.AddMachineUserRequest, resourceowner string) *command.Machine {
|
func AddMachineUserRequestToCommand(req *mgmt_pb.AddMachineUserRequest, resourceowner string) *command.Machine {
|
||||||
|
@ -285,7 +285,7 @@ func (h *AddHuman) shouldAddInitCode() bool {
|
|||||||
h.Password == ""
|
h.Password == ""
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Commands) ImportHuman(ctx context.Context, orgID string, human *domain.Human, passwordless bool, 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, links []*domain.UserIDPLink, initCodeGenerator, emailCodeGenerator, phoneCodeGenerator, passwordlessCodeGenerator crypto.Generator) (_ *domain.Human, passwordlessCode *domain.PasswordlessInitCode, err error) {
|
||||||
if orgID == "" {
|
if orgID == "" {
|
||||||
return nil, nil, errors.ThrowInvalidArgument(nil, "COMMAND-5N8fs", "Errors.ResourceOwnerMissing")
|
return nil, nil, errors.ThrowInvalidArgument(nil, "COMMAND-5N8fs", "Errors.ResourceOwnerMissing")
|
||||||
}
|
}
|
||||||
@ -309,7 +309,7 @@ func (c *Commands) ImportHuman(ctx context.Context, orgID string, human *domain.
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
events, addedHuman, addedCode, code, err := c.importHuman(ctx, orgID, human, passwordless, domainPolicy, pwPolicy, initCodeGenerator, emailCodeGenerator, phoneCodeGenerator, passwordlessCodeGenerator)
|
events, 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
|
||||||
}
|
}
|
||||||
@ -396,11 +396,11 @@ func (c *Commands) addHuman(ctx context.Context, orgID string, human *domain.Hum
|
|||||||
return c.createHuman(ctx, orgID, human, nil, false, false, domainPolicy, pwPolicy, initCodeGenerator, emailCodeGenerator, phoneCodeGenerator)
|
return c.createHuman(ctx, orgID, human, nil, false, false, domainPolicy, pwPolicy, initCodeGenerator, emailCodeGenerator, phoneCodeGenerator)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Commands) importHuman(ctx context.Context, orgID string, human *domain.Human, passwordless bool, 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, humanWriteModel *HumanWriteModel, passwordlessCodeWriteModel *HumanPasswordlessInitCodeWriteModel, code string, err error) {
|
||||||
if orgID == "" || !human.IsValid() {
|
if orgID == "" || !human.IsValid() {
|
||||||
return nil, nil, nil, "", errors.ThrowInvalidArgument(nil, "COMMAND-00p2b", "Errors.User.Invalid")
|
return nil, nil, nil, "", errors.ThrowInvalidArgument(nil, "COMMAND-00p2b", "Errors.User.Invalid")
|
||||||
}
|
}
|
||||||
events, humanWriteModel, err = c.createHuman(ctx, orgID, human, nil, false, passwordless, domainPolicy, pwPolicy, initCodeGenerator, emailCodeGenerator, phoneCodeGenerator)
|
events, humanWriteModel, err = c.createHuman(ctx, orgID, human, links, false, passwordless, domainPolicy, pwPolicy, initCodeGenerator, emailCodeGenerator, phoneCodeGenerator)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, nil, "", err
|
return nil, nil, nil, "", err
|
||||||
}
|
}
|
||||||
@ -428,10 +428,14 @@ func (c *Commands) registerHuman(ctx context.Context, orgID string, human *domai
|
|||||||
if human.Password != nil && human.Password.SecretString != "" {
|
if human.Password != nil && human.Password.SecretString != "" {
|
||||||
human.Password.ChangeRequired = false
|
human.Password.ChangeRequired = false
|
||||||
}
|
}
|
||||||
return c.createHuman(ctx, orgID, human, link, true, false, domainPolicy, pwPolicy, initCodeGenerator, emailCodeGenerator, phoneCodeGenerator)
|
var links []*domain.UserIDPLink
|
||||||
|
if link != nil {
|
||||||
|
links = append(links, link)
|
||||||
|
}
|
||||||
|
return c.createHuman(ctx, orgID, human, links, true, false, domainPolicy, pwPolicy, initCodeGenerator, emailCodeGenerator, phoneCodeGenerator)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Commands) createHuman(ctx context.Context, orgID string, human *domain.Human, link *domain.UserIDPLink, selfregister, 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, selfregister, passwordless bool, domainPolicy *domain.DomainPolicy, pwPolicy *domain.PasswordComplexityPolicy, initCodeGenerator, emailCodeGenerator, phoneCodeGenerator crypto.Generator) (events []eventstore.Command, addedHuman *HumanWriteModel, err error) {
|
||||||
if err := human.CheckDomainPolicy(domainPolicy); err != nil {
|
if err := human.CheckDomainPolicy(domainPolicy); err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
@ -476,7 +480,7 @@ func (c *Commands) createHuman(ctx context.Context, orgID string, human *domain.
|
|||||||
events = append(events, createAddHumanEvent(ctx, userAgg, human, domainPolicy.UserLoginMustBeDomain))
|
events = append(events, createAddHumanEvent(ctx, userAgg, human, domainPolicy.UserLoginMustBeDomain))
|
||||||
}
|
}
|
||||||
|
|
||||||
if link != nil {
|
for _, link := range links {
|
||||||
event, err := c.addUserIDPLink(ctx, userAgg, link)
|
event, err := c.addUserIDPLink(ctx, userAgg, link)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
@ -484,7 +488,7 @@ func (c *Commands) createHuman(ctx context.Context, orgID string, human *domain.
|
|||||||
events = append(events, event)
|
events = append(events, event)
|
||||||
}
|
}
|
||||||
|
|
||||||
if human.IsInitialState(passwordless, link != nil) {
|
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, err
|
||||||
|
@ -703,6 +703,7 @@ func TestCommandSide_ImportHuman(t *testing.T) {
|
|||||||
orgID string
|
orgID string
|
||||||
human *domain.Human
|
human *domain.Human
|
||||||
passwordless bool
|
passwordless bool
|
||||||
|
links []*domain.UserIDPLink
|
||||||
secretGenerator crypto.Generator
|
secretGenerator crypto.Generator
|
||||||
passwordlessInitCode crypto.Generator
|
passwordlessInitCode crypto.Generator
|
||||||
}
|
}
|
||||||
@ -1452,6 +1453,135 @@ func TestCommandSide_ImportHuman(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "add human (with idp), ok",
|
||||||
|
fields: fields{
|
||||||
|
eventstore: eventstoreExpect(
|
||||||
|
t,
|
||||||
|
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(
|
||||||
|
org.NewIdentityProviderAddedEvent(context.Background(),
|
||||||
|
&org.NewAggregate("org1").Aggregate,
|
||||||
|
"idpID",
|
||||||
|
domain.IdentityProviderTypeOrg,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
expectPush(
|
||||||
|
[]*repository.Event{
|
||||||
|
eventFromEventPusher(
|
||||||
|
newAddHumanEvent("", false, ""),
|
||||||
|
),
|
||||||
|
eventFromEventPusher(
|
||||||
|
user.NewUserIDPLinkAddedEvent(context.Background(),
|
||||||
|
&user.NewAggregate("user1", "org1").Aggregate,
|
||||||
|
"idpID",
|
||||||
|
"name",
|
||||||
|
"externalID",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
eventFromEventPusher(
|
||||||
|
user.NewHumanEmailVerifiedEvent(context.Background(),
|
||||||
|
&user.NewAggregate("user1", "org1").Aggregate),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
uniqueConstraintsFromEventConstraint(user.NewAddUsernameUniqueConstraint("username", "org1", true)),
|
||||||
|
uniqueConstraintsFromEventConstraint(user.NewAddUserIDPLinkUniqueConstraint("idpID", "externalID")),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "user1"),
|
||||||
|
userPasswordAlg: crypto.CreateMockHashAlg(gomock.NewController(t)),
|
||||||
|
},
|
||||||
|
args: args{
|
||||||
|
ctx: context.Background(),
|
||||||
|
orgID: "org1",
|
||||||
|
human: &domain.Human{
|
||||||
|
Username: "username",
|
||||||
|
Profile: &domain.Profile{
|
||||||
|
FirstName: "firstname",
|
||||||
|
LastName: "lastname",
|
||||||
|
PreferredLanguage: language.English,
|
||||||
|
},
|
||||||
|
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: language.English,
|
||||||
|
},
|
||||||
|
Email: &domain.Email{
|
||||||
|
EmailAddress: "email@test.ch",
|
||||||
|
IsEmailVerified: true,
|
||||||
|
},
|
||||||
|
State: domain.UserStateActive,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
@ -1460,7 +1590,7 @@ func TestCommandSide_ImportHuman(t *testing.T) {
|
|||||||
idGenerator: tt.fields.idGenerator,
|
idGenerator: tt.fields.idGenerator,
|
||||||
userPasswordAlg: tt.fields.userPasswordAlg,
|
userPasswordAlg: tt.fields.userPasswordAlg,
|
||||||
}
|
}
|
||||||
gotHuman, gotCode, err := r.ImportHuman(tt.args.ctx, tt.args.orgID, tt.args.human, tt.args.passwordless, tt.args.secretGenerator, tt.args.secretGenerator, tt.args.secretGenerator, tt.args.secretGenerator)
|
gotHuman, gotCode, err := r.ImportHuman(tt.args.ctx, tt.args.orgID, tt.args.human, tt.args.passwordless, tt.args.links, tt.args.secretGenerator, tt.args.secretGenerator, tt.args.secretGenerator, tt.args.secretGenerator)
|
||||||
if tt.res.err == nil {
|
if tt.res.err == nil {
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
}
|
}
|
||||||
@ -2479,6 +2609,158 @@ func TestCommandSide_RegisterHuman(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "add with idp link, email verified, ok",
|
||||||
|
fields: fields{
|
||||||
|
eventstore: eventstoreExpect(
|
||||||
|
t,
|
||||||
|
expectFilter(
|
||||||
|
eventFromEventPusher(
|
||||||
|
org.NewDomainPolicyAddedEvent(context.Background(),
|
||||||
|
&user.NewAggregate("org1", "org1").Aggregate,
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
expectFilter(
|
||||||
|
eventFromEventPusher(
|
||||||
|
org.NewPasswordComplexityPolicyAddedEvent(context.Background(),
|
||||||
|
&org.NewAggregate("org1").Aggregate,
|
||||||
|
1,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
expectFilter(
|
||||||
|
eventFromEventPusher(
|
||||||
|
org.NewLoginPolicyAddedEvent(context.Background(),
|
||||||
|
&org.NewAggregate("org1").Aggregate,
|
||||||
|
false,
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
domain.PasswordlessTypeNotAllowed,
|
||||||
|
"",
|
||||||
|
time.Hour*1,
|
||||||
|
time.Hour*2,
|
||||||
|
time.Hour*3,
|
||||||
|
time.Hour*4,
|
||||||
|
time.Hour*5,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
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(
|
||||||
|
org.NewIdentityProviderAddedEvent(context.Background(),
|
||||||
|
&org.NewAggregate("org1").Aggregate,
|
||||||
|
"idpID",
|
||||||
|
domain.IdentityProviderTypeOrg,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
expectPush(
|
||||||
|
[]*repository.Event{
|
||||||
|
eventFromEventPusher(
|
||||||
|
newRegisterHumanEvent("username", "password", false, ""),
|
||||||
|
),
|
||||||
|
eventFromEventPusher(
|
||||||
|
user.NewUserIDPLinkAddedEvent(context.Background(),
|
||||||
|
&user.NewAggregate("user1", "org1").Aggregate,
|
||||||
|
"idpID",
|
||||||
|
"displayName",
|
||||||
|
"externalID",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
eventFromEventPusher(
|
||||||
|
user.NewHumanEmailVerifiedEvent(context.Background(),
|
||||||
|
&user.NewAggregate("user1", "org1").Aggregate),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
uniqueConstraintsFromEventConstraint(user.NewAddUsernameUniqueConstraint("username", "org1", true)),
|
||||||
|
uniqueConstraintsFromEventConstraint(user.NewAddUserIDPLinkUniqueConstraint("idpID", "externalID")),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "user1"),
|
||||||
|
userPasswordAlg: crypto.CreateMockHashAlg(gomock.NewController(t)),
|
||||||
|
},
|
||||||
|
args: args{
|
||||||
|
ctx: context.Background(),
|
||||||
|
orgID: "org1",
|
||||||
|
human: &domain.Human{
|
||||||
|
Username: "username",
|
||||||
|
Password: &domain.Password{
|
||||||
|
SecretString: "password",
|
||||||
|
},
|
||||||
|
Profile: &domain.Profile{
|
||||||
|
FirstName: "firstname",
|
||||||
|
LastName: "lastname",
|
||||||
|
},
|
||||||
|
Email: &domain.Email{
|
||||||
|
EmailAddress: "email@test.ch",
|
||||||
|
IsEmailVerified: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
link: &domain.UserIDPLink{
|
||||||
|
IDPConfigID: "idpID",
|
||||||
|
ExternalUserID: "externalID",
|
||||||
|
DisplayName: "displayName",
|
||||||
|
},
|
||||||
|
secretGenerator: GetMockSecretGenerator(t),
|
||||||
|
},
|
||||||
|
res: res{
|
||||||
|
want: &domain.Human{
|
||||||
|
ObjectRoot: models.ObjectRoot{
|
||||||
|
AggregateID: "user1",
|
||||||
|
ResourceOwner: "org1",
|
||||||
|
},
|
||||||
|
Username: "username",
|
||||||
|
Profile: &domain.Profile{
|
||||||
|
FirstName: "firstname",
|
||||||
|
LastName: "lastname",
|
||||||
|
DisplayName: "firstname lastname",
|
||||||
|
PreferredLanguage: language.Und,
|
||||||
|
},
|
||||||
|
Email: &domain.Email{
|
||||||
|
EmailAddress: "email@test.ch",
|
||||||
|
IsEmailVerified: true,
|
||||||
|
},
|
||||||
|
State: domain.UserStateActive,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
@ -3128,6 +3128,14 @@ message ImportHumanUserRequest {
|
|||||||
string value = 1;
|
string value = 1;
|
||||||
string algorithm = 2;
|
string algorithm = 2;
|
||||||
}
|
}
|
||||||
|
message IDP {
|
||||||
|
// internal id of the IDP in ZITADEL
|
||||||
|
string config_id = 1 [(validate.rules).string = {min_len: 1, max_len: 200}];
|
||||||
|
// id of the user on the IDP
|
||||||
|
string external_user_id = 2 [(validate.rules).string = {min_len: 1, max_len: 200}];
|
||||||
|
// (display) name of the user on the IDP
|
||||||
|
string display_name = 3 [(validate.rules).string = {max_len: 200}];
|
||||||
|
}
|
||||||
|
|
||||||
string user_name = 1 [(validate.rules).string = {min_len: 1, max_len: 200}];
|
string user_name = 1 [(validate.rules).string = {min_len: 1, max_len: 200}];
|
||||||
|
|
||||||
@ -3138,8 +3146,8 @@ message ImportHumanUserRequest {
|
|||||||
HashedPassword hashed_password = 6;
|
HashedPassword hashed_password = 6;
|
||||||
bool password_change_required = 7;
|
bool password_change_required = 7;
|
||||||
bool request_passwordless_registration = 8;
|
bool request_passwordless_registration = 8;
|
||||||
|
|
||||||
string otp_code = 9;
|
string otp_code = 9;
|
||||||
|
repeated IDP idps = 10;
|
||||||
}
|
}
|
||||||
|
|
||||||
message ImportHumanUserResponse {
|
message ImportHumanUserResponse {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user