From 273e706a42ce8df516d5a6d2272794d3e9714c03 Mon Sep 17 00:00:00 2001 From: Bill Burke Date: Sat, 22 Feb 2014 17:24:04 -0500 Subject: [PATCH] undertow refresh token support --- .../undertow/AuthenticatedActionsHandler.java | 49 +++++--- .../KeycloakAuthenticationMechanism.java | 48 ++------ .../undertow/KeycloakIdentityManager.java | 48 ++++++++ .../undertow/KeycloakServletExtension.java | 24 +--- .../undertow/KeycloakUndertowAccount.java | 114 ++++++++++++++++++ .../adapters/undertow/OAuthAuthenticator.java | 6 + .../ServletAuthenticatedActionsHandler.java | 48 -------- ...ervletKeycloakAuthenticationMechanism.java | 3 +- .../ServletPropagateSessionHandler.java | 28 ++--- .../undertow/UndertowKeycloakSession.java | 43 +++++++ .../services/managers/RealmManager.java | 3 + 11 files changed, 271 insertions(+), 143 deletions(-) create mode 100755 integration/undertow/src/main/java/org/keycloak/adapters/undertow/KeycloakIdentityManager.java create mode 100755 integration/undertow/src/main/java/org/keycloak/adapters/undertow/KeycloakUndertowAccount.java delete mode 100755 integration/undertow/src/main/java/org/keycloak/adapters/undertow/ServletAuthenticatedActionsHandler.java create mode 100755 integration/undertow/src/main/java/org/keycloak/adapters/undertow/UndertowKeycloakSession.java diff --git a/integration/undertow/src/main/java/org/keycloak/adapters/undertow/AuthenticatedActionsHandler.java b/integration/undertow/src/main/java/org/keycloak/adapters/undertow/AuthenticatedActionsHandler.java index 23732836de..068f982695 100755 --- a/integration/undertow/src/main/java/org/keycloak/adapters/undertow/AuthenticatedActionsHandler.java +++ b/integration/undertow/src/main/java/org/keycloak/adapters/undertow/AuthenticatedActionsHandler.java @@ -1,11 +1,11 @@ package org.keycloak.adapters.undertow; +import io.undertow.server.HandlerWrapper; import io.undertow.server.HttpHandler; import io.undertow.server.HttpServerExchange; import io.undertow.util.Headers; import io.undertow.util.StatusCodes; import org.jboss.logging.Logger; -import org.keycloak.KeycloakAuthenticatedSession; import org.keycloak.adapters.AdapterConstants; import org.keycloak.representations.AccessToken; import org.keycloak.representations.adapters.config.AdapterConfig; @@ -30,6 +30,20 @@ public class AuthenticatedActionsHandler implements HttpHandler { protected AdapterConfig adapterConfig; protected HttpHandler next; + public static class Wrapper implements HandlerWrapper { + protected AdapterConfig config; + + public Wrapper(AdapterConfig config) { + this.config = config; + } + + @Override + public HttpHandler wrap(HttpHandler handler) { + return new AuthenticatedActionsHandler(config, handler); + } + } + + protected AuthenticatedActionsHandler(AdapterConfig config, HttpHandler next) { this.adapterConfig = config; this.next = next; @@ -38,34 +52,32 @@ public class AuthenticatedActionsHandler implements HttpHandler { @Override public void handleRequest(HttpServerExchange exchange) throws Exception { log.debugv("AuthenticatedActionsValve.invoke {0}", exchange.getRequestURI()); - KeycloakAuthenticatedSession session = getSkeletonKeySession(exchange); - if (corsRequest(exchange, session)) return; + KeycloakUndertowAccount account = getAccount(exchange); + if (corsRequest(exchange, account)) return; String requestUri = exchange.getRequestURI(); if (requestUri.endsWith(AdapterConstants.K_QUERY_BEARER_TOKEN)) { - queryBearerToken(exchange, session); + queryBearerToken(exchange, account); return; } next.handleRequest(exchange); } - public KeycloakAuthenticatedSession getSkeletonKeySession(HttpServerExchange exchange) { - KeycloakAuthenticatedSession skSession = exchange.getAttachment(KeycloakAuthenticationMechanism.SKELETON_KEY_SESSION_ATTACHMENT_KEY); - if (skSession != null) return skSession; - return null; + public KeycloakUndertowAccount getAccount(HttpServerExchange exchange) { + return (KeycloakUndertowAccount)exchange.getSecurityContext().getAuthenticatedAccount(); } - protected void queryBearerToken(HttpServerExchange exchange, KeycloakAuthenticatedSession session) throws IOException, ServletException { + protected void queryBearerToken(HttpServerExchange exchange, KeycloakUndertowAccount account) throws IOException, ServletException { log.debugv("queryBearerToken {0}",exchange.getRequestURI()); - if (abortTokenResponse(exchange, session)) return; + if (abortTokenResponse(exchange, account)) return; exchange.setResponseCode(StatusCodes.OK); exchange.getResponseHeaders().put(Headers.CONTENT_TYPE, "text/plain"); - exchange.getResponseSender().send(session.getTokenString()); + exchange.getResponseSender().send(account.getEncodedAccessToken()); exchange.endExchange(); } - protected boolean abortTokenResponse(HttpServerExchange exchange, KeycloakAuthenticatedSession session) throws IOException { - if (session == null) { - log.debugv("session was null, sending back 401: {0}",exchange.getRequestURI()); + protected boolean abortTokenResponse(HttpServerExchange exchange, KeycloakUndertowAccount account) throws IOException { + if (account == null) { + log.debugv("Not logged in, sending back 401: {0}",exchange.getRequestURI()); exchange.setResponseCode(StatusCodes.UNAUTHORIZED); exchange.endExchange(); return true; @@ -75,6 +87,7 @@ public class AuthenticatedActionsHandler implements HttpHandler { exchange.endExchange(); return true; } + // Don't allow a CORS request if we're not validating CORS requests. if (!adapterConfig.isCors() && exchange.getRequestHeaders().getFirst(Headers.ORIGIN) != null) { exchange.setResponseCode(StatusCodes.OK); exchange.endExchange(); @@ -83,13 +96,13 @@ public class AuthenticatedActionsHandler implements HttpHandler { return false; } - protected boolean corsRequest(HttpServerExchange exchange, KeycloakAuthenticatedSession session) throws IOException { + protected boolean corsRequest(HttpServerExchange exchange, KeycloakUndertowAccount account) throws IOException { if (!adapterConfig.isCors()) return false; log.debugv("CORS enabled + request.getRequestURI()"); String origin = exchange.getRequestHeaders().getFirst("Origin"); log.debugv("Origin: {0} uri: {1}", origin, exchange.getRequestURI()); - if (session != null && origin != null) { - AccessToken token = session.getToken(); + if (account != null && origin != null) { + AccessToken token = account.getAccessToken(); Set allowedOrigins = token.getAllowedOrigins(); if (log.isDebugEnabled()) { for (String a : allowedOrigins) log.debug(" " + a); @@ -111,7 +124,7 @@ public class AuthenticatedActionsHandler implements HttpHandler { exchange.getResponseHeaders().put(PreflightCorsHandler.ACCESS_CONTROL_ALLOW_ORIGIN, origin); exchange.getResponseHeaders().put(PreflightCorsHandler.ACCESS_CONTROL_ALLOW_CREDENTIALS, "true"); } else { - log.debugv("session or origin was null: {0}", exchange.getRequestURI()); + log.debugv("not secured or origin was null: {0}", exchange.getRequestURI()); } return false; } 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 a113150cd7..1794a1975f 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 @@ -59,11 +59,7 @@ public class KeycloakAuthenticationMechanism implements AuthenticationMechanism return AuthenticationMechanismOutcome.NOT_AUTHENTICATED; } else if (outcome == AuthenticationMechanismOutcome.AUTHENTICATED) { - final AccessToken token = bearer.getToken(); - String surrogate = bearer.getSurrogate(); - KeycloakAuthenticatedSession session = new KeycloakAuthenticatedSession(bearer.getTokenString(), token, resourceMetadata); - KeycloakPrincipal principal = completeAuthentication(securityContext, token, surrogate); - propagateBearer(exchange, session, principal); + completeAuthentication(securityContext, bearer); return AuthenticationMechanismOutcome.AUTHENTICATED; } else if (adapterConfig.isBearerOnly()) { @@ -82,9 +78,7 @@ public class KeycloakAuthenticationMechanism implements AuthenticationMechanism return AuthenticationMechanismOutcome.NOT_ATTEMPTED; } - KeycloakAuthenticatedSession session = new KeycloakAuthenticatedSession(oauth.getTokenString(), oauth.getToken(), resourceMetadata); - KeycloakPrincipal principal = completeAuthentication(securityContext, oauth.getToken(), null); - propagateOauth(exchange, session, principal); + completeAuthentication(securityContext, oauth); log.info("AUTHENTICATED"); return AuthenticationMechanismOutcome.AUTHENTICATED; } @@ -97,43 +91,19 @@ public class KeycloakAuthenticationMechanism implements AuthenticationMechanism return new BearerTokenAuthenticator(resourceMetadata, adapterConfig.isUseResourceRoleMappings()); } - protected KeycloakPrincipal completeAuthentication(SecurityContext securityContext, AccessToken token, String surrogate) { - final KeycloakPrincipal skeletonKeyPrincipal = new KeycloakPrincipal(token.getSubject(), surrogate); - Set roles = null; - if (adapterConfig.isUseResourceRoleMappings()) { - AccessToken.Access access = token.getResourceAccess(resourceMetadata.getResourceName()); - if (access != null) roles = access.getRoles(); - } else { - AccessToken.Access access = token.getRealmAccess(); - if (access != null) roles = access.getRoles(); - } - if (roles == null) roles = Collections.emptySet(); - final Set accountRoles = roles; - Account account = new Account() { - @Override - public Principal getPrincipal() { - return skeletonKeyPrincipal; - } - - @Override - public Set getRoles() { - return accountRoles; - } - }; + protected void completeAuthentication(SecurityContext securityContext, OAuthAuthenticator oauth) { + final KeycloakPrincipal principal = new KeycloakPrincipal(oauth.getToken().getSubject(), null); + KeycloakUndertowAccount account = new KeycloakUndertowAccount(principal, oauth.getToken(), oauth.getTokenString(), oauth.getRefreshToken(), realmConfig, resourceMetadata, adapterConfig); securityContext.authenticationComplete(account, "KEYCLOAK", true); - return skeletonKeyPrincipal; } - protected void propagateBearer(HttpServerExchange exchange, KeycloakAuthenticatedSession session, KeycloakPrincipal principal) { - exchange.putAttachment(SKELETON_KEY_SESSION_ATTACHMENT_KEY, session); + protected void completeAuthentication(SecurityContext securityContext, BearerTokenAuthenticator bearer) { + final KeycloakPrincipal principal = new KeycloakPrincipal(bearer.getToken().getSubject(), bearer.getSurrogate()); + KeycloakUndertowAccount account = new KeycloakUndertowAccount(principal, bearer.getToken(), bearer.getTokenString(), null, realmConfig, resourceMetadata, adapterConfig); + securityContext.authenticationComplete(account, "KEYCLOAK", false); } - protected void propagateOauth(HttpServerExchange exchange, KeycloakAuthenticatedSession session, KeycloakPrincipal principal) { - exchange.putAttachment(SKELETON_KEY_SESSION_ATTACHMENT_KEY, session); - } - - @Override public ChallengeResult sendChallenge(HttpServerExchange exchange, SecurityContext securityContext) { KeycloakChallenge challenge = exchange.getAttachment(KEYCLOAK_CHALLENGE_ATTACHMENT_KEY); diff --git a/integration/undertow/src/main/java/org/keycloak/adapters/undertow/KeycloakIdentityManager.java b/integration/undertow/src/main/java/org/keycloak/adapters/undertow/KeycloakIdentityManager.java new file mode 100755 index 0000000000..d5b4e5fcbf --- /dev/null +++ b/integration/undertow/src/main/java/org/keycloak/adapters/undertow/KeycloakIdentityManager.java @@ -0,0 +1,48 @@ +package org.keycloak.adapters.undertow; + +import io.undertow.security.idm.Account; +import io.undertow.security.idm.Credential; +import io.undertow.security.idm.IdentityManager; +import io.undertow.util.StatusCodes; +import org.jboss.logging.Logger; +import org.keycloak.KeycloakPrincipal; +import org.keycloak.RSATokenVerifier; +import org.keycloak.VerificationException; +import org.keycloak.adapters.ResourceMetadata; +import org.keycloak.adapters.TokenGrantRequest; +import org.keycloak.adapters.config.RealmConfiguration; +import org.keycloak.representations.AccessToken; +import org.keycloak.representations.AccessTokenResponse; +import org.keycloak.representations.adapters.config.AdapterConfig; + +import java.io.IOException; + +/** +* @author Bill Burke +* @version $Revision: 1 $ +*/ +class KeycloakIdentityManager implements IdentityManager { + protected static Logger log = Logger.getLogger(KeycloakIdentityManager.class); + + @Override + public Account verify(Account account) { + log.info("Verifying account in IdentityManager"); + KeycloakUndertowAccount keycloakAccount = (KeycloakUndertowAccount)account; + if (keycloakAccount.getAccessToken().isActive()) return account; + keycloakAccount.refreshExpiredToken(); + if (!keycloakAccount.getAccessToken().isActive()) return null; + return account; + } + + @Override + public Account verify(String id, Credential credential) { + KeycloakServletExtension.log.warn("Shouldn't call verify!!!"); + throw new IllegalStateException("Not allowed"); + } + + @Override + public Account verify(Credential credential) { + KeycloakServletExtension.log.warn("Shouldn't call verify!!!"); + throw new IllegalStateException("Not allowed"); + } +} 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 04e0d64130..c7948eed17 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 @@ -28,7 +28,7 @@ import java.util.Map; */ public class KeycloakServletExtension implements ServletExtension { - protected Logger log = Logger.getLogger(KeycloakServletExtension.class); + protected static Logger log = Logger.getLogger(KeycloakServletExtension.class); // todo when this DeploymentInfo method of the same name is fixed. public boolean isAuthenticationMechanismPresent(DeploymentInfo deploymentInfo, final String mechanismName) { @@ -79,7 +79,7 @@ public class KeycloakServletExtension implements ServletExtension { realmConfiguration, deploymentInfo.getConfidentialPortManager()); } - ServletAuthenticatedActionsHandler.Wrapper actions = new ServletAuthenticatedActionsHandler.Wrapper(keycloakConfig); + AuthenticatedActionsHandler.Wrapper actions = new AuthenticatedActionsHandler.Wrapper(keycloakConfig); // setup handlers @@ -95,25 +95,7 @@ public class KeycloakServletExtension implements ServletExtension { deploymentInfo.addInnerHandlerChainWrapper(ServletPropagateSessionHandler.WRAPPER); // propagates SkeletonKeySession deploymentInfo.addInnerHandlerChainWrapper(actions); // handles authenticated actions and cors. - deploymentInfo.setIdentityManager(new IdentityManager() { - @Override - public Account verify(Account account) { - log.info("Verifying account in IdentityManager"); - return account; - } - - @Override - public Account verify(String id, Credential credential) { - log.warn("Shouldn't call verify!!!"); - throw new IllegalStateException("Not allowed"); - } - - @Override - public Account verify(Credential credential) { - log.warn("Shouldn't call verify!!!"); - throw new IllegalStateException("Not allowed"); - } - }); + deploymentInfo.setIdentityManager(new KeycloakIdentityManager()); log.info("Setting jsession cookie path to: " + deploymentInfo.getContextPath()); ServletSessionConfig cookieConfig = new ServletSessionConfig(); diff --git a/integration/undertow/src/main/java/org/keycloak/adapters/undertow/KeycloakUndertowAccount.java b/integration/undertow/src/main/java/org/keycloak/adapters/undertow/KeycloakUndertowAccount.java new file mode 100755 index 0000000000..f50c9d1663 --- /dev/null +++ b/integration/undertow/src/main/java/org/keycloak/adapters/undertow/KeycloakUndertowAccount.java @@ -0,0 +1,114 @@ +package org.keycloak.adapters.undertow; + +import io.undertow.security.idm.Account; +import org.jboss.logging.Logger; +import org.keycloak.KeycloakPrincipal; +import org.keycloak.RSATokenVerifier; +import org.keycloak.VerificationException; +import org.keycloak.adapters.ResourceMetadata; +import org.keycloak.adapters.TokenGrantRequest; +import org.keycloak.adapters.config.RealmConfiguration; +import org.keycloak.representations.AccessToken; +import org.keycloak.representations.AccessTokenResponse; +import org.keycloak.representations.adapters.config.AdapterConfig; + +import java.io.IOException; +import java.security.Principal; +import java.util.Collections; +import java.util.Set; + +/** +* @author Bill Burke +* @version $Revision: 1 $ +*/ +public class KeycloakUndertowAccount implements Account { + protected static Logger log = Logger.getLogger(KeycloakUndertowAccount.class); + protected AccessToken accessToken; + protected String encodedAccessToken; + protected String refreshToken; + protected KeycloakPrincipal principal; + protected Set accountRoles; + protected RealmConfiguration realmConfiguration; + protected ResourceMetadata resourceMetadata; + protected AdapterConfig adapterConfig; + + public KeycloakUndertowAccount(KeycloakPrincipal principal, AccessToken accessToken, String encodedAccessToken, String refreshToken, + RealmConfiguration realmConfiguration, ResourceMetadata resourceMetadata, AdapterConfig adapterConfig) { + this.principal = principal; + this.accessToken = accessToken; + this.encodedAccessToken = encodedAccessToken; + this.refreshToken = refreshToken; + this.realmConfiguration = realmConfiguration; + this.resourceMetadata = resourceMetadata; + this.adapterConfig = adapterConfig; + setRoles(accessToken); + } + + protected void setRoles(AccessToken accessToken) { + Set roles = null; + if (adapterConfig.isUseResourceRoleMappings()) { + AccessToken.Access access = accessToken.getResourceAccess(resourceMetadata.getResourceName()); + if (access != null) roles = access.getRoles(); + } else { + AccessToken.Access access = accessToken.getRealmAccess(); + if (access != null) roles = access.getRoles(); + } + if (roles == null) roles = Collections.emptySet(); + this.accountRoles = roles; + } + + @Override + public Principal getPrincipal() { + return principal; + } + + @Override + public Set getRoles() { + return accountRoles; + } + + public AccessToken getAccessToken() { + return accessToken; + } + + public String getEncodedAccessToken() { + return encodedAccessToken; + } + + public String getRefreshToken() { + return refreshToken; + } + + public ResourceMetadata getResourceMetadata() { + return resourceMetadata; + } + + public void refreshExpiredToken() { + if (accessToken.isActive()) return; + + log.debug("Doing refresh"); + AccessTokenResponse response = null; + try { + response = TokenGrantRequest.invokeRefresh(realmConfiguration, getRefreshToken()); + } catch (IOException e) { + log.error("Refresh token failure", e); + return; + } catch (TokenGrantRequest.HttpFailure httpFailure) { + log.error("Refresh token failure status: " + httpFailure.getStatus() + " " + httpFailure.getError()); + return; + } + String tokenString = response.getToken(); + AccessToken token = null; + try { + token = RSATokenVerifier.verifyToken(tokenString, realmConfiguration.getMetadata().getRealmKey(), realmConfiguration.getMetadata().getRealm()); + log.debug("Token Verification succeeded!"); + } catch (VerificationException e) { + log.error("failed verification of token"); + } + this.accessToken = token; + this.refreshToken = response.getRefreshToken(); + this.encodedAccessToken = tokenString; + setRoles(this.accessToken); + + } +} diff --git a/integration/undertow/src/main/java/org/keycloak/adapters/undertow/OAuthAuthenticator.java b/integration/undertow/src/main/java/org/keycloak/adapters/undertow/OAuthAuthenticator.java index 654e974a77..d21e5d3ed6 100755 --- a/integration/undertow/src/main/java/org/keycloak/adapters/undertow/OAuthAuthenticator.java +++ b/integration/undertow/src/main/java/org/keycloak/adapters/undertow/OAuthAuthenticator.java @@ -34,6 +34,7 @@ public class OAuthAuthenticator { protected AccessToken token; protected HttpServerExchange exchange; protected KeycloakChallenge challenge; + protected String refreshToken; public OAuthAuthenticator(HttpServerExchange exchange, RealmConfiguration realmInfo, int sslRedirectPort) { this.exchange = exchange; @@ -53,6 +54,10 @@ public class OAuthAuthenticator { return token; } + public String getRefreshToken() { + return refreshToken; + } + protected String getRequestUrl() { KeycloakUriBuilder uriBuilder = KeycloakUriBuilder.fromUri(exchange.getRequestURI()) .replaceQuery(exchange.getQueryString()); @@ -249,6 +254,7 @@ public class OAuthAuthenticator { } tokenString = tokenResponse.getToken(); + refreshToken = tokenResponse.getRefreshToken(); try { token = RSATokenVerifier.verifyToken(tokenString, realmInfo.getMetadata().getRealmKey(), realmInfo.getMetadata().getRealm()); log.debug("Token Verification succeeded!"); diff --git a/integration/undertow/src/main/java/org/keycloak/adapters/undertow/ServletAuthenticatedActionsHandler.java b/integration/undertow/src/main/java/org/keycloak/adapters/undertow/ServletAuthenticatedActionsHandler.java deleted file mode 100755 index a09bd48e85..0000000000 --- a/integration/undertow/src/main/java/org/keycloak/adapters/undertow/ServletAuthenticatedActionsHandler.java +++ /dev/null @@ -1,48 +0,0 @@ -package org.keycloak.adapters.undertow; - -import io.undertow.server.HandlerWrapper; -import io.undertow.server.HttpHandler; -import io.undertow.server.HttpServerExchange; -import io.undertow.servlet.handlers.ServletRequestContext; -import org.keycloak.KeycloakAuthenticatedSession; -import org.keycloak.representations.adapters.config.AdapterConfig; - -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpSession; - -/** - * @author Bill Burke - * @version $Revision: 1 $ - */ -public class ServletAuthenticatedActionsHandler extends AuthenticatedActionsHandler { - - protected ServletAuthenticatedActionsHandler(AdapterConfig config, HttpHandler next) { - super(config, next); - } - - public static class Wrapper implements HandlerWrapper { - protected AdapterConfig config; - - public Wrapper(AdapterConfig config) { - this.config = config; - } - - @Override - public HttpHandler wrap(HttpHandler handler) { - return new ServletAuthenticatedActionsHandler(config, handler); - } - } - - @Override - public KeycloakAuthenticatedSession getSkeletonKeySession(HttpServerExchange exchange) { - KeycloakAuthenticatedSession skSession = super.getSkeletonKeySession(exchange); - if (skSession != null) return skSession; - - final ServletRequestContext servletRequestContext = exchange.getAttachment(ServletRequestContext.ATTACHMENT_KEY); - HttpServletRequest req = (HttpServletRequest) servletRequestContext.getServletRequest(); - HttpSession session = req.getSession(false); - if (session == null) return null; - return (KeycloakAuthenticatedSession)session.getAttribute(KeycloakAuthenticatedSession.class.getName()); - - } -} 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 0645084159..6485909074 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 @@ -29,7 +29,6 @@ public class ServletKeycloakAuthenticationMechanism extends KeycloakAuthenticati public ServletKeycloakAuthenticationMechanism(AdapterConfig config, ResourceMetadata metadata, ConfidentialPortManager portManager) { super(config, metadata); this.portManager = portManager; - this.userSessionManagement = userSessionManagement; } @@ -38,6 +37,7 @@ public class ServletKeycloakAuthenticationMechanism extends KeycloakAuthenticati return new ServletOAuthAuthenticator(exchange, realmConfig, portManager); } + /* @Override protected void propagateBearer(HttpServerExchange exchange, KeycloakAuthenticatedSession skSession, KeycloakPrincipal principal) { super.propagateBearer(exchange, skSession, principal); @@ -56,4 +56,5 @@ public class ServletKeycloakAuthenticationMechanism extends KeycloakAuthenticati session.setAttribute(KeycloakAuthenticatedSession.class.getName(), skSession); userSessionManagement.login(servletRequestContext.getDeployment().getSessionManager(), session, principal.getName()); } + */ } diff --git a/integration/undertow/src/main/java/org/keycloak/adapters/undertow/ServletPropagateSessionHandler.java b/integration/undertow/src/main/java/org/keycloak/adapters/undertow/ServletPropagateSessionHandler.java index 608f8671ff..9baa829953 100755 --- a/integration/undertow/src/main/java/org/keycloak/adapters/undertow/ServletPropagateSessionHandler.java +++ b/integration/undertow/src/main/java/org/keycloak/adapters/undertow/ServletPropagateSessionHandler.java @@ -33,31 +33,27 @@ public class ServletPropagateSessionHandler implements HttpHandler { @Override public void handleRequest(HttpServerExchange exchange) throws Exception { - log.info("handleRequest"); - final ServletRequestContext servletRequestContext = exchange.getAttachment(ServletRequestContext.ATTACHMENT_KEY); - HttpServletRequest req = (HttpServletRequest) servletRequestContext.getServletRequest(); - KeycloakAuthenticatedSession skSession = (KeycloakAuthenticatedSession)req.getAttribute(KeycloakAuthenticatedSession.class.getName()); - if (skSession != null) { - log.info("skSession is in request"); + log.debug("handleRequest"); + KeycloakUndertowAccount account = (KeycloakUndertowAccount)exchange.getSecurityContext().getAuthenticatedAccount(); + if (account == null) { + log.debug("Not logged in, nothing to propagate"); next.handleRequest(exchange); return; } + UndertowKeycloakSession skSession = new UndertowKeycloakSession(account); + + + final ServletRequestContext servletRequestContext = exchange.getAttachment(ServletRequestContext.ATTACHMENT_KEY); + HttpServletRequest req = (HttpServletRequest) servletRequestContext.getServletRequest(); + req.setAttribute(KeycloakAuthenticatedSession.class.getName(), skSession); HttpSession session = req.getSession(false); if (session == null) { - log.info("http session was null, nothing to propagate"); next.handleRequest(exchange); return; } - skSession = (KeycloakAuthenticatedSession)session.getAttribute(KeycloakAuthenticatedSession.class.getName()); - if (skSession == null) { - log.info("skSession not in http session, nothing to propagate"); - next.handleRequest(exchange); - return; - } - log.info("propagating"); - req.setAttribute(KeycloakAuthenticatedSession.class.getName(), skSession); - exchange.putAttachment(KeycloakAuthenticationMechanism.SKELETON_KEY_SESSION_ATTACHMENT_KEY, skSession); + log.debug("propagating to HTTP Session"); + session.setAttribute(KeycloakAuthenticatedSession.class.getName(), skSession); next.handleRequest(exchange); } } diff --git a/integration/undertow/src/main/java/org/keycloak/adapters/undertow/UndertowKeycloakSession.java b/integration/undertow/src/main/java/org/keycloak/adapters/undertow/UndertowKeycloakSession.java new file mode 100755 index 0000000000..22f79d946b --- /dev/null +++ b/integration/undertow/src/main/java/org/keycloak/adapters/undertow/UndertowKeycloakSession.java @@ -0,0 +1,43 @@ +package org.keycloak.adapters.undertow; + +import org.keycloak.KeycloakAuthenticatedSession; +import org.keycloak.adapters.ResourceMetadata; +import org.keycloak.representations.AccessToken; + +import java.io.Serializable; + +/** + * @author Bill Burke + * @version $Revision: 1 $ + */ +public class UndertowKeycloakSession extends KeycloakAuthenticatedSession { + + private transient KeycloakUndertowAccount account; + + public UndertowKeycloakSession(KeycloakUndertowAccount account) { + super(account.getEncodedAccessToken(), account.getAccessToken(), account.getResourceMetadata()); + this.account = account; + } + + @Override + public AccessToken getToken() { + checkExpiration(); + return super.getToken(); + } + + private void checkExpiration() { + if (token.isExpired() && account != null) { + account.refreshExpiredToken(); + this.token = account.getAccessToken(); + this.tokenString = account.getEncodedAccessToken(); + + } + } + + @Override + public String getTokenString() { + checkExpiration(); + return super.getTokenString(); + } + +} diff --git a/services/src/main/java/org/keycloak/services/managers/RealmManager.java b/services/src/main/java/org/keycloak/services/managers/RealmManager.java index 4148ca02a1..b4067b465a 100755 --- a/services/src/main/java/org/keycloak/services/managers/RealmManager.java +++ b/services/src/main/java/org/keycloak/services/managers/RealmManager.java @@ -161,6 +161,9 @@ public class RealmManager { if (rep.getAccessTokenLifespan() != null) newRealm.setAccessTokenLifespan(rep.getAccessTokenLifespan()); else newRealm.setAccessTokenLifespan(300); + if (rep.getRefreshTokenLifespan() != null) newRealm.setRefreshTokenLifespan(rep.getRefreshTokenLifespan()); + else newRealm.setRefreshTokenLifespan(3600); + if (rep.getAccessCodeLifespan() != null) newRealm.setAccessCodeLifespan(rep.getAccessCodeLifespan()); else newRealm.setAccessCodeLifespan(60);