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;