Repository: Nerzal/gocloak
Pull request #125 (2019-12-23 22:53:41)

Adding AddClientRoleComposite and DeleteClientRoleComposite methods
These methods will allow for managing composite roles for clients.

It appears that these methods will work for both client and realm composite roles which the current `AddRealmRoleComposite` and `DeleteRealmRoleComposite` only work for realm composite roles.


Patch:
diff --git a/README.md b/README.md
index 0939cc7..17925f7 100644
--- a/README.md
+++ b/README.md
@@ -152,6 +152,8 @@ type GoCloak interface {
 	GetClientRoles(accessToken string, realm string, clientID string) ([]*Role, error)
 	GetClientRole(token string, realm string, clientID string, roleName string) (*Role, error)
 	GetClients(accessToken string, realm string, params GetClientsParams) ([]*Client, error)
+	AddClientRoleComposite(token string, realm string, roleID string, roles []Role) error
+	DeleteClientRoleComposite(token string, realm string, roleID string, roles []Role) error
 	GetUsersByRoleName(token string, realm string, roleName string) ([]*User, error)
 	UserAttributeContains(attributes map[string][]string, attribute string, value string) bool
 	CreateClientProtocolMapper(token, realm, clientID string, mapper ProtocolMapperRepresentation) error
diff --git a/client.go b/client.go
index 01474e9..0619dc3 100644
--- a/client.go
+++ b/client.go
@@ -1279,6 +1279,24 @@ func (client *gocloak) DeleteClientRoleFromUser(token string, realm string, clie
 	return checkForError(resp, err)
 }
 
+// AddClientRoleComposite adds roles as composite
+func (client *gocloak) AddClientRoleComposite(token string, realm string, roleID string, roles []Role) error {
+	resp, err := client.getRequestWithBearerAuth(token).
+		SetBody(roles).
+		Post(client.getAdminRealmURL(realm, "roles-by-id", roleID, "composites"))
+
+	return checkForError(resp, err)
+}
+
+// DeleteClientRoleComposite deletes composites from a role
+func (client *gocloak) DeleteClientRoleComposite(token string, realm string, roleID string, roles []Role) error {
+	resp, err := client.getRequestWithBearerAuth(token).
+		SetBody(roles).
+		Delete(client.getAdminRealmURL(realm, "roles-by-id", roleID, "composites"))
+
+	return checkForError(resp, err)
+}
+
 // ------------------
 // Identity Providers
 // ------------------
diff --git a/gocloak.go b/gocloak.go
index aed3417..398f222 100644
--- a/gocloak.go
+++ b/gocloak.go
@@ -170,6 +170,10 @@ type GoCloak interface {
 	GetClientRoles(accessToken string, realm string, clientID string) ([]*Role, error)
 	// GetClientRole get a role for the given client in a realm by role name
 	GetClientRole(token string, realm string, clientID string, roleName string) (*Role, error)
+	// AddClientRoleComposite adds roles as composite
+	AddClientRoleComposite(token string, realm string, roleID string, roles []Role) error
+	// DeleteClientRoleComposite deletes composites from a role
+	DeleteClientRoleComposite(token string, realm string, roleID string, roles []Role) error
 
 	// *** Realm ***
 


Test patch:
diff --git a/client_test.go b/client_test.go
index f84788c..4ffd5d4 100644
--- a/client_test.go
+++ b/client_test.go
@@ -2345,6 +2345,33 @@ func TestGocloak_AddClientRoleToUser_DeleteClientRoleFromUser(t *testing.T) {
 	assert.NoError(t, err, "DeleteClientRoleFromUser failed")
 }
 
+func TestGocloak_AddDeleteClientRoleComposite(t *testing.T) {
+	t.Parallel()
+	cfg := GetConfig(t)
+	client := NewClientWithDebug(t)
+	token := GetAdminToken(t, client)
+
+	tearDown, compositeRole := CreateClientRole(t, client)
+	defer tearDown()
+
+	tearDown, role := CreateClientRole(t, client)
+	defer tearDown()
+
+	compositeRoleModel, err := client.GetClientRole(token.AccessToken, cfg.GoCloak.Realm, gocloakClientID, compositeRole)
+	assert.NoError(t, err, "Can't get just created role with GetClientRole")
+
+	roleModel, err := client.GetClientRole(token.AccessToken, cfg.GoCloak.Realm, gocloakClientID, role)
+	assert.NoError(t, err, "Can't get just created role with GetClientRole")
+
+	err = client.AddClientRoleComposite(token.AccessToken,
+		cfg.GoCloak.Realm, *(compositeRoleModel.ID), []Role{*roleModel})
+	assert.NoError(t, err, "AddClientRoleComposite failed")
+
+	err = client.DeleteClientRoleComposite(token.AccessToken,
+		cfg.GoCloak.Realm, *(compositeRoleModel.ID), []Role{*roleModel})
+	assert.NoError(t, err, "DeleteClientRoleComposite failed")
+}
+
 func TestGocloak_CreateDeleteClientScopeWithMappers(t *testing.T) {
 	t.Parallel()
 	cfg := GetConfig(t)