diff --git a/core/src/main/java/org/keycloak/representations/KeyStoreConfig.java b/core/src/main/java/org/keycloak/representations/KeyStoreConfig.java
new file mode 100644
index 0000000000..782669472c
--- /dev/null
+++ b/core/src/main/java/org/keycloak/representations/KeyStoreConfig.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright 2016 Red Hat Inc. and/or its affiliates and other contributors
+ * as indicated by the @author tags. All rights reserved.
+ *
+ * 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.representations;
+
+/**
+ * Configuration of KeyStore.
+ *
+ * @author Stan Silvert ssilvert@redhat.com (C) 2016 Red Hat Inc.
+ */
+public class KeyStoreConfig {
+
+ protected Boolean realmCertificate;
+ protected String storePassword;
+ protected String keyPassword;
+ protected String keyAlias;
+ protected String realmAlias;
+ protected String format;
+
+ public Boolean isRealmCertificate() {
+ return realmCertificate;
+ }
+
+ public void setRealmCertificate(Boolean realmCertificate) {
+ this.realmCertificate = realmCertificate;
+ }
+
+ public String getStorePassword() {
+ return storePassword;
+ }
+
+ public void setStorePassword(String storePassword) {
+ this.storePassword = storePassword;
+ }
+
+ public String getKeyPassword() {
+ return keyPassword;
+ }
+
+ public void setKeyPassword(String keyPassword) {
+ this.keyPassword = keyPassword;
+ }
+
+ public String getKeyAlias() {
+ return keyAlias;
+ }
+
+ public void setKeyAlias(String keyAlias) {
+ this.keyAlias = keyAlias;
+ }
+
+ public String getRealmAlias() {
+ return realmAlias;
+ }
+
+ public void setRealmAlias(String realmAlias) {
+ this.realmAlias = realmAlias;
+ }
+
+ public String getFormat() {
+ return format;
+ }
+
+ public void setFormat(String format) {
+ this.format = format;
+ }
+}
diff --git a/integration/admin-client/pom.xml b/integration/admin-client/pom.xml
index 00b5c27082..c0c88996bc 100755
--- a/integration/admin-client/pom.xml
+++ b/integration/admin-client/pom.xml
@@ -55,6 +55,11 @@
resteasy-client
provided
+
+ org.jboss.resteasy
+ resteasy-multipart-provider
+ provided
+
org.jboss.resteasy
resteasy-jackson2-provider
diff --git a/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/ClientAttributeCertificateResource.java b/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/ClientAttributeCertificateResource.java
new file mode 100644
index 0000000000..30d3bfb469
--- /dev/null
+++ b/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/ClientAttributeCertificateResource.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright 2016 Red Hat Inc. and/or its affiliates and other contributors
+ * as indicated by the @author tags. All rights reserved.
+ *
+ * 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 javax.ws.rs.Consumes;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.UriInfo;
+import org.jboss.resteasy.annotations.cache.NoCache;
+import org.jboss.resteasy.plugins.providers.multipart.MultipartFormDataInput;
+import org.keycloak.representations.KeyStoreConfig;
+import org.keycloak.representations.idm.CertificateRepresentation;
+
+/**
+ *
+ * @author Stan Silvert ssilvert@redhat.com (C) 2016 Red Hat Inc.
+ */
+public interface ClientAttributeCertificateResource {
+
+ /**
+ * Get key info
+ *
+ * @return
+ */
+ @GET
+ @NoCache
+ @Produces(MediaType.APPLICATION_JSON)
+ public CertificateRepresentation getKeyInfo();
+
+ /**
+ * Generate a new certificate with new key pair
+ *
+ * @return
+ */
+ @POST
+ @NoCache
+ @Path("generate")
+ @Produces(MediaType.APPLICATION_JSON)
+ public CertificateRepresentation generate();
+
+ /**
+ * Upload certificate and eventually private key
+ *
+ * @param uriInfo
+ * @param input
+ * @return
+ */
+ @POST
+ @Path("upload")
+ @Consumes(MediaType.MULTIPART_FORM_DATA)
+ @Produces(MediaType.APPLICATION_JSON)
+ public CertificateRepresentation uploadJks(@Context final UriInfo uriInfo, MultipartFormDataInput input);
+
+ /**
+ * Upload only certificate, not private key
+ *
+ * @param uriInfo
+ * @param input
+ * @return
+ */
+ @POST
+ @Path("upload-certificate")
+ @Consumes(MediaType.MULTIPART_FORM_DATA)
+ @Produces(MediaType.APPLICATION_JSON)
+ public CertificateRepresentation uploadJksCertificate(@Context final UriInfo uriInfo, MultipartFormDataInput input);
+
+ /**
+ * Get a keystore file for the client, containing private key and public certificate
+ *
+ * @param config Keystore configuration as JSON
+ * @return
+ */
+ @POST
+ @NoCache
+ @Path("/download")
+ @Produces(MediaType.APPLICATION_OCTET_STREAM)
+ @Consumes(MediaType.APPLICATION_JSON)
+ public byte[] getKeystore(final KeyStoreConfig config);
+
+ /**
+ * Generate a new keypair and certificate, and get the private key file
+ *
+ * Generates a keypair and certificate and serves the private key in a specified keystore format.
+ * Only generated public certificate is saved in Keycloak DB - the private key is not.
+ *
+ * @param config Keystore configuration as JSON
+ * @return
+ */
+ @POST
+ @NoCache
+ @Path("/generate-and-download")
+ @Produces(MediaType.APPLICATION_OCTET_STREAM)
+ @Consumes(MediaType.APPLICATION_JSON)
+ public byte[] generateAndGetKeystore(final KeyStoreConfig config);
+}
diff --git a/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/ClientResource.java b/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/ClientResource.java
index ee1c69ad26..644cc7a8e6 100755
--- a/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/ClientResource.java
+++ b/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/ClientResource.java
@@ -34,7 +34,6 @@ import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;
import java.util.List;
import java.util.Map;
-import java.util.Set;
/**
* @author rodrigo.sasaki@icarros.com.br
@@ -55,21 +54,6 @@ public interface ClientResource {
@DELETE
public void remove();
- @GET
- @Path("allowed-origins")
- @Produces(MediaType.APPLICATION_JSON)
- public Set getAllowedOrigins();
-
- @PUT
- @Path("allowed-origins")
- @Consumes(MediaType.APPLICATION_JSON)
- public void updateAllowedOrigins(Set allowedOrigins);
-
- @DELETE
- @Path("allowed-origins")
- @Consumes(MediaType.APPLICATION_JSON)
- public void removeAllowedOrigins(Set originsToRemove);
-
@POST
@Path("client-secret")
@Produces(MediaType.APPLICATION_JSON)
@@ -80,19 +64,31 @@ public interface ClientResource {
@Produces(MediaType.APPLICATION_JSON)
public CredentialRepresentation getSecret();
+ /**
+ * Generate a new registration access token for the client
+ *
+ * @return
+ */
+ @Path("registration-access-token")
+ @POST
+ @Produces(MediaType.APPLICATION_JSON)
+ @Consumes(MediaType.APPLICATION_JSON)
+ public ClientRepresentation regenerateRegistrationAccessToken();
+
+ /**
+ * Get representation of certificate resource
+ *
+ * @param attributePrefix
+ * @return
+ */
+ @Path("certificates/{attr}")
+ public ClientAttributeCertificateResource getCertficateResource(@PathParam("attr") String attributePrefix);
+
@GET
@NoCache
@Path("installation/providers/{providerId}")
public String getInstallationProvider(@PathParam("providerId") String providerId);
- @POST
- @Path("logout-all")
- public void logoutAllUsers();
-
- @POST
- @Path("logout-user/{username}")
- public void logoutUser(@PathParam("username") String username);
-
@Path("session-count")
@GET
@Produces(MediaType.APPLICATION_JSON)
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 15ca073e04..86548ecf84 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
@@ -149,7 +149,7 @@ public interface RealmResource {
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public Response partialImport(PartialImportRepresentation rep);
-
+
@Path("authentication")
@Consumes(MediaType.APPLICATION_JSON)
AuthenticationManagementResource flows();
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/ClientAttributeCertificateResource.java b/services/src/main/java/org/keycloak/services/resources/admin/ClientAttributeCertificateResource.java
index 6633a68f20..bea79a018a 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/ClientAttributeCertificateResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/ClientAttributeCertificateResource.java
@@ -28,6 +28,7 @@ import org.keycloak.models.ClientModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
import org.keycloak.models.utils.KeycloakModelUtils;
+import org.keycloak.representations.KeyStoreConfig;
import org.keycloak.representations.idm.CertificateRepresentation;
import org.keycloak.services.ErrorResponseException;
import org.keycloak.common.util.PemUtils;
@@ -57,7 +58,7 @@ import java.util.Map;
* @version $Revision: 1 $
*/
public class ClientAttributeCertificateResource {
-
+
public static final String PRIVATE_KEY = "private.key";
public static final String X509CERTIFICATE = "certificate";
@@ -112,7 +113,7 @@ public class ClientAttributeCertificateResource {
client.setAttribute(privateAttribute, info.getPrivateKey());
client.setAttribute(certificateAttribute, info.getCertificate());
-
+
adminEvent.operation(OperationType.ACTION).resourcePath(session.getContext().getUri()).representation(info).success();
return info;
@@ -225,64 +226,6 @@ public class ClientAttributeCertificateResource {
return info;
}
-
- public static class KeyStoreConfig {
- protected Boolean realmCertificate;
- protected String storePassword;
- protected String keyPassword;
- protected String keyAlias;
- protected String realmAlias;
- protected String format;
-
- public Boolean isRealmCertificate() {
- return realmCertificate;
- }
-
- public void setRealmCertificate(Boolean realmCertificate) {
- this.realmCertificate = realmCertificate;
- }
-
- public String getStorePassword() {
- return storePassword;
- }
-
- public void setStorePassword(String storePassword) {
- this.storePassword = storePassword;
- }
-
- public String getKeyPassword() {
- return keyPassword;
- }
-
- public void setKeyPassword(String keyPassword) {
- this.keyPassword = keyPassword;
- }
-
- public String getKeyAlias() {
- return keyAlias;
- }
-
- public void setKeyAlias(String keyAlias) {
- this.keyAlias = keyAlias;
- }
-
- public String getRealmAlias() {
- return realmAlias;
- }
-
- public void setRealmAlias(String realmAlias) {
- this.realmAlias = realmAlias;
- }
-
- public String getFormat() {
- return format;
- }
-
- public void setFormat(String format) {
- this.format = format;
- }
- }
-
/**
* Get a keystore file for the client, containing private key and public certificate
*
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/ClientResource.java b/services/src/main/java/org/keycloak/services/resources/admin/ClientResource.java
index 790dd2b8f6..09c3deec81 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/ClientResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/ClientResource.java
@@ -45,7 +45,6 @@ import org.keycloak.services.managers.RealmManager;
import org.keycloak.services.managers.ResourceAdminManager;
import org.keycloak.services.resources.KeycloakApplication;
import org.keycloak.services.ErrorResponse;
-import org.keycloak.util.JsonSerialization;
import org.keycloak.common.util.Time;
import javax.ws.rs.Consumes;
@@ -62,12 +61,11 @@ import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriInfo;
-import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
-import java.util.Set;
+
import static java.lang.Boolean.TRUE;
@@ -172,54 +170,6 @@ public class ClientResource {
return provider.generateInstallation(session, realm, client, keycloak.getBaseUri(uriInfo));
}
-
- /**
- * Get keycloak.json file
- *
- * this method is deprecated, see getInstallationProvider
- *
- * Returns a keycloak.json file to be used to configure the adapter of the specified client.
- *
- * @return
- * @throws IOException
- */
- @Deprecated
- @GET
- @NoCache
- @Path("installation/json")
- @Produces(MediaType.APPLICATION_JSON)
- public String getInstallation() throws IOException {
- auth.requireView();
-
- ClientManager clientManager = new ClientManager(new RealmManager(session));
- Object rep = clientManager.toInstallationRepresentation(realm, client, getKeycloakApplication().getBaseUri(uriInfo));
-
- // TODO Temporary solution to pretty-print
- return JsonSerialization.mapper.writerWithDefaultPrettyPrinter().writeValueAsString(rep);
- }
-
- /**
- * Get adapter configuration XML for JBoss / Wildfly Keycloak subsystem
- *
- * this method is deprecated, see getInstallationProvider
- *
- * Returns XML that can be included in the JBoss / Wildfly Keycloak subsystem to configure the adapter of that client.
- *
- * @return
- * @throws IOException
- */
- @Deprecated
- @GET
- @NoCache
- @Path("installation/jboss")
- @Produces(MediaType.TEXT_PLAIN)
- public String getJBossInstallation() throws IOException {
- auth.requireView();
-
- ClientManager clientManager = new ClientManager(new RealmManager(session));
- return clientManager.toJBossSubsystemConfig(realm, client, getKeycloakApplication().getBaseUri(uriInfo));
- }
-
/**
* Delete the client
*
@@ -306,64 +256,6 @@ public class ClientResource {
return new RoleContainerResource(uriInfo, realm, auth, client, adminEvent);
}
- /**
- * Get allowed origins
- *
- * This is used for CORS requests. Access tokens will have
- * their allowedOrigins claim set to this value for tokens created for this client.
- *
- * @return
- */
- @Path("allowed-origins")
- @GET
- @NoCache
- @Produces(MediaType.APPLICATION_JSON)
- public Set getAllowedOrigins()
- {
- auth.requireView();
- return client.getWebOrigins();
- }
-
- /**
- * Update allowed origins
- *
- * This is used for CORS requests. Access tokens will have
- * their allowedOrigins claim set to this value for tokens created for this client.
- *
- * @param allowedOrigins
- */
- @Path("allowed-origins")
- @PUT
- @Consumes(MediaType.APPLICATION_JSON)
- public void updateAllowedOrigins(Set allowedOrigins)
- {
- auth.requireManage();
-
- client.setWebOrigins(allowedOrigins);
- adminEvent.operation(OperationType.UPDATE).resourcePath(uriInfo).representation(client).success();
- }
-
- /**
- * Delete the specified origins from current allowed origins
- *
- * This is used for CORS requests. Access tokens will have
- * their allowedOrigins claim set to this value for tokens created for this client.
- *
- * @param allowedOrigins List of origins to delete
- */
- @Path("allowed-origins")
- @DELETE
- @Consumes(MediaType.APPLICATION_JSON)
- public void deleteAllowedOrigins(Set allowedOrigins)
- {
- auth.requireManage();
-
- for (String origin : allowedOrigins) {
- client.removeWebOrigin(origin);
- }
- adminEvent.operation(OperationType.DELETE).resourcePath(uriInfo).success();
- }
-
/**
* Get a user dedicated to the service account
*
@@ -507,41 +399,6 @@ public class ClientResource {
return sessions;
}
-
- /**
- * Logout all sessions
- *
- * If the client has an admin URL, invalidate all sessions associated with that client directly.
- *
- */
- @Path("logout-all")
- @POST
- public GlobalRequestResult logoutAll() {
- auth.requireManage();
- adminEvent.operation(OperationType.ACTION).resourcePath(uriInfo).success();
- return new ResourceAdminManager(session).logoutClient(uriInfo.getRequestUri(), realm, client);
-
- }
-
- /**
- * Logout the user by username
- *
- * If the client has an admin URL, invalidate the sessions for a particular user directly.
- *
- */
- @Path("logout-user/{username}")
- @POST
- public void logout(final @PathParam("username") String username) {
- auth.requireManage();
- UserModel user = session.users().getUserByUsername(username, realm);
- if (user == null) {
- throw new NotFoundException("User not found");
- }
- adminEvent.operation(OperationType.ACTION).resourcePath(uriInfo).success();
- new ResourceAdminManager(session).logoutUserFromClient(uriInfo.getRequestUri(), realm, client, user);
-
- }
-
/**
* Register a cluster node with the client
*
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/info/ServerInfoAdminResource.java b/services/src/main/java/org/keycloak/services/resources/admin/info/ServerInfoAdminResource.java
index 419ea1652b..4454ccbfe6 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/info/ServerInfoAdminResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/info/ServerInfoAdminResource.java
@@ -51,8 +51,14 @@ import org.keycloak.provider.Spi;
import org.keycloak.representations.idm.ConfigPropertyRepresentation;
import org.keycloak.representations.idm.ProtocolMapperRepresentation;
import org.keycloak.representations.idm.ProtocolMapperTypeRepresentation;
-import org.keycloak.representations.info.*;
import org.keycloak.broker.social.SocialIdentityProvider;
+import org.keycloak.representations.info.ClientInstallationRepresentation;
+import org.keycloak.representations.info.MemoryInfoRepresentation;
+import org.keycloak.representations.info.ProviderRepresentation;
+import org.keycloak.representations.info.ServerInfoRepresentation;
+import org.keycloak.representations.info.SpiInfoRepresentation;
+import org.keycloak.representations.info.SystemInfoRepresentation;
+import org.keycloak.representations.info.ThemeInfoRepresentation;
/**
* @author Stian Thorgersen
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/servlet/AbstractSessionServletAdapterTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/servlet/AbstractSessionServletAdapterTest.java
index a027234c2b..0bce8a6780 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/servlet/AbstractSessionServletAdapterTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/servlet/AbstractSessionServletAdapterTest.java
@@ -23,22 +23,29 @@ import org.jboss.arquillian.drone.api.annotation.Drone;
import org.jboss.arquillian.graphene.page.Page;
import org.jboss.shrinkwrap.api.spec.WebArchive;
import org.junit.After;
+
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
+
import org.junit.Test;
import org.keycloak.OAuth2Constants;
import org.keycloak.admin.client.resource.ClientResource;
import org.keycloak.protocol.oidc.OIDCLoginProtocolService;
import org.keycloak.representations.idm.ClientRepresentation;
import org.keycloak.representations.idm.RealmRepresentation;
+import org.keycloak.representations.idm.UserRepresentation;
import org.keycloak.testsuite.adapter.page.SessionPortal;
+
import static org.keycloak.testsuite.auth.page.AuthRealm.DEMO;
+
import org.keycloak.testsuite.auth.page.account.Sessions;
import org.keycloak.testsuite.auth.page.login.Login;
+
import static org.keycloak.testsuite.admin.ApiUtil.findClientResourceByClientId;
import static org.keycloak.testsuite.util.URLAssert.assertCurrentUrlEquals;
import static org.keycloak.testsuite.util.URLAssert.assertCurrentUrlStartsWithLoginUrlOf;
+
import org.keycloak.testsuite.util.SecondBrowser;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
@@ -156,9 +163,11 @@ public abstract class AbstractSessionServletAdapterTest extends AbstractServlets
public void testAdminApplicationLogout() {
// login as bburke
loginAndCheckSession(driver, testRealmLoginPage);
+
// logout mposolda with admin client
- findClientResourceByClientId(testRealmResource(), "session-portal")
- .logoutUser("mposolda");
+ UserRepresentation mposolda = testRealmResource().users().search("mposolda", null, null, null, null, null).get(0);
+ testRealmResource().users().get(mposolda.getId()).logout();
+
// bburke should be still logged with original httpSession in our browser window
sessionPortalPage.navigateTo();
assertEquals(driver.getCurrentUrl(), sessionPortalPage.toString());
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/AbstractClientTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/AbstractClientTest.java
index 7059318479..9913c1764c 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/AbstractClientTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/AbstractClientTest.java
@@ -17,10 +17,12 @@
package org.keycloak.testsuite.admin.client;
+import java.util.List;
import javax.ws.rs.core.Response;
import org.keycloak.admin.client.resource.ClientResource;
import org.keycloak.representations.idm.ClientRepresentation;
import org.keycloak.representations.idm.RealmRepresentation;
+import org.keycloak.representations.idm.UserRepresentation;
import org.keycloak.testsuite.AbstractAuthTest;
import org.keycloak.testsuite.admin.ApiUtil;
@@ -34,29 +36,35 @@ public abstract class AbstractClientTest extends AbstractAuthTest {
return testRealmResource().toRepresentation();
}
- protected void createOidcClient(String name) {
+ // returns UserRepresentation retrieved from server, with all fields, including id
+ protected UserRepresentation getFullUserRep(String userName) {
+ List results = testRealmResource().users().search(userName, null, null, null, null, null);
+ if (results.size() != 1) throw new RuntimeException("Did not find single user with username " + userName);
+ return results.get(0);
+ }
+
+ protected String createOidcClient(String name) {
ClientRepresentation clientRep = new ClientRepresentation();
clientRep.setClientId(name);
clientRep.setName(name);
clientRep.setRootUrl("foo");
clientRep.setProtocol("openid-connect");
- createClient(clientRep);
+ return createClient(clientRep);
}
- protected void createSamlClient(String name) {
+ protected String createSamlClient(String name) {
ClientRepresentation clientRep = new ClientRepresentation();
clientRep.setClientId(name);
clientRep.setName(name);
clientRep.setProtocol("saml");
clientRep.setAdminUrl("samlEndpoint");
- createClient(clientRep);
+ return createClient(clientRep);
}
- protected void createClient(ClientRepresentation clientRep) {
+ protected String createClient(ClientRepresentation clientRep) {
Response resp = testRealmResource().clients().create(clientRep);
- // for some reason, findAll() will later fail unless readEntity is called here
- resp.readEntity(String.class);
- //testRealmResource().clients().findAll();
+ resp.close();
+ return ApiUtil.getCreatedId(resp);
}
protected ClientRepresentation findClientRepresentation(String name) {
@@ -69,4 +77,8 @@ public abstract class AbstractClientTest extends AbstractAuthTest {
return ApiUtil.findClientResourceByName(testRealmResource(), name);
}
+ protected ClientResource findClientResourceById(String id) {
+ return ApiUtil.findClientResourceByClientId(testRealmResource(), id);
+ }
+
}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/ClientProtocolMapperTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/ClientProtocolMapperTest.java
new file mode 100644
index 0000000000..acf2329fba
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/ClientProtocolMapperTest.java
@@ -0,0 +1,266 @@
+/*
+ * Copyright 2016 Red Hat Inc. and/or its affiliates and other contributors
+ * as indicated by the @author tags. All rights reserved.
+ *
+ * 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.testsuite.admin.client;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import javax.ws.rs.NotFoundException;
+import javax.ws.rs.core.Response;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.keycloak.admin.client.resource.ClientResource;
+import org.keycloak.admin.client.resource.ProtocolMappersResource;
+import org.keycloak.representations.idm.ProtocolMapperRepresentation;
+import org.keycloak.testsuite.admin.ApiUtil;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+/**
+ *
+ * @author Stan Silvert ssilvert@redhat.com (C) 2016 Red Hat Inc.
+ */
+public class ClientProtocolMapperTest extends AbstractClientTest {
+
+ private ClientResource oidcClientRsc;
+ private ProtocolMappersResource oidcMappersRsc;
+ private ClientResource samlClientRsc;
+ private ProtocolMappersResource samlMappersRsc;
+
+ private Map> builtinMappers = null;
+
+ @Before
+ public void init() {
+ createOidcClient("oidcMapperClient");
+ oidcClientRsc = findClientResource("oidcMapperClient");
+ oidcMappersRsc = oidcClientRsc.getProtocolMappers();
+
+ createSamlClient("samlMapperClient");
+ samlClientRsc = findClientResource("samlMapperClient");
+ samlMappersRsc = samlClientRsc.getProtocolMappers();
+
+ builtinMappers = adminClient.serverInfo().getInfo().getBuiltinProtocolMappers();
+ }
+
+ @After
+ public void tearDown() {
+ oidcClientRsc.remove();
+ samlClientRsc.remove();
+ }
+
+ private ProtocolMapperRepresentation makeMapper(String protocol, String name, String mapperType, Map config) {
+ ProtocolMapperRepresentation rep = new ProtocolMapperRepresentation();
+ rep.setProtocol(protocol);
+ rep.setName(name);
+ rep.setProtocolMapper(mapperType);
+ rep.setConfig(config);
+ rep.setConsentRequired(true);
+ rep.setConsentText("Test Consent Text");
+ return rep;
+ }
+
+ private ProtocolMapperRepresentation makeSamlMapper(String name) {
+ Map config = new HashMap<>();
+ config.put("role", "account.view-profile");
+ config.put("new.role.name", "new-role-name");
+ return makeMapper("saml", name, "saml-role-name-mapper", config);
+ }
+
+ private ProtocolMapperRepresentation makeOidcMapper(String name) {
+ Map config = new HashMap<>();
+ config.put("role", "myrole");
+ return makeMapper("openid-connect", name, "oidc-hardcoded-role-mapper", config);
+ }
+
+ private void assertEqualMappers(ProtocolMapperRepresentation original, ProtocolMapperRepresentation created) {
+ assertNotNull(created);
+ assertEquals(original.getName(), created.getName());
+ assertEquals(original.getConfig(), created.getConfig());
+ assertEquals(original.getConsentText(), created.getConsentText());
+ assertEquals(original.isConsentRequired(), created.isConsentRequired());
+ assertEquals(original.getProtocol(), created.getProtocol());
+ assertEquals(original.getProtocolMapper(), created.getProtocolMapper());
+ }
+
+ @Test
+ public void testGetMappersList() {
+ assertFalse(oidcMappersRsc.getMappers().isEmpty());
+ assertFalse(samlMappersRsc.getMappers().isEmpty());
+ }
+
+ private boolean containsMapper(List mappers, ProtocolMapperRepresentation mapper) {
+ for (ProtocolMapperRepresentation listedMapper : mappers) {
+ if (listedMapper.getName().equals(mapper.getName())) return true;
+ }
+
+ return false;
+ }
+
+ private List mappersToAdd(List oldMappers,
+ List builtins) {
+ List mappersToAdd = new ArrayList<>();
+ for (ProtocolMapperRepresentation builtin : builtins) {
+ if (!containsMapper(oldMappers, builtin)) mappersToAdd.add(builtin);
+ }
+
+ return mappersToAdd;
+ }
+
+ private void testAddAllBuiltinMappers(ProtocolMappersResource resource, String resourceName) {
+ List oldMappers = resource.getMappersPerProtocol(resourceName);
+ List builtins = builtinMappers.get(resourceName);
+
+ List mappersToAdd = mappersToAdd(oldMappers, builtins);
+
+ // This is used by admin console to add builtin mappers
+ resource.createMapper(mappersToAdd);
+
+ List newMappers = resource.getMappersPerProtocol(resourceName);
+ assertEquals(oldMappers.size() + mappersToAdd.size(), newMappers.size());
+
+ for (ProtocolMapperRepresentation rep : mappersToAdd) {
+ assertTrue(containsMapper(newMappers, rep));
+ }
+ }
+
+ @Test
+ public void testCreateOidcMappersFromList() {
+ testAddAllBuiltinMappers(oidcMappersRsc, "openid-connect");
+ }
+
+ @Test
+ public void testCreateSamlMappersFromList() {
+ testAddAllBuiltinMappers(samlMappersRsc, "saml");
+ }
+
+ @Test
+ public void testCreateSamlProtocolMapper() {
+
+ //{"protocol":"saml",
+ // "config":{"role":"account.view-profile","new.role.name":"new-role-name"},
+ // "consentRequired":true,
+ // "consentText":"My consent text",
+ // "name":"saml-role-name-maper",
+ // "protocolMapper":"saml-role-name-mapper"}
+ ProtocolMapperRepresentation rep = makeSamlMapper("saml-role-name-mapper");
+
+ int totalMappers = samlMappersRsc.getMappers().size();
+ int totalSamlMappers = samlMappersRsc.getMappersPerProtocol("saml").size();
+ Response resp = samlMappersRsc.createMapper(rep);
+ resp.close();
+ assertEquals(totalMappers + 1, samlMappersRsc.getMappers().size());
+ assertEquals(totalSamlMappers + 1, samlMappersRsc.getMappersPerProtocol("saml").size());
+
+ String createdId = ApiUtil.getCreatedId(resp);
+ ProtocolMapperRepresentation created = samlMappersRsc.getMapperById(createdId);
+ assertEqualMappers(rep, created);
+ }
+
+ @Test
+ public void testCreateOidcProtocolMapper() {
+ //{"protocol":"openid-connect",
+ // "config":{"role":"myrole"},
+ // "consentRequired":true,
+ // "consentText":"My consent text",
+ // "name":"oidc-hardcoded-role-mapper",
+ // "protocolMapper":"oidc-hardcoded-role-mapper"}
+ ProtocolMapperRepresentation rep = makeOidcMapper("oidc-hardcoded-role-mapper");
+
+ int totalMappers = oidcMappersRsc.getMappers().size();
+ int totalOidcMappers = oidcMappersRsc.getMappersPerProtocol("openid-connect").size();
+ Response resp = oidcMappersRsc.createMapper(rep);
+ resp.close();
+ assertEquals(totalMappers + 1, oidcMappersRsc.getMappers().size());
+ assertEquals(totalOidcMappers + 1, oidcMappersRsc.getMappersPerProtocol("openid-connect").size());
+
+ String createdId = ApiUtil.getCreatedId(resp);
+ ProtocolMapperRepresentation created = oidcMappersRsc.getMapperById(createdId);//findByName(samlMappersRsc, "saml-role-name-mapper");
+ assertEqualMappers(rep, created);
+ }
+
+ @Test
+ public void testUpdateSamlMapper() {
+ ProtocolMapperRepresentation rep = makeSamlMapper("saml-role-name-mapper2");
+
+ Response resp = samlMappersRsc.createMapper(rep);
+ resp.close();
+
+ String createdId = ApiUtil.getCreatedId(resp);
+
+ rep.getConfig().put("role", "account.manage-account");
+ rep.setId(createdId);
+ rep.setConsentRequired(false);
+ samlMappersRsc.update(createdId, rep);
+
+ ProtocolMapperRepresentation updated = samlMappersRsc.getMapperById(createdId);
+ assertEqualMappers(rep, updated);
+ }
+
+ @Test
+ public void testUpdateOidcMapper() {
+ ProtocolMapperRepresentation rep = makeOidcMapper("oidc-hardcoded-role-mapper2");
+
+ Response resp = oidcMappersRsc.createMapper(rep);
+ resp.close();
+
+ String createdId = ApiUtil.getCreatedId(resp);
+
+ rep.getConfig().put("role", "myotherrole");
+ rep.setId(createdId);
+ rep.setConsentRequired(false);
+ oidcMappersRsc.update(createdId, rep);
+
+ ProtocolMapperRepresentation updated = oidcMappersRsc.getMapperById(createdId);
+ assertEqualMappers(rep, updated);
+ }
+
+ @Test (expected = NotFoundException.class)
+ public void testDeleteSamlMapper() {
+ ProtocolMapperRepresentation rep = makeSamlMapper("saml-role-name-mapper3");
+
+ Response resp = samlMappersRsc.createMapper(rep);
+ resp.close();
+
+ String createdId = ApiUtil.getCreatedId(resp);
+
+ samlMappersRsc.delete(createdId);
+
+ samlMappersRsc.getMapperById(createdId);
+ }
+
+ @Test (expected = NotFoundException.class)
+ public void testDeleteOidcMapper() {
+ ProtocolMapperRepresentation rep = makeOidcMapper("oidc-hardcoded-role-mapper3");
+
+ Response resp = oidcMappersRsc.createMapper(rep);
+ resp.close();
+
+ String createdId = ApiUtil.getCreatedId(resp);
+
+ oidcMappersRsc.delete(createdId);
+
+ oidcMappersRsc.getMapperById(createdId);
+ }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/ClientRolesTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/ClientRolesTest.java
index 9180f15242..5fb7c7dd0b 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/ClientRolesTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/ClientRolesTest.java
@@ -17,6 +17,7 @@
package org.keycloak.testsuite.admin.client;
+import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.keycloak.admin.client.resource.ClientResource;
@@ -42,16 +43,17 @@ public class ClientRolesTest extends AbstractClientTest {
rolesRsc = clientRsc.roles();
}
+ @After
+ public void tearDown() {
+ clientRsc.remove();
+ }
+
private RoleRepresentation makeRole(String name) {
RoleRepresentation role = new RoleRepresentation();
role.setName(name);
return role;
}
- /* private boolean hasRole(RolesResource rolesRsc, String name) {
- return rolesRsc.get(name) != null;
- }*/
-
private boolean hasRole(RolesResource rolesRsc, String name) {
for (RoleRepresentation role : rolesRsc.list()) {
if (role.getName().equals(name)) return true;
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/CredentialsTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/CredentialsTest.java
new file mode 100644
index 0000000000..2b79e50af9
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/CredentialsTest.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2016 Red Hat Inc. and/or its affiliates and other contributors
+ * as indicated by the @author tags. All rights reserved.
+ *
+ * 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.testsuite.admin.client;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.keycloak.admin.client.resource.ClientAttributeCertificateResource;
+import org.keycloak.admin.client.resource.ClientResource;
+import org.keycloak.representations.idm.CertificateRepresentation;
+import org.keycloak.representations.idm.ClientRepresentation;
+import org.keycloak.representations.idm.CredentialRepresentation;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNull;
+
+/**
+ *
+ * @author Stan Silvert ssilvert@redhat.com (C) 2016 Red Hat Inc.
+ */
+public class CredentialsTest extends AbstractClientTest {
+
+ private ClientResource accountClient;
+
+ @Before
+ public void init() {
+ accountClient = findClientResourceById("account");
+ }
+
+ @Test
+ public void testGetAndRegenerateSecret() {
+ CredentialRepresentation oldCredential = accountClient.getSecret();
+ CredentialRepresentation newCredential = accountClient.generateNewSecret();
+ assertNotNull(oldCredential);
+ assertNotNull(newCredential);
+ assertNotEquals(newCredential.getValue(), oldCredential.getValue());
+ assertEquals(newCredential.getValue(), accountClient.getSecret().getValue());
+ }
+
+ @Test
+ public void testGetAndRegenerateRegistrationAccessToken() {
+ ClientRepresentation rep = accountClient.toRepresentation();
+ String oldToken = rep.getRegistrationAccessToken();
+ String newToken = accountClient.regenerateRegistrationAccessToken().getRegistrationAccessToken();
+ assertNull(oldToken); // registration access token not saved in ClientRep
+ assertNotNull(newToken); // it's only available via regenerateRegistrationAccessToken()
+ assertNull(accountClient.toRepresentation().getRegistrationAccessToken());
+ }
+
+ @Test
+ public void testGetCertificateResource() {
+ ClientAttributeCertificateResource certRsc = accountClient.getCertficateResource("jwt.credential");
+ CertificateRepresentation cert = certRsc.generate();
+ CertificateRepresentation certFromGet = certRsc.getKeyInfo();
+ assertEquals(cert.getCertificate(), certFromGet.getCertificate());
+ assertEquals(cert.getPrivateKey(), certFromGet.getPrivateKey());
+ }
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/InstallationTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/InstallationTest.java
index 86927e468a..71371988aa 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/InstallationTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/InstallationTest.java
@@ -17,6 +17,7 @@
package org.keycloak.testsuite.admin.client;
+import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.keycloak.admin.client.resource.ClientResource;
@@ -47,6 +48,12 @@ public class InstallationTest extends AbstractClientTest {
samlClient = findClientResource(SAML_NAME);
}
+ @After
+ public void tearDown() {
+ oidcClient.remove();
+ samlClient.remove();
+ }
+
private String authServerUrl() {
return AuthServerTestEnricher.getAuthServerContextRoot() + "/auth";
}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/SessionTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/SessionTest.java
new file mode 100644
index 0000000000..cf15f960a9
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/SessionTest.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright 2016 Red Hat Inc. and/or its affiliates and other contributors
+ * as indicated by the @author tags. All rights reserved.
+ *
+ * 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.testsuite.admin.client;
+
+import java.util.List;
+import org.jboss.arquillian.graphene.page.Page;
+import org.junit.Before;
+import org.junit.Test;
+import org.keycloak.admin.client.resource.ClientResource;
+import org.keycloak.representations.idm.UserRepresentation;
+import org.keycloak.representations.idm.UserSessionRepresentation;
+import org.keycloak.testsuite.auth.page.account.AccountManagement;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+/**
+ *
+ * @author Stan Silvert ssilvert@redhat.com (C) 2016 Red Hat Inc.
+ */
+public class SessionTest extends AbstractClientTest {
+ private static boolean testUserCreated = false;
+
+ @Page
+ protected AccountManagement testRealmAccountManagementPage;
+
+ @Before
+ public void init() {
+ // make user test user exists in test realm
+ if (!testUserCreated) createTestUserWithAdminClient();
+ testUserCreated = true;
+ }
+
+ @Test
+ public void testGetAppSessionCount() {
+ ClientResource accountClient = findClientResourceById("account");
+ int sessionCount = accountClient.getApplicationSessionCount().get("count");
+ assertEquals(0, sessionCount);
+
+ testRealmAccountManagementPage.navigateTo();
+ loginPage.form().login(testUser);
+
+ sessionCount = accountClient.getApplicationSessionCount().get("count");
+ assertEquals(1, sessionCount);
+
+ testRealmAccountManagementPage.signOut();
+
+ sessionCount = accountClient.getApplicationSessionCount().get("count");
+ assertEquals(0, sessionCount);
+ }
+
+ @Test
+ public void testGetUserSessions() {
+ //List> stats = this.testRealmResource().getClientSessionStats();
+ ClientResource account = findClientResourceById("account");
+
+ testRealmAccountManagementPage.navigateTo();
+ loginPage.form().login(testUser);
+
+ List sessions = account.getUserSessions(0, 5);
+ assertEquals(1, sessions.size());
+
+ UserSessionRepresentation rep = sessions.get(0);
+
+ UserRepresentation testUserRep = getFullUserRep(testUser.getUsername());
+ assertEquals(testUserRep.getId(), rep.getUserId());
+ assertEquals(testUserRep.getUsername(), rep.getUsername());
+
+ String clientId = account.toRepresentation().getId();
+ assertEquals("account", rep.getClients().get(clientId));
+ assertNotNull(rep.getIpAddress());
+ assertNotNull(rep.getLastAccess());
+ assertNotNull(rep.getStart());
+
+ testRealmAccountManagementPage.signOut();
+ }
+}
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/adapter/AdapterTestStrategy.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/adapter/AdapterTestStrategy.java
index 7b0d9d3891..7097588b9b 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/adapter/AdapterTestStrategy.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/adapter/AdapterTestStrategy.java
@@ -59,6 +59,7 @@ import java.net.URI;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
+import org.keycloak.representations.idm.UserRepresentation;
/**
* Tests Undertow Adapter
@@ -598,7 +599,8 @@ public class AdapterTestStrategy extends ExternalResource {
// logout mposolda with admin client
Keycloak keycloakAdmin = Keycloak.getInstance(AUTH_SERVER_URL, "master", "admin", "admin", Constants.ADMIN_CLI_CLIENT_ID);
- ApiUtil.findClientByClientId(keycloakAdmin.realm("demo"), "session-portal").logoutUser("mposolda");
+ UserRepresentation mposolda = keycloakAdmin.realm("demo").users().search("mposolda", null, null, null, null, null).get(0);
+ keycloakAdmin.realm("demo").users().get(mposolda.getId()).logout();
// bburke should be still logged with original httpSession in our browser window
driver.navigate().to(APP_SERVER_BASE_URL + "/session-portal");
diff --git a/themes/src/main/resources/theme/base/admin/resources/js/services.js b/themes/src/main/resources/theme/base/admin/resources/js/services.js
index 1ec8513972..868ec4d2b0 100755
--- a/themes/src/main/resources/theme/base/admin/resources/js/services.js
+++ b/themes/src/main/resources/theme/base/admin/resources/js/services.js
@@ -952,19 +952,6 @@ module.factory('ClientOfflineSessions', function($resource) {
});
});
-module.factory('ClientLogoutAll', function($resource) {
- return $resource(authUrl + '/admin/realms/:realm/clients/:client/logout-all', {
- realm : '@realm',
- client : "@client"
- });
-});
-module.factory('ClientLogoutUser', function($resource) {
- return $resource(authUrl + '/admin/realms/:realm/clients/:client/logout-user/:user', {
- realm : '@realm',
- client : "@client",
- user : "@user"
- });
-});
module.factory('RealmLogoutAll', function($resource) {
return $resource(authUrl + '/admin/realms/:realm/logout-all', {
realm : '@realm'