mirror of
https://github.com/zitadel/zitadel.git
synced 2025-08-12 01:37:31 +00:00
fix: scim v2 endpoints enforce user resource owner (#9273)
# Which Problems Are Solved - If a SCIM endpoint is called with an orgID in the URL that is not the resource owner, no error is returned, and the action is executed. # How the Problems Are Solved - The orgID provided in the SCIM URL path must match the resource owner of the target user. Otherwise, an error will be returned. # Additional Context Part of https://github.com/zitadel/zitadel/issues/8140
This commit is contained in:
@@ -159,12 +159,12 @@ func (c *Commands) userStateWriteModel(ctx context.Context, userID string) (writ
|
||||
return writeModel, nil
|
||||
}
|
||||
|
||||
func (c *Commands) RemoveUserV2(ctx context.Context, userID string, cascadingUserMemberships []*CascadingMembership, cascadingGrantIDs ...string) (*domain.ObjectDetails, error) {
|
||||
func (c *Commands) RemoveUserV2(ctx context.Context, userID, resourceOwner string, cascadingUserMemberships []*CascadingMembership, cascadingGrantIDs ...string) (*domain.ObjectDetails, error) {
|
||||
if userID == "" {
|
||||
return nil, zerrors.ThrowInvalidArgument(nil, "COMMAND-vaipl7s13l", "Errors.User.UserIDMissing")
|
||||
}
|
||||
|
||||
existingUser, err := c.userRemoveWriteModel(ctx, userID)
|
||||
existingUser, err := c.userRemoveWriteModel(ctx, userID, resourceOwner)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -210,11 +210,11 @@ func (c *Commands) RemoveUserV2(ctx context.Context, userID string, cascadingUse
|
||||
return writeModelToObjectDetails(&existingUser.WriteModel), nil
|
||||
}
|
||||
|
||||
func (c *Commands) userRemoveWriteModel(ctx context.Context, userID string) (writeModel *UserV2WriteModel, err error) {
|
||||
func (c *Commands) userRemoveWriteModel(ctx context.Context, userID, resourceOwner string) (writeModel *UserV2WriteModel, err error) {
|
||||
ctx, span := tracing.NewSpan(ctx)
|
||||
defer func() { span.EndWithError(err) }()
|
||||
|
||||
writeModel = NewUserRemoveWriteModel(userID, "")
|
||||
writeModel = NewUserRemoveWriteModel(userID, resourceOwner)
|
||||
err = c.eventstore.FilterToQueryReducer(ctx, writeModel)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@@ -14,12 +14,13 @@ import (
|
||||
)
|
||||
|
||||
type ChangeHuman struct {
|
||||
ID string
|
||||
State *domain.UserState
|
||||
Username *string
|
||||
Profile *Profile
|
||||
Email *Email
|
||||
Phone *Phone
|
||||
ID string
|
||||
ResourceOwner string
|
||||
State *domain.UserState
|
||||
Username *string
|
||||
Profile *Profile
|
||||
Email *Email
|
||||
Phone *Phone
|
||||
|
||||
Metadata []*domain.Metadata
|
||||
MetadataKeysToRemove []string
|
||||
@@ -267,6 +268,7 @@ func (c *Commands) ChangeUserHuman(ctx context.Context, human *ChangeHuman, alg
|
||||
existingHuman, err := c.UserHumanWriteModel(
|
||||
ctx,
|
||||
human.ID,
|
||||
human.ResourceOwner,
|
||||
human.Profile != nil,
|
||||
human.Email != nil,
|
||||
human.Phone != nil,
|
||||
@@ -525,11 +527,11 @@ func (c *Commands) userExistsWriteModel(ctx context.Context, userID string) (wri
|
||||
return writeModel, nil
|
||||
}
|
||||
|
||||
func (c *Commands) UserHumanWriteModel(ctx context.Context, userID string, profileWM, emailWM, phoneWM, passwordWM, avatarWM, idpLinksWM, metadataWM bool) (writeModel *UserV2WriteModel, err error) {
|
||||
func (c *Commands) UserHumanWriteModel(ctx context.Context, userID, resourceOwner string, profileWM, emailWM, phoneWM, passwordWM, avatarWM, idpLinksWM, metadataWM bool) (writeModel *UserV2WriteModel, err error) {
|
||||
ctx, span := tracing.NewSpan(ctx)
|
||||
defer func() { span.EndWithError(err) }()
|
||||
|
||||
writeModel = NewUserHumanWriteModel(userID, "", profileWM, emailWM, phoneWM, passwordWM, avatarWM, idpLinksWM, metadataWM)
|
||||
writeModel = NewUserHumanWriteModel(userID, resourceOwner, profileWM, emailWM, phoneWM, passwordWM, avatarWM, idpLinksWM, metadataWM)
|
||||
err = c.eventstore.FilterToQueryReducer(ctx, writeModel)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@@ -567,7 +567,7 @@ func TestCommandSide_userHumanWriteModel_profile(t *testing.T) {
|
||||
r := &Commands{
|
||||
eventstore: tt.fields.eventstore(t),
|
||||
}
|
||||
wm, err := r.UserHumanWriteModel(tt.args.ctx, tt.args.userID, true, false, false, false, false, false, false)
|
||||
wm, err := r.UserHumanWriteModel(tt.args.ctx, tt.args.userID, "", true, false, false, false, false, false, false)
|
||||
if tt.res.err == nil {
|
||||
if !assert.NoError(t, err) {
|
||||
t.FailNow()
|
||||
@@ -912,7 +912,7 @@ func TestCommandSide_userHumanWriteModel_email(t *testing.T) {
|
||||
r := &Commands{
|
||||
eventstore: tt.fields.eventstore(t),
|
||||
}
|
||||
wm, err := r.UserHumanWriteModel(tt.args.ctx, tt.args.userID, false, true, false, false, false, false, false)
|
||||
wm, err := r.UserHumanWriteModel(tt.args.ctx, tt.args.userID, "", false, true, false, false, false, false, false)
|
||||
if tt.res.err == nil {
|
||||
if !assert.NoError(t, err) {
|
||||
t.FailNow()
|
||||
@@ -1344,7 +1344,7 @@ func TestCommandSide_userHumanWriteModel_phone(t *testing.T) {
|
||||
r := &Commands{
|
||||
eventstore: tt.fields.eventstore(t),
|
||||
}
|
||||
wm, err := r.UserHumanWriteModel(tt.args.ctx, tt.args.userID, false, false, true, false, false, false, false)
|
||||
wm, err := r.UserHumanWriteModel(tt.args.ctx, tt.args.userID, "", false, false, true, false, false, false, false)
|
||||
if tt.res.err == nil {
|
||||
if !assert.NoError(t, err) {
|
||||
t.FailNow()
|
||||
@@ -1605,7 +1605,7 @@ func TestCommandSide_userHumanWriteModel_password(t *testing.T) {
|
||||
r := &Commands{
|
||||
eventstore: tt.fields.eventstore(t),
|
||||
}
|
||||
wm, err := r.UserHumanWriteModel(tt.args.ctx, tt.args.userID, false, false, false, true, false, false, false)
|
||||
wm, err := r.UserHumanWriteModel(tt.args.ctx, tt.args.userID, "", false, false, false, true, false, false, false)
|
||||
if tt.res.err == nil {
|
||||
if !assert.NoError(t, err) {
|
||||
t.FailNow()
|
||||
@@ -2132,7 +2132,7 @@ func TestCommandSide_userHumanWriteModel_avatar(t *testing.T) {
|
||||
r := &Commands{
|
||||
eventstore: tt.fields.eventstore(t),
|
||||
}
|
||||
wm, err := r.UserHumanWriteModel(tt.args.ctx, tt.args.userID, false, false, false, false, true, false, false)
|
||||
wm, err := r.UserHumanWriteModel(tt.args.ctx, tt.args.userID, "", false, false, false, false, true, false, false)
|
||||
if tt.res.err == nil {
|
||||
if !assert.NoError(t, err) {
|
||||
t.FailNow()
|
||||
@@ -2441,7 +2441,7 @@ func TestCommandSide_userHumanWriteModel_idpLinks(t *testing.T) {
|
||||
r := &Commands{
|
||||
eventstore: tt.fields.eventstore(t),
|
||||
}
|
||||
wm, err := r.userRemoveWriteModel(tt.args.ctx, tt.args.userID)
|
||||
wm, err := r.userRemoveWriteModel(tt.args.ctx, tt.args.userID, "")
|
||||
if tt.res.err == nil {
|
||||
if !assert.NoError(t, err) {
|
||||
t.FailNow()
|
||||
@@ -2744,7 +2744,7 @@ func TestCommandSide_userHumanWriteModel_metadata(t *testing.T) {
|
||||
r := &Commands{
|
||||
eventstore: tt.fields.eventstore(t),
|
||||
}
|
||||
wm, err := r.UserHumanWriteModel(tt.args.ctx, tt.args.userID, false, false, false, false, false, false, true)
|
||||
wm, err := r.UserHumanWriteModel(tt.args.ctx, tt.args.userID, "", false, false, false, false, false, false, true)
|
||||
if tt.res.err == nil {
|
||||
if !assert.NoError(t, err) {
|
||||
t.FailNow()
|
||||
|
@@ -1358,7 +1358,7 @@ func TestCommandSide_RemoveUserV2(t *testing.T) {
|
||||
eventstore: tt.fields.eventstore(t),
|
||||
checkPermission: tt.fields.checkPermission,
|
||||
}
|
||||
got, err := r.RemoveUserV2(tt.args.ctx, tt.args.userID, tt.args.cascadingMemberships, tt.args.grantIDs...)
|
||||
got, err := r.RemoveUserV2(tt.args.ctx, tt.args.userID, "", tt.args.cascadingMemberships, tt.args.grantIDs...)
|
||||
if tt.res.err == nil {
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
Reference in New Issue
Block a user