undertow logout
This commit is contained in:
parent
834baf0e27
commit
30cb9df307
9 changed files with 370 additions and 49 deletions
31
core/src/main/java/org/keycloak/util/StreamUtil.java
Executable file
31
core/src/main/java/org/keycloak/util/StreamUtil.java
Executable file
|
@ -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 <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @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();
|
||||
}
|
||||
}
|
|
@ -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 {
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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<String> 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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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<String, String> stringStringMap) {
|
||||
return auth;
|
||||
return theAuth;
|
||||
}
|
||||
}); // authentication
|
||||
deploymentInfo.addInnerHandlerChainWrapper(ServletPropagateSessionHandler.WRAPPER); // propagates SkeletonKeySession
|
||||
|
|
|
@ -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 <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @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<String, Set<String>> userSessionMap = new ConcurrentHashMap<String, Set<String>>();
|
||||
|
||||
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<String> map = userSessionMap.get(username);
|
||||
if (map == null) {
|
||||
final Set<String> value = new HashSet<String>();
|
||||
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<String> 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<String> users = new ArrayList<String>();
|
||||
users.addAll(userSessionMap.keySet());
|
||||
for (String user : users) logout(manager, user);
|
||||
}
|
||||
|
||||
public void logoutAllBut(SessionManager manager, String but) {
|
||||
List<String> users = new ArrayList<String>();
|
||||
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<String> 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) {
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue