mirror of
https://github.com/zitadel/zitadel.git
synced 2025-04-05 14:35:52 +00:00
fix(projections): user idp link projection (#2583)
* fix(projections): add app * fix(migration): add index for project_id * test: app projection * fix(projections): add idp_user_link * test: idp user link * fix: migration versions * refactor: rename externalIDP to UserIDPLink * fix: interface methods
This commit is contained in:
parent
5ba1e45423
commit
92f9eedbe0
@ -146,10 +146,10 @@ func idpConfigTypeToDomain(idpType iam_model.IDPProviderType) domain.IdentityPro
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func externalIDPViewsToDomain(idps []*user_model.ExternalIDPView) []*domain.ExternalIDP {
|
func externalIDPViewsToDomain(idps []*user_model.ExternalIDPView) []*domain.UserIDPLink {
|
||||||
externalIDPs := make([]*domain.ExternalIDP, len(idps))
|
externalIDPs := make([]*domain.UserIDPLink, len(idps))
|
||||||
for i, idp := range idps {
|
for i, idp := range idps {
|
||||||
externalIDPs[i] = &domain.ExternalIDP{
|
externalIDPs[i] = &domain.UserIDPLink{
|
||||||
ObjectRoot: models.ObjectRoot{
|
ObjectRoot: models.ObjectRoot{
|
||||||
AggregateID: idp.UserID,
|
AggregateID: idp.UserID,
|
||||||
ResourceOwner: idp.ResourceOwner,
|
ResourceOwner: idp.ResourceOwner,
|
||||||
|
@ -24,7 +24,7 @@ func (s *Server) ListMyLinkedIDPs(ctx context.Context, req *auth_pb.ListMyLinked
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) RemoveMyLinkedIDP(ctx context.Context, req *auth_pb.RemoveMyLinkedIDPRequest) (*auth_pb.RemoveMyLinkedIDPResponse, error) {
|
func (s *Server) RemoveMyLinkedIDP(ctx context.Context, req *auth_pb.RemoveMyLinkedIDPRequest) (*auth_pb.RemoveMyLinkedIDPResponse, error) {
|
||||||
objectDetails, err := s.command.RemoveHumanExternalIDP(ctx, RemoveMyLinkedIDPRequestToDomain(ctx, req))
|
objectDetails, err := s.command.RemoveUserIDPLink(ctx, RemoveMyLinkedIDPRequestToDomain(ctx, req))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -18,8 +18,8 @@ func ListMyLinkedIDPsRequestToModel(req *auth_pb.ListMyLinkedIDPsRequest) *model
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func RemoveMyLinkedIDPRequestToDomain(ctx context.Context, req *auth_pb.RemoveMyLinkedIDPRequest) *domain.ExternalIDP {
|
func RemoveMyLinkedIDPRequestToDomain(ctx context.Context, req *auth_pb.RemoveMyLinkedIDPRequest) *domain.UserIDPLink {
|
||||||
return &domain.ExternalIDP{
|
return &domain.UserIDPLink{
|
||||||
ObjectRoot: ctxToObjectRoot(ctx),
|
ObjectRoot: ctxToObjectRoot(ctx),
|
||||||
IDPConfigID: req.IdpId,
|
IDPConfigID: req.IdpId,
|
||||||
ExternalUserID: req.LinkedUserId,
|
ExternalUserID: req.LinkedUserId,
|
||||||
|
@ -148,10 +148,10 @@ func idpConfigTypeToDomain(idpType iam_model.IDPProviderType) domain.IdentityPro
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func externalIDPViewsToDomain(idps []*user_model.ExternalIDPView) []*domain.ExternalIDP {
|
func externalIDPViewsToDomain(idps []*user_model.ExternalIDPView) []*domain.UserIDPLink {
|
||||||
externalIDPs := make([]*domain.ExternalIDP, len(idps))
|
externalIDPs := make([]*domain.UserIDPLink, len(idps))
|
||||||
for i, idp := range idps {
|
for i, idp := range idps {
|
||||||
externalIDPs[i] = &domain.ExternalIDP{
|
externalIDPs[i] = &domain.UserIDPLink{
|
||||||
ObjectRoot: models.ObjectRoot{
|
ObjectRoot: models.ObjectRoot{
|
||||||
AggregateID: idp.UserID,
|
AggregateID: idp.UserID,
|
||||||
ResourceOwner: idp.ResourceOwner,
|
ResourceOwner: idp.ResourceOwner,
|
||||||
|
@ -598,7 +598,7 @@ func (s *Server) ListHumanLinkedIDPs(ctx context.Context, req *mgmt_pb.ListHuman
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
func (s *Server) RemoveHumanLinkedIDP(ctx context.Context, req *mgmt_pb.RemoveHumanLinkedIDPRequest) (*mgmt_pb.RemoveHumanLinkedIDPResponse, error) {
|
func (s *Server) RemoveHumanLinkedIDP(ctx context.Context, req *mgmt_pb.RemoveHumanLinkedIDPRequest) (*mgmt_pb.RemoveHumanLinkedIDPResponse, error) {
|
||||||
objectDetails, err := s.command.RemoveHumanExternalIDP(ctx, RemoveHumanLinkedIDPRequestToDomain(ctx, req))
|
objectDetails, err := s.command.RemoveUserIDPLink(ctx, RemoveHumanLinkedIDPRequestToDomain(ctx, req))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -223,8 +223,8 @@ func AddMachineKeyRequestToDomain(req *mgmt_pb.AddMachineKeyRequest) *domain.Mac
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func RemoveHumanLinkedIDPRequestToDomain(ctx context.Context, req *mgmt_pb.RemoveHumanLinkedIDPRequest) *domain.ExternalIDP {
|
func RemoveHumanLinkedIDPRequestToDomain(ctx context.Context, req *mgmt_pb.RemoveHumanLinkedIDPRequest) *domain.UserIDPLink {
|
||||||
return &domain.ExternalIDP{
|
return &domain.UserIDPLink{
|
||||||
ObjectRoot: models.ObjectRoot{
|
ObjectRoot: models.ObjectRoot{
|
||||||
AggregateID: req.UserId,
|
AggregateID: req.UserId,
|
||||||
ResourceOwner: authz.GetCtxData(ctx).OrgID,
|
ResourceOwner: authz.GetCtxData(ctx).OrgID,
|
||||||
|
@ -233,10 +233,10 @@ func WebAuthNTokenToWebAuthNKeyPb(token *domain.WebAuthNToken) *user_pb.WebAuthN
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func ExternalIDPViewsToExternalIDPs(externalIDPs []*model.ExternalIDPView) []*domain.ExternalIDP {
|
func ExternalIDPViewsToExternalIDPs(externalIDPs []*model.ExternalIDPView) []*domain.UserIDPLink {
|
||||||
idps := make([]*domain.ExternalIDP, len(externalIDPs))
|
idps := make([]*domain.UserIDPLink, len(externalIDPs))
|
||||||
for i, idp := range externalIDPs {
|
for i, idp := range externalIDPs {
|
||||||
idps[i] = &domain.ExternalIDP{
|
idps[i] = &domain.UserIDPLink{
|
||||||
ObjectRoot: models.ObjectRoot{
|
ObjectRoot: models.ObjectRoot{
|
||||||
AggregateID: idp.UserID,
|
AggregateID: idp.UserID,
|
||||||
ResourceOwner: idp.ResourceOwner,
|
ResourceOwner: idp.ResourceOwner,
|
||||||
|
@ -32,6 +32,6 @@ type AuthRequestRepository interface {
|
|||||||
VerifyPasswordless(ctx context.Context, userID, resourceOwner, authRequestID, userAgentID string, credentialData []byte, info *domain.BrowserInfo) error
|
VerifyPasswordless(ctx context.Context, userID, resourceOwner, authRequestID, userAgentID string, credentialData []byte, info *domain.BrowserInfo) error
|
||||||
|
|
||||||
LinkExternalUsers(ctx context.Context, authReqID, userAgentID string, info *domain.BrowserInfo) error
|
LinkExternalUsers(ctx context.Context, authReqID, userAgentID string, info *domain.BrowserInfo) error
|
||||||
AutoRegisterExternalUser(ctx context.Context, user *domain.Human, externalIDP *domain.ExternalIDP, orgMemberRoles []string, authReqID, userAgentID, resourceOwner string, metadatas []*domain.Metadata, info *domain.BrowserInfo) error
|
AutoRegisterExternalUser(ctx context.Context, user *domain.Human, externalIDP *domain.UserIDPLink, orgMemberRoles []string, authReqID, userAgentID, resourceOwner string, metadatas []*domain.Metadata, info *domain.BrowserInfo) error
|
||||||
ResetLinkingUsers(ctx context.Context, authReqID, userAgentID string) error
|
ResetLinkingUsers(ctx context.Context, authReqID, userAgentID string) error
|
||||||
}
|
}
|
||||||
|
@ -87,7 +87,7 @@ type userEventProvider interface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type userCommandProvider interface {
|
type userCommandProvider interface {
|
||||||
BulkAddedHumanExternalIDP(ctx context.Context, userID, resourceOwner string, externalIDPs []*domain.ExternalIDP) error
|
BulkAddedUserIDPLinks(ctx context.Context, userID, resourceOwner string, externalIDPs []*domain.UserIDPLink) error
|
||||||
}
|
}
|
||||||
|
|
||||||
type orgViewProvider interface {
|
type orgViewProvider interface {
|
||||||
@ -238,7 +238,7 @@ func (repo *AuthRequestRepo) CheckExternalUserLogin(ctx context.Context, authReq
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = repo.Command.HumanExternalLoginChecked(ctx, request.UserOrgID, request.UserID, request.WithCurrentInfo(info))
|
err = repo.Command.UserIDPLoginChecked(ctx, request.UserOrgID, request.UserID, request.WithCurrentInfo(info))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -404,7 +404,7 @@ func (repo *AuthRequestRepo) LinkExternalUsers(ctx context.Context, authReqID, u
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
err = repo.Command.HumanExternalLoginChecked(ctx, request.UserOrgID, request.UserID, request.WithCurrentInfo(info))
|
err = repo.Command.UserIDPLoginChecked(ctx, request.UserOrgID, request.UserID, request.WithCurrentInfo(info))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -422,7 +422,7 @@ func (repo *AuthRequestRepo) ResetLinkingUsers(ctx context.Context, authReqID, u
|
|||||||
return repo.AuthRequests.UpdateAuthRequest(ctx, request)
|
return repo.AuthRequests.UpdateAuthRequest(ctx, request)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (repo *AuthRequestRepo) AutoRegisterExternalUser(ctx context.Context, registerUser *domain.Human, externalIDP *domain.ExternalIDP, orgMemberRoles []string, authReqID, userAgentID, resourceOwner string, metadatas []*domain.Metadata, info *domain.BrowserInfo) (err error) {
|
func (repo *AuthRequestRepo) AutoRegisterExternalUser(ctx context.Context, registerUser *domain.Human, externalIDP *domain.UserIDPLink, orgMemberRoles []string, authReqID, userAgentID, resourceOwner string, metadatas []*domain.Metadata, info *domain.BrowserInfo) (err error) {
|
||||||
ctx, span := tracing.NewSpan(ctx)
|
ctx, span := tracing.NewSpan(ctx)
|
||||||
defer func() { span.EndWithError(err) }()
|
defer func() { span.EndWithError(err) }()
|
||||||
request, err := repo.getAuthRequest(ctx, authReqID, userAgentID)
|
request, err := repo.getAuthRequest(ctx, authReqID, userAgentID)
|
||||||
@ -437,7 +437,7 @@ func (repo *AuthRequestRepo) AutoRegisterExternalUser(ctx context.Context, regis
|
|||||||
request.UserOrgID = human.ResourceOwner
|
request.UserOrgID = human.ResourceOwner
|
||||||
request.SelectedIDPConfigID = externalIDP.IDPConfigID
|
request.SelectedIDPConfigID = externalIDP.IDPConfigID
|
||||||
request.LinkingUsers = nil
|
request.LinkingUsers = nil
|
||||||
err = repo.Command.HumanExternalLoginChecked(ctx, request.UserOrgID, request.UserID, request.WithCurrentInfo(info))
|
err = repo.Command.UserIDPLoginChecked(ctx, request.UserOrgID, request.UserID, request.WithCurrentInfo(info))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -1093,9 +1093,9 @@ func userByID(ctx context.Context, viewProvider userViewProvider, eventProvider
|
|||||||
}
|
}
|
||||||
|
|
||||||
func linkExternalIDPs(ctx context.Context, userCommandProvider userCommandProvider, request *domain.AuthRequest) error {
|
func linkExternalIDPs(ctx context.Context, userCommandProvider userCommandProvider, request *domain.AuthRequest) error {
|
||||||
externalIDPs := make([]*domain.ExternalIDP, len(request.LinkingUsers))
|
externalIDPs := make([]*domain.UserIDPLink, len(request.LinkingUsers))
|
||||||
for i, linkingUser := range request.LinkingUsers {
|
for i, linkingUser := range request.LinkingUsers {
|
||||||
externalIDP := &domain.ExternalIDP{
|
externalIDP := &domain.UserIDPLink{
|
||||||
ObjectRoot: es_models.ObjectRoot{AggregateID: request.UserID},
|
ObjectRoot: es_models.ObjectRoot{AggregateID: request.UserID},
|
||||||
IDPConfigID: linkingUser.IDPConfigID,
|
IDPConfigID: linkingUser.IDPConfigID,
|
||||||
ExternalUserID: linkingUser.ExternalUserID,
|
ExternalUserID: linkingUser.ExternalUserID,
|
||||||
@ -1107,7 +1107,7 @@ func linkExternalIDPs(ctx context.Context, userCommandProvider userCommandProvid
|
|||||||
UserID: "LOGIN",
|
UserID: "LOGIN",
|
||||||
OrgID: request.UserOrgID,
|
OrgID: request.UserOrgID,
|
||||||
}
|
}
|
||||||
return userCommandProvider.BulkAddedHumanExternalIDP(authz.SetCtxData(ctx, data), request.UserID, request.UserOrgID, externalIDPs)
|
return userCommandProvider.BulkAddedUserIDPLinks(authz.SetCtxData(ctx, data), request.UserID, request.UserOrgID, externalIDPs)
|
||||||
}
|
}
|
||||||
|
|
||||||
func linkingIDPConfigExistingInAllowedIDPs(linkingUsers []*domain.ExternalUser, idpProviders []*domain.IDPProvider) bool {
|
func linkingIDPConfigExistingInAllowedIDPs(linkingUsers []*domain.ExternalUser, idpProviders []*domain.IDPProvider) bool {
|
||||||
|
@ -145,7 +145,7 @@ func (c *Commands) ReactivateDefaultIDPConfig(ctx context.Context, idpID string)
|
|||||||
return writeModelToObjectDetails(&existingIDP.IDPConfigWriteModel.WriteModel), nil
|
return writeModelToObjectDetails(&existingIDP.IDPConfigWriteModel.WriteModel), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Commands) RemoveDefaultIDPConfig(ctx context.Context, idpID string, idpProviders []*domain.IDPProvider, externalIDPs ...*domain.ExternalIDP) (*domain.ObjectDetails, error) {
|
func (c *Commands) RemoveDefaultIDPConfig(ctx context.Context, idpID string, idpProviders []*domain.IDPProvider, externalIDPs ...*domain.UserIDPLink) (*domain.ObjectDetails, error) {
|
||||||
existingIDP, err := c.iamIDPConfigWriteModelByID(ctx, idpID)
|
existingIDP, err := c.iamIDPConfigWriteModelByID(ctx, idpID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -123,7 +123,7 @@ func (c *Commands) AddIDPProviderToDefaultLoginPolicy(ctx context.Context, idpPr
|
|||||||
return writeModelToIDPProvider(&idpModel.IdentityProviderWriteModel), nil
|
return writeModelToIDPProvider(&idpModel.IdentityProviderWriteModel), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Commands) RemoveIDPProviderFromDefaultLoginPolicy(ctx context.Context, idpProvider *domain.IDPProvider, cascadeExternalIDPs ...*domain.ExternalIDP) (*domain.ObjectDetails, error) {
|
func (c *Commands) RemoveIDPProviderFromDefaultLoginPolicy(ctx context.Context, idpProvider *domain.IDPProvider, cascadeExternalIDPs ...*domain.UserIDPLink) (*domain.ObjectDetails, error) {
|
||||||
if !idpProvider.IsValid() {
|
if !idpProvider.IsValid() {
|
||||||
return nil, caos_errs.ThrowInvalidArgument(nil, "IAM-66m9s", "Errors.IAM.LoginPolicy.IDP.Invalid")
|
return nil, caos_errs.ThrowInvalidArgument(nil, "IAM-66m9s", "Errors.IAM.LoginPolicy.IDP.Invalid")
|
||||||
}
|
}
|
||||||
@ -158,7 +158,7 @@ func (c *Commands) RemoveIDPProviderFromDefaultLoginPolicy(ctx context.Context,
|
|||||||
return writeModelToObjectDetails(&idpModel.IdentityProviderWriteModel.WriteModel), nil
|
return writeModelToObjectDetails(&idpModel.IdentityProviderWriteModel.WriteModel), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Commands) removeIDPProviderFromDefaultLoginPolicy(ctx context.Context, iamAgg *eventstore.Aggregate, idpProvider *domain.IDPProvider, cascade bool, cascadeExternalIDPs ...*domain.ExternalIDP) []eventstore.EventPusher {
|
func (c *Commands) removeIDPProviderFromDefaultLoginPolicy(ctx context.Context, iamAgg *eventstore.Aggregate, idpProvider *domain.IDPProvider, cascade bool, cascadeExternalIDPs ...*domain.UserIDPLink) []eventstore.EventPusher {
|
||||||
var events []eventstore.EventPusher
|
var events []eventstore.EventPusher
|
||||||
if cascade {
|
if cascade {
|
||||||
events = append(events, iam_repo.NewIdentityProviderCascadeRemovedEvent(ctx, iamAgg, idpProvider.IDPConfigID))
|
events = append(events, iam_repo.NewIdentityProviderCascadeRemovedEvent(ctx, iamAgg, idpProvider.IDPConfigID))
|
||||||
@ -167,7 +167,7 @@ func (c *Commands) removeIDPProviderFromDefaultLoginPolicy(ctx context.Context,
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, idp := range cascadeExternalIDPs {
|
for _, idp := range cascadeExternalIDPs {
|
||||||
userEvent, _, err := c.removeHumanExternalIDP(ctx, idp, true)
|
userEvent, _, err := c.removeUserIDPLink(ctx, idp, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logging.LogWithFields("COMMAND-4nfsf", "userid", idp.AggregateID, "idp-id", idp.IDPConfigID).WithError(err).Warn("could not cascade remove externalidp in remove provider from policy")
|
logging.LogWithFields("COMMAND-4nfsf", "userid", idp.AggregateID, "idp-id", idp.IDPConfigID).WithError(err).Warn("could not cascade remove externalidp in remove provider from policy")
|
||||||
continue
|
continue
|
||||||
|
@ -497,7 +497,7 @@ func TestCommandSide_RemoveIDPProviderDefaultLoginPolicy(t *testing.T) {
|
|||||||
type args struct {
|
type args struct {
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
provider *domain.IDPProvider
|
provider *domain.IDPProvider
|
||||||
cascadeExternalIDPs []*domain.ExternalIDP
|
cascadeExternalIDPs []*domain.UserIDPLink
|
||||||
}
|
}
|
||||||
type res struct {
|
type res struct {
|
||||||
want *domain.ObjectDetails
|
want *domain.ObjectDetails
|
||||||
@ -708,7 +708,7 @@ func TestCommandSide_RemoveIDPProviderDefaultLoginPolicy(t *testing.T) {
|
|||||||
provider: &domain.IDPProvider{
|
provider: &domain.IDPProvider{
|
||||||
IDPConfigID: "config1",
|
IDPConfigID: "config1",
|
||||||
},
|
},
|
||||||
cascadeExternalIDPs: []*domain.ExternalIDP{
|
cascadeExternalIDPs: []*domain.UserIDPLink{
|
||||||
{
|
{
|
||||||
ObjectRoot: models.ObjectRoot{
|
ObjectRoot: models.ObjectRoot{
|
||||||
AggregateID: "user1",
|
AggregateID: "user1",
|
||||||
@ -751,7 +751,7 @@ func TestCommandSide_RemoveIDPProviderDefaultLoginPolicy(t *testing.T) {
|
|||||||
),
|
),
|
||||||
expectFilter(
|
expectFilter(
|
||||||
eventFromEventPusher(
|
eventFromEventPusher(
|
||||||
user.NewHumanExternalIDPAddedEvent(context.Background(),
|
user.NewUserIDPLinkAddedEvent(context.Background(),
|
||||||
&user.NewAggregate("user1", "org1").Aggregate,
|
&user.NewAggregate("user1", "org1").Aggregate,
|
||||||
"config1", "", "externaluser1"),
|
"config1", "", "externaluser1"),
|
||||||
),
|
),
|
||||||
@ -764,11 +764,11 @@ func TestCommandSide_RemoveIDPProviderDefaultLoginPolicy(t *testing.T) {
|
|||||||
"config1"),
|
"config1"),
|
||||||
),
|
),
|
||||||
eventFromEventPusher(
|
eventFromEventPusher(
|
||||||
user.NewHumanExternalIDPCascadeRemovedEvent(context.Background(),
|
user.NewUserIDPLinkCascadeRemovedEvent(context.Background(),
|
||||||
&user.NewAggregate("user1", "org1").Aggregate,
|
&user.NewAggregate("user1", "org1").Aggregate,
|
||||||
"config1", "externaluser1")),
|
"config1", "externaluser1")),
|
||||||
},
|
},
|
||||||
uniqueConstraintsFromEventConstraint(user.NewRemoveExternalIDPUniqueConstraint("config1", "externaluser1")),
|
uniqueConstraintsFromEventConstraint(user.NewRemoveUserIDPLinkUniqueConstraint("config1", "externaluser1")),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
@ -777,7 +777,7 @@ func TestCommandSide_RemoveIDPProviderDefaultLoginPolicy(t *testing.T) {
|
|||||||
provider: &domain.IDPProvider{
|
provider: &domain.IDPProvider{
|
||||||
IDPConfigID: "config1",
|
IDPConfigID: "config1",
|
||||||
},
|
},
|
||||||
cascadeExternalIDPs: []*domain.ExternalIDP{
|
cascadeExternalIDPs: []*domain.UserIDPLink{
|
||||||
{
|
{
|
||||||
ObjectRoot: models.ObjectRoot{
|
ObjectRoot: models.ObjectRoot{
|
||||||
AggregateID: "user1",
|
AggregateID: "user1",
|
||||||
|
@ -153,7 +153,7 @@ func (c *Commands) ReactivateIDPConfig(ctx context.Context, idpID, orgID string)
|
|||||||
return writeModelToObjectDetails(&existingIDP.IDPConfigWriteModel.WriteModel), nil
|
return writeModelToObjectDetails(&existingIDP.IDPConfigWriteModel.WriteModel), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Commands) RemoveIDPConfig(ctx context.Context, idpID, orgID string, cascadeRemoveProvider bool, cascadeExternalIDPs ...*domain.ExternalIDP) (*domain.ObjectDetails, error) {
|
func (c *Commands) RemoveIDPConfig(ctx context.Context, idpID, orgID string, cascadeRemoveProvider bool, cascadeExternalIDPs ...*domain.UserIDPLink) (*domain.ObjectDetails, error) {
|
||||||
existingIDP, err := c.orgIDPConfigWriteModelByID(ctx, idpID, orgID)
|
existingIDP, err := c.orgIDPConfigWriteModelByID(ctx, idpID, orgID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -173,7 +173,7 @@ func (c *Commands) RemoveIDPConfig(ctx context.Context, idpID, orgID string, cas
|
|||||||
return writeModelToObjectDetails(&existingIDP.IDPConfigWriteModel.WriteModel), nil
|
return writeModelToObjectDetails(&existingIDP.IDPConfigWriteModel.WriteModel), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Commands) removeIDPConfig(ctx context.Context, existingIDP *OrgIDPConfigWriteModel, cascadeRemoveProvider bool, cascadeExternalIDPs ...*domain.ExternalIDP) ([]eventstore.EventPusher, error) {
|
func (c *Commands) removeIDPConfig(ctx context.Context, existingIDP *OrgIDPConfigWriteModel, cascadeRemoveProvider bool, cascadeExternalIDPs ...*domain.UserIDPLink) ([]eventstore.EventPusher, error) {
|
||||||
if existingIDP.State == domain.IDPConfigStateRemoved || existingIDP.State == domain.IDPConfigStateUnspecified {
|
if existingIDP.State == domain.IDPConfigStateRemoved || existingIDP.State == domain.IDPConfigStateUnspecified {
|
||||||
return nil, caos_errs.ThrowNotFound(nil, "Org-Yx9vd", "Errors.Org.IDPConfig.NotExisting")
|
return nil, caos_errs.ThrowNotFound(nil, "Org-Yx9vd", "Errors.Org.IDPConfig.NotExisting")
|
||||||
}
|
}
|
||||||
|
@ -426,7 +426,7 @@ func TestCommands_RemoveIDPConfig(t *testing.T) {
|
|||||||
idpID string
|
idpID string
|
||||||
orgID string
|
orgID string
|
||||||
cascadeRemoveProvider bool
|
cascadeRemoveProvider bool
|
||||||
cascadeExternalIDPs []*domain.ExternalIDP
|
cascadeExternalIDPs []*domain.UserIDPLink
|
||||||
}
|
}
|
||||||
type res struct {
|
type res struct {
|
||||||
want *domain.ObjectDetails
|
want *domain.ObjectDetails
|
||||||
@ -531,7 +531,7 @@ func TestCommands_RemoveIDPConfig(t *testing.T) {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
eventFromEventPusher(
|
eventFromEventPusher(
|
||||||
user.NewHumanExternalIDPAddedEvent(context.Background(),
|
user.NewUserIDPLinkAddedEvent(context.Background(),
|
||||||
&org.NewAggregate("user1", "org1").Aggregate,
|
&org.NewAggregate("user1", "org1").Aggregate,
|
||||||
"idp1",
|
"idp1",
|
||||||
"name",
|
"name",
|
||||||
@ -550,14 +550,14 @@ func TestCommands_RemoveIDPConfig(t *testing.T) {
|
|||||||
&org.NewAggregate("org1", "org1").Aggregate,
|
&org.NewAggregate("org1", "org1").Aggregate,
|
||||||
"idp1",
|
"idp1",
|
||||||
),
|
),
|
||||||
user.NewHumanExternalIDPCascadeRemovedEvent(context.Background(),
|
user.NewUserIDPLinkCascadeRemovedEvent(context.Background(),
|
||||||
&user.NewAggregate("user1", "org1").Aggregate,
|
&user.NewAggregate("user1", "org1").Aggregate,
|
||||||
"idp1",
|
"idp1",
|
||||||
"id1",
|
"id1",
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
uniqueConstraintsFromEventConstraint(idpconfig.NewRemoveIDPConfigNameUniqueConstraint("name1", "org1")),
|
uniqueConstraintsFromEventConstraint(idpconfig.NewRemoveIDPConfigNameUniqueConstraint("name1", "org1")),
|
||||||
uniqueConstraintsFromEventConstraint(user.NewRemoveExternalIDPUniqueConstraint("idp1", "id1")),
|
uniqueConstraintsFromEventConstraint(user.NewRemoveUserIDPLinkUniqueConstraint("idp1", "id1")),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
@ -566,7 +566,7 @@ func TestCommands_RemoveIDPConfig(t *testing.T) {
|
|||||||
"idp1",
|
"idp1",
|
||||||
"org1",
|
"org1",
|
||||||
true,
|
true,
|
||||||
[]*domain.ExternalIDP{
|
[]*domain.UserIDPLink{
|
||||||
{
|
{
|
||||||
ObjectRoot: models.ObjectRoot{
|
ObjectRoot: models.ObjectRoot{
|
||||||
AggregateID: "user1",
|
AggregateID: "user1",
|
||||||
|
@ -201,7 +201,7 @@ func (c *Commands) AddIDPProviderToLoginPolicy(ctx context.Context, resourceOwne
|
|||||||
return writeModelToIDPProvider(&idpModel.IdentityProviderWriteModel), nil
|
return writeModelToIDPProvider(&idpModel.IdentityProviderWriteModel), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Commands) RemoveIDPProviderFromLoginPolicy(ctx context.Context, resourceOwner string, idpProvider *domain.IDPProvider, cascadeExternalIDPs ...*domain.ExternalIDP) (*domain.ObjectDetails, error) {
|
func (c *Commands) RemoveIDPProviderFromLoginPolicy(ctx context.Context, resourceOwner string, idpProvider *domain.IDPProvider, cascadeExternalIDPs ...*domain.UserIDPLink) (*domain.ObjectDetails, error) {
|
||||||
if resourceOwner == "" {
|
if resourceOwner == "" {
|
||||||
return nil, caos_errs.ThrowInvalidArgument(nil, "Org-M0fs9", "Errors.ResourceOwnerMissing")
|
return nil, caos_errs.ThrowInvalidArgument(nil, "Org-M0fs9", "Errors.ResourceOwnerMissing")
|
||||||
}
|
}
|
||||||
@ -239,7 +239,7 @@ func (c *Commands) RemoveIDPProviderFromLoginPolicy(ctx context.Context, resourc
|
|||||||
return writeModelToObjectDetails(&idpModel.WriteModel), nil
|
return writeModelToObjectDetails(&idpModel.WriteModel), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Commands) removeIDPProviderFromLoginPolicy(ctx context.Context, orgAgg *eventstore.Aggregate, idpConfigID string, cascade bool, cascadeExternalIDPs ...*domain.ExternalIDP) []eventstore.EventPusher {
|
func (c *Commands) removeIDPProviderFromLoginPolicy(ctx context.Context, orgAgg *eventstore.Aggregate, idpConfigID string, cascade bool, cascadeExternalIDPs ...*domain.UserIDPLink) []eventstore.EventPusher {
|
||||||
var events []eventstore.EventPusher
|
var events []eventstore.EventPusher
|
||||||
if cascade {
|
if cascade {
|
||||||
events = append(events, org.NewIdentityProviderCascadeRemovedEvent(ctx, orgAgg, idpConfigID))
|
events = append(events, org.NewIdentityProviderCascadeRemovedEvent(ctx, orgAgg, idpConfigID))
|
||||||
@ -248,7 +248,7 @@ func (c *Commands) removeIDPProviderFromLoginPolicy(ctx context.Context, orgAgg
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, idp := range cascadeExternalIDPs {
|
for _, idp := range cascadeExternalIDPs {
|
||||||
event, _, err := c.removeHumanExternalIDP(ctx, idp, true)
|
event, _, err := c.removeUserIDPLink(ctx, idp, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logging.LogWithFields("COMMAND-n8RRf", "userid", idp.AggregateID, "idpconfigid", idp.IDPConfigID).WithError(err).Warn("could not cascade remove external idp")
|
logging.LogWithFields("COMMAND-n8RRf", "userid", idp.AggregateID, "idpconfigid", idp.IDPConfigID).WithError(err).Warn("could not cascade remove external idp")
|
||||||
continue
|
continue
|
||||||
|
@ -824,7 +824,7 @@ func TestCommandSide_RemoveIDPProviderLoginPolicy(t *testing.T) {
|
|||||||
ctx context.Context
|
ctx context.Context
|
||||||
resourceOwner string
|
resourceOwner string
|
||||||
provider *domain.IDPProvider
|
provider *domain.IDPProvider
|
||||||
cascadeExternalIDPs []*domain.ExternalIDP
|
cascadeExternalIDPs []*domain.UserIDPLink
|
||||||
}
|
}
|
||||||
type res struct {
|
type res struct {
|
||||||
want *domain.ObjectDetails
|
want *domain.ObjectDetails
|
||||||
@ -1069,7 +1069,7 @@ func TestCommandSide_RemoveIDPProviderLoginPolicy(t *testing.T) {
|
|||||||
Name: "name",
|
Name: "name",
|
||||||
Type: domain.IdentityProviderTypeOrg,
|
Type: domain.IdentityProviderTypeOrg,
|
||||||
},
|
},
|
||||||
cascadeExternalIDPs: []*domain.ExternalIDP{
|
cascadeExternalIDPs: []*domain.UserIDPLink{
|
||||||
{
|
{
|
||||||
ObjectRoot: models.ObjectRoot{
|
ObjectRoot: models.ObjectRoot{
|
||||||
AggregateID: "user1",
|
AggregateID: "user1",
|
||||||
@ -1113,7 +1113,7 @@ func TestCommandSide_RemoveIDPProviderLoginPolicy(t *testing.T) {
|
|||||||
),
|
),
|
||||||
expectFilter(
|
expectFilter(
|
||||||
eventFromEventPusher(
|
eventFromEventPusher(
|
||||||
user.NewHumanExternalIDPAddedEvent(context.Background(),
|
user.NewUserIDPLinkAddedEvent(context.Background(),
|
||||||
&user.NewAggregate("user1", "org1").Aggregate,
|
&user.NewAggregate("user1", "org1").Aggregate,
|
||||||
"config1", "", "externaluser1"),
|
"config1", "", "externaluser1"),
|
||||||
),
|
),
|
||||||
@ -1126,11 +1126,11 @@ func TestCommandSide_RemoveIDPProviderLoginPolicy(t *testing.T) {
|
|||||||
"config1"),
|
"config1"),
|
||||||
),
|
),
|
||||||
eventFromEventPusher(
|
eventFromEventPusher(
|
||||||
user.NewHumanExternalIDPCascadeRemovedEvent(context.Background(),
|
user.NewUserIDPLinkCascadeRemovedEvent(context.Background(),
|
||||||
&user.NewAggregate("user1", "org1").Aggregate,
|
&user.NewAggregate("user1", "org1").Aggregate,
|
||||||
"config1", "externaluser1")),
|
"config1", "externaluser1")),
|
||||||
},
|
},
|
||||||
uniqueConstraintsFromEventConstraint(user.NewRemoveExternalIDPUniqueConstraint("config1", "externaluser1")),
|
uniqueConstraintsFromEventConstraint(user.NewRemoveUserIDPLinkUniqueConstraint("config1", "externaluser1")),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
@ -1140,7 +1140,7 @@ func TestCommandSide_RemoveIDPProviderLoginPolicy(t *testing.T) {
|
|||||||
provider: &domain.IDPProvider{
|
provider: &domain.IDPProvider{
|
||||||
IDPConfigID: "config1",
|
IDPConfigID: "config1",
|
||||||
},
|
},
|
||||||
cascadeExternalIDPs: []*domain.ExternalIDP{
|
cascadeExternalIDPs: []*domain.UserIDPLink{
|
||||||
{
|
{
|
||||||
ObjectRoot: models.ObjectRoot{
|
ObjectRoot: models.ObjectRoot{
|
||||||
AggregateID: "user1",
|
AggregateID: "user1",
|
||||||
|
@ -131,7 +131,7 @@ func (rm *UniqueConstraintReadModel) Reduce() error {
|
|||||||
rm.addUniqueConstraint(e.Aggregate().ID, e.Aggregate().ID, user.NewAddUsernameUniqueConstraint(e.UserName, e.Aggregate().ResourceOwner, policy.UserLoginMustBeDomain))
|
rm.addUniqueConstraint(e.Aggregate().ID, e.Aggregate().ID, user.NewAddUsernameUniqueConstraint(e.UserName, e.Aggregate().ResourceOwner, policy.UserLoginMustBeDomain))
|
||||||
case *user.UserRemovedEvent:
|
case *user.UserRemovedEvent:
|
||||||
rm.removeUniqueConstraint(e.Aggregate().ID, e.Aggregate().ID, user.UniqueUsername)
|
rm.removeUniqueConstraint(e.Aggregate().ID, e.Aggregate().ID, user.UniqueUsername)
|
||||||
rm.listRemoveUniqueConstraint(e.Aggregate().ID, user.UniqueExternalIDPType)
|
rm.listRemoveUniqueConstraint(e.Aggregate().ID, user.UniqueUserIDPLinkType)
|
||||||
case *user.UsernameChangedEvent:
|
case *user.UsernameChangedEvent:
|
||||||
policy, err := rm.commandProvider.getOrgIAMPolicy(rm.ctx, e.Aggregate().ResourceOwner)
|
policy, err := rm.commandProvider.getOrgIAMPolicy(rm.ctx, e.Aggregate().ResourceOwner)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -146,12 +146,12 @@ func (rm *UniqueConstraintReadModel) Reduce() error {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
rm.changeUniqueConstraint(e.Aggregate().ID, e.Aggregate().ID, user.NewAddUsernameUniqueConstraint(e.UserName, e.Aggregate().ResourceOwner, policy.UserLoginMustBeDomain))
|
rm.changeUniqueConstraint(e.Aggregate().ID, e.Aggregate().ID, user.NewAddUsernameUniqueConstraint(e.UserName, e.Aggregate().ResourceOwner, policy.UserLoginMustBeDomain))
|
||||||
case *user.HumanExternalIDPAddedEvent:
|
case *user.UserIDPLinkAddedEvent:
|
||||||
rm.addUniqueConstraint(e.Aggregate().ID, e.IDPConfigID+e.ExternalUserID, user.NewAddExternalIDPUniqueConstraint(e.IDPConfigID, e.ExternalUserID))
|
rm.addUniqueConstraint(e.Aggregate().ID, e.IDPConfigID+e.ExternalUserID, user.NewAddUserIDPLinkUniqueConstraint(e.IDPConfigID, e.ExternalUserID))
|
||||||
case *user.HumanExternalIDPRemovedEvent:
|
case *user.UserIDPLinkRemovedEvent:
|
||||||
rm.removeUniqueConstraint(e.Aggregate().ID, e.IDPConfigID+e.ExternalUserID, user.UniqueExternalIDPType)
|
rm.removeUniqueConstraint(e.Aggregate().ID, e.IDPConfigID+e.ExternalUserID, user.UniqueUserIDPLinkType)
|
||||||
case *user.HumanExternalIDPCascadeRemovedEvent:
|
case *user.UserIDPLinkCascadeRemovedEvent:
|
||||||
rm.removeUniqueConstraint(e.Aggregate().ID, e.IDPConfigID+e.ExternalUserID, user.UniqueExternalIDPType)
|
rm.removeUniqueConstraint(e.Aggregate().ID, e.IDPConfigID+e.ExternalUserID, user.UniqueUserIDPLinkType)
|
||||||
case *usergrant.UserGrantAddedEvent:
|
case *usergrant.UserGrantAddedEvent:
|
||||||
rm.addUniqueConstraint(e.Aggregate().ID, e.Aggregate().ID, usergrant.NewAddUserGrantUniqueConstraint(e.Aggregate().ResourceOwner, e.UserID, e.ProjectID, e.ProjectGrantID))
|
rm.addUniqueConstraint(e.Aggregate().ID, e.Aggregate().ID, usergrant.NewAddUserGrantUniqueConstraint(e.Aggregate().ResourceOwner, e.UserID, e.ProjectID, e.ProjectGrantID))
|
||||||
case *usergrant.UserGrantRemovedEvent:
|
case *usergrant.UserGrantRemovedEvent:
|
||||||
@ -224,9 +224,9 @@ func (rm *UniqueConstraintReadModel) Query() *eventstore.SearchQueryBuilder {
|
|||||||
user.UserUserNameChangedType,
|
user.UserUserNameChangedType,
|
||||||
user.UserDomainClaimedType,
|
user.UserDomainClaimedType,
|
||||||
user.UserRemovedType,
|
user.UserRemovedType,
|
||||||
user.HumanExternalIDPAddedType,
|
user.UserIDPLinkAddedType,
|
||||||
user.HumanExternalIDPRemovedType,
|
user.UserIDPLinkRemovedType,
|
||||||
user.HumanExternalIDPCascadeRemovedType,
|
user.UserIDPLinkCascadeRemovedType,
|
||||||
usergrant.UserGrantAddedType,
|
usergrant.UserGrantAddedType,
|
||||||
usergrant.UserGrantRemovedType,
|
usergrant.UserGrantRemovedType,
|
||||||
usergrant.UserGrantCascadeRemovedType,
|
usergrant.UserGrantCascadeRemovedType,
|
||||||
|
@ -188,7 +188,7 @@ func (c *Commands) RemoveUser(ctx context.Context, userID, resourceOwner string,
|
|||||||
}
|
}
|
||||||
var events []eventstore.EventPusher
|
var events []eventstore.EventPusher
|
||||||
userAgg := UserAggregateFromWriteModel(&existingUser.WriteModel)
|
userAgg := UserAggregateFromWriteModel(&existingUser.WriteModel)
|
||||||
events = append(events, user.NewUserRemovedEvent(ctx, userAgg, existingUser.UserName, existingUser.ExternalIDPs, orgIAMPolicy.UserLoginMustBeDomain))
|
events = append(events, user.NewUserRemovedEvent(ctx, userAgg, existingUser.UserName, existingUser.IDPLinks, orgIAMPolicy.UserLoginMustBeDomain))
|
||||||
|
|
||||||
for _, grantID := range cascadingGrantIDs {
|
for _, grantID := range cascadingGrantIDs {
|
||||||
removeEvent, _, err := c.removeUserGrant(ctx, grantID, "", true)
|
removeEvent, _, err := c.removeUserGrant(ctx, grantID, "", true)
|
||||||
|
@ -117,7 +117,7 @@ func (c *Commands) importHuman(ctx context.Context, orgID string, human *domain.
|
|||||||
return events, humanWriteModel, passwordlessCodeWriteModel, code, nil
|
return events, humanWriteModel, passwordlessCodeWriteModel, code, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Commands) RegisterHuman(ctx context.Context, orgID string, human *domain.Human, externalIDP *domain.ExternalIDP, orgMemberRoles []string) (*domain.Human, error) {
|
func (c *Commands) RegisterHuman(ctx context.Context, orgID string, human *domain.Human, link *domain.UserIDPLink, orgMemberRoles []string) (*domain.Human, error) {
|
||||||
if orgID == "" {
|
if orgID == "" {
|
||||||
return nil, caos_errs.ThrowInvalidArgument(nil, "COMMAND-GEdf2", "Errors.ResourceOwnerMissing")
|
return nil, caos_errs.ThrowInvalidArgument(nil, "COMMAND-GEdf2", "Errors.ResourceOwnerMissing")
|
||||||
}
|
}
|
||||||
@ -129,7 +129,7 @@ func (c *Commands) RegisterHuman(ctx context.Context, orgID string, human *domai
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, caos_errs.ThrowPreconditionFailed(err, "COMMAND-M5Fsd", "Errors.Org.PasswordComplexity.NotFound")
|
return nil, caos_errs.ThrowPreconditionFailed(err, "COMMAND-M5Fsd", "Errors.Org.PasswordComplexity.NotFound")
|
||||||
}
|
}
|
||||||
userEvents, registeredHuman, err := c.registerHuman(ctx, orgID, human, externalIDP, orgIAMPolicy, pwPolicy)
|
userEvents, registeredHuman, err := c.registerHuman(ctx, orgID, human, link, orgIAMPolicy, pwPolicy)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -163,20 +163,20 @@ func (c *Commands) RegisterHuman(ctx context.Context, orgID string, human *domai
|
|||||||
return writeModelToHuman(registeredHuman), nil
|
return writeModelToHuman(registeredHuman), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Commands) registerHuman(ctx context.Context, orgID string, human *domain.Human, externalIDP *domain.ExternalIDP, orgIAMPolicy *domain.OrgIAMPolicy, pwPolicy *domain.PasswordComplexityPolicy) ([]eventstore.EventPusher, *HumanWriteModel, error) {
|
func (c *Commands) registerHuman(ctx context.Context, orgID string, human *domain.Human, link *domain.UserIDPLink, orgIAMPolicy *domain.OrgIAMPolicy, pwPolicy *domain.PasswordComplexityPolicy) ([]eventstore.EventPusher, *HumanWriteModel, error) {
|
||||||
if human != nil && human.Username == "" {
|
if human != nil && human.Username == "" {
|
||||||
human.Username = human.EmailAddress
|
human.Username = human.EmailAddress
|
||||||
}
|
}
|
||||||
if orgID == "" || !human.IsValid() || externalIDP == nil && (human.Password == nil || human.SecretString == "") {
|
if orgID == "" || !human.IsValid() || link == nil && (human.Password == nil || human.SecretString == "") {
|
||||||
return nil, nil, caos_errs.ThrowInvalidArgument(nil, "COMMAND-9dk45", "Errors.User.Invalid")
|
return nil, nil, caos_errs.ThrowInvalidArgument(nil, "COMMAND-9dk45", "Errors.User.Invalid")
|
||||||
}
|
}
|
||||||
if human.Password != nil && human.SecretString != "" {
|
if human.Password != nil && human.SecretString != "" {
|
||||||
human.ChangeRequired = false
|
human.ChangeRequired = false
|
||||||
}
|
}
|
||||||
return c.createHuman(ctx, orgID, human, externalIDP, true, false, orgIAMPolicy, pwPolicy)
|
return c.createHuman(ctx, orgID, human, link, true, false, orgIAMPolicy, pwPolicy)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Commands) createHuman(ctx context.Context, orgID string, human *domain.Human, externalIDP *domain.ExternalIDP, selfregister, passwordless bool, orgIAMPolicy *domain.OrgIAMPolicy, pwPolicy *domain.PasswordComplexityPolicy) ([]eventstore.EventPusher, *HumanWriteModel, error) {
|
func (c *Commands) createHuman(ctx context.Context, orgID string, human *domain.Human, link *domain.UserIDPLink, selfregister, passwordless bool, orgIAMPolicy *domain.OrgIAMPolicy, pwPolicy *domain.PasswordComplexityPolicy) ([]eventstore.EventPusher, *HumanWriteModel, error) {
|
||||||
if err := human.CheckOrgIAMPolicy(orgIAMPolicy); err != nil {
|
if err := human.CheckOrgIAMPolicy(orgIAMPolicy); err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
@ -216,15 +216,15 @@ func (c *Commands) createHuman(ctx context.Context, orgID string, human *domain.
|
|||||||
events = append(events, createAddHumanEvent(ctx, userAgg, human, orgIAMPolicy.UserLoginMustBeDomain))
|
events = append(events, createAddHumanEvent(ctx, userAgg, human, orgIAMPolicy.UserLoginMustBeDomain))
|
||||||
}
|
}
|
||||||
|
|
||||||
if externalIDP != nil {
|
if link != nil {
|
||||||
event, err := c.addHumanExternalIDP(ctx, userAgg, externalIDP)
|
event, err := c.addUserIDPLink(ctx, userAgg, link)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
events = append(events, event)
|
events = append(events, event)
|
||||||
}
|
}
|
||||||
|
|
||||||
if human.IsInitialState(passwordless, externalIDP != nil) {
|
if human.IsInitialState(passwordless, link != nil) {
|
||||||
initCode, err := domain.NewInitUserCode(c.initializeUserCode)
|
initCode, err := domain.NewInitUserCode(c.initializeUserCode)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
|
@ -1,116 +0,0 @@
|
|||||||
package command
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"github.com/caos/zitadel/internal/eventstore"
|
|
||||||
|
|
||||||
"github.com/caos/zitadel/internal/domain"
|
|
||||||
caos_errs "github.com/caos/zitadel/internal/errors"
|
|
||||||
"github.com/caos/zitadel/internal/repository/user"
|
|
||||||
"github.com/caos/zitadel/internal/telemetry/tracing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func (c *Commands) BulkAddedHumanExternalIDP(ctx context.Context, userID, resourceOwner string, externalIDPs []*domain.ExternalIDP) (err error) {
|
|
||||||
if userID == "" {
|
|
||||||
return caos_errs.ThrowInvalidArgument(nil, "COMMAND-03j8f", "Errors.IDMissing")
|
|
||||||
}
|
|
||||||
if len(externalIDPs) == 0 {
|
|
||||||
return caos_errs.ThrowInvalidArgument(nil, "COMMAND-Ek9s", "Errors.User.ExternalIDP.MinimumExternalIDPNeeded")
|
|
||||||
}
|
|
||||||
|
|
||||||
events := make([]eventstore.EventPusher, len(externalIDPs))
|
|
||||||
for i, externalIDP := range externalIDPs {
|
|
||||||
externalIDPWriteModel := NewHumanExternalIDPWriteModel(userID, externalIDP.IDPConfigID, externalIDP.ExternalUserID, resourceOwner)
|
|
||||||
userAgg := UserAggregateFromWriteModel(&externalIDPWriteModel.WriteModel)
|
|
||||||
|
|
||||||
events[i], err = c.addHumanExternalIDP(ctx, userAgg, externalIDP)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err = c.eventstore.PushEvents(ctx, events...)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Commands) addHumanExternalIDP(ctx context.Context, humanAgg *eventstore.Aggregate, externalIDP *domain.ExternalIDP) (eventstore.EventPusher, error) {
|
|
||||||
if externalIDP.AggregateID != "" && humanAgg.ID != externalIDP.AggregateID {
|
|
||||||
return nil, caos_errs.ThrowInvalidArgument(nil, "COMMAND-33M0g", "Errors.IDMissing")
|
|
||||||
}
|
|
||||||
if !externalIDP.IsValid() {
|
|
||||||
return nil, caos_errs.ThrowInvalidArgument(nil, "COMMAND-6m9Kd", "Errors.User.ExternalIDP.Invalid")
|
|
||||||
}
|
|
||||||
_, err := c.getOrgIDPConfigByID(ctx, externalIDP.IDPConfigID, humanAgg.ResourceOwner)
|
|
||||||
if caos_errs.IsNotFound(err) {
|
|
||||||
_, err = c.getIAMIDPConfigByID(ctx, externalIDP.IDPConfigID)
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
return nil, caos_errs.ThrowPreconditionFailed(err, "COMMAND-39nfs", "Errors.IDPConfig.NotExisting")
|
|
||||||
}
|
|
||||||
return user.NewHumanExternalIDPAddedEvent(ctx, humanAgg, externalIDP.IDPConfigID, externalIDP.DisplayName, externalIDP.ExternalUserID), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Commands) RemoveHumanExternalIDP(ctx context.Context, externalIDP *domain.ExternalIDP) (*domain.ObjectDetails, error) {
|
|
||||||
event, externalIDPWriteModel, err := c.removeHumanExternalIDP(ctx, externalIDP, false)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
pushedEvents, err := c.eventstore.PushEvents(ctx, event)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
err = AppendAndReduce(externalIDPWriteModel, pushedEvents...)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return writeModelToObjectDetails(&externalIDPWriteModel.WriteModel), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Commands) removeHumanExternalIDP(ctx context.Context, externalIDP *domain.ExternalIDP, cascade bool) (eventstore.EventPusher, *HumanExternalIDPWriteModel, error) {
|
|
||||||
if !externalIDP.IsValid() || externalIDP.AggregateID == "" {
|
|
||||||
return nil, nil, caos_errs.ThrowInvalidArgument(nil, "COMMAND-3M9ds", "Errors.IDMissing")
|
|
||||||
}
|
|
||||||
|
|
||||||
existingExternalIDP, err := c.externalIDPWriteModelByID(ctx, externalIDP.AggregateID, externalIDP.IDPConfigID, externalIDP.ExternalUserID, externalIDP.ResourceOwner)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
if existingExternalIDP.State == domain.ExternalIDPStateUnspecified || existingExternalIDP.State == domain.ExternalIDPStateRemoved {
|
|
||||||
return nil, nil, caos_errs.ThrowNotFound(nil, "COMMAND-1M9xR", "Errors.User.ExternalIDP.NotFound")
|
|
||||||
}
|
|
||||||
userAgg := UserAggregateFromWriteModel(&existingExternalIDP.WriteModel)
|
|
||||||
if cascade {
|
|
||||||
return user.NewHumanExternalIDPCascadeRemovedEvent(ctx, userAgg, externalIDP.IDPConfigID, externalIDP.ExternalUserID), existingExternalIDP, nil
|
|
||||||
}
|
|
||||||
return user.NewHumanExternalIDPRemovedEvent(ctx, userAgg, externalIDP.IDPConfigID, externalIDP.ExternalUserID), existingExternalIDP, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Commands) HumanExternalLoginChecked(ctx context.Context, orgID, userID string, authRequest *domain.AuthRequest) (err error) {
|
|
||||||
if userID == "" {
|
|
||||||
return caos_errs.ThrowInvalidArgument(nil, "COMMAND-5n8sM", "Errors.IDMissing")
|
|
||||||
}
|
|
||||||
|
|
||||||
existingHuman, err := c.getHumanWriteModelByID(ctx, userID, orgID)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if existingHuman.UserState == domain.UserStateUnspecified || existingHuman.UserState == domain.UserStateDeleted {
|
|
||||||
return caos_errs.ThrowPreconditionFailed(nil, "COMMAND-dn88J", "Errors.User.NotFound")
|
|
||||||
}
|
|
||||||
|
|
||||||
userAgg := UserAggregateFromWriteModel(&existingHuman.WriteModel)
|
|
||||||
_, err = c.eventstore.PushEvents(ctx, user.NewHumanExternalIDPCheckSucceededEvent(ctx, userAgg, authRequestDomainToAuthRequestInfo(authRequest)))
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Commands) externalIDPWriteModelByID(ctx context.Context, userID, idpConfigID, externalUserID, resourceOwner string) (writeModel *HumanExternalIDPWriteModel, err error) {
|
|
||||||
ctx, span := tracing.NewSpan(ctx)
|
|
||||||
defer func() { span.EndWithError(err) }()
|
|
||||||
|
|
||||||
writeModel = NewHumanExternalIDPWriteModel(userID, idpConfigID, externalUserID, resourceOwner)
|
|
||||||
err = c.eventstore.FilterToQueryReducer(ctx, writeModel)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return writeModel, nil
|
|
||||||
}
|
|
@ -1425,7 +1425,7 @@ func TestCommandSide_RegisterHuman(t *testing.T) {
|
|||||||
ctx context.Context
|
ctx context.Context
|
||||||
orgID string
|
orgID string
|
||||||
human *domain.Human
|
human *domain.Human
|
||||||
externalIDP *domain.ExternalIDP
|
link *domain.UserIDPLink
|
||||||
orgMemberRoles []string
|
orgMemberRoles []string
|
||||||
}
|
}
|
||||||
type res struct {
|
type res struct {
|
||||||
@ -2134,7 +2134,7 @@ func TestCommandSide_RegisterHuman(t *testing.T) {
|
|||||||
phoneVerificationCode: tt.fields.secretGenerator,
|
phoneVerificationCode: tt.fields.secretGenerator,
|
||||||
userPasswordAlg: tt.fields.userPasswordAlg,
|
userPasswordAlg: tt.fields.userPasswordAlg,
|
||||||
}
|
}
|
||||||
got, err := r.RegisterHuman(tt.args.ctx, tt.args.orgID, tt.args.human, tt.args.externalIDP, tt.args.orgMemberRoles)
|
got, err := r.RegisterHuman(tt.args.ctx, tt.args.orgID, tt.args.human, tt.args.link, tt.args.orgMemberRoles)
|
||||||
if tt.res.err == nil {
|
if tt.res.err == nil {
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
}
|
}
|
||||||
|
117
internal/command/user_idp_link.go
Normal file
117
internal/command/user_idp_link.go
Normal file
@ -0,0 +1,117 @@
|
|||||||
|
package command
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/caos/zitadel/internal/eventstore"
|
||||||
|
|
||||||
|
"github.com/caos/zitadel/internal/domain"
|
||||||
|
caos_errs "github.com/caos/zitadel/internal/errors"
|
||||||
|
"github.com/caos/zitadel/internal/repository/user"
|
||||||
|
"github.com/caos/zitadel/internal/telemetry/tracing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (c *Commands) BulkAddedUserIDPLinks(ctx context.Context, userID, resourceOwner string, links []*domain.UserIDPLink) (err error) {
|
||||||
|
if userID == "" {
|
||||||
|
return caos_errs.ThrowInvalidArgument(nil, "COMMAND-03j8f", "Errors.IDMissing")
|
||||||
|
}
|
||||||
|
if len(links) == 0 {
|
||||||
|
return caos_errs.ThrowInvalidArgument(nil, "COMMAND-Ek9s", "Errors.User.ExternalIDP.MinimumExternalIDPNeeded")
|
||||||
|
}
|
||||||
|
|
||||||
|
events := make([]eventstore.EventPusher, len(links))
|
||||||
|
for i, link := range links {
|
||||||
|
linkWriteModel := NewUserIDPLinkWriteModel(userID, link.IDPConfigID, link.ExternalUserID, resourceOwner)
|
||||||
|
userAgg := UserAggregateFromWriteModel(&linkWriteModel.WriteModel)
|
||||||
|
|
||||||
|
events[i], err = c.addUserIDPLink(ctx, userAgg, link)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = c.eventstore.PushEvents(ctx, events...)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Commands) addUserIDPLink(ctx context.Context, human *eventstore.Aggregate, link *domain.UserIDPLink) (eventstore.EventPusher, error) {
|
||||||
|
if link.AggregateID != "" && human.ID != link.AggregateID {
|
||||||
|
return nil, caos_errs.ThrowInvalidArgument(nil, "COMMAND-33M0g", "Errors.IDMissing")
|
||||||
|
}
|
||||||
|
if !link.IsValid() {
|
||||||
|
return nil, caos_errs.ThrowInvalidArgument(nil, "COMMAND-6m9Kd", "Errors.User.ExternalIDP.Invalid")
|
||||||
|
}
|
||||||
|
_, err := c.getOrgIDPConfigByID(ctx, link.IDPConfigID, human.ResourceOwner)
|
||||||
|
if caos_errs.IsNotFound(err) {
|
||||||
|
_, err = c.getIAMIDPConfigByID(ctx, link.IDPConfigID)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return nil, caos_errs.ThrowPreconditionFailed(err, "COMMAND-39nfs", "Errors.IDPConfig.NotExisting")
|
||||||
|
}
|
||||||
|
return user.NewUserIDPLinkAddedEvent(ctx, human, link.IDPConfigID, link.DisplayName, link.ExternalUserID), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Commands) RemoveUserIDPLink(ctx context.Context, link *domain.UserIDPLink) (*domain.ObjectDetails, error) {
|
||||||
|
event, linkWriteModel, err := c.removeUserIDPLink(ctx, link, false)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
pushedEvents, err := c.eventstore.PushEvents(ctx, event)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
err = AppendAndReduce(linkWriteModel, pushedEvents...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return writeModelToObjectDetails(&linkWriteModel.WriteModel), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Commands) removeUserIDPLink(ctx context.Context, link *domain.UserIDPLink, cascade bool) (eventstore.EventPusher, *UserIDPLinkWriteModel, error) {
|
||||||
|
if !link.IsValid() || link.AggregateID == "" {
|
||||||
|
return nil, nil, caos_errs.ThrowInvalidArgument(nil, "COMMAND-3M9ds", "Errors.IDMissing")
|
||||||
|
}
|
||||||
|
|
||||||
|
existingLink, err := c.userIDPLinkWriteModelByID(ctx, link.AggregateID, link.IDPConfigID, link.ExternalUserID, link.ResourceOwner)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
if existingLink.State == domain.UserIDPLinkStateUnspecified || existingLink.State == domain.UserIDPLinkStateRemoved {
|
||||||
|
return nil, nil, caos_errs.ThrowNotFound(nil, "COMMAND-1M9xR", "Errors.User.ExternalIDP.NotFound")
|
||||||
|
}
|
||||||
|
userAgg := UserAggregateFromWriteModel(&existingLink.WriteModel)
|
||||||
|
if cascade {
|
||||||
|
return user.NewUserIDPLinkCascadeRemovedEvent(ctx, userAgg, link.IDPConfigID, link.ExternalUserID), existingLink, nil
|
||||||
|
}
|
||||||
|
return user.NewUserIDPLinkRemovedEvent(ctx, userAgg, link.IDPConfigID, link.ExternalUserID), existingLink, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Commands) UserIDPLoginChecked(ctx context.Context, orgID, userID string, authRequest *domain.AuthRequest) (err error) {
|
||||||
|
if userID == "" {
|
||||||
|
return caos_errs.ThrowInvalidArgument(nil, "COMMAND-5n8sM", "Errors.IDMissing")
|
||||||
|
}
|
||||||
|
|
||||||
|
existingHuman, err := c.getHumanWriteModelByID(ctx, userID, orgID)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if existingHuman.UserState == domain.UserStateUnspecified || existingHuman.UserState == domain.UserStateDeleted {
|
||||||
|
return caos_errs.ThrowPreconditionFailed(nil, "COMMAND-dn88J", "Errors.User.NotFound")
|
||||||
|
}
|
||||||
|
|
||||||
|
userAgg := UserAggregateFromWriteModel(&existingHuman.WriteModel)
|
||||||
|
_, err = c.eventstore.PushEvents(ctx, user.NewUserIDPCheckSucceededEvent(ctx, userAgg, authRequestDomainToAuthRequestInfo(authRequest)))
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Commands) userIDPLinkWriteModelByID(ctx context.Context, userID, idpConfigID, externalUserID, resourceOwner string) (writeModel *UserIDPLinkWriteModel, err error) {
|
||||||
|
ctx, span := tracing.NewSpan(ctx)
|
||||||
|
defer func() { span.EndWithError(err) }()
|
||||||
|
|
||||||
|
writeModel = NewUserIDPLinkWriteModel(userID, idpConfigID, externalUserID, resourceOwner)
|
||||||
|
err = c.eventstore.FilterToQueryReducer(ctx, writeModel)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return writeModel, nil
|
||||||
|
}
|
@ -6,18 +6,18 @@ import (
|
|||||||
"github.com/caos/zitadel/internal/repository/user"
|
"github.com/caos/zitadel/internal/repository/user"
|
||||||
)
|
)
|
||||||
|
|
||||||
type HumanExternalIDPWriteModel struct {
|
type UserIDPLinkWriteModel struct {
|
||||||
eventstore.WriteModel
|
eventstore.WriteModel
|
||||||
|
|
||||||
IDPConfigID string
|
IDPConfigID string
|
||||||
ExternalUserID string
|
ExternalUserID string
|
||||||
DisplayName string
|
DisplayName string
|
||||||
|
|
||||||
State domain.ExternalIDPState
|
State domain.UserIDPLinkState
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewHumanExternalIDPWriteModel(userID, idpConfigID, externalUserID, resourceOwner string) *HumanExternalIDPWriteModel {
|
func NewUserIDPLinkWriteModel(userID, idpConfigID, externalUserID, resourceOwner string) *UserIDPLinkWriteModel {
|
||||||
return &HumanExternalIDPWriteModel{
|
return &UserIDPLinkWriteModel{
|
||||||
WriteModel: eventstore.WriteModel{
|
WriteModel: eventstore.WriteModel{
|
||||||
AggregateID: userID,
|
AggregateID: userID,
|
||||||
ResourceOwner: resourceOwner,
|
ResourceOwner: resourceOwner,
|
||||||
@ -27,20 +27,20 @@ func NewHumanExternalIDPWriteModel(userID, idpConfigID, externalUserID, resource
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (wm *HumanExternalIDPWriteModel) AppendEvents(events ...eventstore.EventReader) {
|
func (wm *UserIDPLinkWriteModel) AppendEvents(events ...eventstore.EventReader) {
|
||||||
for _, event := range events {
|
for _, event := range events {
|
||||||
switch e := event.(type) {
|
switch e := event.(type) {
|
||||||
case *user.HumanExternalIDPAddedEvent:
|
case *user.UserIDPLinkAddedEvent:
|
||||||
if e.IDPConfigID != wm.IDPConfigID && e.ExternalUserID != wm.ExternalUserID {
|
if e.IDPConfigID != wm.IDPConfigID && e.ExternalUserID != wm.ExternalUserID {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
wm.WriteModel.AppendEvents(e)
|
wm.WriteModel.AppendEvents(e)
|
||||||
case *user.HumanExternalIDPRemovedEvent:
|
case *user.UserIDPLinkRemovedEvent:
|
||||||
if e.IDPConfigID != wm.IDPConfigID && e.ExternalUserID != wm.ExternalUserID {
|
if e.IDPConfigID != wm.IDPConfigID && e.ExternalUserID != wm.ExternalUserID {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
wm.WriteModel.AppendEvents(e)
|
wm.WriteModel.AppendEvents(e)
|
||||||
case *user.HumanExternalIDPCascadeRemovedEvent:
|
case *user.UserIDPLinkCascadeRemovedEvent:
|
||||||
if e.IDPConfigID != wm.IDPConfigID && e.ExternalUserID != wm.ExternalUserID {
|
if e.IDPConfigID != wm.IDPConfigID && e.ExternalUserID != wm.ExternalUserID {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@ -51,34 +51,34 @@ func (wm *HumanExternalIDPWriteModel) AppendEvents(events ...eventstore.EventRea
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (wm *HumanExternalIDPWriteModel) Reduce() error {
|
func (wm *UserIDPLinkWriteModel) Reduce() error {
|
||||||
for _, event := range wm.Events {
|
for _, event := range wm.Events {
|
||||||
switch e := event.(type) {
|
switch e := event.(type) {
|
||||||
case *user.HumanExternalIDPAddedEvent:
|
case *user.UserIDPLinkAddedEvent:
|
||||||
wm.IDPConfigID = e.IDPConfigID
|
wm.IDPConfigID = e.IDPConfigID
|
||||||
wm.DisplayName = e.DisplayName
|
wm.DisplayName = e.DisplayName
|
||||||
wm.ExternalUserID = e.ExternalUserID
|
wm.ExternalUserID = e.ExternalUserID
|
||||||
wm.State = domain.ExternalIDPStateActive
|
wm.State = domain.UserIDPLinkStateActive
|
||||||
case *user.HumanExternalIDPRemovedEvent:
|
case *user.UserIDPLinkRemovedEvent:
|
||||||
wm.State = domain.ExternalIDPStateRemoved
|
wm.State = domain.UserIDPLinkStateRemoved
|
||||||
case *user.HumanExternalIDPCascadeRemovedEvent:
|
case *user.UserIDPLinkCascadeRemovedEvent:
|
||||||
wm.State = domain.ExternalIDPStateRemoved
|
wm.State = domain.UserIDPLinkStateRemoved
|
||||||
case *user.UserRemovedEvent:
|
case *user.UserRemovedEvent:
|
||||||
wm.State = domain.ExternalIDPStateRemoved
|
wm.State = domain.UserIDPLinkStateRemoved
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return wm.WriteModel.Reduce()
|
return wm.WriteModel.Reduce()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (wm *HumanExternalIDPWriteModel) Query() *eventstore.SearchQueryBuilder {
|
func (wm *UserIDPLinkWriteModel) Query() *eventstore.SearchQueryBuilder {
|
||||||
return eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent).
|
return eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent).
|
||||||
ResourceOwner(wm.ResourceOwner).
|
ResourceOwner(wm.ResourceOwner).
|
||||||
AddQuery().
|
AddQuery().
|
||||||
AggregateTypes(user.AggregateType).
|
AggregateTypes(user.AggregateType).
|
||||||
AggregateIDs(wm.AggregateID).
|
AggregateIDs(wm.AggregateID).
|
||||||
EventTypes(user.HumanExternalIDPAddedType,
|
EventTypes(user.UserIDPLinkAddedType,
|
||||||
user.HumanExternalIDPRemovedType,
|
user.UserIDPLinkRemovedType,
|
||||||
user.HumanExternalIDPCascadeRemovedType,
|
user.UserIDPLinkCascadeRemovedType,
|
||||||
user.UserRemovedType).
|
user.UserRemovedType).
|
||||||
Builder()
|
Builder()
|
||||||
}
|
}
|
@ -17,7 +17,7 @@ import (
|
|||||||
"github.com/caos/zitadel/internal/repository/user"
|
"github.com/caos/zitadel/internal/repository/user"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestCommandSide_BulkAddExternalIDPs(t *testing.T) {
|
func TestCommandSide_BulkAddUserIDPLinks(t *testing.T) {
|
||||||
type fields struct {
|
type fields struct {
|
||||||
eventstore *eventstore.Eventstore
|
eventstore *eventstore.Eventstore
|
||||||
}
|
}
|
||||||
@ -25,7 +25,7 @@ func TestCommandSide_BulkAddExternalIDPs(t *testing.T) {
|
|||||||
ctx context.Context
|
ctx context.Context
|
||||||
userID string
|
userID string
|
||||||
resourceOwner string
|
resourceOwner string
|
||||||
externalIDPs []*domain.ExternalIDP
|
links []*domain.UserIDPLink
|
||||||
}
|
}
|
||||||
type res struct {
|
type res struct {
|
||||||
err func(error) bool
|
err func(error) bool
|
||||||
@ -46,7 +46,7 @@ func TestCommandSide_BulkAddExternalIDPs(t *testing.T) {
|
|||||||
args: args{
|
args: args{
|
||||||
ctx: context.Background(),
|
ctx: context.Background(),
|
||||||
userID: "",
|
userID: "",
|
||||||
externalIDPs: []*domain.ExternalIDP{
|
links: []*domain.UserIDPLink{
|
||||||
{
|
{
|
||||||
IDPConfigID: "config1",
|
IDPConfigID: "config1",
|
||||||
ExternalUserID: "externaluser1",
|
ExternalUserID: "externaluser1",
|
||||||
@ -85,7 +85,7 @@ func TestCommandSide_BulkAddExternalIDPs(t *testing.T) {
|
|||||||
ctx: context.Background(),
|
ctx: context.Background(),
|
||||||
userID: "user1",
|
userID: "user1",
|
||||||
resourceOwner: "org1",
|
resourceOwner: "org1",
|
||||||
externalIDPs: []*domain.ExternalIDP{
|
links: []*domain.UserIDPLink{
|
||||||
{
|
{
|
||||||
ObjectRoot: models.ObjectRoot{
|
ObjectRoot: models.ObjectRoot{
|
||||||
AggregateID: "user2",
|
AggregateID: "user2",
|
||||||
@ -110,7 +110,7 @@ func TestCommandSide_BulkAddExternalIDPs(t *testing.T) {
|
|||||||
ctx: context.Background(),
|
ctx: context.Background(),
|
||||||
userID: "user1",
|
userID: "user1",
|
||||||
resourceOwner: "org1",
|
resourceOwner: "org1",
|
||||||
externalIDPs: []*domain.ExternalIDP{
|
links: []*domain.UserIDPLink{
|
||||||
{
|
{
|
||||||
ObjectRoot: models.ObjectRoot{
|
ObjectRoot: models.ObjectRoot{
|
||||||
AggregateID: "user1",
|
AggregateID: "user1",
|
||||||
@ -137,7 +137,7 @@ func TestCommandSide_BulkAddExternalIDPs(t *testing.T) {
|
|||||||
ctx: context.Background(),
|
ctx: context.Background(),
|
||||||
userID: "user1",
|
userID: "user1",
|
||||||
resourceOwner: "org1",
|
resourceOwner: "org1",
|
||||||
externalIDPs: []*domain.ExternalIDP{
|
links: []*domain.UserIDPLink{
|
||||||
{
|
{
|
||||||
ObjectRoot: models.ObjectRoot{
|
ObjectRoot: models.ObjectRoot{
|
||||||
AggregateID: "user1",
|
AggregateID: "user1",
|
||||||
@ -171,7 +171,7 @@ func TestCommandSide_BulkAddExternalIDPs(t *testing.T) {
|
|||||||
expectPush(
|
expectPush(
|
||||||
[]*repository.Event{
|
[]*repository.Event{
|
||||||
eventFromEventPusher(
|
eventFromEventPusher(
|
||||||
user.NewHumanExternalIDPAddedEvent(context.Background(),
|
user.NewUserIDPLinkAddedEvent(context.Background(),
|
||||||
&user.NewAggregate("user1", "org1").Aggregate,
|
&user.NewAggregate("user1", "org1").Aggregate,
|
||||||
"config1",
|
"config1",
|
||||||
"name",
|
"name",
|
||||||
@ -179,7 +179,7 @@ func TestCommandSide_BulkAddExternalIDPs(t *testing.T) {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
uniqueConstraintsFromEventConstraint(user.NewAddExternalIDPUniqueConstraint("config1", "externaluser1")),
|
uniqueConstraintsFromEventConstraint(user.NewAddUserIDPLinkUniqueConstraint("config1", "externaluser1")),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
@ -187,7 +187,7 @@ func TestCommandSide_BulkAddExternalIDPs(t *testing.T) {
|
|||||||
ctx: context.Background(),
|
ctx: context.Background(),
|
||||||
userID: "user1",
|
userID: "user1",
|
||||||
resourceOwner: "org1",
|
resourceOwner: "org1",
|
||||||
externalIDPs: []*domain.ExternalIDP{
|
links: []*domain.UserIDPLink{
|
||||||
{
|
{
|
||||||
ObjectRoot: models.ObjectRoot{
|
ObjectRoot: models.ObjectRoot{
|
||||||
AggregateID: "user1",
|
AggregateID: "user1",
|
||||||
@ -221,7 +221,7 @@ func TestCommandSide_BulkAddExternalIDPs(t *testing.T) {
|
|||||||
expectPush(
|
expectPush(
|
||||||
[]*repository.Event{
|
[]*repository.Event{
|
||||||
eventFromEventPusher(
|
eventFromEventPusher(
|
||||||
user.NewHumanExternalIDPAddedEvent(context.Background(),
|
user.NewUserIDPLinkAddedEvent(context.Background(),
|
||||||
&user.NewAggregate("user1", "org1").Aggregate,
|
&user.NewAggregate("user1", "org1").Aggregate,
|
||||||
"config1",
|
"config1",
|
||||||
"name",
|
"name",
|
||||||
@ -229,7 +229,7 @@ func TestCommandSide_BulkAddExternalIDPs(t *testing.T) {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
uniqueConstraintsFromEventConstraint(user.NewAddExternalIDPUniqueConstraint("config1", "externaluser1")),
|
uniqueConstraintsFromEventConstraint(user.NewAddUserIDPLinkUniqueConstraint("config1", "externaluser1")),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
@ -237,7 +237,7 @@ func TestCommandSide_BulkAddExternalIDPs(t *testing.T) {
|
|||||||
ctx: context.Background(),
|
ctx: context.Background(),
|
||||||
userID: "user1",
|
userID: "user1",
|
||||||
resourceOwner: "org1",
|
resourceOwner: "org1",
|
||||||
externalIDPs: []*domain.ExternalIDP{
|
links: []*domain.UserIDPLink{
|
||||||
{
|
{
|
||||||
ObjectRoot: models.ObjectRoot{
|
ObjectRoot: models.ObjectRoot{
|
||||||
AggregateID: "user1",
|
AggregateID: "user1",
|
||||||
@ -256,7 +256,7 @@ func TestCommandSide_BulkAddExternalIDPs(t *testing.T) {
|
|||||||
r := &Commands{
|
r := &Commands{
|
||||||
eventstore: tt.fields.eventstore,
|
eventstore: tt.fields.eventstore,
|
||||||
}
|
}
|
||||||
err := r.BulkAddedHumanExternalIDP(tt.args.ctx, tt.args.userID, tt.args.resourceOwner, tt.args.externalIDPs)
|
err := r.BulkAddedUserIDPLinks(tt.args.ctx, tt.args.userID, tt.args.resourceOwner, tt.args.links)
|
||||||
if tt.res.err == nil {
|
if tt.res.err == nil {
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
}
|
}
|
||||||
@ -267,13 +267,13 @@ func TestCommandSide_BulkAddExternalIDPs(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCommandSide_RemoveExternalIDP(t *testing.T) {
|
func TestCommandSide_RemoveUserIDPLink(t *testing.T) {
|
||||||
type fields struct {
|
type fields struct {
|
||||||
eventstore *eventstore.Eventstore
|
eventstore *eventstore.Eventstore
|
||||||
}
|
}
|
||||||
type args struct {
|
type args struct {
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
externalIDP *domain.ExternalIDP
|
link *domain.UserIDPLink
|
||||||
}
|
}
|
||||||
type res struct {
|
type res struct {
|
||||||
want *domain.ObjectDetails
|
want *domain.ObjectDetails
|
||||||
@ -294,7 +294,7 @@ func TestCommandSide_RemoveExternalIDP(t *testing.T) {
|
|||||||
},
|
},
|
||||||
args: args{
|
args: args{
|
||||||
ctx: context.Background(),
|
ctx: context.Background(),
|
||||||
externalIDP: &domain.ExternalIDP{
|
link: &domain.UserIDPLink{
|
||||||
ObjectRoot: models.ObjectRoot{
|
ObjectRoot: models.ObjectRoot{
|
||||||
AggregateID: "user1",
|
AggregateID: "user1",
|
||||||
},
|
},
|
||||||
@ -315,7 +315,7 @@ func TestCommandSide_RemoveExternalIDP(t *testing.T) {
|
|||||||
},
|
},
|
||||||
args: args{
|
args: args{
|
||||||
ctx: context.Background(),
|
ctx: context.Background(),
|
||||||
externalIDP: &domain.ExternalIDP{
|
link: &domain.UserIDPLink{
|
||||||
IDPConfigID: "config1",
|
IDPConfigID: "config1",
|
||||||
ExternalUserID: "externaluser1",
|
ExternalUserID: "externaluser1",
|
||||||
},
|
},
|
||||||
@ -331,7 +331,7 @@ func TestCommandSide_RemoveExternalIDP(t *testing.T) {
|
|||||||
t,
|
t,
|
||||||
expectFilter(
|
expectFilter(
|
||||||
eventFromEventPusher(
|
eventFromEventPusher(
|
||||||
user.NewHumanExternalIDPAddedEvent(context.Background(),
|
user.NewUserIDPLinkAddedEvent(context.Background(),
|
||||||
&user.NewAggregate("user1", "org1").Aggregate,
|
&user.NewAggregate("user1", "org1").Aggregate,
|
||||||
"config1",
|
"config1",
|
||||||
"name",
|
"name",
|
||||||
@ -351,7 +351,7 @@ func TestCommandSide_RemoveExternalIDP(t *testing.T) {
|
|||||||
},
|
},
|
||||||
args: args{
|
args: args{
|
||||||
ctx: context.Background(),
|
ctx: context.Background(),
|
||||||
externalIDP: &domain.ExternalIDP{
|
link: &domain.UserIDPLink{
|
||||||
ObjectRoot: models.ObjectRoot{
|
ObjectRoot: models.ObjectRoot{
|
||||||
AggregateID: "user1",
|
AggregateID: "user1",
|
||||||
},
|
},
|
||||||
@ -373,7 +373,7 @@ func TestCommandSide_RemoveExternalIDP(t *testing.T) {
|
|||||||
},
|
},
|
||||||
args: args{
|
args: args{
|
||||||
ctx: context.Background(),
|
ctx: context.Background(),
|
||||||
externalIDP: &domain.ExternalIDP{
|
link: &domain.UserIDPLink{
|
||||||
ObjectRoot: models.ObjectRoot{
|
ObjectRoot: models.ObjectRoot{
|
||||||
AggregateID: "user1",
|
AggregateID: "user1",
|
||||||
},
|
},
|
||||||
@ -392,7 +392,7 @@ func TestCommandSide_RemoveExternalIDP(t *testing.T) {
|
|||||||
t,
|
t,
|
||||||
expectFilter(
|
expectFilter(
|
||||||
eventFromEventPusher(
|
eventFromEventPusher(
|
||||||
user.NewHumanExternalIDPAddedEvent(context.Background(),
|
user.NewUserIDPLinkAddedEvent(context.Background(),
|
||||||
&user.NewAggregate("user1", "org1").Aggregate,
|
&user.NewAggregate("user1", "org1").Aggregate,
|
||||||
"config1",
|
"config1",
|
||||||
"name",
|
"name",
|
||||||
@ -403,20 +403,20 @@ func TestCommandSide_RemoveExternalIDP(t *testing.T) {
|
|||||||
expectPush(
|
expectPush(
|
||||||
[]*repository.Event{
|
[]*repository.Event{
|
||||||
eventFromEventPusher(
|
eventFromEventPusher(
|
||||||
user.NewHumanExternalIDPRemovedEvent(context.Background(),
|
user.NewUserIDPLinkRemovedEvent(context.Background(),
|
||||||
&user.NewAggregate("user1", "org1").Aggregate,
|
&user.NewAggregate("user1", "org1").Aggregate,
|
||||||
"config1",
|
"config1",
|
||||||
"externaluser1",
|
"externaluser1",
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
uniqueConstraintsFromEventConstraint(user.NewRemoveExternalIDPUniqueConstraint("config1", "externaluser1")),
|
uniqueConstraintsFromEventConstraint(user.NewRemoveUserIDPLinkUniqueConstraint("config1", "externaluser1")),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
args: args{
|
args: args{
|
||||||
ctx: context.Background(),
|
ctx: context.Background(),
|
||||||
externalIDP: &domain.ExternalIDP{
|
link: &domain.UserIDPLink{
|
||||||
ObjectRoot: models.ObjectRoot{
|
ObjectRoot: models.ObjectRoot{
|
||||||
AggregateID: "user1",
|
AggregateID: "user1",
|
||||||
},
|
},
|
||||||
@ -436,7 +436,7 @@ func TestCommandSide_RemoveExternalIDP(t *testing.T) {
|
|||||||
r := &Commands{
|
r := &Commands{
|
||||||
eventstore: tt.fields.eventstore,
|
eventstore: tt.fields.eventstore,
|
||||||
}
|
}
|
||||||
got, err := r.RemoveHumanExternalIDP(tt.args.ctx, tt.args.externalIDP)
|
got, err := r.RemoveUserIDPLink(tt.args.ctx, tt.args.link)
|
||||||
if tt.res.err == nil {
|
if tt.res.err == nil {
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
}
|
}
|
||||||
@ -492,7 +492,7 @@ func TestCommandSide_ExternalLoginCheck(t *testing.T) {
|
|||||||
t,
|
t,
|
||||||
expectFilter(
|
expectFilter(
|
||||||
eventFromEventPusher(
|
eventFromEventPusher(
|
||||||
user.NewHumanExternalIDPAddedEvent(context.Background(),
|
user.NewUserIDPLinkAddedEvent(context.Background(),
|
||||||
&user.NewAggregate("user1", "org1").Aggregate,
|
&user.NewAggregate("user1", "org1").Aggregate,
|
||||||
"config1",
|
"config1",
|
||||||
"name",
|
"name",
|
||||||
@ -543,7 +543,7 @@ func TestCommandSide_ExternalLoginCheck(t *testing.T) {
|
|||||||
expectPush(
|
expectPush(
|
||||||
[]*repository.Event{
|
[]*repository.Event{
|
||||||
eventFromEventPusher(
|
eventFromEventPusher(
|
||||||
user.NewHumanExternalIDPCheckSucceededEvent(context.Background(),
|
user.NewUserIDPCheckSucceededEvent(context.Background(),
|
||||||
&user.NewAggregate("user1", "org1").Aggregate,
|
&user.NewAggregate("user1", "org1").Aggregate,
|
||||||
&user.AuthRequestInfo{
|
&user.AuthRequestInfo{
|
||||||
ID: "request1",
|
ID: "request1",
|
||||||
@ -574,7 +574,7 @@ func TestCommandSide_ExternalLoginCheck(t *testing.T) {
|
|||||||
r := &Commands{
|
r := &Commands{
|
||||||
eventstore: tt.fields.eventstore,
|
eventstore: tt.fields.eventstore,
|
||||||
}
|
}
|
||||||
err := r.HumanExternalLoginChecked(tt.args.ctx, tt.args.orgID, tt.args.userID, tt.args.authRequest)
|
err := r.UserIDPLoginChecked(tt.args.ctx, tt.args.orgID, tt.args.userID, tt.args.authRequest)
|
||||||
if tt.res.err == nil {
|
if tt.res.err == nil {
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
}
|
}
|
@ -13,9 +13,9 @@ import (
|
|||||||
type UserWriteModel struct {
|
type UserWriteModel struct {
|
||||||
eventstore.WriteModel
|
eventstore.WriteModel
|
||||||
|
|
||||||
UserName string
|
UserName string
|
||||||
ExternalIDPs []*domain.ExternalIDP
|
IDPLinks []*domain.UserIDPLink
|
||||||
UserState domain.UserState
|
UserState domain.UserState
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewUserWriteModel(userID, resourceOwner string) *UserWriteModel {
|
func NewUserWriteModel(userID, resourceOwner string) *UserWriteModel {
|
||||||
@ -24,7 +24,7 @@ func NewUserWriteModel(userID, resourceOwner string) *UserWriteModel {
|
|||||||
AggregateID: userID,
|
AggregateID: userID,
|
||||||
ResourceOwner: resourceOwner,
|
ResourceOwner: resourceOwner,
|
||||||
},
|
},
|
||||||
ExternalIDPs: make([]*domain.ExternalIDP, 0),
|
IDPLinks: make([]*domain.UserIDPLink, 0),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -41,24 +41,24 @@ func (wm *UserWriteModel) Reduce() error {
|
|||||||
wm.UserState = domain.UserStateInitial
|
wm.UserState = domain.UserStateInitial
|
||||||
case *user.HumanInitializedCheckSucceededEvent:
|
case *user.HumanInitializedCheckSucceededEvent:
|
||||||
wm.UserState = domain.UserStateActive
|
wm.UserState = domain.UserStateActive
|
||||||
case *user.HumanExternalIDPAddedEvent:
|
case *user.UserIDPLinkAddedEvent:
|
||||||
wm.ExternalIDPs = append(wm.ExternalIDPs, &domain.ExternalIDP{IDPConfigID: e.IDPConfigID, ExternalUserID: e.ExternalUserID})
|
wm.IDPLinks = append(wm.IDPLinks, &domain.UserIDPLink{IDPConfigID: e.IDPConfigID, ExternalUserID: e.ExternalUserID})
|
||||||
case *user.HumanExternalIDPRemovedEvent:
|
case *user.UserIDPLinkRemovedEvent:
|
||||||
idx, _ := wm.ExternalIDPByID(e.IDPConfigID, e.ExternalUserID)
|
idx, _ := wm.IDPLinkByID(e.IDPConfigID, e.ExternalUserID)
|
||||||
if idx < 0 {
|
if idx < 0 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
copy(wm.ExternalIDPs[idx:], wm.ExternalIDPs[idx+1:])
|
copy(wm.IDPLinks[idx:], wm.IDPLinks[idx+1:])
|
||||||
wm.ExternalIDPs[len(wm.ExternalIDPs)-1] = nil
|
wm.IDPLinks[len(wm.IDPLinks)-1] = nil
|
||||||
wm.ExternalIDPs = wm.ExternalIDPs[:len(wm.ExternalIDPs)-1]
|
wm.IDPLinks = wm.IDPLinks[:len(wm.IDPLinks)-1]
|
||||||
case *user.HumanExternalIDPCascadeRemovedEvent:
|
case *user.UserIDPLinkCascadeRemovedEvent:
|
||||||
idx, _ := wm.ExternalIDPByID(e.IDPConfigID, e.ExternalUserID)
|
idx, _ := wm.IDPLinkByID(e.IDPConfigID, e.ExternalUserID)
|
||||||
if idx < 0 {
|
if idx < 0 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
copy(wm.ExternalIDPs[idx:], wm.ExternalIDPs[idx+1:])
|
copy(wm.IDPLinks[idx:], wm.IDPLinks[idx+1:])
|
||||||
wm.ExternalIDPs[len(wm.ExternalIDPs)-1] = nil
|
wm.IDPLinks[len(wm.IDPLinks)-1] = nil
|
||||||
wm.ExternalIDPs = wm.ExternalIDPs[:len(wm.ExternalIDPs)-1]
|
wm.IDPLinks = wm.IDPLinks[:len(wm.IDPLinks)-1]
|
||||||
case *user.MachineAddedEvent:
|
case *user.MachineAddedEvent:
|
||||||
wm.UserName = e.UserName
|
wm.UserName = e.UserName
|
||||||
wm.UserState = domain.UserStateActive
|
wm.UserState = domain.UserStateActive
|
||||||
@ -96,9 +96,9 @@ func (wm *UserWriteModel) Query() *eventstore.SearchQueryBuilder {
|
|||||||
user.HumanAddedType,
|
user.HumanAddedType,
|
||||||
user.HumanRegisteredType,
|
user.HumanRegisteredType,
|
||||||
user.HumanInitializedCheckSucceededType,
|
user.HumanInitializedCheckSucceededType,
|
||||||
user.HumanExternalIDPAddedType,
|
user.UserIDPLinkAddedType,
|
||||||
user.HumanExternalIDPRemovedType,
|
user.UserIDPLinkRemovedType,
|
||||||
user.HumanExternalIDPCascadeRemovedType,
|
user.UserIDPLinkCascadeRemovedType,
|
||||||
user.MachineAddedEventType,
|
user.MachineAddedEventType,
|
||||||
user.UserUserNameChangedType,
|
user.UserUserNameChangedType,
|
||||||
user.MachineChangedEventType,
|
user.MachineChangedEventType,
|
||||||
@ -149,8 +149,8 @@ func hasUserState(check domain.UserState, states ...domain.UserState) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (wm *UserWriteModel) ExternalIDPByID(idpID, externalUserID string) (idx int, idp *domain.ExternalIDP) {
|
func (wm *UserWriteModel) IDPLinkByID(idpID, externalUserID string) (idx int, idp *domain.UserIDPLink) {
|
||||||
for idx, idp = range wm.ExternalIDPs {
|
for idx, idp = range wm.IDPLinks {
|
||||||
if idp.IDPConfigID == idpID && idp.ExternalUserID == externalUserID {
|
if idp.IDPConfigID == idpID && idp.ExternalUserID == externalUserID {
|
||||||
return idx, idp
|
return idx, idp
|
||||||
}
|
}
|
||||||
|
@ -1078,7 +1078,7 @@ func TestCommandSide_RemoveUser(t *testing.T) {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
eventFromEventPusher(
|
eventFromEventPusher(
|
||||||
user.NewHumanExternalIDPAddedEvent(context.Background(),
|
user.NewUserIDPLinkAddedEvent(context.Background(),
|
||||||
&user.NewAggregate("user1", "org1").Aggregate,
|
&user.NewAggregate("user1", "org1").Aggregate,
|
||||||
"idpConfigID",
|
"idpConfigID",
|
||||||
"displayName",
|
"displayName",
|
||||||
@ -1107,7 +1107,7 @@ func TestCommandSide_RemoveUser(t *testing.T) {
|
|||||||
),
|
),
|
||||||
},
|
},
|
||||||
uniqueConstraintsFromEventConstraint(user.NewRemoveUsernameUniqueConstraint("username", "org1", true)),
|
uniqueConstraintsFromEventConstraint(user.NewRemoveUsernameUniqueConstraint("username", "org1", true)),
|
||||||
uniqueConstraintsFromEventConstraint(user.NewRemoveExternalIDPUniqueConstraint("idpConfigID", "externalUserID")),
|
uniqueConstraintsFromEventConstraint(user.NewRemoveUserIDPLinkUniqueConstraint("idpConfigID", "externalUserID")),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
|
@ -1,29 +0,0 @@
|
|||||||
package domain
|
|
||||||
|
|
||||||
import es_models "github.com/caos/zitadel/internal/eventstore/v1/models"
|
|
||||||
|
|
||||||
type ExternalIDP struct {
|
|
||||||
es_models.ObjectRoot
|
|
||||||
|
|
||||||
IDPConfigID string
|
|
||||||
ExternalUserID string
|
|
||||||
DisplayName string
|
|
||||||
}
|
|
||||||
|
|
||||||
func (idp *ExternalIDP) IsValid() bool {
|
|
||||||
return idp.IDPConfigID != "" && idp.ExternalUserID != ""
|
|
||||||
}
|
|
||||||
|
|
||||||
type ExternalIDPState int32
|
|
||||||
|
|
||||||
const (
|
|
||||||
ExternalIDPStateUnspecified ExternalIDPState = iota
|
|
||||||
ExternalIDPStateActive
|
|
||||||
ExternalIDPStateRemoved
|
|
||||||
|
|
||||||
externalIDPStateCount
|
|
||||||
)
|
|
||||||
|
|
||||||
func (s ExternalIDPState) Valid() bool {
|
|
||||||
return s >= 0 && s < externalIDPStateCount
|
|
||||||
}
|
|
29
internal/domain/user_idp_link.go
Normal file
29
internal/domain/user_idp_link.go
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
package domain
|
||||||
|
|
||||||
|
import es_models "github.com/caos/zitadel/internal/eventstore/v1/models"
|
||||||
|
|
||||||
|
type UserIDPLink struct {
|
||||||
|
es_models.ObjectRoot
|
||||||
|
|
||||||
|
IDPConfigID string
|
||||||
|
ExternalUserID string
|
||||||
|
DisplayName string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (idp *UserIDPLink) IsValid() bool {
|
||||||
|
return idp.IDPConfigID != "" && idp.ExternalUserID != ""
|
||||||
|
}
|
||||||
|
|
||||||
|
type UserIDPLinkState int32
|
||||||
|
|
||||||
|
const (
|
||||||
|
UserIDPLinkStateUnspecified UserIDPLinkState = iota
|
||||||
|
UserIDPLinkStateActive
|
||||||
|
UserIDPLinkStateRemoved
|
||||||
|
|
||||||
|
userIDPLinkStateCount
|
||||||
|
)
|
||||||
|
|
||||||
|
func (s UserIDPLinkState) Valid() bool {
|
||||||
|
return s >= 0 && s < userIDPLinkStateCount
|
||||||
|
}
|
@ -64,15 +64,15 @@ func assertReduce(t *testing.T, stmt *handler.Statement, err error, want wantRed
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
if stmt.AggregateType != want.aggregateType {
|
if stmt.AggregateType != want.aggregateType {
|
||||||
t.Errorf("wront aggregate type: want: %q got: %q", want.aggregateType, stmt.AggregateType)
|
t.Errorf("wrong aggregate type: want: %q got: %q", want.aggregateType, stmt.AggregateType)
|
||||||
}
|
}
|
||||||
|
|
||||||
if stmt.PreviousSequence != want.previousSequence {
|
if stmt.PreviousSequence != want.previousSequence {
|
||||||
t.Errorf("wront previous sequence: want: %d got: %d", want.previousSequence, stmt.PreviousSequence)
|
t.Errorf("wrong previous sequence: want: %d got: %d", want.previousSequence, stmt.PreviousSequence)
|
||||||
}
|
}
|
||||||
|
|
||||||
if stmt.Sequence != want.sequence {
|
if stmt.Sequence != want.sequence {
|
||||||
t.Errorf("wront sequence: want: %d got: %d", want.sequence, stmt.Sequence)
|
t.Errorf("wrong sequence: want: %d got: %d", want.sequence, stmt.Sequence)
|
||||||
}
|
}
|
||||||
if stmt.Execute == nil {
|
if stmt.Execute == nil {
|
||||||
want.executer.Validate(t)
|
want.executer.Validate(t)
|
||||||
|
111
internal/query/projection/idp_user_link.go
Normal file
111
internal/query/projection/idp_user_link.go
Normal file
@ -0,0 +1,111 @@
|
|||||||
|
package projection
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/caos/logging"
|
||||||
|
"github.com/caos/zitadel/internal/errors"
|
||||||
|
"github.com/caos/zitadel/internal/eventstore"
|
||||||
|
"github.com/caos/zitadel/internal/eventstore/handler"
|
||||||
|
"github.com/caos/zitadel/internal/eventstore/handler/crdb"
|
||||||
|
"github.com/caos/zitadel/internal/repository/user"
|
||||||
|
)
|
||||||
|
|
||||||
|
type IDPUserLinkProjection struct {
|
||||||
|
crdb.StatementHandler
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
IDPUserLinkTable = "zitadel.projections.idp_user_links"
|
||||||
|
)
|
||||||
|
|
||||||
|
func NewIDPUserLinkProjection(ctx context.Context, config crdb.StatementHandlerConfig) *IDPUserLinkProjection {
|
||||||
|
p := &IDPUserLinkProjection{}
|
||||||
|
config.ProjectionName = IDPUserLinkTable
|
||||||
|
config.Reducers = p.reducers()
|
||||||
|
p.StatementHandler = crdb.NewStatementHandler(ctx, config)
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *IDPUserLinkProjection) reducers() []handler.AggregateReducer {
|
||||||
|
return []handler.AggregateReducer{
|
||||||
|
{
|
||||||
|
Aggregate: user.AggregateType,
|
||||||
|
EventRedusers: []handler.EventReducer{
|
||||||
|
{
|
||||||
|
Event: user.UserIDPLinkAddedType,
|
||||||
|
Reduce: p.reduceAdded,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Event: user.UserIDPLinkCascadeRemovedType,
|
||||||
|
Reduce: p.reduceCascadeRemoved,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Event: user.UserIDPLinkRemovedType,
|
||||||
|
Reduce: p.reduceRemoved,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
IDPUserLinkIDPIDCol = "idp_id"
|
||||||
|
IDPUserLinkUserIDCol = "user_id"
|
||||||
|
IDPUserLinkExternalUserIDCol = "external_user_id"
|
||||||
|
IDPUserLinkCreationDateCol = "creation_date"
|
||||||
|
IDPUserLinkChangeDateCol = "change_date"
|
||||||
|
IDPUserLinkSequenceCol = "sequence"
|
||||||
|
IDPUserLinkResourceOwnerCol = "resource_owner"
|
||||||
|
IDPUserLinkDisplayNameCol = "display_name"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (p *IDPUserLinkProjection) reduceAdded(event eventstore.EventReader) (*handler.Statement, error) {
|
||||||
|
e, ok := event.(*user.UserIDPLinkAddedEvent)
|
||||||
|
if !ok {
|
||||||
|
logging.LogWithFields("HANDL-v2qC3", "seq", event.Sequence(), "expectedType", user.UserIDPLinkAddedType).Error("wrong event type")
|
||||||
|
return nil, errors.ThrowInvalidArgument(nil, "HANDL-DpmXq", "reduce.wrong.event.type")
|
||||||
|
}
|
||||||
|
return crdb.NewCreateStatement(e,
|
||||||
|
[]handler.Column{
|
||||||
|
handler.NewCol(IDPUserLinkIDPIDCol, e.IDPConfigID),
|
||||||
|
handler.NewCol(IDPUserLinkUserIDCol, e.Aggregate().ID),
|
||||||
|
handler.NewCol(IDPUserLinkExternalUserIDCol, e.ExternalUserID),
|
||||||
|
handler.NewCol(IDPUserLinkCreationDateCol, e.CreationDate()),
|
||||||
|
handler.NewCol(IDPUserLinkChangeDateCol, e.CreationDate()),
|
||||||
|
handler.NewCol(IDPUserLinkSequenceCol, e.Sequence()),
|
||||||
|
handler.NewCol(IDPUserLinkResourceOwnerCol, e.Aggregate().ResourceOwner),
|
||||||
|
handler.NewCol(IDPUserLinkDisplayNameCol, e.DisplayName),
|
||||||
|
},
|
||||||
|
), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *IDPUserLinkProjection) reduceRemoved(event eventstore.EventReader) (*handler.Statement, error) {
|
||||||
|
e, ok := event.(*user.UserIDPLinkRemovedEvent)
|
||||||
|
if !ok {
|
||||||
|
logging.LogWithFields("HANDL-zX5m9", "seq", event.Sequence(), "expectedType", user.UserIDPLinkRemovedType).Error("wrong event type")
|
||||||
|
return nil, errors.ThrowInvalidArgument(nil, "HANDL-AZmfJ", "reduce.wrong.event.type")
|
||||||
|
}
|
||||||
|
return crdb.NewDeleteStatement(e,
|
||||||
|
[]handler.Condition{
|
||||||
|
handler.NewCond(IDPUserLinkIDPIDCol, e.IDPConfigID),
|
||||||
|
handler.NewCond(IDPUserLinkUserIDCol, e.Aggregate().ID),
|
||||||
|
handler.NewCond(IDPUserLinkExternalUserIDCol, e.ExternalUserID),
|
||||||
|
},
|
||||||
|
), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *IDPUserLinkProjection) reduceCascadeRemoved(event eventstore.EventReader) (*handler.Statement, error) {
|
||||||
|
e, ok := event.(*user.UserIDPLinkCascadeRemovedEvent)
|
||||||
|
if !ok {
|
||||||
|
logging.LogWithFields("HANDL-I0s2H", "seq", event.Sequence(), "expectedType", user.UserIDPLinkCascadeRemovedType).Error("wrong event type")
|
||||||
|
return nil, errors.ThrowInvalidArgument(nil, "HANDL-jQpv9", "reduce.wrong.event.type")
|
||||||
|
}
|
||||||
|
return crdb.NewDeleteStatement(e,
|
||||||
|
[]handler.Condition{
|
||||||
|
handler.NewCond(IDPUserLinkIDPIDCol, e.IDPConfigID),
|
||||||
|
handler.NewCond(IDPUserLinkUserIDCol, e.Aggregate().ID),
|
||||||
|
handler.NewCond(IDPUserLinkExternalUserIDCol, e.ExternalUserID),
|
||||||
|
},
|
||||||
|
), nil
|
||||||
|
}
|
139
internal/query/projection/idp_user_link_test.go
Normal file
139
internal/query/projection/idp_user_link_test.go
Normal file
@ -0,0 +1,139 @@
|
|||||||
|
package projection
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/caos/zitadel/internal/errors"
|
||||||
|
"github.com/caos/zitadel/internal/eventstore"
|
||||||
|
"github.com/caos/zitadel/internal/eventstore/handler"
|
||||||
|
"github.com/caos/zitadel/internal/eventstore/repository"
|
||||||
|
"github.com/caos/zitadel/internal/repository/user"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestIDPUserLinkProjection_reduces(t *testing.T) {
|
||||||
|
type args struct {
|
||||||
|
event func(t *testing.T) eventstore.EventReader
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
args args
|
||||||
|
reduce func(event eventstore.EventReader) (*handler.Statement, error)
|
||||||
|
want wantReduce
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "reduceAdded",
|
||||||
|
args: args{
|
||||||
|
event: getEvent(testEvent(
|
||||||
|
repository.EventType(user.UserIDPLinkAddedType),
|
||||||
|
user.AggregateType,
|
||||||
|
[]byte(`{
|
||||||
|
"idpConfigId": "idp-config-id",
|
||||||
|
"userId": "external-user-id",
|
||||||
|
"displayName": "gigi@caos.ch"
|
||||||
|
}`),
|
||||||
|
), user.UserIDPLinkAddedEventMapper),
|
||||||
|
},
|
||||||
|
reduce: (&IDPUserLinkProjection{}).reduceAdded,
|
||||||
|
want: wantReduce{
|
||||||
|
aggregateType: user.AggregateType,
|
||||||
|
sequence: 15,
|
||||||
|
previousSequence: 10,
|
||||||
|
projection: IDPUserLinkTable,
|
||||||
|
executer: &testExecuter{
|
||||||
|
executions: []execution{
|
||||||
|
{
|
||||||
|
expectedStmt: "INSERT INTO zitadel.projections.idp_user_links (idp_id, user_id, external_user_id, creation_date, change_date, sequence, resource_owner, display_name) VALUES ($1, $2, $3, $4, $5, $6, $7, $8)",
|
||||||
|
expectedArgs: []interface{}{
|
||||||
|
"idp-config-id",
|
||||||
|
"agg-id",
|
||||||
|
"external-user-id",
|
||||||
|
anyArg{},
|
||||||
|
anyArg{},
|
||||||
|
uint64(15),
|
||||||
|
"ro-id",
|
||||||
|
"gigi@caos.ch",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "reduceRemoved",
|
||||||
|
args: args{
|
||||||
|
event: getEvent(testEvent(
|
||||||
|
repository.EventType(user.UserIDPLinkRemovedType),
|
||||||
|
user.AggregateType,
|
||||||
|
[]byte(`{
|
||||||
|
"idpConfigId": "idp-config-id",
|
||||||
|
"userId": "external-user-id"
|
||||||
|
}`),
|
||||||
|
), user.UserIDPLinkRemovedEventMapper),
|
||||||
|
},
|
||||||
|
reduce: (&IDPUserLinkProjection{}).reduceRemoved,
|
||||||
|
want: wantReduce{
|
||||||
|
aggregateType: user.AggregateType,
|
||||||
|
sequence: 15,
|
||||||
|
previousSequence: 10,
|
||||||
|
projection: IDPUserLinkTable,
|
||||||
|
executer: &testExecuter{
|
||||||
|
executions: []execution{
|
||||||
|
{
|
||||||
|
expectedStmt: "DELETE FROM zitadel.projections.idp_user_links WHERE (idp_id = $1) AND (user_id = $2) AND (external_user_id = $3)",
|
||||||
|
expectedArgs: []interface{}{
|
||||||
|
"idp-config-id",
|
||||||
|
"agg-id",
|
||||||
|
"external-user-id",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "reduceCascadeRemoved",
|
||||||
|
args: args{
|
||||||
|
event: getEvent(testEvent(
|
||||||
|
repository.EventType(user.UserIDPLinkCascadeRemovedType),
|
||||||
|
user.AggregateType,
|
||||||
|
[]byte(`{
|
||||||
|
"idpConfigId": "idp-config-id",
|
||||||
|
"userId": "external-user-id"
|
||||||
|
}`),
|
||||||
|
), user.UserIDPLinkCascadeRemovedEventMapper),
|
||||||
|
},
|
||||||
|
reduce: (&IDPUserLinkProjection{}).reduceCascadeRemoved,
|
||||||
|
want: wantReduce{
|
||||||
|
aggregateType: user.AggregateType,
|
||||||
|
sequence: 15,
|
||||||
|
previousSequence: 10,
|
||||||
|
projection: IDPUserLinkTable,
|
||||||
|
executer: &testExecuter{
|
||||||
|
executions: []execution{
|
||||||
|
{
|
||||||
|
expectedStmt: "DELETE FROM zitadel.projections.idp_user_links WHERE (idp_id = $1) AND (user_id = $2) AND (external_user_id = $3)",
|
||||||
|
expectedArgs: []interface{}{
|
||||||
|
"idp-config-id",
|
||||||
|
"agg-id",
|
||||||
|
"external-user-id",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
event := baseEvent(t)
|
||||||
|
got, err := tt.reduce(event)
|
||||||
|
if _, ok := err.(errors.InvalidArgument); !ok {
|
||||||
|
t.Errorf("no wrong event mapping: %v, got: %v", err, got)
|
||||||
|
}
|
||||||
|
|
||||||
|
event = tt.args.event(t)
|
||||||
|
got, err = tt.reduce(event)
|
||||||
|
assertReduce(t, got, err, tt.want)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
@ -49,6 +49,7 @@ func Start(ctx context.Context, sqlClient *sql.DB, es *eventstore.Eventstore, co
|
|||||||
NewLoginPolicyProjection(ctx, applyCustomConfig(projectionConfig, config.Customizations["login_policies"]))
|
NewLoginPolicyProjection(ctx, applyCustomConfig(projectionConfig, config.Customizations["login_policies"]))
|
||||||
NewIDPProjection(ctx, applyCustomConfig(projectionConfig, config.Customizations["idps"]))
|
NewIDPProjection(ctx, applyCustomConfig(projectionConfig, config.Customizations["idps"]))
|
||||||
NewAppProjection(ctx, applyCustomConfig(projectionConfig, config.Customizations["apps"]))
|
NewAppProjection(ctx, applyCustomConfig(projectionConfig, config.Customizations["apps"]))
|
||||||
|
NewIDPUserLinkProjection(ctx, applyCustomConfig(projectionConfig, config.Customizations["idp_user_links"]))
|
||||||
NewMailTemplateProjection(ctx, applyCustomConfig(projectionConfig, config.Customizations["mail_templates"]))
|
NewMailTemplateProjection(ctx, applyCustomConfig(projectionConfig, config.Customizations["mail_templates"]))
|
||||||
NewMessageTextProjection(ctx, applyCustomConfig(projectionConfig, config.Customizations["message_texts"]))
|
NewMessageTextProjection(ctx, applyCustomConfig(projectionConfig, config.Customizations["message_texts"]))
|
||||||
NewCustomTextProjection(ctx, applyCustomConfig(projectionConfig, config.Customizations["custom_texts"]))
|
NewCustomTextProjection(ctx, applyCustomConfig(projectionConfig, config.Customizations["custom_texts"]))
|
||||||
|
@ -60,10 +60,10 @@ func RegisterEventMappers(es *eventstore.Eventstore) {
|
|||||||
RegisterFilterEventMapper(HumanPasswordCodeSentType, HumanPasswordCodeSentEventMapper).
|
RegisterFilterEventMapper(HumanPasswordCodeSentType, HumanPasswordCodeSentEventMapper).
|
||||||
RegisterFilterEventMapper(HumanPasswordCheckSucceededType, HumanPasswordCheckSucceededEventMapper).
|
RegisterFilterEventMapper(HumanPasswordCheckSucceededType, HumanPasswordCheckSucceededEventMapper).
|
||||||
RegisterFilterEventMapper(HumanPasswordCheckFailedType, HumanPasswordCheckFailedEventMapper).
|
RegisterFilterEventMapper(HumanPasswordCheckFailedType, HumanPasswordCheckFailedEventMapper).
|
||||||
RegisterFilterEventMapper(HumanExternalIDPAddedType, HumanExternalIDPAddedEventMapper).
|
RegisterFilterEventMapper(UserIDPLinkAddedType, UserIDPLinkAddedEventMapper).
|
||||||
RegisterFilterEventMapper(HumanExternalIDPRemovedType, HumanExternalIDPRemovedEventMapper).
|
RegisterFilterEventMapper(UserIDPLinkRemovedType, UserIDPLinkRemovedEventMapper).
|
||||||
RegisterFilterEventMapper(HumanExternalIDPCascadeRemovedType, HumanExternalIDPCascadeRemovedEventMapper).
|
RegisterFilterEventMapper(UserIDPLinkCascadeRemovedType, UserIDPLinkCascadeRemovedEventMapper).
|
||||||
RegisterFilterEventMapper(HumanExternalLoginCheckSucceededType, HumanExternalIDPCheckSucceededEventMapper).
|
RegisterFilterEventMapper(UserIDPLoginCheckSucceededType, UserIDPCheckSucceededEventMapper).
|
||||||
RegisterFilterEventMapper(HumanEmailChangedType, HumanEmailChangedEventMapper).
|
RegisterFilterEventMapper(HumanEmailChangedType, HumanEmailChangedEventMapper).
|
||||||
RegisterFilterEventMapper(HumanEmailVerifiedType, HumanEmailVerifiedEventMapper).
|
RegisterFilterEventMapper(HumanEmailVerifiedType, HumanEmailVerifiedEventMapper).
|
||||||
RegisterFilterEventMapper(HumanEmailVerificationFailedType, HumanEmailVerificationFailedEventMapper).
|
RegisterFilterEventMapper(HumanEmailVerificationFailedType, HumanEmailVerificationFailedEventMapper).
|
||||||
|
@ -3,6 +3,7 @@ package user
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
|
||||||
"github.com/caos/zitadel/internal/eventstore"
|
"github.com/caos/zitadel/internal/eventstore"
|
||||||
|
|
||||||
"github.com/caos/zitadel/internal/errors"
|
"github.com/caos/zitadel/internal/errors"
|
||||||
@ -10,31 +11,31 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
UniqueExternalIDPType = "external_idps"
|
UniqueUserIDPLinkType = "external_idps"
|
||||||
externalIDPEventPrefix = humanEventPrefix + "externalidp."
|
UserIDPLinkEventPrefix = humanEventPrefix + "externalidp."
|
||||||
externalLoginEventPrefix = humanEventPrefix + "externallogin."
|
idpLoginEventPrefix = humanEventPrefix + "externallogin."
|
||||||
|
|
||||||
HumanExternalIDPAddedType = externalIDPEventPrefix + "added"
|
UserIDPLinkAddedType = UserIDPLinkEventPrefix + "added"
|
||||||
HumanExternalIDPRemovedType = externalIDPEventPrefix + "removed"
|
UserIDPLinkRemovedType = UserIDPLinkEventPrefix + "removed"
|
||||||
HumanExternalIDPCascadeRemovedType = externalIDPEventPrefix + "cascade.removed"
|
UserIDPLinkCascadeRemovedType = UserIDPLinkEventPrefix + "cascade.removed"
|
||||||
|
|
||||||
HumanExternalLoginCheckSucceededType = externalLoginEventPrefix + "check.succeeded"
|
UserIDPLoginCheckSucceededType = idpLoginEventPrefix + "check.succeeded"
|
||||||
)
|
)
|
||||||
|
|
||||||
func NewAddExternalIDPUniqueConstraint(idpConfigID, externalUserID string) *eventstore.EventUniqueConstraint {
|
func NewAddUserIDPLinkUniqueConstraint(idpConfigID, externalUserID string) *eventstore.EventUniqueConstraint {
|
||||||
return eventstore.NewAddEventUniqueConstraint(
|
return eventstore.NewAddEventUniqueConstraint(
|
||||||
UniqueExternalIDPType,
|
UniqueUserIDPLinkType,
|
||||||
idpConfigID+externalUserID,
|
idpConfigID+externalUserID,
|
||||||
"Errors.User.ExternalIDP.AlreadyExists")
|
"Errors.User.ExternalIDP.AlreadyExists")
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewRemoveExternalIDPUniqueConstraint(idpConfigID, externalUserID string) *eventstore.EventUniqueConstraint {
|
func NewRemoveUserIDPLinkUniqueConstraint(idpConfigID, externalUserID string) *eventstore.EventUniqueConstraint {
|
||||||
return eventstore.NewRemoveEventUniqueConstraint(
|
return eventstore.NewRemoveEventUniqueConstraint(
|
||||||
UniqueExternalIDPType,
|
UniqueUserIDPLinkType,
|
||||||
idpConfigID+externalUserID)
|
idpConfigID+externalUserID)
|
||||||
}
|
}
|
||||||
|
|
||||||
type HumanExternalIDPAddedEvent struct {
|
type UserIDPLinkAddedEvent struct {
|
||||||
eventstore.BaseEvent `json:"-"`
|
eventstore.BaseEvent `json:"-"`
|
||||||
|
|
||||||
IDPConfigID string `json:"idpConfigId,omitempty"`
|
IDPConfigID string `json:"idpConfigId,omitempty"`
|
||||||
@ -42,26 +43,26 @@ type HumanExternalIDPAddedEvent struct {
|
|||||||
DisplayName string `json:"displayName,omitempty"`
|
DisplayName string `json:"displayName,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *HumanExternalIDPAddedEvent) Data() interface{} {
|
func (e *UserIDPLinkAddedEvent) Data() interface{} {
|
||||||
return e
|
return e
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *HumanExternalIDPAddedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
|
func (e *UserIDPLinkAddedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
|
||||||
return []*eventstore.EventUniqueConstraint{NewAddExternalIDPUniqueConstraint(e.IDPConfigID, e.ExternalUserID)}
|
return []*eventstore.EventUniqueConstraint{NewAddUserIDPLinkUniqueConstraint(e.IDPConfigID, e.ExternalUserID)}
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewHumanExternalIDPAddedEvent(
|
func NewUserIDPLinkAddedEvent(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
aggregate *eventstore.Aggregate,
|
aggregate *eventstore.Aggregate,
|
||||||
idpConfigID,
|
idpConfigID,
|
||||||
displayName,
|
displayName,
|
||||||
externalUserID string,
|
externalUserID string,
|
||||||
) *HumanExternalIDPAddedEvent {
|
) *UserIDPLinkAddedEvent {
|
||||||
return &HumanExternalIDPAddedEvent{
|
return &UserIDPLinkAddedEvent{
|
||||||
BaseEvent: *eventstore.NewBaseEventForPush(
|
BaseEvent: *eventstore.NewBaseEventForPush(
|
||||||
ctx,
|
ctx,
|
||||||
aggregate,
|
aggregate,
|
||||||
HumanExternalIDPAddedType,
|
UserIDPLinkAddedType,
|
||||||
),
|
),
|
||||||
IDPConfigID: idpConfigID,
|
IDPConfigID: idpConfigID,
|
||||||
DisplayName: displayName,
|
DisplayName: displayName,
|
||||||
@ -69,8 +70,8 @@ func NewHumanExternalIDPAddedEvent(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func HumanExternalIDPAddedEventMapper(event *repository.Event) (eventstore.EventReader, error) {
|
func UserIDPLinkAddedEventMapper(event *repository.Event) (eventstore.EventReader, error) {
|
||||||
e := &HumanExternalIDPAddedEvent{
|
e := &UserIDPLinkAddedEvent{
|
||||||
BaseEvent: *eventstore.BaseEventFromRepo(event),
|
BaseEvent: *eventstore.BaseEventFromRepo(event),
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -82,40 +83,40 @@ func HumanExternalIDPAddedEventMapper(event *repository.Event) (eventstore.Event
|
|||||||
return e, nil
|
return e, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type HumanExternalIDPRemovedEvent struct {
|
type UserIDPLinkRemovedEvent struct {
|
||||||
eventstore.BaseEvent `json:"-"`
|
eventstore.BaseEvent `json:"-"`
|
||||||
|
|
||||||
IDPConfigID string `json:"idpConfigId"`
|
IDPConfigID string `json:"idpConfigId"`
|
||||||
ExternalUserID string `json:"userId,omitempty"`
|
ExternalUserID string `json:"userId,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *HumanExternalIDPRemovedEvent) Data() interface{} {
|
func (e *UserIDPLinkRemovedEvent) Data() interface{} {
|
||||||
return e
|
return e
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *HumanExternalIDPRemovedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
|
func (e *UserIDPLinkRemovedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
|
||||||
return []*eventstore.EventUniqueConstraint{NewRemoveExternalIDPUniqueConstraint(e.IDPConfigID, e.ExternalUserID)}
|
return []*eventstore.EventUniqueConstraint{NewRemoveUserIDPLinkUniqueConstraint(e.IDPConfigID, e.ExternalUserID)}
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewHumanExternalIDPRemovedEvent(
|
func NewUserIDPLinkRemovedEvent(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
aggregate *eventstore.Aggregate,
|
aggregate *eventstore.Aggregate,
|
||||||
idpConfigID,
|
idpConfigID,
|
||||||
externalUserID string,
|
externalUserID string,
|
||||||
) *HumanExternalIDPRemovedEvent {
|
) *UserIDPLinkRemovedEvent {
|
||||||
return &HumanExternalIDPRemovedEvent{
|
return &UserIDPLinkRemovedEvent{
|
||||||
BaseEvent: *eventstore.NewBaseEventForPush(
|
BaseEvent: *eventstore.NewBaseEventForPush(
|
||||||
ctx,
|
ctx,
|
||||||
aggregate,
|
aggregate,
|
||||||
HumanExternalIDPRemovedType,
|
UserIDPLinkRemovedType,
|
||||||
),
|
),
|
||||||
IDPConfigID: idpConfigID,
|
IDPConfigID: idpConfigID,
|
||||||
ExternalUserID: externalUserID,
|
ExternalUserID: externalUserID,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func HumanExternalIDPRemovedEventMapper(event *repository.Event) (eventstore.EventReader, error) {
|
func UserIDPLinkRemovedEventMapper(event *repository.Event) (eventstore.EventReader, error) {
|
||||||
e := &HumanExternalIDPRemovedEvent{
|
e := &UserIDPLinkRemovedEvent{
|
||||||
BaseEvent: *eventstore.BaseEventFromRepo(event),
|
BaseEvent: *eventstore.BaseEventFromRepo(event),
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -127,86 +128,86 @@ func HumanExternalIDPRemovedEventMapper(event *repository.Event) (eventstore.Eve
|
|||||||
return e, nil
|
return e, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type HumanExternalIDPCascadeRemovedEvent struct {
|
type UserIDPLinkCascadeRemovedEvent struct {
|
||||||
eventstore.BaseEvent `json:"-"`
|
eventstore.BaseEvent `json:"-"`
|
||||||
|
|
||||||
IDPConfigID string `json:"idpConfigId"`
|
IDPConfigID string `json:"idpConfigId"`
|
||||||
ExternalUserID string `json:"userId,omitempty"`
|
ExternalUserID string `json:"userId,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *HumanExternalIDPCascadeRemovedEvent) Data() interface{} {
|
func (e *UserIDPLinkCascadeRemovedEvent) Data() interface{} {
|
||||||
return e
|
return e
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *HumanExternalIDPCascadeRemovedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
|
func (e *UserIDPLinkCascadeRemovedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
|
||||||
return []*eventstore.EventUniqueConstraint{NewRemoveExternalIDPUniqueConstraint(e.IDPConfigID, e.ExternalUserID)}
|
return []*eventstore.EventUniqueConstraint{NewRemoveUserIDPLinkUniqueConstraint(e.IDPConfigID, e.ExternalUserID)}
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewHumanExternalIDPCascadeRemovedEvent(
|
func NewUserIDPLinkCascadeRemovedEvent(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
aggregate *eventstore.Aggregate,
|
aggregate *eventstore.Aggregate,
|
||||||
idpConfigID,
|
idpConfigID,
|
||||||
externalUserID string,
|
externalUserID string,
|
||||||
) *HumanExternalIDPCascadeRemovedEvent {
|
) *UserIDPLinkCascadeRemovedEvent {
|
||||||
return &HumanExternalIDPCascadeRemovedEvent{
|
return &UserIDPLinkCascadeRemovedEvent{
|
||||||
BaseEvent: *eventstore.NewBaseEventForPush(
|
BaseEvent: *eventstore.NewBaseEventForPush(
|
||||||
ctx,
|
ctx,
|
||||||
aggregate,
|
aggregate,
|
||||||
HumanExternalIDPCascadeRemovedType,
|
UserIDPLinkCascadeRemovedType,
|
||||||
),
|
),
|
||||||
IDPConfigID: idpConfigID,
|
IDPConfigID: idpConfigID,
|
||||||
ExternalUserID: externalUserID,
|
ExternalUserID: externalUserID,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func HumanExternalIDPCascadeRemovedEventMapper(event *repository.Event) (eventstore.EventReader, error) {
|
func UserIDPLinkCascadeRemovedEventMapper(event *repository.Event) (eventstore.EventReader, error) {
|
||||||
e := &HumanExternalIDPCascadeRemovedEvent{
|
e := &UserIDPLinkCascadeRemovedEvent{
|
||||||
BaseEvent: *eventstore.BaseEventFromRepo(event),
|
BaseEvent: *eventstore.BaseEventFromRepo(event),
|
||||||
}
|
}
|
||||||
|
|
||||||
err := json.Unmarshal(event.Data, e)
|
err := json.Unmarshal(event.Data, e)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.ThrowInternal(err, "USER-2M0sd", "unable to unmarshal user external idp cascade removed")
|
return nil, errors.ThrowInternal(err, "USER-dKGqO", "unable to unmarshal user external idp cascade removed")
|
||||||
}
|
}
|
||||||
|
|
||||||
return e, nil
|
return e, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type HumanExternalIDPCheckSucceededEvent struct {
|
type UserIDPCheckSucceededEvent struct {
|
||||||
eventstore.BaseEvent `json:"-"`
|
eventstore.BaseEvent `json:"-"`
|
||||||
*AuthRequestInfo
|
*AuthRequestInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *HumanExternalIDPCheckSucceededEvent) Data() interface{} {
|
func (e *UserIDPCheckSucceededEvent) Data() interface{} {
|
||||||
return e
|
return e
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *HumanExternalIDPCheckSucceededEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
|
func (e *UserIDPCheckSucceededEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewHumanExternalIDPCheckSucceededEvent(
|
func NewUserIDPCheckSucceededEvent(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
aggregate *eventstore.Aggregate,
|
aggregate *eventstore.Aggregate,
|
||||||
info *AuthRequestInfo) *HumanExternalIDPCheckSucceededEvent {
|
info *AuthRequestInfo) *UserIDPCheckSucceededEvent {
|
||||||
return &HumanExternalIDPCheckSucceededEvent{
|
return &UserIDPCheckSucceededEvent{
|
||||||
BaseEvent: *eventstore.NewBaseEventForPush(
|
BaseEvent: *eventstore.NewBaseEventForPush(
|
||||||
ctx,
|
ctx,
|
||||||
aggregate,
|
aggregate,
|
||||||
HumanExternalLoginCheckSucceededType,
|
UserIDPLoginCheckSucceededType,
|
||||||
),
|
),
|
||||||
AuthRequestInfo: info,
|
AuthRequestInfo: info,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func HumanExternalIDPCheckSucceededEventMapper(event *repository.Event) (eventstore.EventReader, error) {
|
func UserIDPCheckSucceededEventMapper(event *repository.Event) (eventstore.EventReader, error) {
|
||||||
e := &HumanExternalIDPCheckSucceededEvent{
|
e := &UserIDPCheckSucceededEvent{
|
||||||
BaseEvent: *eventstore.BaseEventFromRepo(event),
|
BaseEvent: *eventstore.BaseEventFromRepo(event),
|
||||||
}
|
}
|
||||||
|
|
||||||
err := json.Unmarshal(event.Data, e)
|
err := json.Unmarshal(event.Data, e)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.ThrowInternal(err, "USER-2M0sd", "unable to unmarshal user external idp check succeeded")
|
return nil, errors.ThrowInternal(err, "USER-oikSS", "unable to unmarshal user external idp check succeeded")
|
||||||
}
|
}
|
||||||
|
|
||||||
return e, nil
|
return e, nil
|
||||||
|
@ -163,7 +163,7 @@ type UserRemovedEvent struct {
|
|||||||
eventstore.BaseEvent `json:"-"`
|
eventstore.BaseEvent `json:"-"`
|
||||||
|
|
||||||
userName string
|
userName string
|
||||||
externalIDPs []*domain.ExternalIDP
|
externalIDPs []*domain.UserIDPLink
|
||||||
loginMustBeDomain bool
|
loginMustBeDomain bool
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -177,7 +177,7 @@ func (e *UserRemovedEvent) UniqueConstraints() []*eventstore.EventUniqueConstrai
|
|||||||
events = append(events, NewRemoveUsernameUniqueConstraint(e.userName, e.Aggregate().ResourceOwner, e.loginMustBeDomain))
|
events = append(events, NewRemoveUsernameUniqueConstraint(e.userName, e.Aggregate().ResourceOwner, e.loginMustBeDomain))
|
||||||
}
|
}
|
||||||
for _, idp := range e.externalIDPs {
|
for _, idp := range e.externalIDPs {
|
||||||
events = append(events, NewRemoveExternalIDPUniqueConstraint(idp.IDPConfigID, idp.ExternalUserID))
|
events = append(events, NewRemoveUserIDPLinkUniqueConstraint(idp.IDPConfigID, idp.ExternalUserID))
|
||||||
}
|
}
|
||||||
return events
|
return events
|
||||||
}
|
}
|
||||||
@ -186,7 +186,7 @@ func NewUserRemovedEvent(
|
|||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
aggregate *eventstore.Aggregate,
|
aggregate *eventstore.Aggregate,
|
||||||
userName string,
|
userName string,
|
||||||
externalIDPs []*domain.ExternalIDP,
|
externalIDPs []*domain.UserIDPLink,
|
||||||
userLoginMustBeDomain bool,
|
userLoginMustBeDomain bool,
|
||||||
) *UserRemovedEvent {
|
) *UserRemovedEvent {
|
||||||
return &UserRemovedEvent{
|
return &UserRemovedEvent{
|
||||||
|
@ -348,7 +348,7 @@ func (l *Login) mapTokenToLoginUser(tokens *oidc.Tokens, idpConfig *iam_model.ID
|
|||||||
}
|
}
|
||||||
return externalUser
|
return externalUser
|
||||||
}
|
}
|
||||||
func (l *Login) mapExternalUserToLoginUser(orgIamPolicy *query.OrgIAMPolicy, linkingUser *domain.ExternalUser, idpConfig *iam_model.IDPConfigView) (*domain.Human, *domain.ExternalIDP, []*domain.Metadata) {
|
func (l *Login) mapExternalUserToLoginUser(orgIamPolicy *query.OrgIAMPolicy, linkingUser *domain.ExternalUser, idpConfig *iam_model.IDPConfigView) (*domain.Human, *domain.UserIDPLink, []*domain.Metadata) {
|
||||||
username := linkingUser.PreferredUsername
|
username := linkingUser.PreferredUsername
|
||||||
switch idpConfig.OIDCUsernameMapping {
|
switch idpConfig.OIDCUsernameMapping {
|
||||||
case iam_model.OIDCMappingFieldEmail:
|
case iam_model.OIDCMappingFieldEmail:
|
||||||
@ -398,7 +398,7 @@ func (l *Login) mapExternalUserToLoginUser(orgIamPolicy *query.OrgIAMPolicy, lin
|
|||||||
displayName = linkingUser.Email
|
displayName = linkingUser.Email
|
||||||
}
|
}
|
||||||
|
|
||||||
externalIDP := &domain.ExternalIDP{
|
externalIDP := &domain.UserIDPLink{
|
||||||
IDPConfigID: idpConfig.IDPConfigID,
|
IDPConfigID: idpConfig.IDPConfigID,
|
||||||
ExternalUserID: linkingUser.ExternalUserID,
|
ExternalUserID: linkingUser.ExternalUserID,
|
||||||
DisplayName: displayName,
|
DisplayName: displayName,
|
||||||
|
@ -130,7 +130,7 @@ func (l *Login) handleExternalUserRegister(w http.ResponseWriter, r *http.Reques
|
|||||||
l.registerExternalUser(w, r, authReq, iam, user, externalIDP)
|
l.registerExternalUser(w, r, authReq, iam, user, externalIDP)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *Login) registerExternalUser(w http.ResponseWriter, r *http.Request, authReq *domain.AuthRequest, iam *iam_model.IAM, user *domain.Human, externalIDP *domain.ExternalIDP) {
|
func (l *Login) registerExternalUser(w http.ResponseWriter, r *http.Request, authReq *domain.AuthRequest, iam *iam_model.IAM, user *domain.Human, externalIDP *domain.UserIDPLink) {
|
||||||
resourceOwner := iam.GlobalOrgID
|
resourceOwner := iam.GlobalOrgID
|
||||||
memberRoles := []string{domain.RoleOrgProjectCreator}
|
memberRoles := []string{domain.RoleOrgProjectCreator}
|
||||||
|
|
||||||
@ -146,7 +146,7 @@ func (l *Login) registerExternalUser(w http.ResponseWriter, r *http.Request, aut
|
|||||||
l.renderNextStep(w, r, authReq)
|
l.renderNextStep(w, r, authReq)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *Login) renderExternalRegisterOverview(w http.ResponseWriter, r *http.Request, authReq *domain.AuthRequest, orgIAMPolicy *query.OrgIAMPolicy, human *domain.Human, idp *domain.ExternalIDP, err error) {
|
func (l *Login) renderExternalRegisterOverview(w http.ResponseWriter, r *http.Request, authReq *domain.AuthRequest, orgIAMPolicy *query.OrgIAMPolicy, human *domain.Human, idp *domain.UserIDPLink, err error) {
|
||||||
var errID, errMessage string
|
var errID, errMessage string
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errID, errMessage = l.getErrorMessage(r, err)
|
errID, errMessage = l.getErrorMessage(r, err)
|
||||||
@ -216,7 +216,7 @@ func (l *Login) handleExternalRegisterCheck(w http.ResponseWriter, r *http.Reque
|
|||||||
l.renderNextStep(w, r, authReq)
|
l.renderNextStep(w, r, authReq)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *Login) mapTokenToLoginHumanAndExternalIDP(orgIamPolicy *query.OrgIAMPolicy, tokens *oidc.Tokens, idpConfig *iam_model.IDPConfigView) (*domain.Human, *domain.ExternalIDP) {
|
func (l *Login) mapTokenToLoginHumanAndExternalIDP(orgIamPolicy *query.OrgIAMPolicy, tokens *oidc.Tokens, idpConfig *iam_model.IDPConfigView) (*domain.Human, *domain.UserIDPLink) {
|
||||||
username := tokens.IDTokenClaims.GetPreferredUsername()
|
username := tokens.IDTokenClaims.GetPreferredUsername()
|
||||||
switch idpConfig.OIDCUsernameMapping {
|
switch idpConfig.OIDCUsernameMapping {
|
||||||
case iam_model.OIDCMappingFieldEmail:
|
case iam_model.OIDCMappingFieldEmail:
|
||||||
@ -264,7 +264,7 @@ func (l *Login) mapTokenToLoginHumanAndExternalIDP(orgIamPolicy *query.OrgIAMPol
|
|||||||
displayName = tokens.IDTokenClaims.GetEmail()
|
displayName = tokens.IDTokenClaims.GetEmail()
|
||||||
}
|
}
|
||||||
|
|
||||||
externalIDP := &domain.ExternalIDP{
|
externalIDP := &domain.UserIDPLink{
|
||||||
IDPConfigID: idpConfig.IDPConfigID,
|
IDPConfigID: idpConfig.IDPConfigID,
|
||||||
ExternalUserID: tokens.IDTokenClaims.GetSubject(),
|
ExternalUserID: tokens.IDTokenClaims.GetSubject(),
|
||||||
DisplayName: displayName,
|
DisplayName: displayName,
|
||||||
@ -304,8 +304,8 @@ func (l *Login) mapExternalRegisterDataToUser(r *http.Request, data *externalReg
|
|||||||
return human, nil
|
return human, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *Login) getExternalIDP(data *externalRegisterFormData) (*domain.ExternalIDP, error) {
|
func (l *Login) getExternalIDP(data *externalRegisterFormData) (*domain.UserIDPLink, error) {
|
||||||
return &domain.ExternalIDP{
|
return &domain.UserIDPLink{
|
||||||
IDPConfigID: data.ExternalIDPConfigID,
|
IDPConfigID: data.ExternalIDPConfigID,
|
||||||
ExternalUserID: data.ExternalIDPExtUserID,
|
ExternalUserID: data.ExternalIDPExtUserID,
|
||||||
DisplayName: data.ExternalIDPDisplayName,
|
DisplayName: data.ExternalIDPDisplayName,
|
||||||
|
14
migrations/cockroach/V1.88__user_idp_link.sql
Normal file
14
migrations/cockroach/V1.88__user_idp_link.sql
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
CREATE TABLE zitadel.projections.idp_user_links(
|
||||||
|
idp_id STRING,
|
||||||
|
user_id STRING,
|
||||||
|
external_user_id STRING,
|
||||||
|
display_name STRING,
|
||||||
|
|
||||||
|
creation_date TIMESTAMPTZ,
|
||||||
|
change_date TIMESTAMPTZ,
|
||||||
|
sequence INT8,
|
||||||
|
resource_owner STRING,
|
||||||
|
|
||||||
|
PRIMARY KEY (idp_id, external_user_id),
|
||||||
|
INDEX idx_user (user_id)
|
||||||
|
);
|
Loading…
x
Reference in New Issue
Block a user