diff --git a/core/src/main/java/org/keycloak/util/StreamUtil.java b/core/src/main/java/org/keycloak/util/StreamUtil.java
new file mode 100755
index 0000000000..428a5903d8
--- /dev/null
+++ b/core/src/main/java/org/keycloak/util/StreamUtil.java
@@ -0,0 +1,31 @@
+package org.keycloak.util;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+
+/**
+ * @author Bill Burke
+ * @version $Revision: 1 $
+ */
+public class StreamUtil {
+ public static String readString(InputStream in) throws IOException
+ {
+ char[] buffer = new char[1024];
+ StringBuilder builder = new StringBuilder();
+ BufferedReader reader = new BufferedReader(new InputStreamReader(in));
+ int wasRead = 0;
+ do
+ {
+ wasRead = reader.read(buffer, 0, 1024);
+ if (wasRead > 0)
+ {
+ builder.append(buffer, 0, wasRead);
+ }
+ }
+ while (wasRead > -1);
+
+ return builder.toString();
+ }
+}
diff --git a/integration/adapter-core/src/main/java/org/keycloak/adapters/TokenGrantRequest.java b/integration/adapter-core/src/main/java/org/keycloak/adapters/TokenGrantRequest.java
index 469ab0683a..76fdf4b06d 100755
--- a/integration/adapter-core/src/main/java/org/keycloak/adapters/TokenGrantRequest.java
+++ b/integration/adapter-core/src/main/java/org/keycloak/adapters/TokenGrantRequest.java
@@ -12,11 +12,10 @@ import org.keycloak.representations.AccessTokenResponse;
import org.keycloak.representations.idm.CredentialRepresentation;
import org.keycloak.util.JsonSerialization;
import org.keycloak.util.KeycloakUriBuilder;
+import org.keycloak.util.StreamUtil;
-import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
-import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@@ -89,32 +88,12 @@ public class TokenGrantRequest {
}
- protected static String readString(InputStream in) throws IOException
- {
- char[] buffer = new char[1024];
- StringBuilder builder = new StringBuilder();
- BufferedReader reader = new BufferedReader(new InputStreamReader(in));
- int wasRead = 0;
- do
- {
- wasRead = reader.read(buffer, 0, 1024);
- if (wasRead > 0)
- {
- builder.append(buffer, 0, wasRead);
- }
- }
- while (wasRead > -1);
-
- return builder.toString();
- }
-
-
protected static void error(int status, HttpEntity entity) throws HttpFailure, IOException {
String body = null;
if (entity != null) {
InputStream is = entity.getContent();
try {
- body = readString(is);
+ body = StreamUtil.readString(is);
} catch (IOException e) {
} finally {
diff --git a/integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/OAuthAuthenticatorValve.java b/integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/OAuthAuthenticatorValve.java
index c218d3677c..b8b068836c 100755
--- a/integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/OAuthAuthenticatorValve.java
+++ b/integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/OAuthAuthenticatorValve.java
@@ -26,9 +26,11 @@ import org.keycloak.jose.jws.crypto.RSAProvider;
import org.keycloak.representations.SkeletonKeyToken;
import org.keycloak.representations.adapters.action.LogoutAction;
import org.keycloak.util.JsonSerialization;
+import org.keycloak.util.StreamUtil;
import javax.security.auth.login.LoginException;
import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashSet;
@@ -120,8 +122,8 @@ public class OAuthAuthenticatorValve extends FormAuthenticator implements Lifecy
return false;
}
- protected JWSInput verifyAdminRequest(Request request, HttpServletResponse response) throws IOException {
- String token = request.getParameter("token");
+ protected JWSInput verifyAdminRequest(HttpServletRequest request, HttpServletResponse response) throws IOException {
+ String token = StreamUtil.readString(request.getInputStream());
if (token == null) {
log.warn("admin request failed, no token");
response.sendError(403, "no token");
diff --git a/integration/undertow/src/main/java/org/keycloak/adapters/undertow/KeycloakAuthenticationMechanism.java b/integration/undertow/src/main/java/org/keycloak/adapters/undertow/KeycloakAuthenticationMechanism.java
index 25a2e7dd2a..120546f9b9 100755
--- a/integration/undertow/src/main/java/org/keycloak/adapters/undertow/KeycloakAuthenticationMechanism.java
+++ b/integration/undertow/src/main/java/org/keycloak/adapters/undertow/KeycloakAuthenticationMechanism.java
@@ -32,16 +32,21 @@ public class KeycloakAuthenticationMechanism implements AuthenticationMechanism
protected RealmConfiguration realmConfig;
protected int sslRedirectPort;
- public KeycloakAuthenticationMechanism(ResourceMetadata resourceMetadata, AdapterConfig config, RealmConfiguration realmConfig, int sslRedirectPort) {
- this.resourceMetadata = resourceMetadata;
+ public KeycloakAuthenticationMechanism(AdapterConfig config, RealmConfiguration realmConfig, int sslRedirectPort) {
+ this.resourceMetadata = realmConfig.getMetadata();
this.adapterConfig = config;
this.realmConfig = realmConfig;
this.sslRedirectPort = sslRedirectPort;
}
- public KeycloakAuthenticationMechanism(ResourceMetadata resourceMetadata, AdapterConfig config, RealmConfiguration realmConfig) {
+ public KeycloakAuthenticationMechanism(AdapterConfig adapterConfig, ResourceMetadata resourceMetadata) {
this.resourceMetadata = resourceMetadata;
- this.adapterConfig = config;
+ this.adapterConfig = adapterConfig;
+ }
+
+ public KeycloakAuthenticationMechanism(AdapterConfig adapterConfig, RealmConfiguration realmConfig) {
+ this.resourceMetadata = realmConfig.getMetadata();
+ this.adapterConfig = adapterConfig;
this.realmConfig = realmConfig;
}
@@ -57,8 +62,8 @@ public class KeycloakAuthenticationMechanism implements AuthenticationMechanism
final SkeletonKeyToken token = bearer.getToken();
String surrogate = bearer.getSurrogate();
SkeletonKeySession session = new SkeletonKeySession(bearer.getTokenString(), token, resourceMetadata);
- propagateBearer(exchange, session);
- completeAuthentication(exchange, securityContext, token, surrogate);
+ SkeletonKeyPrincipal principal = completeAuthentication(securityContext, token, surrogate);
+ propagateBearer(exchange, session, principal);
return AuthenticationMechanismOutcome.AUTHENTICATED;
}
else if (adapterConfig.isBearerOnly()) {
@@ -78,8 +83,8 @@ public class KeycloakAuthenticationMechanism implements AuthenticationMechanism
}
SkeletonKeySession session = new SkeletonKeySession(oauth.getTokenString(), oauth.getToken(), resourceMetadata);
- propagateOauth(exchange, session);
- completeAuthentication(exchange, securityContext, oauth.getToken(), null);
+ SkeletonKeyPrincipal principal = completeAuthentication(securityContext, oauth.getToken(), null);
+ propagateOauth(exchange, session, principal);
log.info("AUTHENTICATED");
return AuthenticationMechanismOutcome.AUTHENTICATED;
}
@@ -92,7 +97,7 @@ public class KeycloakAuthenticationMechanism implements AuthenticationMechanism
return new BearerTokenAuthenticator(resourceMetadata, adapterConfig.isUseResourceRoleMappings());
}
- protected void completeAuthentication(HttpServerExchange exchange, SecurityContext securityContext, SkeletonKeyToken token, String surrogate) {
+ protected SkeletonKeyPrincipal completeAuthentication(SecurityContext securityContext, SkeletonKeyToken token, String surrogate) {
final SkeletonKeyPrincipal skeletonKeyPrincipal = new SkeletonKeyPrincipal(token.getPrincipal(), surrogate);
Set roles = null;
if (adapterConfig.isUseResourceRoleMappings()) {
@@ -116,14 +121,15 @@ public class KeycloakAuthenticationMechanism implements AuthenticationMechanism
}
};
securityContext.authenticationComplete(account, "KEYCLOAK", true);
+ return skeletonKeyPrincipal;
}
- protected void propagateBearer(HttpServerExchange exchange, SkeletonKeySession session) {
+ protected void propagateBearer(HttpServerExchange exchange, SkeletonKeySession session, SkeletonKeyPrincipal principal) {
exchange.putAttachment(SKELETON_KEY_SESSION_ATTACHMENT_KEY, session);
}
- protected void propagateOauth(HttpServerExchange exchange, SkeletonKeySession session) {
+ protected void propagateOauth(HttpServerExchange exchange, SkeletonKeySession session, SkeletonKeyPrincipal principal) {
exchange.putAttachment(SKELETON_KEY_SESSION_ATTACHMENT_KEY, session);
}
diff --git a/integration/undertow/src/main/java/org/keycloak/adapters/undertow/KeycloakServletExtension.java b/integration/undertow/src/main/java/org/keycloak/adapters/undertow/KeycloakServletExtension.java
index 0527d387a5..52eb239bdd 100755
--- a/integration/undertow/src/main/java/org/keycloak/adapters/undertow/KeycloakServletExtension.java
+++ b/integration/undertow/src/main/java/org/keycloak/adapters/undertow/KeycloakServletExtension.java
@@ -12,6 +12,7 @@ import io.undertow.servlet.api.DeploymentInfo;
import io.undertow.servlet.api.LoginConfig;
import io.undertow.servlet.api.ServletSessionConfig;
import org.jboss.logging.Logger;
+import org.keycloak.adapters.config.RealmConfiguration;
import org.keycloak.representations.adapters.config.AdapterConfig;
import org.keycloak.adapters.config.RealmConfigurationLoader;
@@ -52,20 +53,30 @@ public class KeycloakServletExtension implements ServletExtension {
RealmConfigurationLoader loader = new RealmConfigurationLoader(is);
loader.init(true);
AdapterConfig keycloakConfig = loader.getAdapterConfig();
+ RealmConfiguration realmConfiguration = loader.getRealmConfiguration();
PreflightCorsHandler.Wrapper preflight = new PreflightCorsHandler.Wrapper(keycloakConfig);
- final ServletKeycloakAuthenticationMechanism auth = new ServletKeycloakAuthenticationMechanism(loader.getResourceMetadata(),
+ UserSessionManagement userSessionManagement = new UserSessionManagement(realmConfiguration);
+ ServletKeycloakAuthenticationMechanism auth = null;
+ if (keycloakConfig.isBearerOnly()) {
+ auth = new ServletKeycloakAuthenticationMechanism(keycloakConfig, loader.getResourceMetadata(), deploymentInfo.getConfidentialPortManager());
+ } else {
+ auth = new ServletKeycloakAuthenticationMechanism(
+ userSessionManagement,
keycloakConfig,
- loader.getRealmConfiguration(),
+ realmConfiguration,
deploymentInfo.getConfidentialPortManager());
+ }
ServletAuthenticatedActionsHandler.Wrapper actions = new ServletAuthenticatedActionsHandler.Wrapper(keycloakConfig);
// setup handlers
deploymentInfo.addInitialHandlerChainWrapper(preflight); // cors preflight
+ deploymentInfo.addOuterHandlerChainWrapper(new ServletAdminActionsHandler.Wrapper(realmConfiguration, userSessionManagement));
+ final ServletKeycloakAuthenticationMechanism theAuth = auth;
deploymentInfo.addAuthenticationMechanism("KEYCLOAK", new AuthenticationMechanismFactory() {
@Override
public AuthenticationMechanism create(String s, FormParserFactory formParserFactory, Map stringStringMap) {
- return auth;
+ return theAuth;
}
}); // authentication
deploymentInfo.addInnerHandlerChainWrapper(ServletPropagateSessionHandler.WRAPPER); // propagates SkeletonKeySession
diff --git a/integration/undertow/src/main/java/org/keycloak/adapters/undertow/ServletAdminActionsHandler.java b/integration/undertow/src/main/java/org/keycloak/adapters/undertow/ServletAdminActionsHandler.java
new file mode 100755
index 0000000000..4bfacca382
--- /dev/null
+++ b/integration/undertow/src/main/java/org/keycloak/adapters/undertow/ServletAdminActionsHandler.java
@@ -0,0 +1,95 @@
+package org.keycloak.adapters.undertow;
+
+import io.undertow.server.HandlerWrapper;
+import io.undertow.server.HttpHandler;
+import io.undertow.server.HttpServerExchange;
+import io.undertow.server.session.SessionManager;
+import io.undertow.servlet.handlers.ServletRequestContext;
+import org.jboss.logging.Logger;
+import org.keycloak.adapters.AdapterAdminResourceConstants;
+import org.keycloak.adapters.config.RealmConfiguration;
+import org.keycloak.jose.jws.JWSInput;
+import org.keycloak.jose.jws.crypto.RSAProvider;
+import org.keycloak.util.StreamUtil;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+/**
+ * @author Bill Burke
+ * @version $Revision: 1 $
+ */
+public class ServletAdminActionsHandler implements HttpHandler {
+
+ private static final Logger log = Logger.getLogger(ServletAdminActionsHandler.class);
+ protected HttpHandler next;
+ protected UserSessionManagement userSessionManagement;
+ protected RealmConfiguration realmConfig;
+
+ public static class Wrapper implements HandlerWrapper {
+ protected RealmConfiguration realmConfig;
+ protected UserSessionManagement userSessionManagement;
+
+ public Wrapper(RealmConfiguration realmConfig, UserSessionManagement userSessionManagement) {
+ this.realmConfig = realmConfig;
+ this.userSessionManagement = userSessionManagement;
+ }
+
+ @Override
+ public HttpHandler wrap(HttpHandler handler) {
+ return new ServletAdminActionsHandler(realmConfig, userSessionManagement, handler);
+ }
+ }
+
+ protected ServletAdminActionsHandler(RealmConfiguration realmConfig,
+ UserSessionManagement userSessionManagement,
+ HttpHandler next) {
+ this.next = next;
+ this.userSessionManagement = userSessionManagement;
+ this.realmConfig = realmConfig;
+ }
+
+ protected JWSInput verifyAdminRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
+ String token = StreamUtil.readString(request.getInputStream());
+ if (token == null) {
+ log.warn("admin request failed, no token");
+ response.sendError(403, "no token");
+ return null;
+ }
+
+ JWSInput input = new JWSInput(token);
+ boolean verified = false;
+ try {
+ verified = RSAProvider.verify(input, realmConfig.getMetadata().getRealmKey());
+ } catch (Exception ignore) {
+ }
+ if (!verified) {
+ log.warn("admin request failed, unable to verify token");
+ response.sendError(403, "verification failed");
+ return null;
+ }
+ return input;
+ }
+
+
+
+
+ @Override
+ public void handleRequest(HttpServerExchange exchange) throws Exception {
+ log.debugv("adminActions {0}", exchange.getRequestURI());
+ final ServletRequestContext servletRequestContext = exchange.getAttachment(ServletRequestContext.ATTACHMENT_KEY);
+ HttpServletRequest request = (HttpServletRequest) servletRequestContext.getServletRequest();
+ HttpServletResponse response = (HttpServletResponse) servletRequestContext.getServletResponse();
+ SessionManager manager = servletRequestContext.getDeployment().getSessionManager();
+ String requestUri = exchange.getRequestURI();
+ if (requestUri.endsWith(AdapterAdminResourceConstants.LOGOUT)) {
+ JWSInput token = verifyAdminRequest(request, response);
+ if (token == null) return;
+ userSessionManagement.remoteLogout(token, manager, response);
+ return;
+ } else {
+ next.handleRequest(exchange);
+ return;
+ }
+ }
+}
diff --git a/integration/undertow/src/main/java/org/keycloak/adapters/undertow/ServletKeycloakAuthenticationMechanism.java b/integration/undertow/src/main/java/org/keycloak/adapters/undertow/ServletKeycloakAuthenticationMechanism.java
index 2bae77212e..89f8719c92 100755
--- a/integration/undertow/src/main/java/org/keycloak/adapters/undertow/ServletKeycloakAuthenticationMechanism.java
+++ b/integration/undertow/src/main/java/org/keycloak/adapters/undertow/ServletKeycloakAuthenticationMechanism.java
@@ -3,6 +3,7 @@ package org.keycloak.adapters.undertow;
import io.undertow.server.HttpServerExchange;
import io.undertow.servlet.api.ConfidentialPortManager;
import io.undertow.servlet.handlers.ServletRequestContext;
+import org.keycloak.SkeletonKeyPrincipal;
import org.keycloak.adapters.config.RealmConfiguration;
import org.keycloak.adapters.ResourceMetadata;
import org.keycloak.SkeletonKeySession;
@@ -17,32 +18,42 @@ import javax.servlet.http.HttpSession;
*/
public class ServletKeycloakAuthenticationMechanism extends KeycloakAuthenticationMechanism {
protected ConfidentialPortManager portManager;
+ protected UserSessionManagement userSessionManagement;
- public ServletKeycloakAuthenticationMechanism(ResourceMetadata resourceMetadata, AdapterConfig config, RealmConfiguration realmConfig, ConfidentialPortManager portManager) {
- super(resourceMetadata, config, realmConfig);
+ public ServletKeycloakAuthenticationMechanism(UserSessionManagement userSessionManagement, AdapterConfig config, RealmConfiguration realmConfig, ConfidentialPortManager portManager) {
+ super(config, realmConfig);
this.portManager = portManager;
+ this.userSessionManagement = userSessionManagement;
}
+ public ServletKeycloakAuthenticationMechanism(AdapterConfig config, ResourceMetadata metadata, ConfidentialPortManager portManager) {
+ super(config, metadata);
+ this.portManager = portManager;
+ this.userSessionManagement = userSessionManagement;
+ }
+
+
@Override
protected OAuthAuthenticator createOAuthAuthenticator(HttpServerExchange exchange) {
return new ServletOAuthAuthenticator(exchange, realmConfig, portManager);
}
@Override
- protected void propagateBearer(HttpServerExchange exchange, SkeletonKeySession session) {
- super.propagateBearer(exchange, session);
+ protected void propagateBearer(HttpServerExchange exchange, SkeletonKeySession skSession, SkeletonKeyPrincipal principal) {
+ super.propagateBearer(exchange, skSession, principal);
final ServletRequestContext servletRequestContext = exchange.getAttachment(ServletRequestContext.ATTACHMENT_KEY);
HttpServletRequest req = (HttpServletRequest) servletRequestContext.getServletRequest();
- req.setAttribute(SkeletonKeySession.class.getName(), session);
+ req.setAttribute(SkeletonKeySession.class.getName(), skSession);
}
@Override
- protected void propagateOauth(HttpServerExchange exchange, SkeletonKeySession skSession) {
- super.propagateOauth(exchange, skSession);
+ protected void propagateOauth(HttpServerExchange exchange, SkeletonKeySession skSession, SkeletonKeyPrincipal principal) {
+ super.propagateBearer(exchange, skSession, principal);
final ServletRequestContext servletRequestContext = exchange.getAttachment(ServletRequestContext.ATTACHMENT_KEY);
HttpServletRequest req = (HttpServletRequest) servletRequestContext.getServletRequest();
req.setAttribute(SkeletonKeySession.class.getName(), skSession);
HttpSession session = req.getSession(true);
session.setAttribute(SkeletonKeySession.class.getName(), skSession);
+ userSessionManagement.login(servletRequestContext.getDeployment().getSessionManager(), session, principal.getName());
}
}
diff --git a/integration/undertow/src/main/java/org/keycloak/adapters/undertow/UserSessionManagement.java b/integration/undertow/src/main/java/org/keycloak/adapters/undertow/UserSessionManagement.java
new file mode 100755
index 0000000000..0cc1b8ba3b
--- /dev/null
+++ b/integration/undertow/src/main/java/org/keycloak/adapters/undertow/UserSessionManagement.java
@@ -0,0 +1,188 @@
+package org.keycloak.adapters.undertow;
+
+import io.undertow.security.api.AuthenticatedSessionManager;
+import io.undertow.server.HttpServerExchange;
+import io.undertow.server.session.Session;
+import io.undertow.server.session.SessionListener;
+import io.undertow.server.session.SessionManager;
+import io.undertow.servlet.handlers.security.CachedAuthenticatedSessionHandler;
+import org.jboss.logging.Logger;
+import org.keycloak.SkeletonKeySession;
+import org.keycloak.adapters.config.RealmConfiguration;
+import org.keycloak.jose.jws.JWSInput;
+import org.keycloak.jose.jws.crypto.RSAProvider;
+import org.keycloak.representations.adapters.action.LogoutAction;
+import org.keycloak.util.JsonSerialization;
+import org.keycloak.util.StreamUtil;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * Manages relationship to users and sessions so that forced admin logout can be implemented
+ *
+ * @author Bill Burke
+ * @version $Revision: 1 $
+ */
+public class UserSessionManagement implements SessionListener {
+ private static final Logger log = Logger.getLogger(UserSessionManagement.class);
+ private static final String AUTH_SESSION_NAME = CachedAuthenticatedSessionHandler.class.getName() + ".AuthenticatedSession";
+ protected ConcurrentHashMap> userSessionMap = new ConcurrentHashMap>();
+
+ protected RealmConfiguration realmInfo;
+
+ public UserSessionManagement(RealmConfiguration realmInfo) {
+ this.realmInfo = realmInfo;
+ }
+
+ public void remoteLogout(JWSInput token, SessionManager manager, HttpServletResponse response) throws IOException {
+ try {
+ log.debug("->> remoteLogout: ");
+ LogoutAction action = JsonSerialization.readValue(token.getContent(), LogoutAction.class);
+ if (action.isExpired()) {
+ log.warn("admin request failed, expired token");
+ response.sendError(400, "Expired token");
+ return;
+ }
+ if (!realmInfo.getMetadata().getResourceName().equals(action.getResource())) {
+ log.warn("Resource name does not match");
+ response.sendError(400, "Resource name does not match");
+ return;
+
+ }
+ String user = action.getUser();
+ if (user != null) {
+ log.debug("logout of session for: " + user);
+ logout(manager, user);
+ } else {
+ log.debug("logout of all sessions");
+ logoutAll(manager);
+ }
+ } catch (Exception e) {
+ log.warn("failed to logout", e);
+ response.sendError(500, "Failed to logout");
+ }
+ response.setStatus(204);
+ }
+
+ public void login(SessionManager manager, HttpSession session, String username) {
+ String sessionId = session.getId();
+ addAuthenticatedSession(username, sessionId);
+ manager.registerSessionListener(this);
+ }
+
+ protected void addAuthenticatedSession(String username, String sessionId) {
+ synchronized (userSessionMap) {
+ Set map = userSessionMap.get(username);
+ if (map == null) {
+ final Set value = new HashSet();
+ map = userSessionMap.putIfAbsent(username, value);
+ if (map == null) {
+ map = value;
+ }
+ }
+ synchronized (map) {
+ map.add(sessionId);
+ }
+
+ }
+ }
+
+ protected void removeAuthenticatedSession(String sessionId, String username) {
+ synchronized (userSessionMap) {
+ Set map = userSessionMap.get(username);
+ if (map == null) return;
+ synchronized (map) {
+ map.remove(sessionId);
+ if (map.isEmpty()) userSessionMap.remove(username);
+ }
+ }
+ }
+
+ public void logoutAll(SessionManager manager) {
+ List users = new ArrayList();
+ users.addAll(userSessionMap.keySet());
+ for (String user : users) logout(manager, user);
+ }
+
+ public void logoutAllBut(SessionManager manager, String but) {
+ List users = new ArrayList();
+ users.addAll(userSessionMap.keySet());
+ for (String user : users) {
+ if (!but.equals(user)) logout(manager, user);
+ }
+ }
+
+ public void logout(SessionManager manager, String user) {
+ log.debug("logoutUser: " + user);
+ Set map = userSessionMap.remove(user);
+ if (map == null) {
+ log.debug("no session for user: " + user);
+ return;
+ }
+ log.debug("found session for user");
+ synchronized (map) {
+ for (String id : map) {
+ log.debug("invalidating session for user: " + user);
+ Session session = manager.getSession(id);
+ try {
+ session.invalidate(null);
+ } catch (Exception e) {
+ log.warn("Session already invalidated.");
+ }
+ }
+ }
+
+ }
+
+ @Override
+ public void sessionCreated(Session session, HttpServerExchange exchange) {
+ }
+
+ @Override
+ public void sessionDestroyed(Session session, HttpServerExchange exchange, SessionDestroyedReason reason) {
+ // Look up the single session id associated with this session (if any)
+ String username = getUsernameFromSession(session);
+ if (username == null) return;
+ String sessionId = session.getId();
+ removeAuthenticatedSession(sessionId, username);
+ }
+
+ protected String getUsernameFromSession(Session session) {
+ AuthenticatedSessionManager.AuthenticatedSession authSession = (AuthenticatedSessionManager.AuthenticatedSession) session.getAttribute(AUTH_SESSION_NAME);
+ if (authSession == null) return null;
+ return authSession.getAccount().getPrincipal().getName();
+
+ }
+
+
+ @Override
+ public void sessionIdChanged(Session session, String oldSessionId) {
+ String username = getUsernameFromSession(session);
+ if (username == null) return;
+ removeAuthenticatedSession(oldSessionId, username);
+ addAuthenticatedSession(session.getId(), username);
+ }
+
+ @Override
+ public void attributeAdded(Session session, String name, Object value) {
+ }
+
+ @Override
+ public void attributeUpdated(Session session, String name, Object newValue, Object oldValue) {
+ }
+
+ @Override
+ public void attributeRemoved(Session session, String name, Object oldValue) {
+ }
+
+}
diff --git a/services/src/main/java/org/keycloak/services/managers/ResourceAdminManager.java b/services/src/main/java/org/keycloak/services/managers/ResourceAdminManager.java
index 2d1c518f4c..82f7adeedf 100755
--- a/services/src/main/java/org/keycloak/services/managers/ResourceAdminManager.java
+++ b/services/src/main/java/org/keycloak/services/managers/ResourceAdminManager.java
@@ -42,10 +42,8 @@ public class ResourceAdminManager {
if (managementUrl != null) {
LogoutAction adminAction = new LogoutAction(TokenIdGenerator.generateId(), System.currentTimeMillis() / 1000 + 30, resource.getName(), user);
String token = new TokenManager().encodeToken(realm, adminAction);
- Form form = new Form();
- form.param("token", token);
logger.debug("logout user: {0} resource: {1} url: {2}", user, resource.getName(), managementUrl);
- Response response = client.target(managementUrl).path(AdapterAdminResourceConstants.LOGOUT).request().post(Entity.form(form));
+ Response response = client.target(managementUrl).path(AdapterAdminResourceConstants.LOGOUT).request().post(Entity.text(token));
boolean success = response.getStatus() == 204;
response.close();
return success;