diff --git a/services/src/main/java/org/keycloak/services/resources/account/AccountRestService.java b/services/src/main/java/org/keycloak/services/resources/account/AccountRestService.java index 97b5e38c43..0bb7bce7c9 100755 --- a/services/src/main/java/org/keycloak/services/resources/account/AccountRestService.java +++ b/services/src/main/java/org/keycloak/services/resources/account/AccountRestService.java @@ -56,6 +56,7 @@ import javax.ws.rs.PUT; import javax.ws.rs.Path; import javax.ws.rs.PathParam; import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; import javax.ws.rs.core.Context; import javax.ws.rs.core.HttpHeaders; import javax.ws.rs.core.MediaType; @@ -259,39 +260,6 @@ public class AccountRestService { // TODO Federated identities - /** - * Returns the applications with the given id in the specified realm. - * - * @param clientId client id to search for - * @return application with the provided id - */ - @Path("/applications/{clientId}") - @GET - @Produces(MediaType.APPLICATION_JSON) - public Response getApplication(final @PathParam("clientId") String clientId) { - checkAccountApiEnabled(); - auth.requireOneOf(AccountRoles.MANAGE_ACCOUNT, AccountRoles.VIEW_APPLICATIONS); - ClientModel client = realm.getClientByClientId(clientId); - if (client == null || client.isBearerOnly() || client.getBaseUrl() == null) { - return Cors.add(request, Response.status(Response.Status.NOT_FOUND).entity("No client with clientId: " + clientId + " found.")).build(); - } - - List inUseClients = new LinkedList<>(); - if(!session.sessions().getUserSessions(realm, client).isEmpty()) { - inUseClients.add(clientId); - } - - List offlineClients = new LinkedList<>(); - if(session.sessions().getOfflineSessionsCount(realm, client) > 0) { - offlineClients.add(clientId); - } - - UserConsentModel consentModel = session.users().getConsentByClient(realm, user.getId(), client.getId()); - Map consentModels = Collections.singletonMap(client.getClientId(), consentModel); - - return Cors.add(request, Response.ok(modelToRepresentation(client, inUseClients, offlineClients, consentModels))).build(); - } - private ClientRepresentation modelToRepresentation(ClientModel model, List inUseClients, List offlineClients, Map consents) { ClientRepresentation representation = new ClientRepresentation(); representation.setClientId(model.getClientId()); @@ -497,7 +465,7 @@ public class AccountRestService { @GET @Produces(MediaType.APPLICATION_JSON) @NoCache - public Response applications() { + public Response applications(@QueryParam("name") String name) { checkAccountApiEnabled(); auth.requireOneOf(AccountRoles.MANAGE_ACCOUNT, AccountRoles.VIEW_APPLICATIONS); @@ -540,12 +508,23 @@ public class AccountRestService { if (client.isBearerOnly() || client.getBaseUrl() == null || client.getBaseUrl().isEmpty()) { continue; } - apps.add(modelToRepresentation(client, inUseClients, offlineClients, consentModels)); + else if (matches(client, name)) { + apps.add(modelToRepresentation(client, inUseClients, offlineClients, consentModels)); + } } return Cors.add(request, Response.ok(apps)).auth().allowedOrigins(auth.getToken()).build(); } + private boolean matches(ClientModel client, String name) { + if(name == null) + return true; + else if(client.getName() == null) + return false; + else + return client.getName().toLowerCase().contains(name.toLowerCase()); + } + // TODO Logs private static void checkAccountApiEnabled() { diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/account/AccountRestServiceTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/account/AccountRestServiceTest.java index 3c158cb4be..1656cb7fa0 100755 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/account/AccountRestServiceTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/account/AccountRestServiceTest.java @@ -648,6 +648,28 @@ public class AccountRestServiceTest extends AbstractRestServiceTest { assertClientRep(apps.get("always-display-client"), "Always Display Client", null, false, false, false, null, alwaysDisplayClientAppUri); } + @Test + public void listApplicationsFiltered() throws Exception { + oauth.clientId("in-use-client"); + OAuthClient.AccessTokenResponse tokenResponse = oauth.doGrantAccessTokenRequest("secret1", "view-applications-access", "password"); + Assert.assertNull(tokenResponse.getErrorDescription()); + + TokenUtil token = new TokenUtil("view-applications-access", "password"); + List applications = SimpleHttp + .doGet(getAccountUrl("applications"), httpClient) + .header("Accept", "application/json") + .param("name", "In Use") + .auth(token.getToken()) + .asJson(new TypeReference>() { + }); + assertFalse(applications.isEmpty()); + + Map apps = applications.stream().collect(Collectors.toMap(x -> x.getClientId(), x -> x)); + Assert.assertThat(apps.keySet(), containsInAnyOrder("in-use-client")); + + assertClientRep(apps.get("in-use-client"), "In Use Client", null, false, true, false, null, inUseClientAppUri); + } + @Test public void listApplicationsOfflineAccess() throws Exception { oauth.scope(OAuth2Constants.OFFLINE_ACCESS); @@ -757,30 +779,6 @@ public class AccountRestServiceTest extends AbstractRestServiceTest { assertEquals(403, response.getStatus()); } - @Test - public void getWebConsoleApplication() throws IOException { - TokenUtil token = new TokenUtil("view-applications-access", "password"); - String appId = "security-admin-console"; - ClientRepresentation webConsole = SimpleHttp - .doGet(getAccountUrl("applications/" + appId), httpClient) - .header("Accept", "application/json") - .auth(token.getToken()) - .asJson(ClientRepresentation.class); - assertEquals(appId, webConsole.getClientId()); - } - - @Test - public void getWebConsoleApplicationWithoutPermission() throws IOException { - TokenUtil token = new TokenUtil("no-account-access", "password"); - String appId = "security-admin-console"; - SimpleHttp.Response response = SimpleHttp - .doGet(getAccountUrl("applications/" + appId), httpClient) - .header("Accept", "application/json") - .auth(token.getToken()) - .asResponse(); - assertEquals(403, response.getStatus()); - } - @Test public void getNotExistingApplication() throws IOException { TokenUtil token = new TokenUtil("view-applications-access", "password");