diff --git a/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/RealmResource.java b/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/RealmResource.java
index 456bc01759..6b4f368c7f 100644
--- a/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/RealmResource.java
+++ b/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/RealmResource.java
@@ -63,6 +63,9 @@ public interface RealmResource {
@Path("roles")
RolesResource roles();
+ @Path("roles-by-id")
+ RoleByIdResource rolesById();
+
@Path("groups")
GroupsResource groups();
diff --git a/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/RoleByIdResource.java b/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/RoleByIdResource.java
new file mode 100755
index 0000000000..e837f5ff58
--- /dev/null
+++ b/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/RoleByIdResource.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.admin.client.resource;
+
+import org.keycloak.representations.idm.RoleRepresentation;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * Sometimes its easier to just interact with roles by their ID instead of container/role-name
+ *
+ * @author Bill Burke
+ * @version $Revision: 1 $
+ */
+public interface RoleByIdResource {
+
+ @Path("{role-id}")
+ @GET
+ @Produces(MediaType.APPLICATION_JSON)
+ RoleRepresentation getRole(final @PathParam("role-id") String id);
+
+ @Path("{role-id}")
+ @DELETE
+ void deleteRole(final @PathParam("role-id") String id);
+
+ @Path("{role-id}")
+ @PUT
+ @Consumes(MediaType.APPLICATION_JSON)
+ void updateRole(final @PathParam("role-id") String id, RoleRepresentation rep);
+
+ @Path("{role-id}/composites")
+ @POST
+ @Consumes(MediaType.APPLICATION_JSON)
+ void addComposites(final @PathParam("role-id") String id, List roles);
+
+ @Path("{role-id}/composites")
+ @GET
+ @Produces(MediaType.APPLICATION_JSON)
+ Set getRoleComposites(@PathParam("role-id") String id);
+
+ @Path("{role-id}/composites/realm")
+ @GET
+ @Produces(MediaType.APPLICATION_JSON)
+ Set getRealmRoleComposites(@PathParam("role-id") String id);
+
+ @Path("{role-id}/composites/clients/{client}")
+ @GET
+ @Produces(MediaType.APPLICATION_JSON)
+ Set getClientRoleComposites(@PathParam("role-id") String id, @PathParam("client") String client);
+
+ @Path("{role-id}/composites")
+ @DELETE
+ @Consumes(MediaType.APPLICATION_JSON)
+ void deleteComposites(final @PathParam("role-id") String id, List roles);
+
+}
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/RoleByIdResource.java b/services/src/main/java/org/keycloak/services/resources/admin/RoleByIdResource.java
index 26b1a4a7dd..58ccb6aac2 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/RoleByIdResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/RoleByIdResource.java
@@ -213,30 +213,6 @@ public class RoleByIdResource extends RoleResource {
return getClientRoleComposites(clientModel, role);
}
- /**
- * Get client-level roles for the client that are in the role's composite
- *
- * @param role
- * @param client
- * @return
- */
- @Path("{role-id}/composites/clients/{client}")
- @GET
- @NoCache
- @Produces(MediaType.APPLICATION_JSON)
- public Set getClientByIdRoleComposites(final @PathParam("role-id") String role,
- final @PathParam("client") String client) {
- auth.requireAny();
-
- RoleModel roleModel = getRoleModel(role);
- ClientModel clientModel = realm.getClientById(client);
- if (clientModel == null) {
- throw new NotFoundException("Could not find client");
-
- }
- return getClientRoleComposites(clientModel, roleModel);
- }
-
/**
* Remove a set of roles from the role's composite
*
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/Assert.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/Assert.java
index ddd2f53bbb..770dffa592 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/Assert.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/Assert.java
@@ -20,11 +20,14 @@ package org.keycloak.testsuite;
import org.keycloak.representations.idm.ClientRepresentation;
import org.keycloak.representations.idm.IdentityProviderRepresentation;
import org.keycloak.representations.idm.RealmRepresentation;
+import org.keycloak.representations.idm.RoleRepresentation;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
+import java.util.LinkedList;
import java.util.List;
+import java.util.Set;
import static org.junit.Assert.assertArrayEquals;
@@ -33,6 +36,12 @@ import static org.junit.Assert.assertArrayEquals;
*/
public class Assert extends org.junit.Assert {
+ public static void assertNames(Set actual, String... expected) {
+ Arrays.sort(expected);
+ String[] actualNames = names(new LinkedList