Skip to content

Commit 03a28c0

Browse files
authored
[CLOUDTRUST-7433] Fixes add/del attributes in IDP interface
1 parent 75bf575 commit 03a28c0

2 files changed

Lines changed: 30 additions & 9 deletions

File tree

pkg/idp/component.go

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -477,18 +477,18 @@ func (c *component) GetUsersWithAttribute(ctx context.Context, realmName string,
477477
func (c *component) AddUserAttributes(ctx context.Context, realmName string, userID string, attributes map[string][]string) error {
478478
// For now, we don't check which attributes are allowed to be set. If needed, we should use UserProfile feature and
479479
// check if annotations tell that the attribute is writable or not for the given interface.
480-
return c.updateUser(ctx, realmName, userID, func(user kc.UserRepresentation) bool {
480+
return c.updateUser(ctx, realmName, userID, func(user *kc.UserRepresentation) bool {
481481
var updated = false
482482
for attributeKey, attributeValues := range attributes {
483-
if c.addUserAttribute(user, attributeKey, attributeValues) {
483+
if c.addUserAttribute(ctx, user, attributeKey, attributeValues) {
484484
updated = true
485485
}
486486
}
487487
return updated
488488
})
489489
}
490490

491-
func (c *component) addUserAttribute(user kc.UserRepresentation, attributeKey string, attributeValues []string) bool {
491+
func (c *component) addUserAttribute(ctx context.Context, user *kc.UserRepresentation, attributeKey string, attributeValues []string) bool {
492492
var key = kc.AttributeKey(attributeKey)
493493
if user.Attributes == nil {
494494
var attributes = make(kc.Attributes)
@@ -507,7 +507,7 @@ func (c *component) addUserAttribute(user kc.UserRepresentation, attributeKey st
507507
func (c *component) DeleteUserAttributes(ctx context.Context, realmName string, userID string, attributeKeys []string) error {
508508
// For now, we don't check which attributes are allowed to be removed. If needed, we should use UserProfile feature and
509509
// check if annotations tell that the attribute is writable or not for the given interface.
510-
return c.updateUser(ctx, realmName, userID, func(user kc.UserRepresentation) bool {
510+
return c.updateUser(ctx, realmName, userID, func(user *kc.UserRepresentation) bool {
511511
var count = 0
512512
for _, attributeKey := range attributeKeys {
513513
var key = kc.AttributeKey(attributeKey)
@@ -523,7 +523,7 @@ func (c *component) DeleteUserAttributes(ctx context.Context, realmName string,
523523
})
524524
}
525525

526-
func (c *component) updateUser(ctx context.Context, realmName string, userID string, updateFunc func(user kc.UserRepresentation) bool) error {
526+
func (c *component) updateUser(ctx context.Context, realmName string, userID string, updateFunc func(user *kc.UserRepresentation) bool) error {
527527
accessToken, err := c.tokenProvider.ProvideTokenForRealm(ctx, realmName)
528528
if err != nil {
529529
c.logger.Warn(ctx, "msg", "Failed to get OIDC token from keycloak", "err", err.Error())
@@ -534,7 +534,7 @@ func (c *component) updateUser(ctx context.Context, realmName string, userID str
534534
c.logger.Warn(ctx, "msg", "Failed to get Keycloak user", "err", err.Error(), "realm", realmName, "user", userID)
535535
return err
536536
}
537-
if updateFunc(user) {
537+
if updateFunc(&user) {
538538
err = overrideKeycloakError(c.keycloakIdpClient.UpdateUser(accessToken, realmName, userID, user), "attribute")
539539
if err != nil {
540540
c.logger.Warn(ctx, "msg", "Failed to update user from keycloak", "err", err.Error(), "realm", realmName, "user", userID)

pkg/idp/component_test.go

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,27 @@ func ptrBool(value bool) *bool {
3939
return &value
4040
}
4141

42+
type hasSingleAttributeValue struct {
43+
Key string
44+
Value string
45+
}
46+
47+
func (h hasSingleAttributeValue) Matches(x any) bool {
48+
var user, ok = x.(kc.UserRepresentation)
49+
if !ok || user.Attributes == nil {
50+
return false
51+
}
52+
var currValue = user.Attributes.Get(kc.AttributeKey(h.Key))
53+
if len(currValue) != 1 {
54+
return false
55+
}
56+
return currValue[0] == h.Value
57+
}
58+
59+
func (h hasSingleAttributeValue) String() string {
60+
return fmt.Sprintf("hasSingleAttributeValue{Key: %s, Value: %s}", h.Key, h.Value)
61+
}
62+
4263
func createTestKcIdp() kc.IdentityProviderRepresentation {
4364
return kc.IdentityProviderRepresentation{
4465
AddReadTokenRoleOnCreate: ptrBool(false),
@@ -922,22 +943,22 @@ func TestAddDeleteUserAttributes(t *testing.T) {
922943
t.Run("Success adding first attribute", func(t *testing.T) {
923944
mocks.tokenProvider.EXPECT().ProvideTokenForRealm(ctx, realmName).Return(accessToken, nil)
924945
mocks.keycloakIdpClient.EXPECT().GetUser(accessToken, realmName, userID).Return(kc.UserRepresentation{Attributes: nil}, nil)
925-
mocks.keycloakIdpClient.EXPECT().UpdateUser(accessToken, realmName, userID, gomock.Any()).Return(nil)
946+
mocks.keycloakIdpClient.EXPECT().UpdateUser(accessToken, realmName, userID, hasSingleAttributeValue{Key: attribKey, Value: attribValue}).Return(nil)
926947
err := idpComponent.AddUserAttributes(ctx, realmName, userID, map[string][]string{attribKey: {attribValue}})
927948
assert.NoError(t, err)
928949
})
929950
t.Run("Success adding not yet existing attribute", func(t *testing.T) {
930951
mocks.tokenProvider.EXPECT().ProvideTokenForRealm(ctx, realmName).Return(accessToken, nil)
931952
mocks.keycloakIdpClient.EXPECT().GetUser(accessToken, realmName, userID).Return(kc.UserRepresentation{Attributes: &kc.Attributes{}}, nil)
932-
mocks.keycloakIdpClient.EXPECT().UpdateUser(accessToken, realmName, userID, gomock.Any()).Return(nil)
953+
mocks.keycloakIdpClient.EXPECT().UpdateUser(accessToken, realmName, userID, hasSingleAttributeValue{Key: attribKey, Value: attribValue}).Return(nil)
933954
err := idpComponent.AddUserAttributes(ctx, realmName, userID, map[string][]string{attribKey: {attribValue}})
934955
assert.NoError(t, err)
935956
})
936957
t.Run("Success adding existing attribute with different value", func(t *testing.T) {
937958
kcUser := kc.UserRepresentation{Attributes: &kc.Attributes{kc.AttributeKey(attribKey): []string{"some-other-value"}}}
938959
mocks.tokenProvider.EXPECT().ProvideTokenForRealm(ctx, realmName).Return(accessToken, nil)
939960
mocks.keycloakIdpClient.EXPECT().GetUser(accessToken, realmName, userID).Return(kcUser, nil)
940-
mocks.keycloakIdpClient.EXPECT().UpdateUser(accessToken, realmName, userID, gomock.Any()).Return(nil)
961+
mocks.keycloakIdpClient.EXPECT().UpdateUser(accessToken, realmName, userID, hasSingleAttributeValue{Key: attribKey, Value: attribValue}).Return(nil)
941962
err := idpComponent.AddUserAttributes(ctx, realmName, userID, map[string][]string{attribKey: {attribValue}})
942963
assert.NoError(t, err)
943964
})

0 commit comments

Comments
 (0)