keycloak-uncached

[KEYCLOAK-7435] Added code to delete a specific session and

7/20/2018 5:24:03 AM

Details

diff --git a/server-spi-private/src/main/java/org/keycloak/broker/provider/util/SimpleHttp.java b/server-spi-private/src/main/java/org/keycloak/broker/provider/util/SimpleHttp.java
index 24ebb8a..a3d2968 100755
--- a/server-spi-private/src/main/java/org/keycloak/broker/provider/util/SimpleHttp.java
+++ b/server-spi-private/src/main/java/org/keycloak/broker/provider/util/SimpleHttp.java
@@ -48,6 +48,7 @@ import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.zip.GZIPInputStream;
+import org.apache.http.client.methods.HttpDelete;
 
 /**
  * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
@@ -72,6 +73,14 @@ public class SimpleHttp {
         this.method = method;
     }
 
+    public static SimpleHttp doDelete(String url, KeycloakSession session) {
+        return doDelete(url, session.getProvider(HttpClientProvider.class).getHttpClient());
+    }
+
+    public static SimpleHttp doDelete(String url, HttpClient client) {
+        return new SimpleHttp(url, "DELETE", client);
+    }
+
     public static SimpleHttp doGet(String url, KeycloakSession session) {
         return doGet(url, session.getProvider(HttpClientProvider.class).getHttpClient());
     }
@@ -157,12 +166,17 @@ public class SimpleHttp {
     private Response makeRequest() throws IOException {
         boolean get = method.equals("GET");
         boolean post = method.equals("POST");
+        boolean delete = method.equals("DELETE");
 
         HttpRequestBase httpRequest = new HttpPost(url);
         if (get) {
             httpRequest = new HttpGet(appendParameterToUrl(url));
         }
 
+        if (delete) {
+            httpRequest = new HttpDelete(appendParameterToUrl(url));
+        }
+
         if (post) {
             if (params != null) {
                 ((HttpPost) httpRequest).setEntity(getFormEntityFromParameter());
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 57b808c..7a71167 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
@@ -39,14 +39,7 @@ import org.keycloak.services.messages.Messages;
 import org.keycloak.services.resources.Cors;
 import org.keycloak.storage.ReadOnlyException;
 
-import javax.ws.rs.Consumes;
-import javax.ws.rs.DELETE;
-import javax.ws.rs.GET;
-import javax.ws.rs.OPTIONS;
-import javax.ws.rs.POST;
-import javax.ws.rs.Path;
-import javax.ws.rs.Produces;
-import javax.ws.rs.QueryParam;
+import javax.ws.rs.*;
 import javax.ws.rs.core.Context;
 import javax.ws.rs.core.HttpHeaders;
 import javax.ws.rs.core.MediaType;
@@ -261,12 +254,30 @@ public class AccountRestService {
         return Cors.add(request, Response.ok()).auth().allowedOrigins(auth.getToken()).build();
     }
 
+    /**
+     * Remove a specific session
+     *
+     * @param id a specific session to remove
+     * @return
+     */
+    @Path("/session")
+    @DELETE
+    @Produces(MediaType.APPLICATION_JSON)
+    @NoCache
+    public Response sessionLogout(@QueryParam("id") String id) {
+        UserSessionModel userSession = session.sessions().getUserSession(realm, id);
+        if (userSession != null && userSession.getUser().equals(user)) {
+            AuthenticationManager.backchannelLogout(session, userSession, true);
+        }
+        return Cors.add(request, Response.ok()).auth().allowedOrigins(auth.getToken()).build();
+    }
+
     @Path("/credentials")
     public AccountCredentialResource credentials() {
         return new AccountCredentialResource(session, event, user);
     }
 
-    // TODO Federated identities
+   // TODO Federated identities
     // TODO Applications
     // TODO Logs
 
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 01bf87b..509665f 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
@@ -250,6 +250,29 @@ public class AccountRestServiceTest extends AbstractTestRealmKeycloakTest {
         assertEquals(expectedStatus, status);
     }
 
+    public void testDeleteSessions() throws IOException {
+        TokenUtil viewToken = new TokenUtil("view-account-access", "password");
+        oauth.doLogin("view-account-access", "password");
+        List<SessionRepresentation> sessions = SimpleHttp.doGet(getAccountUrl("sessions"), client).auth(viewToken.getToken()).asJson(new TypeReference<List<SessionRepresentation>>() {});
+        assertEquals(2, sessions.size());
+        int status = SimpleHttp.doDelete(getAccountUrl("sessions?current=false"), client).acceptJson().auth(viewToken.getToken()).asStatus();
+        assertEquals(200, status);
+        sessions = SimpleHttp.doGet(getAccountUrl("sessions"), client).auth(viewToken.getToken()).asJson(new TypeReference<List<SessionRepresentation>>() {});
+        assertEquals(1, sessions.size());
+    }
+
+    @Test
+    public void testDeleteSession() throws IOException {
+        TokenUtil viewToken = new TokenUtil("view-account-access", "password");
+        String sessionId = oauth.doLogin("view-account-access", "password").getSessionState();
+        List<SessionRepresentation> sessions = SimpleHttp.doGet(getAccountUrl("sessions"), client).auth(viewToken.getToken()).asJson(new TypeReference<List<SessionRepresentation>>() {});
+        assertEquals(2, sessions.size());
+        int status = SimpleHttp.doDelete(getAccountUrl("session?id=" + sessionId), client).acceptJson().auth(viewToken.getToken()).asStatus();
+        assertEquals(200, status);
+        sessions = SimpleHttp.doGet(getAccountUrl("sessions"), client).auth(viewToken.getToken()).asJson(new TypeReference<List<SessionRepresentation>>() {});
+        assertEquals(1, sessions.size());
+    }
+
     private String getAccountUrl(String resource) {
         return suiteContext.getAuthServerInfo().getContextRoot().toString() + "/auth/realms/test/account" + (resource != null ? "/" + resource : "");
     }