saved requests
This commit is contained in:
parent
17a8a92bb3
commit
08be04b337
70 changed files with 1465 additions and 445 deletions
40
core/src/main/java/org/keycloak/util/UriUtils.java
Normal file → Executable file
40
core/src/main/java/org/keycloak/util/UriUtils.java
Normal file → Executable file
|
@ -1,6 +1,8 @@
|
|||
package org.keycloak.util;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URI;
|
||||
import java.net.URLDecoder;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
|
@ -23,4 +25,42 @@ public class UriUtils {
|
|||
return originPattern.matcher(url).matches();
|
||||
}
|
||||
|
||||
public static MultivaluedHashMap<String, String> decodeQueryString(String queryString) {
|
||||
MultivaluedHashMap<String, String> map = new MultivaluedHashMap<String, String>();
|
||||
if (queryString == null || queryString.equals("")) return map;
|
||||
|
||||
String[] params = queryString.split("&");
|
||||
|
||||
for (String param : params)
|
||||
{
|
||||
if (param.indexOf('=') >= 0)
|
||||
{
|
||||
String[] nv = param.split("=", 2);
|
||||
try
|
||||
{
|
||||
String name = URLDecoder.decode(nv[0], "UTF-8");
|
||||
String val = nv.length > 1 ? nv[1] : "";
|
||||
map.add(name, URLDecoder.decode(val, "UTF-8"));
|
||||
}
|
||||
catch (UnsupportedEncodingException e)
|
||||
{
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
String name = URLDecoder.decode(param, "UTF-8");
|
||||
map.add(name, "");
|
||||
}
|
||||
catch (UnsupportedEncodingException e)
|
||||
{
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
3
integration/adapter-core/src/main/java/org/keycloak/adapters/AdapterTokenStore.java
Normal file → Executable file
3
integration/adapter-core/src/main/java/org/keycloak/adapters/AdapterTokenStore.java
Normal file → Executable file
|
@ -38,4 +38,7 @@ public interface AdapterTokenStore {
|
|||
* @param securityContext context where refresh was performed
|
||||
*/
|
||||
void refreshCallback(RefreshableKeycloakSecurityContext securityContext);
|
||||
|
||||
void saveRequest();
|
||||
boolean restoreRequest();
|
||||
}
|
||||
|
|
|
@ -19,11 +19,12 @@ import java.util.concurrent.atomic.AtomicLong;
|
|||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public abstract class OAuthRequestAuthenticator {
|
||||
public class OAuthRequestAuthenticator {
|
||||
private static final Logger log = Logger.getLogger(OAuthRequestAuthenticator.class);
|
||||
protected KeycloakDeployment deployment;
|
||||
protected RequestAuthenticator reqAuthenticator;
|
||||
protected int sslRedirectPort;
|
||||
protected AdapterTokenStore tokenStore;
|
||||
protected String tokenString;
|
||||
protected String idTokenString;
|
||||
protected IDToken idToken;
|
||||
|
@ -33,11 +34,12 @@ public abstract class OAuthRequestAuthenticator {
|
|||
protected String refreshToken;
|
||||
protected String strippedOauthParametersRequestUri;
|
||||
|
||||
public OAuthRequestAuthenticator(RequestAuthenticator requestAuthenticator, HttpFacade facade, KeycloakDeployment deployment, int sslRedirectPort) {
|
||||
public OAuthRequestAuthenticator(RequestAuthenticator requestAuthenticator, HttpFacade facade, KeycloakDeployment deployment, int sslRedirectPort, AdapterTokenStore tokenStore) {
|
||||
this.reqAuthenticator = requestAuthenticator;
|
||||
this.facade = facade;
|
||||
this.deployment = deployment;
|
||||
this.sslRedirectPort = sslRedirectPort;
|
||||
this.tokenStore = tokenStore;
|
||||
}
|
||||
|
||||
public AuthChallenge getChallenge() {
|
||||
|
@ -200,7 +202,7 @@ public abstract class OAuthRequestAuthenticator {
|
|||
} else {
|
||||
log.debug("redirecting to auth server");
|
||||
challenge = loginRedirect();
|
||||
saveRequest();
|
||||
tokenStore.saveRequest();
|
||||
return AuthOutcome.NOT_ATTEMPTED;
|
||||
}
|
||||
} else {
|
||||
|
@ -214,12 +216,6 @@ public abstract class OAuthRequestAuthenticator {
|
|||
|
||||
}
|
||||
|
||||
/**
|
||||
* Cache the request so that when we get redirected back, it gets invoked
|
||||
*
|
||||
*/
|
||||
protected abstract void saveRequest();
|
||||
|
||||
protected AuthChallenge challenge(final int code) {
|
||||
return new AuthChallenge() {
|
||||
@Override
|
||||
|
|
|
@ -1,148 +0,0 @@
|
|||
package org.keycloak.adapters.jetty;
|
||||
|
||||
import org.eclipse.jetty.http.MimeTypes;
|
||||
import org.eclipse.jetty.security.authentication.FormAuthenticator;
|
||||
import org.eclipse.jetty.server.Request;
|
||||
import org.eclipse.jetty.util.MultiMap;
|
||||
import org.jboss.logging.Logger;
|
||||
import org.keycloak.KeycloakPrincipal;
|
||||
import org.keycloak.KeycloakSecurityContext;
|
||||
import org.keycloak.adapters.AdapterTokenStore;
|
||||
import org.keycloak.adapters.AdapterUtils;
|
||||
import org.keycloak.adapters.HttpFacade;
|
||||
import org.keycloak.adapters.KeycloakAccount;
|
||||
import org.keycloak.adapters.KeycloakDeployment;
|
||||
import org.keycloak.adapters.OAuthRequestAuthenticator;
|
||||
import org.keycloak.adapters.RefreshableKeycloakSecurityContext;
|
||||
import org.keycloak.adapters.RequestAuthenticator;
|
||||
import org.keycloak.enums.TokenStore;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpSession;
|
||||
import java.security.Principal;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public abstract class AbstractJettyRequestAuthenticator extends RequestAuthenticator {
|
||||
public final static String __J_METHOD = "org.eclipse.jetty.security.HTTP_METHOD";
|
||||
protected static final Logger log = Logger.getLogger(AbstractJettyRequestAuthenticator.class);
|
||||
protected AbstractKeycloakJettyAuthenticator valve;
|
||||
protected Request request;
|
||||
protected KeycloakPrincipal<RefreshableKeycloakSecurityContext> principal;
|
||||
|
||||
public AbstractJettyRequestAuthenticator(HttpFacade facade, KeycloakDeployment deployment, AdapterTokenStore tokenStore, int sslRedirectPort, AbstractKeycloakJettyAuthenticator valve, Request request) {
|
||||
super(facade, deployment, tokenStore, sslRedirectPort);
|
||||
this.valve = valve;
|
||||
this.request = request;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected OAuthRequestAuthenticator createOAuthAuthenticator() {
|
||||
return new OAuthRequestAuthenticator(this, facade, deployment, sslRedirectPort) {
|
||||
@Override
|
||||
protected void saveRequest() {
|
||||
if (deployment.getTokenStore() == TokenStore.SESSION) {
|
||||
saveServletRequest();
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void completeOAuthAuthentication(final KeycloakPrincipal<RefreshableKeycloakSecurityContext> skp) {
|
||||
principal = skp;
|
||||
final RefreshableKeycloakSecurityContext securityContext = skp.getKeycloakSecurityContext();
|
||||
final Set<String> roles = AdapterUtils.getRolesFromSecurityContext(securityContext);
|
||||
KeycloakAccount account = new KeycloakAccount() {
|
||||
|
||||
@Override
|
||||
public Principal getPrincipal() {
|
||||
return skp;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getRoles() {
|
||||
return roles;
|
||||
}
|
||||
|
||||
@Override
|
||||
public KeycloakSecurityContext getKeycloakSecurityContext() {
|
||||
return securityContext;
|
||||
}
|
||||
|
||||
};
|
||||
request.setAttribute(KeycloakSecurityContext.class.getName(), securityContext);
|
||||
this.tokenStore.saveAccountInfo(account);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void completeBearerAuthentication(KeycloakPrincipal<RefreshableKeycloakSecurityContext> principal, String method) {
|
||||
this.principal = principal;
|
||||
RefreshableKeycloakSecurityContext securityContext = principal.getKeycloakSecurityContext();
|
||||
Set<String> roles = AdapterUtils.getRolesFromSecurityContext(securityContext);
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Completing bearer authentication. Bearer roles: " + roles);
|
||||
}
|
||||
request.setAttribute(KeycloakSecurityContext.class.getName(), securityContext);
|
||||
}
|
||||
|
||||
protected void restoreRequest() {
|
||||
HttpSession session = request.getSession(false);
|
||||
if (session == null) return;
|
||||
synchronized (session) {
|
||||
String j_uri = (String) session.getAttribute(FormAuthenticator.__J_URI);
|
||||
if (j_uri != null) {
|
||||
// check if the request is for the same url as the original and restore
|
||||
// params if it was a post
|
||||
StringBuffer buf = request.getRequestURL();
|
||||
if (request.getQueryString() != null)
|
||||
buf.append("?").append(request.getQueryString());
|
||||
|
||||
/*
|
||||
* if (j_uri.equals(buf.toString())) {
|
||||
*/
|
||||
MultiMap<String> j_post = (MultiMap<String>) session.getAttribute(FormAuthenticator.__J_POST);
|
||||
if (j_post != null) {
|
||||
restoreFormParameters(j_post, request);
|
||||
}
|
||||
session.removeAttribute(FormAuthenticator.__J_URI);
|
||||
session.removeAttribute(__J_METHOD);
|
||||
session.removeAttribute(FormAuthenticator.__J_POST);
|
||||
// }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getHttpSessionId(boolean create) {
|
||||
HttpSession session = request.getSession(create);
|
||||
return session != null ? session.getId() : null;
|
||||
}
|
||||
|
||||
protected void saveServletRequest() {
|
||||
// remember the current URI
|
||||
HttpSession session = request.getSession();
|
||||
synchronized (session) {
|
||||
// But only if it is not set already, or we save every uri that leads to a login form redirect
|
||||
if (session.getAttribute(FormAuthenticator.__J_URI) == null) {
|
||||
StringBuffer buf = request.getRequestURL();
|
||||
if (request.getQueryString() != null)
|
||||
buf.append("?").append(request.getQueryString());
|
||||
session.setAttribute(FormAuthenticator.__J_URI, buf.toString());
|
||||
session.setAttribute(__J_METHOD, request.getMethod());
|
||||
|
||||
if ("application/x-www-form-urlencoded".equals(request.getContentType()) && "POST".equalsIgnoreCase(request.getMethod())) {
|
||||
MultiMap<String> formParameters = extractFormParameters(request);
|
||||
session.setAttribute(FormAuthenticator.__J_POST, formParameters);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract MultiMap<String> extractFormParameters(Request base_request);
|
||||
|
||||
protected abstract void restoreFormParameters(MultiMap<String> j_post, Request base_request);
|
||||
}
|
|
@ -1,94 +1,99 @@
|
|||
package org.keycloak.adapters.jetty;
|
||||
|
||||
import org.eclipse.jetty.server.Request;
|
||||
import org.jboss.logging.Logger;
|
||||
import org.keycloak.KeycloakPrincipal;
|
||||
import org.keycloak.KeycloakSecurityContext;
|
||||
import org.keycloak.adapters.AdapterTokenStore;
|
||||
import org.keycloak.adapters.AdapterUtils;
|
||||
import org.keycloak.adapters.KeycloakAccount;
|
||||
import org.keycloak.adapters.KeycloakDeployment;
|
||||
import org.keycloak.adapters.RefreshableKeycloakSecurityContext;
|
||||
import org.keycloak.adapters.RequestAuthenticator;
|
||||
|
||||
import javax.servlet.http.HttpSession;
|
||||
|
||||
/**
|
||||
* Handle storage of token info in HTTP Session. Per-request object
|
||||
*
|
||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
*/
|
||||
public class JettySessionTokenStore implements AdapterTokenStore {
|
||||
|
||||
private static final Logger log = Logger.getLogger(JettySessionTokenStore.class);
|
||||
|
||||
private Request request;
|
||||
private KeycloakDeployment deployment;
|
||||
|
||||
public JettySessionTokenStore(Request request, KeycloakDeployment deployment) {
|
||||
this.request = request;
|
||||
this.deployment = deployment;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkCurrentToken() {
|
||||
if (request.getSession(false) == null) return;
|
||||
RefreshableKeycloakSecurityContext session = (RefreshableKeycloakSecurityContext) request.getSession().getAttribute(KeycloakSecurityContext.class.getName());
|
||||
if (session == null) return;
|
||||
|
||||
// just in case session got serialized
|
||||
if (session.getDeployment() == null) session.setCurrentRequestInfo(deployment, this);
|
||||
|
||||
if (session.isActive() && !session.getDeployment().isAlwaysRefreshToken()) return;
|
||||
|
||||
// FYI: A refresh requires same scope, so same roles will be set. Otherwise, refresh will fail and token will
|
||||
// not be updated
|
||||
boolean success = session.refreshExpiredToken(false);
|
||||
if (success && session.isActive()) return;
|
||||
|
||||
// Refresh failed, so user is already logged out from keycloak. Cleanup and expire our session
|
||||
request.getSession().removeAttribute(KeycloakSecurityContext.class.getName());
|
||||
request.getSession().invalidate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCached(RequestAuthenticator authenticator) {
|
||||
if (request.getSession(false) == null || request.getSession().getAttribute(KeycloakSecurityContext.class.getName()) == null)
|
||||
return false;
|
||||
log.debug("remote logged in already. Establish state from session");
|
||||
|
||||
RefreshableKeycloakSecurityContext securityContext = (RefreshableKeycloakSecurityContext) request.getSession().getAttribute(KeycloakSecurityContext.class.getName());
|
||||
if (!deployment.getRealm().equals(securityContext.getRealm())) {
|
||||
log.debug("Account from cookie is from a different realm than for the request.");
|
||||
return false;
|
||||
}
|
||||
|
||||
securityContext.setCurrentRequestInfo(deployment, this);
|
||||
request.setAttribute(KeycloakSecurityContext.class.getName(), securityContext);
|
||||
|
||||
AbstractJettyRequestAuthenticator jettyAuthenticator = (AbstractJettyRequestAuthenticator) authenticator;
|
||||
KeycloakPrincipal<RefreshableKeycloakSecurityContext> principal = AdapterUtils.createPrincipal(deployment, securityContext);
|
||||
jettyAuthenticator.principal = principal;
|
||||
jettyAuthenticator.restoreRequest();
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveAccountInfo(KeycloakAccount account) {
|
||||
RefreshableKeycloakSecurityContext securityContext = (RefreshableKeycloakSecurityContext)account.getKeycloakSecurityContext();
|
||||
request.getSession().setAttribute(KeycloakSecurityContext.class.getName(), securityContext);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void logout() {
|
||||
HttpSession session = request.getSession(false);
|
||||
if (session != null) {
|
||||
session.removeAttribute(KeycloakSecurityContext.class.getName());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void refreshCallback(RefreshableKeycloakSecurityContext securityContext) {
|
||||
// no-op
|
||||
}
|
||||
}
|
||||
package org.keycloak.adapters.jetty;
|
||||
|
||||
import org.eclipse.jetty.security.authentication.FormAuthenticator;
|
||||
import org.eclipse.jetty.server.Request;
|
||||
import org.eclipse.jetty.util.MultiMap;
|
||||
import org.jboss.logging.Logger;
|
||||
import org.keycloak.KeycloakPrincipal;
|
||||
import org.keycloak.KeycloakSecurityContext;
|
||||
import org.keycloak.adapters.AdapterTokenStore;
|
||||
import org.keycloak.adapters.AdapterUtils;
|
||||
import org.keycloak.adapters.KeycloakAccount;
|
||||
import org.keycloak.adapters.KeycloakDeployment;
|
||||
import org.keycloak.adapters.RefreshableKeycloakSecurityContext;
|
||||
import org.keycloak.adapters.RequestAuthenticator;
|
||||
import org.keycloak.util.MultivaluedHashMap;
|
||||
|
||||
import javax.servlet.http.HttpSession;
|
||||
|
||||
/**
|
||||
* Handle storage of token info in HTTP Session. Per-request object
|
||||
*
|
||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
*/
|
||||
public abstract class AbstractJettySessionTokenStore implements AdapterTokenStore {
|
||||
public final static String __J_METHOD = "org.eclipse.jetty.security.HTTP_METHOD";
|
||||
|
||||
private static final Logger log = Logger.getLogger(AbstractJettySessionTokenStore.class);
|
||||
|
||||
private Request request;
|
||||
protected KeycloakDeployment deployment;
|
||||
|
||||
public AbstractJettySessionTokenStore(Request request, KeycloakDeployment deployment) {
|
||||
this.request = request;
|
||||
this.deployment = deployment;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkCurrentToken() {
|
||||
if (request.getSession(false) == null) return;
|
||||
RefreshableKeycloakSecurityContext session = (RefreshableKeycloakSecurityContext) request.getSession().getAttribute(KeycloakSecurityContext.class.getName());
|
||||
if (session == null) return;
|
||||
|
||||
// just in case session got serialized
|
||||
if (session.getDeployment() == null) session.setCurrentRequestInfo(deployment, this);
|
||||
|
||||
if (session.isActive() && !session.getDeployment().isAlwaysRefreshToken()) return;
|
||||
|
||||
// FYI: A refresh requires same scope, so same roles will be set. Otherwise, refresh will fail and token will
|
||||
// not be updated
|
||||
boolean success = session.refreshExpiredToken(false);
|
||||
if (success && session.isActive()) return;
|
||||
|
||||
// Refresh failed, so user is already logged out from keycloak. Cleanup and expire our session
|
||||
request.getSession().removeAttribute(KeycloakSecurityContext.class.getName());
|
||||
request.getSession().invalidate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCached(RequestAuthenticator authenticator) {
|
||||
if (request.getSession(false) == null || request.getSession().getAttribute(KeycloakSecurityContext.class.getName()) == null)
|
||||
return false;
|
||||
log.debug("remote logged in already. Establish state from session");
|
||||
|
||||
RefreshableKeycloakSecurityContext securityContext = (RefreshableKeycloakSecurityContext) request.getSession().getAttribute(KeycloakSecurityContext.class.getName());
|
||||
if (!deployment.getRealm().equals(securityContext.getRealm())) {
|
||||
log.debug("Account from cookie is from a different realm than for the request.");
|
||||
return false;
|
||||
}
|
||||
|
||||
securityContext.setCurrentRequestInfo(deployment, this);
|
||||
request.setAttribute(KeycloakSecurityContext.class.getName(), securityContext);
|
||||
|
||||
JettyRequestAuthenticator jettyAuthenticator = (JettyRequestAuthenticator) authenticator;
|
||||
KeycloakPrincipal<RefreshableKeycloakSecurityContext> principal = AdapterUtils.createPrincipal(deployment, securityContext);
|
||||
jettyAuthenticator.principal = principal;
|
||||
restoreRequest();
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveAccountInfo(KeycloakAccount account) {
|
||||
RefreshableKeycloakSecurityContext securityContext = (RefreshableKeycloakSecurityContext) account.getKeycloakSecurityContext();
|
||||
request.getSession().setAttribute(KeycloakSecurityContext.class.getName(), securityContext);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void logout() {
|
||||
HttpSession session = request.getSession(false);
|
||||
if (session != null) {
|
||||
session.removeAttribute(KeycloakSecurityContext.class.getName());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void refreshCallback(RefreshableKeycloakSecurityContext securityContext) {
|
||||
// no-op
|
||||
}
|
||||
|
||||
}
|
|
@ -65,14 +65,14 @@ public abstract class AbstractKeycloakJettyAuthenticator extends LoginAuthentica
|
|||
return new ByteArrayInputStream(json.getBytes());
|
||||
}
|
||||
|
||||
public static AdapterTokenStore getTokenStore(Request request, HttpFacade facade, KeycloakDeployment resolvedDeployment) {
|
||||
public AdapterTokenStore getTokenStore(Request request, HttpFacade facade, KeycloakDeployment resolvedDeployment) {
|
||||
AdapterTokenStore store = (AdapterTokenStore)request.getAttribute(TOKEN_STORE_NOTE);
|
||||
if (store != null) {
|
||||
return store;
|
||||
}
|
||||
|
||||
if (resolvedDeployment.getTokenStore() == TokenStore.SESSION) {
|
||||
store = new JettySessionTokenStore(request, resolvedDeployment);
|
||||
store = createSessionTokenStore(request, resolvedDeployment);
|
||||
} else {
|
||||
store = new JettyCookieTokenStore(request, facade, resolvedDeployment);
|
||||
}
|
||||
|
@ -81,7 +81,9 @@ public abstract class AbstractKeycloakJettyAuthenticator extends LoginAuthentica
|
|||
return store;
|
||||
}
|
||||
|
||||
public static void logoutCurrent(Request request) {
|
||||
public abstract AdapterTokenStore createSessionTokenStore(Request request, KeycloakDeployment resolvedDeployment);
|
||||
|
||||
public void logoutCurrent(Request request) {
|
||||
AdapterDeploymentContext deploymentContext = (AdapterDeploymentContext)request.getAttribute(AdapterDeploymentContext.class.getName());
|
||||
KeycloakSecurityContext ksc = (KeycloakSecurityContext)request.getAttribute(KeycloakSecurityContext.class.getName());
|
||||
if (ksc != null) {
|
||||
|
@ -212,7 +214,7 @@ public abstract class AbstractKeycloakJettyAuthenticator extends LoginAuthentica
|
|||
nodesRegistrationManagement.tryRegister(deployment);
|
||||
|
||||
tokenStore.checkCurrentToken();
|
||||
AbstractJettyRequestAuthenticator authenticator = createRequestAuthenticator(request, facade, deployment, tokenStore);
|
||||
JettyRequestAuthenticator authenticator = createRequestAuthenticator(request, facade, deployment, tokenStore);
|
||||
AuthOutcome outcome = authenticator.authenticate();
|
||||
if (outcome == AuthOutcome.AUTHENTICATED) {
|
||||
if (facade.isEnded()) {
|
||||
|
@ -238,7 +240,10 @@ public abstract class AbstractKeycloakJettyAuthenticator extends LoginAuthentica
|
|||
|
||||
protected abstract Request resolveRequest(ServletRequest req);
|
||||
|
||||
protected abstract AbstractJettyRequestAuthenticator createRequestAuthenticator(Request request, JettyHttpFacade facade, KeycloakDeployment deployment, AdapterTokenStore tokenStore);
|
||||
protected JettyRequestAuthenticator createRequestAuthenticator(Request request, JettyHttpFacade facade,
|
||||
KeycloakDeployment deployment, AdapterTokenStore tokenStore) {
|
||||
return new JettyRequestAuthenticator(facade, deployment, tokenStore, -1, request);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAuthMethod() {
|
||||
|
|
|
@ -99,4 +99,14 @@ public class JettyCookieTokenStore implements AdapterTokenStore {
|
|||
CookieTokenStore.removeCookie(facade);
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveRequest() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean restoreRequest() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,8 @@ package org.keycloak.adapters.jetty;
|
|||
|
||||
import org.keycloak.KeycloakSecurityContext;
|
||||
import org.keycloak.adapters.HttpFacade;
|
||||
import org.keycloak.util.MultivaluedHashMap;
|
||||
import org.keycloak.util.UriUtils;
|
||||
|
||||
import javax.security.cert.X509Certificate;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
@ -21,6 +23,7 @@ public class JettyHttpFacade implements HttpFacade {
|
|||
protected HttpServletResponse response;
|
||||
protected RequestFacade requestFacade = new RequestFacade();
|
||||
protected ResponseFacade responseFacade = new ResponseFacade();
|
||||
protected MultivaluedHashMap<String, String> queryParameters;
|
||||
|
||||
protected class RequestFacade implements Request {
|
||||
@Override
|
||||
|
@ -39,7 +42,10 @@ public class JettyHttpFacade implements HttpFacade {
|
|||
|
||||
@Override
|
||||
public String getQueryParamValue(String paramName) {
|
||||
return request.getParameter(paramName);
|
||||
if (queryParameters == null) {
|
||||
queryParameters = UriUtils.decodeQueryString(request.getQueryString());
|
||||
}
|
||||
return queryParameters.getFirst(paramName);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -0,0 +1,85 @@
|
|||
package org.keycloak.adapters.jetty;
|
||||
|
||||
import org.eclipse.jetty.server.Request;
|
||||
import org.jboss.logging.Logger;
|
||||
import org.keycloak.KeycloakPrincipal;
|
||||
import org.keycloak.KeycloakSecurityContext;
|
||||
import org.keycloak.adapters.AdapterTokenStore;
|
||||
import org.keycloak.adapters.AdapterUtils;
|
||||
import org.keycloak.adapters.HttpFacade;
|
||||
import org.keycloak.adapters.KeycloakAccount;
|
||||
import org.keycloak.adapters.KeycloakDeployment;
|
||||
import org.keycloak.adapters.OAuthRequestAuthenticator;
|
||||
import org.keycloak.adapters.RefreshableKeycloakSecurityContext;
|
||||
import org.keycloak.adapters.RequestAuthenticator;
|
||||
|
||||
import javax.servlet.http.HttpSession;
|
||||
import java.security.Principal;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class JettyRequestAuthenticator extends RequestAuthenticator {
|
||||
protected static final Logger log = Logger.getLogger(JettyRequestAuthenticator.class);
|
||||
protected Request request;
|
||||
protected KeycloakPrincipal<RefreshableKeycloakSecurityContext> principal;
|
||||
|
||||
public JettyRequestAuthenticator(HttpFacade facade, KeycloakDeployment deployment, AdapterTokenStore tokenStore, int sslRedirectPort, Request request) {
|
||||
super(facade, deployment, tokenStore, sslRedirectPort);
|
||||
this.request = request;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected OAuthRequestAuthenticator createOAuthAuthenticator() {
|
||||
return new OAuthRequestAuthenticator(this, facade, deployment, sslRedirectPort, tokenStore);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void completeOAuthAuthentication(final KeycloakPrincipal<RefreshableKeycloakSecurityContext> skp) {
|
||||
principal = skp;
|
||||
final RefreshableKeycloakSecurityContext securityContext = skp.getKeycloakSecurityContext();
|
||||
final Set<String> roles = AdapterUtils.getRolesFromSecurityContext(securityContext);
|
||||
KeycloakAccount account = new KeycloakAccount() {
|
||||
|
||||
@Override
|
||||
public Principal getPrincipal() {
|
||||
return skp;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getRoles() {
|
||||
return roles;
|
||||
}
|
||||
|
||||
@Override
|
||||
public KeycloakSecurityContext getKeycloakSecurityContext() {
|
||||
return securityContext;
|
||||
}
|
||||
|
||||
};
|
||||
request.setAttribute(KeycloakSecurityContext.class.getName(), securityContext);
|
||||
this.tokenStore.saveAccountInfo(account);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void completeBearerAuthentication(KeycloakPrincipal<RefreshableKeycloakSecurityContext> principal, String method) {
|
||||
this.principal = principal;
|
||||
RefreshableKeycloakSecurityContext securityContext = principal.getKeycloakSecurityContext();
|
||||
Set<String> roles = AdapterUtils.getRolesFromSecurityContext(securityContext);
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Completing bearer authentication. Bearer roles: " + roles);
|
||||
}
|
||||
request.setAttribute(KeycloakSecurityContext.class.getName(), securityContext);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected String getHttpSessionId(boolean create) {
|
||||
HttpSession session = request.getSession(create);
|
||||
return session != null ? session.getId() : null;
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -1,32 +0,0 @@
|
|||
package org.keycloak.adapters.jetty;
|
||||
|
||||
import org.eclipse.jetty.server.Request;
|
||||
import org.eclipse.jetty.util.MultiMap;
|
||||
import org.keycloak.adapters.AdapterTokenStore;
|
||||
import org.keycloak.adapters.KeycloakDeployment;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class JettyRequestAuthenticator extends AbstractJettyRequestAuthenticator {
|
||||
|
||||
public JettyRequestAuthenticator(KeycloakDeployment deployment,
|
||||
AbstractKeycloakJettyAuthenticator valve, AdapterTokenStore tokenStore,
|
||||
JettyHttpFacade facade,
|
||||
Request request) {
|
||||
super(facade, deployment, tokenStore, -1, valve, request);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected MultiMap<String> extractFormParameters(Request base_request) {
|
||||
MultiMap<String> formParameters = new MultiMap<String>();
|
||||
base_request.extractParameters();
|
||||
return base_request.getParameters();
|
||||
}
|
||||
@Override
|
||||
protected void restoreFormParameters(MultiMap<String> j_post, Request base_request) {
|
||||
base_request.setParameters(j_post);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,93 @@
|
|||
package org.keycloak.adapters.jetty;
|
||||
|
||||
import org.eclipse.jetty.security.authentication.FormAuthenticator;
|
||||
import org.eclipse.jetty.server.Request;
|
||||
import org.eclipse.jetty.util.MultiMap;
|
||||
import org.keycloak.adapters.KeycloakDeployment;
|
||||
import org.keycloak.util.MultivaluedHashMap;
|
||||
|
||||
import javax.servlet.http.HttpSession;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class JettySessionTokenStore extends AbstractJettySessionTokenStore {
|
||||
public static final String CACHED_FORM_PARAMETERS = "__CACHED_FORM_PARAMETERS";
|
||||
protected Request myRequest;
|
||||
|
||||
public JettySessionTokenStore(Request request, KeycloakDeployment deployment) {
|
||||
super(request, deployment);
|
||||
this.myRequest = request; // for IDE/compilation purposes
|
||||
}
|
||||
|
||||
protected MultiMap<String> extractFormParameters(Request base_request) {
|
||||
MultiMap<String> formParameters = new MultiMap<String>();
|
||||
base_request.extractParameters();
|
||||
return base_request.getParameters();
|
||||
}
|
||||
protected void restoreFormParameters(MultiMap<String> j_post, Request base_request) {
|
||||
base_request.setParameters(j_post);
|
||||
}
|
||||
|
||||
public boolean restoreRequest() {
|
||||
HttpSession session = myRequest.getSession(false);
|
||||
if (session == null) return false;
|
||||
synchronized (session) {
|
||||
String j_uri = (String) session.getAttribute(FormAuthenticator.__J_URI);
|
||||
if (j_uri != null) {
|
||||
// check if the request is for the same url as the original and restore
|
||||
// params if it was a post
|
||||
StringBuffer buf = myRequest.getRequestURL();
|
||||
if (myRequest.getQueryString() != null)
|
||||
buf.append("?").append(myRequest.getQueryString());
|
||||
if (j_uri.equals(buf.toString())) {
|
||||
String method = (String)session.getAttribute(__J_METHOD);
|
||||
myRequest.setMethod(method);
|
||||
MultivaluedHashMap<String, String> j_post = (MultivaluedHashMap<String, String>) session.getAttribute(CACHED_FORM_PARAMETERS);
|
||||
if (j_post != null) {
|
||||
MultiMap<String> map = new MultiMap<String>();
|
||||
for (String key : j_post.keySet()) {
|
||||
for (String val : j_post.getList(key)) {
|
||||
map.add(key, val);
|
||||
}
|
||||
}
|
||||
restoreFormParameters(map, myRequest);
|
||||
}
|
||||
session.removeAttribute(FormAuthenticator.__J_URI);
|
||||
session.removeAttribute(__J_METHOD);
|
||||
session.removeAttribute(FormAuthenticator.__J_POST);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void saveRequest() {
|
||||
// remember the current URI
|
||||
HttpSession session = myRequest.getSession();
|
||||
synchronized (session) {
|
||||
// But only if it is not set already, or we save every uri that leads to a login form redirect
|
||||
if (session.getAttribute(FormAuthenticator.__J_URI) == null) {
|
||||
StringBuffer buf = myRequest.getRequestURL();
|
||||
if (myRequest.getQueryString() != null)
|
||||
buf.append("?").append(myRequest.getQueryString());
|
||||
session.setAttribute(FormAuthenticator.__J_URI, buf.toString());
|
||||
session.setAttribute(__J_METHOD, myRequest.getMethod());
|
||||
|
||||
if ("application/x-www-form-urlencoded".equals(myRequest.getContentType()) && "POST".equalsIgnoreCase(myRequest.getMethod())) {
|
||||
MultiMap<String> formParameters = extractFormParameters(myRequest);
|
||||
MultivaluedHashMap<String, String> map = new MultivaluedHashMap<String, String>();
|
||||
for (String key : formParameters.keySet()) {
|
||||
for (Object value : formParameters.getValues(key)) {
|
||||
map.add(key, (String) value);
|
||||
}
|
||||
}
|
||||
session.setAttribute(CACHED_FORM_PARAMETERS, map);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -21,8 +21,8 @@ public class KeycloakJettyAuthenticator extends AbstractKeycloakJettyAuthenticat
|
|||
|
||||
|
||||
@Override
|
||||
protected AbstractJettyRequestAuthenticator createRequestAuthenticator(Request request, JettyHttpFacade facade, KeycloakDeployment deployment, AdapterTokenStore tokenStore) {
|
||||
return new JettyRequestAuthenticator(deployment, this, tokenStore, facade, request);
|
||||
public AdapterTokenStore createSessionTokenStore(Request request, KeycloakDeployment resolvedDeployment) {
|
||||
return new JettySessionTokenStore(request, resolvedDeployment);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -36,6 +36,20 @@
|
|||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-jetty-core</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-server</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-util</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-security</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.httpcomponents</groupId>
|
||||
|
|
|
@ -1,32 +0,0 @@
|
|||
package org.keycloak.adapters.jetty;
|
||||
|
||||
import org.eclipse.jetty.server.Request;
|
||||
import org.eclipse.jetty.util.MultiMap;
|
||||
import org.keycloak.adapters.AdapterTokenStore;
|
||||
import org.keycloak.adapters.KeycloakDeployment;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class JettyRequestAuthenticator extends AbstractJettyRequestAuthenticator {
|
||||
|
||||
public JettyRequestAuthenticator(KeycloakDeployment deployment,
|
||||
AbstractKeycloakJettyAuthenticator valve, AdapterTokenStore tokenStore,
|
||||
JettyHttpFacade facade,
|
||||
Request request) {
|
||||
super(facade, deployment, tokenStore, -1, valve, request);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected MultiMap<String> extractFormParameters(Request base_request) {
|
||||
MultiMap<String> formParameters = new MultiMap<String>();
|
||||
base_request.extractParameters();
|
||||
return base_request.getParameters();
|
||||
}
|
||||
@Override
|
||||
protected void restoreFormParameters(MultiMap<String> j_post, Request base_request) {
|
||||
base_request.setParameters(j_post);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,94 @@
|
|||
package org.keycloak.adapters.jetty;
|
||||
|
||||
import org.eclipse.jetty.http.HttpMethod;
|
||||
import org.eclipse.jetty.security.authentication.FormAuthenticator;
|
||||
import org.eclipse.jetty.server.Request;
|
||||
import org.eclipse.jetty.util.MultiMap;
|
||||
import org.keycloak.adapters.KeycloakDeployment;
|
||||
import org.keycloak.util.MultivaluedHashMap;
|
||||
|
||||
import javax.servlet.http.HttpSession;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class JettySessionTokenStore extends AbstractJettySessionTokenStore {
|
||||
public static final String CACHED_FORM_PARAMETERS = "__CACHED_FORM_PARAMETERS";
|
||||
protected Request myRequest;
|
||||
|
||||
public JettySessionTokenStore(Request request, KeycloakDeployment deployment) {
|
||||
super(request, deployment);
|
||||
this.myRequest = request; // for IDE/compilation purposes
|
||||
}
|
||||
|
||||
protected MultiMap<String> extractFormParameters(Request base_request) {
|
||||
MultiMap<String> formParameters = new MultiMap<String>();
|
||||
base_request.extractParameters();
|
||||
return base_request.getParameters();
|
||||
}
|
||||
protected void restoreFormParameters(MultiMap<String> j_post, Request base_request) {
|
||||
base_request.setParameters(j_post);
|
||||
}
|
||||
|
||||
public boolean restoreRequest() {
|
||||
HttpSession session = myRequest.getSession(false);
|
||||
if (session == null) return false;
|
||||
synchronized (session) {
|
||||
String j_uri = (String) session.getAttribute(FormAuthenticator.__J_URI);
|
||||
if (j_uri != null) {
|
||||
// check if the request is for the same url as the original and restore
|
||||
// params if it was a post
|
||||
StringBuffer buf = myRequest.getRequestURL();
|
||||
if (myRequest.getQueryString() != null)
|
||||
buf.append("?").append(myRequest.getQueryString());
|
||||
if (j_uri.equals(buf.toString())) {
|
||||
String method = (String)session.getAttribute(__J_METHOD);
|
||||
myRequest.setMethod(HttpMethod.valueOf(method.toUpperCase()), method);
|
||||
MultivaluedHashMap<String, String> j_post = (MultivaluedHashMap<String, String>) session.getAttribute(CACHED_FORM_PARAMETERS);
|
||||
if (j_post != null) {
|
||||
MultiMap<String> map = new MultiMap<String>();
|
||||
for (String key : j_post.keySet()) {
|
||||
for (String val : j_post.getList(key)) {
|
||||
map.add(key, val);
|
||||
}
|
||||
}
|
||||
restoreFormParameters(map, myRequest);
|
||||
}
|
||||
session.removeAttribute(FormAuthenticator.__J_URI);
|
||||
session.removeAttribute(__J_METHOD);
|
||||
session.removeAttribute(FormAuthenticator.__J_POST);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void saveRequest() {
|
||||
// remember the current URI
|
||||
HttpSession session = myRequest.getSession();
|
||||
synchronized (session) {
|
||||
// But only if it is not set already, or we save every uri that leads to a login form redirect
|
||||
if (session.getAttribute(FormAuthenticator.__J_URI) == null) {
|
||||
StringBuffer buf = myRequest.getRequestURL();
|
||||
if (myRequest.getQueryString() != null)
|
||||
buf.append("?").append(myRequest.getQueryString());
|
||||
session.setAttribute(FormAuthenticator.__J_URI, buf.toString());
|
||||
session.setAttribute(__J_METHOD, myRequest.getMethod());
|
||||
|
||||
if ("application/x-www-form-urlencoded".equals(myRequest.getContentType()) && "POST".equalsIgnoreCase(myRequest.getMethod())) {
|
||||
MultiMap<String> formParameters = extractFormParameters(myRequest);
|
||||
MultivaluedHashMap<String, String> map = new MultivaluedHashMap<String, String>();
|
||||
for (String key : formParameters.keySet()) {
|
||||
for (Object value : formParameters.getValues(key)) {
|
||||
map.add(key, (String) value);
|
||||
}
|
||||
}
|
||||
session.setAttribute(CACHED_FORM_PARAMETERS, map);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -21,8 +21,8 @@ public class KeycloakJettyAuthenticator extends AbstractKeycloakJettyAuthenticat
|
|||
|
||||
|
||||
@Override
|
||||
protected AbstractJettyRequestAuthenticator createRequestAuthenticator(Request request, JettyHttpFacade facade, KeycloakDeployment deployment, AdapterTokenStore tokenStore) {
|
||||
return new JettyRequestAuthenticator(deployment, this, tokenStore, facade, request);
|
||||
public AdapterTokenStore createSessionTokenStore(Request request, KeycloakDeployment resolvedDeployment) {
|
||||
return new JettySessionTokenStore(request, resolvedDeployment);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -1,32 +0,0 @@
|
|||
package org.keycloak.adapters.jetty;
|
||||
|
||||
import org.eclipse.jetty.server.Request;
|
||||
import org.eclipse.jetty.util.MultiMap;
|
||||
import org.keycloak.adapters.AdapterTokenStore;
|
||||
import org.keycloak.adapters.KeycloakDeployment;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class JettyRequestAuthenticator extends AbstractJettyRequestAuthenticator {
|
||||
|
||||
public JettyRequestAuthenticator(KeycloakDeployment deployment,
|
||||
AbstractKeycloakJettyAuthenticator valve, AdapterTokenStore tokenStore,
|
||||
JettyHttpFacade facade,
|
||||
Request request) {
|
||||
super(facade, deployment, tokenStore, -1, valve, request);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected MultiMap<String> extractFormParameters(Request base_request) {
|
||||
MultiMap<String> formParameters = new MultiMap<String>();
|
||||
base_request.extractFormParameters(formParameters);
|
||||
return formParameters;
|
||||
}
|
||||
@Override
|
||||
protected void restoreFormParameters(MultiMap<String> j_post, Request base_request) {
|
||||
base_request.setContentParameters(j_post);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,95 @@
|
|||
package org.keycloak.adapters.jetty;
|
||||
|
||||
import org.eclipse.jetty.http.HttpMethod;
|
||||
import org.eclipse.jetty.security.authentication.FormAuthenticator;
|
||||
import org.eclipse.jetty.server.Request;
|
||||
import org.eclipse.jetty.util.MultiMap;
|
||||
import org.keycloak.adapters.KeycloakDeployment;
|
||||
import org.keycloak.util.MultivaluedHashMap;
|
||||
|
||||
import javax.servlet.http.HttpSession;
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class JettySessionTokenStore extends AbstractJettySessionTokenStore {
|
||||
public static final String CACHED_FORM_PARAMETERS = "__CACHED_FORM_PARAMETERS";
|
||||
protected Request myRequest;
|
||||
|
||||
public JettySessionTokenStore(Request request, KeycloakDeployment deployment) {
|
||||
super(request, deployment);
|
||||
this.myRequest = request; // for IDE/compilation purposes
|
||||
}
|
||||
|
||||
protected MultiMap<String> extractFormParameters(Request base_request) {
|
||||
MultiMap<String> formParameters = new MultiMap<String>();
|
||||
base_request.extractFormParameters(formParameters);
|
||||
return formParameters;
|
||||
}
|
||||
protected void restoreFormParameters(MultiMap<String> j_post, Request base_request) {
|
||||
base_request.setContentParameters(j_post);
|
||||
}
|
||||
|
||||
public boolean restoreRequest() {
|
||||
HttpSession session = myRequest.getSession(false);
|
||||
if (session == null) return false;
|
||||
synchronized (session) {
|
||||
String j_uri = (String) session.getAttribute(FormAuthenticator.__J_URI);
|
||||
if (j_uri != null) {
|
||||
// check if the request is for the same url as the original and restore
|
||||
// params if it was a post
|
||||
StringBuffer buf = myRequest.getRequestURL();
|
||||
if (myRequest.getQueryString() != null)
|
||||
buf.append("?").append(myRequest.getQueryString());
|
||||
if (j_uri.equals(buf.toString())) {
|
||||
String method = (String)session.getAttribute(__J_METHOD);
|
||||
myRequest.setMethod(HttpMethod.valueOf(method.toUpperCase()), method);
|
||||
MultivaluedHashMap<String, String> j_post = (MultivaluedHashMap<String, String>) session.getAttribute(CACHED_FORM_PARAMETERS);
|
||||
if (j_post != null) {
|
||||
MultiMap<String> map = new MultiMap<String>();
|
||||
for (String key : j_post.keySet()) {
|
||||
for (String val : j_post.getList(key)) {
|
||||
map.add(key, val);
|
||||
}
|
||||
}
|
||||
restoreFormParameters(map, myRequest);
|
||||
}
|
||||
session.removeAttribute(FormAuthenticator.__J_URI);
|
||||
session.removeAttribute(__J_METHOD);
|
||||
session.removeAttribute(FormAuthenticator.__J_POST);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void saveRequest() {
|
||||
// remember the current URI
|
||||
HttpSession session = myRequest.getSession();
|
||||
synchronized (session) {
|
||||
// But only if it is not set already, or we save every uri that leads to a login form redirect
|
||||
if (session.getAttribute(FormAuthenticator.__J_URI) == null) {
|
||||
StringBuffer buf = myRequest.getRequestURL();
|
||||
if (myRequest.getQueryString() != null)
|
||||
buf.append("?").append(myRequest.getQueryString());
|
||||
session.setAttribute(FormAuthenticator.__J_URI, buf.toString());
|
||||
session.setAttribute(__J_METHOD, myRequest.getMethod());
|
||||
|
||||
if ("application/x-www-form-urlencoded".equals(myRequest.getContentType()) && "POST".equalsIgnoreCase(myRequest.getMethod())) {
|
||||
MultiMap<String> formParameters = extractFormParameters(myRequest);
|
||||
MultivaluedHashMap<String, String> map = new MultivaluedHashMap<String, String>();
|
||||
for (String key : formParameters.keySet()) {
|
||||
for (Object value : formParameters.getValues(key)) {
|
||||
map.add(key, (String) value);
|
||||
}
|
||||
}
|
||||
session.setAttribute(CACHED_FORM_PARAMETERS, map);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -20,12 +20,7 @@ public class KeycloakJettyAuthenticator extends AbstractKeycloakJettyAuthenticat
|
|||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected AbstractJettyRequestAuthenticator createRequestAuthenticator(Request request, JettyHttpFacade facade, KeycloakDeployment deployment, AdapterTokenStore tokenStore) {
|
||||
return new JettyRequestAuthenticator(deployment, this, tokenStore, facade, request);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Override
|
||||
protected Request resolveRequest(ServletRequest req) {
|
||||
return (req instanceof Request) ? (Request)req : HttpChannel.getCurrentHttpChannel().getRequest();
|
||||
}
|
||||
|
@ -40,6 +35,8 @@ public class KeycloakJettyAuthenticator extends AbstractKeycloakJettyAuthenticat
|
|||
};
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public AdapterTokenStore createSessionTokenStore(Request request, KeycloakDeployment resolvedDeployment) {
|
||||
return new JettySessionTokenStore(request, resolvedDeployment);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,9 +5,12 @@ import org.apache.catalina.Lifecycle;
|
|||
import org.apache.catalina.LifecycleEvent;
|
||||
import org.apache.catalina.LifecycleListener;
|
||||
import org.apache.catalina.Manager;
|
||||
import org.apache.catalina.authenticator.Constants;
|
||||
import org.apache.catalina.authenticator.FormAuthenticator;
|
||||
import org.apache.catalina.authenticator.SavedRequest;
|
||||
import org.apache.catalina.connector.Request;
|
||||
import org.apache.catalina.connector.Response;
|
||||
import org.apache.tomcat.util.buf.ByteChunk;
|
||||
import org.keycloak.KeycloakSecurityContext;
|
||||
import org.keycloak.constants.AdapterConstants;
|
||||
import org.keycloak.adapters.AdapterDeploymentContext;
|
||||
|
@ -24,12 +27,15 @@ import org.keycloak.enums.TokenStore;
|
|||
|
||||
import javax.servlet.ServletContext;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.Cookie;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Enumeration;
|
||||
import java.util.Locale;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import org.keycloak.adapters.KeycloakConfigResolver;
|
||||
|
@ -180,7 +186,7 @@ public abstract class AbstractKeycloakAuthenticatorValve extends FormAuthenticat
|
|||
|
||||
nodesRegistrationManagement.tryRegister(deployment);
|
||||
|
||||
CatalinaRequestAuthenticator authenticator = new CatalinaRequestAuthenticator(deployment, this, tokenStore, facade, request, createPrincipalFactory());
|
||||
CatalinaRequestAuthenticator authenticator = new CatalinaRequestAuthenticator(deployment, tokenStore, facade, request, createPrincipalFactory());
|
||||
AuthOutcome outcome = authenticator.authenticate();
|
||||
if (outcome == AuthOutcome.AUTHENTICATED) {
|
||||
if (facade.isEnded()) {
|
||||
|
@ -225,7 +231,7 @@ public abstract class AbstractKeycloakAuthenticatorValve extends FormAuthenticat
|
|||
}
|
||||
|
||||
if (resolvedDeployment.getTokenStore() == TokenStore.SESSION) {
|
||||
store = new CatalinaSessionTokenStore(request, resolvedDeployment, userSessionManagement, createPrincipalFactory());
|
||||
store = new CatalinaSessionTokenStore(request, resolvedDeployment, userSessionManagement, createPrincipalFactory(), this);
|
||||
} else {
|
||||
store = new CatalinaCookieTokenStore(request, facade, resolvedDeployment, createPrincipalFactory());
|
||||
}
|
||||
|
|
|
@ -84,6 +84,16 @@ public class CatalinaCookieTokenStore implements AdapterTokenStore {
|
|||
CookieTokenStore.setTokenCookie(deployment, facade, secContext);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveRequest() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean restoreRequest() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify if we already have authenticated and active principal in cookie. Perform refresh if it's not active
|
||||
*
|
||||
|
|
|
@ -2,7 +2,9 @@ package org.keycloak.adapters.tomcat;
|
|||
|
||||
import org.keycloak.KeycloakSecurityContext;
|
||||
import org.keycloak.adapters.HttpFacade;
|
||||
import org.keycloak.util.MultivaluedHashMap;
|
||||
import org.keycloak.util.ServerCookie;
|
||||
import org.keycloak.util.UriUtils;
|
||||
|
||||
import javax.security.cert.X509Certificate;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
@ -22,6 +24,7 @@ public class CatalinaHttpFacade implements HttpFacade {
|
|||
protected HttpServletResponse response;
|
||||
protected RequestFacade requestFacade = new RequestFacade();
|
||||
protected ResponseFacade responseFacade = new ResponseFacade();
|
||||
protected MultivaluedHashMap<String, String> queryParameters;
|
||||
|
||||
protected class RequestFacade implements Request {
|
||||
@Override
|
||||
|
@ -40,7 +43,10 @@ public class CatalinaHttpFacade implements HttpFacade {
|
|||
|
||||
@Override
|
||||
public String getQueryParamValue(String paramName) {
|
||||
return request.getParameter(paramName);
|
||||
if (queryParameters == null) {
|
||||
queryParameters = UriUtils.decodeQueryString(request.getQueryString());
|
||||
}
|
||||
return queryParameters.getFirst(paramName);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -27,36 +27,22 @@ import javax.servlet.http.HttpSession;
|
|||
*/
|
||||
public class CatalinaRequestAuthenticator extends RequestAuthenticator {
|
||||
private static final Logger log = Logger.getLogger(""+CatalinaRequestAuthenticator.class);
|
||||
protected AbstractKeycloakAuthenticatorValve valve;
|
||||
protected Request request;
|
||||
protected GenericPrincipalFactory principalFactory;
|
||||
|
||||
public CatalinaRequestAuthenticator(KeycloakDeployment deployment,
|
||||
AbstractKeycloakAuthenticatorValve valve, AdapterTokenStore tokenStore,
|
||||
AdapterTokenStore tokenStore,
|
||||
CatalinaHttpFacade facade,
|
||||
Request request,
|
||||
GenericPrincipalFactory principalFactory) {
|
||||
super(facade, deployment, tokenStore, request.getConnector().getRedirectPort());
|
||||
this.valve = valve;
|
||||
this.request = request;
|
||||
this.principalFactory = principalFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected OAuthRequestAuthenticator createOAuthAuthenticator() {
|
||||
return new OAuthRequestAuthenticator(this, facade, deployment, sslRedirectPort) {
|
||||
@Override
|
||||
protected void saveRequest() {
|
||||
try {
|
||||
// Support saving request just for TokenStore.SESSION TODO: Add to tokenStore spi?
|
||||
if (deployment.getTokenStore() == TokenStore.SESSION) {
|
||||
valve.keycloakSaveRequest(request);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
};
|
||||
return new OAuthRequestAuthenticator(this, facade, deployment, sslRedirectPort, tokenStore);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -99,17 +85,6 @@ public class CatalinaRequestAuthenticator extends RequestAuthenticator {
|
|||
request.setAttribute(KeycloakSecurityContext.class.getName(), securityContext);
|
||||
}
|
||||
|
||||
protected void restoreRequest() {
|
||||
if (request.getSessionInternal().getNote(Constants.FORM_REQUEST_NOTE) != null) {
|
||||
if (valve.keycloakRestoreRequest(request)) {
|
||||
log.finer("restoreRequest");
|
||||
} else {
|
||||
log.finer("Restore of original request failed");
|
||||
throw new RuntimeException("Restore of original request failed");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getHttpSessionId(boolean create) {
|
||||
HttpSession session = request.getSession(create);
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package org.keycloak.adapters.tomcat;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
|
@ -24,12 +25,18 @@ public class CatalinaSessionTokenStore implements AdapterTokenStore {
|
|||
private KeycloakDeployment deployment;
|
||||
private CatalinaUserSessionManagement sessionManagement;
|
||||
protected GenericPrincipalFactory principalFactory;
|
||||
protected AbstractKeycloakAuthenticatorValve valve;
|
||||
|
||||
public CatalinaSessionTokenStore(Request request, KeycloakDeployment deployment, CatalinaUserSessionManagement sessionManagement, GenericPrincipalFactory principalFactory) {
|
||||
|
||||
public CatalinaSessionTokenStore(Request request, KeycloakDeployment deployment,
|
||||
CatalinaUserSessionManagement sessionManagement,
|
||||
GenericPrincipalFactory principalFactory,
|
||||
AbstractKeycloakAuthenticatorValve valve) {
|
||||
this.request = request;
|
||||
this.deployment = deployment;
|
||||
this.sessionManagement = sessionManagement;
|
||||
this.principalFactory = principalFactory;
|
||||
this.valve = valve;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -81,7 +88,7 @@ public class CatalinaSessionTokenStore implements AdapterTokenStore {
|
|||
request.setUserPrincipal(principal);
|
||||
request.setAuthType("KEYCLOAK");
|
||||
|
||||
((CatalinaRequestAuthenticator)authenticator).restoreRequest();
|
||||
restoreRequest();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -112,4 +119,18 @@ public class CatalinaSessionTokenStore implements AdapterTokenStore {
|
|||
public void refreshCallback(RefreshableKeycloakSecurityContext securityContext) {
|
||||
// no-op
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveRequest() {
|
||||
try {
|
||||
valve.keycloakSaveRequest(request);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean restoreRequest() {
|
||||
return valve.keycloakRestoreRequest(request);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -53,12 +53,7 @@ public abstract class AbstractUndertowRequestAuthenticator extends RequestAuthen
|
|||
|
||||
@Override
|
||||
protected OAuthRequestAuthenticator createOAuthAuthenticator() {
|
||||
return new OAuthRequestAuthenticator(this, facade, deployment, sslRedirectPort) {
|
||||
@Override
|
||||
protected void saveRequest() {
|
||||
// todo
|
||||
}
|
||||
};
|
||||
return new OAuthRequestAuthenticator(this, facade, deployment, sslRedirectPort, tokenStore);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -0,0 +1,131 @@
|
|||
package org.keycloak.adapters.undertow;
|
||||
import io.undertow.UndertowLogger;
|
||||
import io.undertow.UndertowOptions;
|
||||
import io.undertow.server.Connectors;
|
||||
import io.undertow.server.HttpServerExchange;
|
||||
import io.undertow.server.session.Session;
|
||||
import io.undertow.servlet.handlers.ServletRequestContext;
|
||||
import io.undertow.servlet.spec.HttpSessionImpl;
|
||||
import io.undertow.util.HeaderMap;
|
||||
import io.undertow.util.HeaderValues;
|
||||
import io.undertow.util.Headers;
|
||||
import io.undertow.util.HttpString;
|
||||
import io.undertow.util.ImmediatePooled;
|
||||
|
||||
import javax.servlet.http.HttpSession;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.Serializable;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.security.AccessController;
|
||||
import java.util.Iterator;
|
||||
|
||||
/**
|
||||
* Saved servlet request.
|
||||
*
|
||||
* Note bill burke: I had to fork this because Undertow was automatically restoring the request before the code could be processed and redirected.
|
||||
*
|
||||
* @author Stuart Douglas
|
||||
*/
|
||||
public class SavedRequest implements Serializable {
|
||||
|
||||
private static final String SESSION_KEY = SavedRequest.class.getName();
|
||||
|
||||
private final byte[] data;
|
||||
private final int dataLength;
|
||||
private final HttpString method;
|
||||
private final String requestUri;
|
||||
private final HeaderMap headerMap;
|
||||
|
||||
public SavedRequest(byte[] data, int dataLength, HttpString method, String requestUri, HeaderMap headerMap) {
|
||||
this.data = data;
|
||||
this.dataLength = dataLength;
|
||||
this.method = method;
|
||||
this.requestUri = requestUri;
|
||||
this.headerMap = headerMap;
|
||||
}
|
||||
|
||||
public static void trySaveRequest(final HttpServerExchange exchange) {
|
||||
int maxSize = exchange.getConnection().getUndertowOptions().get(UndertowOptions.MAX_BUFFERED_REQUEST_SIZE, 16384);
|
||||
if (maxSize > 0) {
|
||||
//if this request has a body try and cache the response
|
||||
if (!exchange.isRequestComplete()) {
|
||||
final long requestContentLength = exchange.getRequestContentLength();
|
||||
if (requestContentLength > maxSize) {
|
||||
UndertowLogger.REQUEST_LOGGER.debugf("Request to %s was to large to save", exchange.getRequestURI());
|
||||
return;//failed to save the request, we just return
|
||||
}
|
||||
//TODO: we should really be used pooled buffers
|
||||
//TODO: we should probably limit the number of saved requests at any given time
|
||||
byte[] buffer = new byte[maxSize];
|
||||
int read = 0;
|
||||
int res = 0;
|
||||
InputStream in = exchange.getInputStream();
|
||||
try {
|
||||
while ((res = in.read(buffer, read, buffer.length - read)) > 0) {
|
||||
read += res;
|
||||
if (read == maxSize) {
|
||||
UndertowLogger.REQUEST_LOGGER.debugf("Request to %s was to large to save", exchange.getRequestURI());
|
||||
return;//failed to save the request, we just return
|
||||
}
|
||||
}
|
||||
HeaderMap headers = new HeaderMap();
|
||||
for(HeaderValues entry : exchange.getRequestHeaders()) {
|
||||
if(entry.getHeaderName().equals(Headers.CONTENT_LENGTH) ||
|
||||
entry.getHeaderName().equals(Headers.TRANSFER_ENCODING) ||
|
||||
entry.getHeaderName().equals(Headers.CONNECTION)) {
|
||||
continue;
|
||||
}
|
||||
headers.putAll(entry.getHeaderName(), entry);
|
||||
}
|
||||
SavedRequest request = new SavedRequest(buffer, read, exchange.getRequestMethod(), exchange.getRequestURI(), exchange.getRequestHeaders());
|
||||
final ServletRequestContext sc = exchange.getAttachment(ServletRequestContext.ATTACHMENT_KEY);
|
||||
HttpSessionImpl session = sc.getCurrentServletContext().getSession(exchange, true);
|
||||
Session underlyingSession;
|
||||
if(System.getSecurityManager() == null) {
|
||||
underlyingSession = session.getSession();
|
||||
} else {
|
||||
underlyingSession = AccessController.doPrivileged(new HttpSessionImpl.UnwrapSessionAction(session));
|
||||
}
|
||||
underlyingSession.setAttribute(SESSION_KEY, request);
|
||||
} catch (IOException e) {
|
||||
UndertowLogger.REQUEST_IO_LOGGER.ioException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void tryRestoreRequest(final HttpServerExchange exchange, HttpSession session) {
|
||||
if(session instanceof HttpSessionImpl) {
|
||||
|
||||
Session underlyingSession;
|
||||
if(System.getSecurityManager() == null) {
|
||||
underlyingSession = ((HttpSessionImpl) session).getSession();
|
||||
} else {
|
||||
underlyingSession = AccessController.doPrivileged(new HttpSessionImpl.UnwrapSessionAction(session));
|
||||
}
|
||||
SavedRequest request = (SavedRequest) underlyingSession.getAttribute(SESSION_KEY);
|
||||
if(request != null) {
|
||||
if(request.requestUri.equals(exchange.getRequestURI()) && exchange.isRequestComplete()) {
|
||||
UndertowLogger.REQUEST_LOGGER.debugf("restoring request body for request to %s", request.requestUri);
|
||||
exchange.setRequestMethod(request.method);
|
||||
Connectors.ungetRequestBytes(exchange, new ImmediatePooled<ByteBuffer>(ByteBuffer.wrap(request.data, 0, request.dataLength)));
|
||||
underlyingSession.removeAttribute(SESSION_KEY);
|
||||
//clear the existing header map of everything except the connection header
|
||||
//TODO: are there other headers we should preserve?
|
||||
Iterator<HeaderValues> headerIterator = exchange.getRequestHeaders().iterator();
|
||||
while (headerIterator.hasNext()) {
|
||||
HeaderValues header = headerIterator.next();
|
||||
if(!header.getHeaderName().equals(Headers.CONNECTION)) {
|
||||
headerIterator.remove();
|
||||
}
|
||||
}
|
||||
for(HeaderValues header : request.headerMap) {
|
||||
exchange.getRequestHeaders().putAll(header.getHeaderName(), header);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -19,12 +19,15 @@ package org.keycloak.adapters.undertow;
|
|||
import io.undertow.security.api.SecurityContext;
|
||||
import io.undertow.server.HttpServerExchange;
|
||||
import io.undertow.servlet.handlers.ServletRequestContext;
|
||||
import io.undertow.servlet.util.SavedRequest;
|
||||
import org.keycloak.KeycloakPrincipal;
|
||||
import org.keycloak.KeycloakSecurityContext;
|
||||
import org.keycloak.adapters.AdapterTokenStore;
|
||||
import org.keycloak.adapters.HttpFacade;
|
||||
import org.keycloak.adapters.KeycloakDeployment;
|
||||
import org.keycloak.adapters.OAuthRequestAuthenticator;
|
||||
import org.keycloak.adapters.RefreshableKeycloakSecurityContext;
|
||||
import org.keycloak.enums.TokenStore;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpSession;
|
||||
|
@ -43,6 +46,11 @@ public class ServletRequestAuthenticator extends AbstractUndertowRequestAuthenti
|
|||
super(facade, deployment, sslRedirectPort, securityContext, exchange, tokenStore);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected OAuthRequestAuthenticator createOAuthAuthenticator() {
|
||||
return new OAuthRequestAuthenticator(this, facade, deployment, sslRedirectPort, tokenStore);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void propagateKeycloakContext(KeycloakUndertowAccount account) {
|
||||
super.propagateKeycloakContext(account);
|
||||
|
|
|
@ -64,6 +64,7 @@ public class ServletSessionTokenStore implements AdapterTokenStore {
|
|||
log.debug("Cached account found");
|
||||
securityContext.authenticationComplete(account, "KEYCLOAK", false);
|
||||
((AbstractUndertowRequestAuthenticator)authenticator).propagateKeycloakContext(account);
|
||||
restoreRequest();
|
||||
return true;
|
||||
} else {
|
||||
log.debug("Refresh failed. Account was not active. Returning null and invalidating Http session");
|
||||
|
@ -105,6 +106,20 @@ public class ServletSessionTokenStore implements AdapterTokenStore {
|
|||
// no-op
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveRequest() {
|
||||
SavedRequest.trySaveRequest(exchange);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean restoreRequest() {
|
||||
HttpSession session = getSession(false);
|
||||
if (session == null) return false;
|
||||
SavedRequest.tryRestoreRequest(exchange, session);
|
||||
return false;
|
||||
}
|
||||
|
||||
protected HttpSession getSession(boolean create) {
|
||||
final ServletRequestContext servletRequestContext = exchange.getAttachment(ServletRequestContext.ATTACHMENT_KEY);
|
||||
HttpServletRequest req = (HttpServletRequest) servletRequestContext.getServletRequest();
|
||||
|
|
|
@ -80,4 +80,14 @@ public class UndertowCookieTokenStore implements AdapterTokenStore {
|
|||
public void refreshCallback(RefreshableKeycloakSecurityContext securityContext) {
|
||||
CookieTokenStore.setTokenCookie(deployment, facade, securityContext);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveRequest() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean restoreRequest() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -70,6 +70,16 @@ public class UndertowSessionTokenStore implements AdapterTokenStore {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveRequest() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean restoreRequest() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveAccountInfo(KeycloakAccount account) {
|
||||
Session session = Sessions.getOrCreateSession(exchange);
|
||||
|
|
|
@ -74,7 +74,6 @@ import java.util.concurrent.atomic.AtomicInteger;
|
|||
*/
|
||||
public class AdapterTest {
|
||||
|
||||
public static final String LOGIN_URL = OpenIDConnectService.loginPageUrl(UriBuilder.fromUri("http://localhost:8081/auth")).build("demo").toString();
|
||||
public static PublicKey realmPublicKey;
|
||||
@ClassRule
|
||||
public static AbstractKeycloakRule keycloakRule = new AbstractKeycloakRule() {
|
||||
|
@ -99,6 +98,8 @@ public class AdapterTest {
|
|||
System.setProperty("my.host.name", "localhost");
|
||||
url = getClass().getResource("/adapter-test/session-keycloak.json");
|
||||
deployApplication("session-portal", "/session-portal", SessionServlet.class, url.getPath(), "user");
|
||||
url = getClass().getResource("/adapter-test/input-keycloak.json");
|
||||
deployApplication("input-portal", "/input-portal", InputServlet.class, url.getPath(), "user", true, null, "/secured/*");
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -110,6 +111,11 @@ public class AdapterTest {
|
|||
testStrategy.testLoginSSOAndLogout();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSavedPostRequest() throws Exception {
|
||||
testStrategy.testSavedPostRequest();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testServletRequestLogout() throws Exception {
|
||||
testStrategy.testServletRequestLogout();
|
||||
|
|
|
@ -87,6 +87,9 @@ public class AdapterTestStrategy extends ExternalResource {
|
|||
@WebResource
|
||||
protected LoginPage loginPage;
|
||||
|
||||
@WebResource
|
||||
protected InputPage inputPage;
|
||||
|
||||
protected String LOGIN_URL = OpenIDConnectService.loginPageUrl(UriBuilder.fromUri(AUTH_SERVER_URL)).build("demo").toString();
|
||||
|
||||
public AdapterTestStrategy(String AUTH_SERVER_URL, String APP_SERVER_BASE_URL, AbstractKeycloakRule keycloakRule) {
|
||||
|
@ -132,6 +135,35 @@ public class AdapterTestStrategy extends ExternalResource {
|
|||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSavedPostRequest() throws Exception {
|
||||
// test login to customer-portal which does a bearer request to customer-db
|
||||
driver.navigate().to(APP_SERVER_BASE_URL + "/input-portal");
|
||||
System.out.println("Current url: " + driver.getCurrentUrl());
|
||||
Assert.assertEquals(driver.getCurrentUrl(), APP_SERVER_BASE_URL + "/input-portal" + slash);
|
||||
inputPage.execute("hello");
|
||||
|
||||
Assert.assertTrue(driver.getCurrentUrl().startsWith(LOGIN_URL));
|
||||
loginPage.login("bburke@redhat.com", "password");
|
||||
System.out.println("Current url: " + driver.getCurrentUrl());
|
||||
Assert.assertEquals(driver.getCurrentUrl(), APP_SERVER_BASE_URL + "/input-portal/secured/post");
|
||||
String pageSource = driver.getPageSource();
|
||||
System.out.println(pageSource);
|
||||
Assert.assertTrue(pageSource.contains("parameter=hello"));
|
||||
|
||||
// test logout
|
||||
|
||||
String logoutUri = OpenIDConnectService.logoutUrl(UriBuilder.fromUri(AUTH_SERVER_URL))
|
||||
.queryParam(OAuth2Constants.REDIRECT_URI, APP_SERVER_BASE_URL + "/customer-portal").build("demo").toString();
|
||||
driver.navigate().to(logoutUri);
|
||||
Assert.assertTrue(driver.getCurrentUrl().startsWith(LOGIN_URL));
|
||||
driver.navigate().to(APP_SERVER_BASE_URL + "/product-portal");
|
||||
Assert.assertTrue(driver.getCurrentUrl().startsWith(LOGIN_URL));
|
||||
driver.navigate().to(APP_SERVER_BASE_URL + "/customer-portal");
|
||||
Assert.assertTrue(driver.getCurrentUrl().startsWith(LOGIN_URL));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testLoginSSOAndLogout() throws Exception {
|
||||
// test login to customer-portal which does a bearer request to customer-db
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
package org.keycloak.testsuite.adapter;
|
||||
|
||||
import org.keycloak.testsuite.pages.AbstractPage;
|
||||
import org.openqa.selenium.WebElement;
|
||||
import org.openqa.selenium.support.FindBy;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class InputPage extends AbstractPage {
|
||||
@FindBy(id = "parameter")
|
||||
private WebElement parameter;
|
||||
|
||||
@FindBy(name = "submit")
|
||||
private WebElement submit;
|
||||
|
||||
public void execute(String param) {
|
||||
parameter.clear();
|
||||
parameter.sendKeys(param);
|
||||
|
||||
submit.click();
|
||||
}
|
||||
|
||||
|
||||
public boolean isCurrent() {
|
||||
return driver.getTitle().equals("Input Page");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void open() {
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
package org.keycloak.testsuite.adapter;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServlet;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.servlet.http.HttpSession;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:bburke@redhat.com">Bill Burke</a>
|
||||
*/
|
||||
public class InputServlet extends HttpServlet {
|
||||
|
||||
@Override
|
||||
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
|
||||
String appBase = System.getProperty("app.server.base.url", "http://localhost:8081");
|
||||
String actionUrl = appBase + "/input-portal/secured/post";
|
||||
|
||||
|
||||
resp.setContentType("text/html");
|
||||
PrintWriter pw = resp.getWriter();
|
||||
pw.printf("<html><head><title>%s</title></head><body>", "Input Page");
|
||||
pw.printf("<form action=\"%s\" method=\"POST\">", actionUrl);
|
||||
pw.println("<input id=\"parameter\" type=\"text\" name=\"parameter\">");
|
||||
pw.println("<input name=\"submit\" type=\"submit\" value=\"Submit\"></form>");
|
||||
pw.print("</body></html>");
|
||||
pw.flush();
|
||||
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
|
||||
resp.setContentType("text/plain");
|
||||
PrintWriter pw = resp.getWriter();
|
||||
pw.printf("parameter="+req.getParameter("parameter"));
|
||||
pw.flush();
|
||||
}
|
||||
|
||||
}
|
76
testsuite/integration/src/test/java/org/keycloak/testsuite/adapter/SessionServlet.java
Normal file → Executable file
76
testsuite/integration/src/test/java/org/keycloak/testsuite/adapter/SessionServlet.java
Normal file → Executable file
|
@ -1,38 +1,38 @@
|
|||
package org.keycloak.testsuite.adapter;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServlet;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.servlet.http.HttpSession;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
*/
|
||||
public class SessionServlet extends HttpServlet {
|
||||
|
||||
@Override
|
||||
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
|
||||
String counter = increaseAndGetCounter(req);
|
||||
|
||||
resp.setContentType("text/html");
|
||||
PrintWriter pw = resp.getWriter();
|
||||
pw.printf("<html><head><title>%s</title></head><body>", "Session Test");
|
||||
pw.printf("Counter=%s", counter);
|
||||
pw.print("</body></html>");
|
||||
pw.flush();
|
||||
|
||||
|
||||
}
|
||||
|
||||
private String increaseAndGetCounter(HttpServletRequest req) {
|
||||
HttpSession session = req.getSession();
|
||||
Integer counter = (Integer)session.getAttribute("counter");
|
||||
counter = (counter == null) ? 1 : counter + 1;
|
||||
session.setAttribute("counter", counter);
|
||||
return String.valueOf(counter);
|
||||
}
|
||||
}
|
||||
package org.keycloak.testsuite.adapter;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServlet;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.servlet.http.HttpSession;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
*/
|
||||
public class SessionServlet extends HttpServlet {
|
||||
|
||||
@Override
|
||||
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
|
||||
String counter = increaseAndGetCounter(req);
|
||||
|
||||
resp.setContentType("text/html");
|
||||
PrintWriter pw = resp.getWriter();
|
||||
pw.printf("<html><head><title>%s</title></head><body>", "Session Test");
|
||||
pw.printf("Counter=%s", counter);
|
||||
pw.print("</body></html>");
|
||||
pw.flush();
|
||||
|
||||
|
||||
}
|
||||
|
||||
private String increaseAndGetCounter(HttpServletRequest req) {
|
||||
HttpSession session = req.getSession();
|
||||
Integer counter = (Integer)session.getAttribute("counter");
|
||||
counter = (counter == null) ? 1 : counter + 1;
|
||||
session.setAttribute("counter", counter);
|
||||
return String.valueOf(counter);
|
||||
}
|
||||
}
|
||||
|
|
4
testsuite/integration/src/test/java/org/keycloak/testsuite/pages/AbstractPage.java
Normal file → Executable file
4
testsuite/integration/src/test/java/org/keycloak/testsuite/pages/AbstractPage.java
Normal file → Executable file
|
@ -39,8 +39,8 @@ public abstract class AbstractPage {
|
|||
isCurrent());
|
||||
}
|
||||
|
||||
abstract boolean isCurrent();
|
||||
abstract public boolean isCurrent();
|
||||
|
||||
abstract void open() throws Exception;
|
||||
abstract public void open() throws Exception;
|
||||
|
||||
}
|
||||
|
|
2
testsuite/integration/src/test/java/org/keycloak/testsuite/pages/OAuthGrantPage.java
Normal file → Executable file
2
testsuite/integration/src/test/java/org/keycloak/testsuite/pages/OAuthGrantPage.java
Normal file → Executable file
|
@ -49,7 +49,7 @@ public class OAuthGrantPage extends AbstractPage {
|
|||
}
|
||||
|
||||
@Override
|
||||
void open() {
|
||||
public void open() {
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -150,6 +150,10 @@ public abstract class AbstractKeycloakRule extends ExternalResource {
|
|||
|
||||
public void deployApplication(String name, String contextPath, Class<? extends Servlet> servletClass, String adapterConfigPath, String role, boolean isConstrained, Class<? extends KeycloakConfigResolver> keycloakConfigResolver) {
|
||||
String constraintUrl = "/*";
|
||||
deployApplication(name, contextPath, servletClass, adapterConfigPath, role, isConstrained, keycloakConfigResolver, constraintUrl);
|
||||
}
|
||||
|
||||
public void deployApplication(String name, String contextPath, Class<? extends Servlet> servletClass, String adapterConfigPath, String role, boolean isConstrained, Class<? extends KeycloakConfigResolver> keycloakConfigResolver, String constraintUrl) {
|
||||
DeploymentInfo di = createDeploymentInfo(name, contextPath, servletClass);
|
||||
if (null == keycloakConfigResolver) {
|
||||
di.addInitParameter("keycloak.config.file", adapterConfigPath);
|
||||
|
|
|
@ -125,6 +125,16 @@
|
|||
"http://localhost:8081/session-portal/*"
|
||||
],
|
||||
"secret": "password"
|
||||
},
|
||||
{
|
||||
"name": "input-portal",
|
||||
"enabled": true,
|
||||
"adminUrl": "http://localhost:8081/input-portal",
|
||||
"baseUrl": "http://localhost:8081/input-portal",
|
||||
"redirectUris": [
|
||||
"http://localhost:8081/input-portal/*"
|
||||
],
|
||||
"secret": "password"
|
||||
}
|
||||
],
|
||||
"oauthClients": [
|
||||
|
|
10
testsuite/integration/src/test/resources/adapter-test/input-keycloak.json
Executable file
10
testsuite/integration/src/test/resources/adapter-test/input-keycloak.json
Executable file
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"realm" : "demo",
|
||||
"resource" : "input-portal",
|
||||
"realm-public-key" : "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
|
||||
"auth-server-url" : "http://${my.host.name}:8081/auth",
|
||||
"ssl-required" : "external",
|
||||
"credentials" : {
|
||||
"secret": "password"
|
||||
}
|
||||
}
|
|
@ -95,6 +95,7 @@ public class Jetty9Test {
|
|||
list.add(new WebAppContext(new File(base, "customer-db").toString(), "/customer-db"));
|
||||
list.add(new WebAppContext(new File(base, "product-portal").toString(), "/product-portal"));
|
||||
list.add(new WebAppContext(new File(base, "session-portal").toString(), "/session-portal"));
|
||||
list.add(new WebAppContext(new File(base, "input-portal").toString(), "/input-portal"));
|
||||
list.add(new WebAppContext(new File(base, "secure-portal").toString(), "/secure-portal"));
|
||||
|
||||
|
||||
|
@ -117,6 +118,11 @@ public class Jetty9Test {
|
|||
@Rule
|
||||
public AdapterTestStrategy testStrategy = new AdapterTestStrategy("http://localhost:8081/auth", "http://localhost:8082", keycloakRule, true);
|
||||
|
||||
@Test
|
||||
public void testSavedPostRequest() throws Exception {
|
||||
testStrategy.testSavedPostRequest();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLoginSSOAndLogout() throws Exception {
|
||||
testStrategy.testLoginSSOAndLogout();
|
||||
|
|
|
@ -125,6 +125,16 @@
|
|||
"http://localhost:8082/session-portal/*"
|
||||
],
|
||||
"secret": "password"
|
||||
},
|
||||
{
|
||||
"name": "input-portal",
|
||||
"enabled": true,
|
||||
"adminUrl": "http://localhost:8082/input-portal",
|
||||
"baseUrl": "http://localhost:8082/input-portal",
|
||||
"redirectUris": [
|
||||
"http://localhost:8082/input-portal/*"
|
||||
],
|
||||
"secret": "password"
|
||||
}
|
||||
],
|
||||
"oauthClients": [
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
<?xml version="1.0"?>
|
||||
<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">
|
||||
<Configure class="org.eclipse.jetty.webapp.WebAppContext">
|
||||
<Get name="securityHandler">
|
||||
<Set name="authenticator">
|
||||
<New class="org.keycloak.adapters.jetty.KeycloakJettyAuthenticator">
|
||||
<!--
|
||||
<Set name="adapterConfig">
|
||||
<New class="org.keycloak.representations.adapters.config.AdapterConfig">
|
||||
<Set name="realm">tomcat</Set>
|
||||
<Set name="resource">customer-portal</Set>
|
||||
<Set name="authServerUrl">http://localhost:8081/auth</Set>
|
||||
<Set name="sslRequired">external</Set>
|
||||
<Set name="credentials">
|
||||
<Map>
|
||||
<Entry>
|
||||
<Item>secret</Item>
|
||||
<Item>password</Item>
|
||||
</Entry>
|
||||
</Map>
|
||||
</Set>
|
||||
<Set name="realmKey">MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB</Set>
|
||||
</New>
|
||||
</Set>
|
||||
-->
|
||||
</New>
|
||||
</Set>
|
||||
</Get>
|
||||
</Configure>
|
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"realm" : "demo",
|
||||
"resource" : "input-portal",
|
||||
"realm-public-key" : "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
|
||||
"auth-server-url" : "http://${my.host.name}:8081/auth",
|
||||
"ssl-required" : "external",
|
||||
"credentials" : {
|
||||
"secret": "password"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
|
||||
version="3.0">
|
||||
|
||||
<module-name>adapter-test</module-name>
|
||||
|
||||
<servlet>
|
||||
<servlet-name>Servlet</servlet-name>
|
||||
<servlet-class>org.keycloak.testsuite.adapter.InputServlet</servlet-class>
|
||||
</servlet>
|
||||
|
||||
<servlet-mapping>
|
||||
<servlet-name>Servlet</servlet-name>
|
||||
<url-pattern>/*</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
<security-constraint>
|
||||
<web-resource-collection>
|
||||
<web-resource-name>Users</web-resource-name>
|
||||
<url-pattern>/secured/*</url-pattern>
|
||||
</web-resource-collection>
|
||||
<auth-constraint>
|
||||
<role-name>user</role-name>
|
||||
</auth-constraint>
|
||||
</security-constraint>
|
||||
|
||||
<login-config>
|
||||
<auth-method>BASIC</auth-method>
|
||||
<realm-name>demo</realm-name>
|
||||
</login-config>
|
||||
|
||||
<security-role>
|
||||
<role-name>admin</role-name>
|
||||
</security-role>
|
||||
<security-role>
|
||||
<role-name>user</role-name>
|
||||
</security-role>
|
||||
</web-app>
|
|
@ -95,6 +95,7 @@ public class Jetty9Test {
|
|||
list.add(new WebAppContext(new File(base, "customer-db").toString(), "/customer-db"));
|
||||
list.add(new WebAppContext(new File(base, "product-portal").toString(), "/product-portal"));
|
||||
list.add(new WebAppContext(new File(base, "session-portal").toString(), "/session-portal"));
|
||||
list.add(new WebAppContext(new File(base, "input-portal").toString(), "/input-portal"));
|
||||
list.add(new WebAppContext(new File(base, "secure-portal").toString(), "/secure-portal"));
|
||||
|
||||
|
||||
|
@ -117,6 +118,11 @@ public class Jetty9Test {
|
|||
@Rule
|
||||
public AdapterTestStrategy testStrategy = new AdapterTestStrategy("http://localhost:8081/auth", "http://localhost:8082", keycloakRule, true);
|
||||
|
||||
@Test
|
||||
public void testSavedPostRequest() throws Exception {
|
||||
testStrategy.testSavedPostRequest();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLoginSSOAndLogout() throws Exception {
|
||||
testStrategy.testLoginSSOAndLogout();
|
||||
|
|
|
@ -125,6 +125,16 @@
|
|||
"http://localhost:8082/session-portal/*"
|
||||
],
|
||||
"secret": "password"
|
||||
},
|
||||
{
|
||||
"name": "input-portal",
|
||||
"enabled": true,
|
||||
"adminUrl": "http://localhost:8082/input-portal",
|
||||
"baseUrl": "http://localhost:8082/input-portal",
|
||||
"redirectUris": [
|
||||
"http://localhost:8082/input-portal/*"
|
||||
],
|
||||
"secret": "password"
|
||||
}
|
||||
],
|
||||
"oauthClients": [
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
<?xml version="1.0"?>
|
||||
<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">
|
||||
<Configure class="org.eclipse.jetty.webapp.WebAppContext">
|
||||
<Get name="securityHandler">
|
||||
<Set name="authenticator">
|
||||
<New class="org.keycloak.adapters.jetty.KeycloakJettyAuthenticator">
|
||||
<!--
|
||||
<Set name="adapterConfig">
|
||||
<New class="org.keycloak.representations.adapters.config.AdapterConfig">
|
||||
<Set name="realm">tomcat</Set>
|
||||
<Set name="resource">customer-portal</Set>
|
||||
<Set name="authServerUrl">http://localhost:8081/auth</Set>
|
||||
<Set name="sslRequired">external</Set>
|
||||
<Set name="credentials">
|
||||
<Map>
|
||||
<Entry>
|
||||
<Item>secret</Item>
|
||||
<Item>password</Item>
|
||||
</Entry>
|
||||
</Map>
|
||||
</Set>
|
||||
<Set name="realmKey">MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB</Set>
|
||||
</New>
|
||||
</Set>
|
||||
-->
|
||||
</New>
|
||||
</Set>
|
||||
</Get>
|
||||
</Configure>
|
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"realm" : "demo",
|
||||
"resource" : "input-portal",
|
||||
"realm-public-key" : "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
|
||||
"auth-server-url" : "http://${my.host.name}:8081/auth",
|
||||
"ssl-required" : "external",
|
||||
"credentials" : {
|
||||
"secret": "password"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
|
||||
version="3.0">
|
||||
|
||||
<module-name>adapter-test</module-name>
|
||||
|
||||
<servlet>
|
||||
<servlet-name>Servlet</servlet-name>
|
||||
<servlet-class>org.keycloak.testsuite.adapter.InputServlet</servlet-class>
|
||||
</servlet>
|
||||
|
||||
<servlet-mapping>
|
||||
<servlet-name>Servlet</servlet-name>
|
||||
<url-pattern>/*</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
<security-constraint>
|
||||
<web-resource-collection>
|
||||
<web-resource-name>Users</web-resource-name>
|
||||
<url-pattern>/secured/*</url-pattern>
|
||||
</web-resource-collection>
|
||||
<auth-constraint>
|
||||
<role-name>user</role-name>
|
||||
</auth-constraint>
|
||||
</security-constraint>
|
||||
|
||||
<login-config>
|
||||
<auth-method>BASIC</auth-method>
|
||||
<realm-name>demo</realm-name>
|
||||
</login-config>
|
||||
|
||||
<security-role>
|
||||
<role-name>admin</role-name>
|
||||
</security-role>
|
||||
<security-role>
|
||||
<role-name>user</role-name>
|
||||
</security-role>
|
||||
</web-app>
|
|
@ -95,6 +95,7 @@ public class Jetty9Test {
|
|||
list.add(new WebAppContext(new File(base, "customer-db").toString(), "/customer-db"));
|
||||
list.add(new WebAppContext(new File(base, "product-portal").toString(), "/product-portal"));
|
||||
list.add(new WebAppContext(new File(base, "session-portal").toString(), "/session-portal"));
|
||||
list.add(new WebAppContext(new File(base, "input-portal").toString(), "/input-portal"));
|
||||
list.add(new WebAppContext(new File(base, "secure-portal").toString(), "/secure-portal"));
|
||||
|
||||
|
||||
|
@ -122,6 +123,11 @@ public class Jetty9Test {
|
|||
testStrategy.testLoginSSOAndLogout();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSavedPostRequest() throws Exception {
|
||||
testStrategy.testSavedPostRequest();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testServletRequestLogout() throws Exception {
|
||||
testStrategy.testServletRequestLogout();
|
||||
|
|
|
@ -125,6 +125,16 @@
|
|||
"http://localhost:8082/session-portal/*"
|
||||
],
|
||||
"secret": "password"
|
||||
},
|
||||
{
|
||||
"name": "input-portal",
|
||||
"enabled": true,
|
||||
"adminUrl": "http://localhost:8082/input-portal",
|
||||
"baseUrl": "http://localhost:8082/input-portal",
|
||||
"redirectUris": [
|
||||
"http://localhost:8082/input-portal/*"
|
||||
],
|
||||
"secret": "password"
|
||||
}
|
||||
],
|
||||
"oauthClients": [
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
<?xml version="1.0"?>
|
||||
<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">
|
||||
<Configure class="org.eclipse.jetty.webapp.WebAppContext">
|
||||
<Get name="securityHandler">
|
||||
<Set name="authenticator">
|
||||
<New class="org.keycloak.adapters.jetty.KeycloakJettyAuthenticator">
|
||||
<!--
|
||||
<Set name="adapterConfig">
|
||||
<New class="org.keycloak.representations.adapters.config.AdapterConfig">
|
||||
<Set name="realm">tomcat</Set>
|
||||
<Set name="resource">customer-portal</Set>
|
||||
<Set name="authServerUrl">http://localhost:8081/auth</Set>
|
||||
<Set name="sslRequired">external</Set>
|
||||
<Set name="credentials">
|
||||
<Map>
|
||||
<Entry>
|
||||
<Item>secret</Item>
|
||||
<Item>password</Item>
|
||||
</Entry>
|
||||
</Map>
|
||||
</Set>
|
||||
<Set name="realmKey">MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB</Set>
|
||||
</New>
|
||||
</Set>
|
||||
-->
|
||||
</New>
|
||||
</Set>
|
||||
</Get>
|
||||
</Configure>
|
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"realm" : "demo",
|
||||
"resource" : "input-portal",
|
||||
"realm-public-key" : "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
|
||||
"auth-server-url" : "http://${my.host.name}:8081/auth",
|
||||
"ssl-required" : "external",
|
||||
"credentials" : {
|
||||
"secret": "password"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
|
||||
version="3.0">
|
||||
|
||||
<module-name>adapter-test</module-name>
|
||||
|
||||
<servlet>
|
||||
<servlet-name>Servlet</servlet-name>
|
||||
<servlet-class>org.keycloak.testsuite.adapter.InputServlet</servlet-class>
|
||||
</servlet>
|
||||
|
||||
<servlet-mapping>
|
||||
<servlet-name>Servlet</servlet-name>
|
||||
<url-pattern>/*</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
<security-constraint>
|
||||
<web-resource-collection>
|
||||
<web-resource-name>Users</web-resource-name>
|
||||
<url-pattern>/secured/*</url-pattern>
|
||||
</web-resource-collection>
|
||||
<auth-constraint>
|
||||
<role-name>user</role-name>
|
||||
</auth-constraint>
|
||||
</security-constraint>
|
||||
|
||||
<login-config>
|
||||
<auth-method>BASIC</auth-method>
|
||||
<realm-name>demo</realm-name>
|
||||
</login-config>
|
||||
|
||||
<security-role>
|
||||
<role-name>admin</role-name>
|
||||
</security-role>
|
||||
<security-role>
|
||||
<role-name>user</role-name>
|
||||
</security-role>
|
||||
</web-app>
|
|
@ -83,6 +83,7 @@ public class TomcatTest {
|
|||
tomcat.deploy("/product-portal", "product-portal");
|
||||
tomcat.deploy("/secure-portal", "secure-portal");
|
||||
tomcat.deploy("/session-portal", "session-portal");
|
||||
tomcat.deploy("/input-portal", "input-portal");
|
||||
|
||||
|
||||
tomcat.start();
|
||||
|
@ -102,6 +103,11 @@ public class TomcatTest {
|
|||
testStrategy.testLoginSSOAndLogout();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSavedPostRequest() throws Exception {
|
||||
testStrategy.testSavedPostRequest();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testServletRequestLogout() throws Exception {
|
||||
// can't test this. Servlet 2.5 doesn't have logout()
|
||||
|
|
|
@ -125,6 +125,16 @@
|
|||
"http://localhost:8082/session-portal/*"
|
||||
],
|
||||
"secret": "password"
|
||||
},
|
||||
{
|
||||
"name": "input-portal",
|
||||
"enabled": true,
|
||||
"adminUrl": "http://localhost:8082/input-portal",
|
||||
"baseUrl": "http://localhost:8082/input-portal",
|
||||
"redirectUris": [
|
||||
"http://localhost:8082/input-portal/*"
|
||||
],
|
||||
"secret": "password"
|
||||
}
|
||||
],
|
||||
"oauthClients": [
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
<Context path="/customer-portal">
|
||||
<Valve className="org.keycloak.adapters.tomcat.KeycloakAuthenticatorValve"/>
|
||||
</Context>
|
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"realm" : "demo",
|
||||
"resource" : "input-portal",
|
||||
"realm-public-key" : "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
|
||||
"auth-server-url" : "http://${my.host.name}:8081/auth",
|
||||
"ssl-required" : "external",
|
||||
"credentials" : {
|
||||
"secret": "password"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
|
||||
version="3.0">
|
||||
|
||||
<module-name>adapter-test</module-name>
|
||||
|
||||
<servlet>
|
||||
<servlet-name>Servlet</servlet-name>
|
||||
<servlet-class>org.keycloak.testsuite.adapter.InputServlet</servlet-class>
|
||||
</servlet>
|
||||
|
||||
<servlet-mapping>
|
||||
<servlet-name>Servlet</servlet-name>
|
||||
<url-pattern>/*</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
<security-constraint>
|
||||
<web-resource-collection>
|
||||
<web-resource-name>Users</web-resource-name>
|
||||
<url-pattern>/secured/*</url-pattern>
|
||||
</web-resource-collection>
|
||||
<auth-constraint>
|
||||
<role-name>user</role-name>
|
||||
</auth-constraint>
|
||||
</security-constraint>
|
||||
|
||||
<login-config>
|
||||
<auth-method>BASIC</auth-method>
|
||||
<realm-name>demo</realm-name>
|
||||
</login-config>
|
||||
|
||||
<security-role>
|
||||
<role-name>admin</role-name>
|
||||
</security-role>
|
||||
<security-role>
|
||||
<role-name>user</role-name>
|
||||
</security-role>
|
||||
</web-app>
|
|
@ -87,6 +87,7 @@ public class Tomcat7Test {
|
|||
tomcat.addWebapp("/product-portal", new File(base, "product-portal").toString());
|
||||
tomcat.addWebapp("/secure-portal", new File(base, "secure-portal").toString());
|
||||
tomcat.addWebapp("/session-portal", new File(base, "session-portal").toString());
|
||||
tomcat.addWebapp("/input-portal", new File(base, "input-portal").toString());
|
||||
|
||||
tomcat.start();
|
||||
//tomcat.getServer().await();
|
||||
|
@ -106,6 +107,12 @@ public class Tomcat7Test {
|
|||
testStrategy.testLoginSSOAndLogout();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSavedPostRequest() throws Exception {
|
||||
testStrategy.testSavedPostRequest();
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testServletRequestLogout() throws Exception {
|
||||
testStrategy.testServletRequestLogout();
|
||||
|
|
|
@ -125,6 +125,16 @@
|
|||
"http://localhost:8082/session-portal/*"
|
||||
],
|
||||
"secret": "password"
|
||||
},
|
||||
{
|
||||
"name": "input-portal",
|
||||
"enabled": true,
|
||||
"adminUrl": "http://localhost:8082/input-portal",
|
||||
"baseUrl": "http://localhost:8082/input-portal",
|
||||
"redirectUris": [
|
||||
"http://localhost:8082/input-portal/*"
|
||||
],
|
||||
"secret": "password"
|
||||
}
|
||||
],
|
||||
"oauthClients": [
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
<Context path="/customer-portal">
|
||||
<Valve className="org.keycloak.adapters.tomcat.KeycloakAuthenticatorValve"/>
|
||||
</Context>
|
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"realm" : "demo",
|
||||
"resource" : "input-portal",
|
||||
"realm-public-key" : "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
|
||||
"auth-server-url" : "http://${my.host.name}:8081/auth",
|
||||
"ssl-required" : "external",
|
||||
"credentials" : {
|
||||
"secret": "password"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
|
||||
version="3.0">
|
||||
|
||||
<module-name>adapter-test</module-name>
|
||||
|
||||
<servlet>
|
||||
<servlet-name>Servlet</servlet-name>
|
||||
<servlet-class>org.keycloak.testsuite.adapter.InputServlet</servlet-class>
|
||||
</servlet>
|
||||
|
||||
<servlet-mapping>
|
||||
<servlet-name>Servlet</servlet-name>
|
||||
<url-pattern>/*</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
<security-constraint>
|
||||
<web-resource-collection>
|
||||
<web-resource-name>Users</web-resource-name>
|
||||
<url-pattern>/secured/*</url-pattern>
|
||||
</web-resource-collection>
|
||||
<auth-constraint>
|
||||
<role-name>user</role-name>
|
||||
</auth-constraint>
|
||||
</security-constraint>
|
||||
|
||||
<login-config>
|
||||
<auth-method>BASIC</auth-method>
|
||||
<realm-name>demo</realm-name>
|
||||
</login-config>
|
||||
|
||||
<security-role>
|
||||
<role-name>admin</role-name>
|
||||
</security-role>
|
||||
<security-role>
|
||||
<role-name>user</role-name>
|
||||
</security-role>
|
||||
</web-app>
|
|
@ -87,6 +87,7 @@ public class TomcatTest {
|
|||
tomcat.addWebapp("/product-portal", new File(base, "product-portal").toString());
|
||||
tomcat.addWebapp("/secure-portal", new File(base, "secure-portal").toString());
|
||||
tomcat.addWebapp("/session-portal", new File(base, "session-portal").toString());
|
||||
tomcat.addWebapp("/input-portal", new File(base, "input-portal").toString());
|
||||
|
||||
tomcat.start();
|
||||
//tomcat.getServer().await();
|
||||
|
@ -106,6 +107,13 @@ public class TomcatTest {
|
|||
testStrategy.testLoginSSOAndLogout();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSavedPostRequest() throws Exception {
|
||||
testStrategy.testSavedPostRequest();
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Test
|
||||
public void testServletRequestLogout() throws Exception {
|
||||
testStrategy.testServletRequestLogout();
|
||||
|
|
|
@ -125,6 +125,16 @@
|
|||
"http://localhost:8082/session-portal/*"
|
||||
],
|
||||
"secret": "password"
|
||||
},
|
||||
{
|
||||
"name": "input-portal",
|
||||
"enabled": true,
|
||||
"adminUrl": "http://localhost:8082/input-portal",
|
||||
"baseUrl": "http://localhost:8082/input-portal",
|
||||
"redirectUris": [
|
||||
"http://localhost:8082/input-portal/*"
|
||||
],
|
||||
"secret": "password"
|
||||
}
|
||||
],
|
||||
"oauthClients": [
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
<Context path="/customer-portal">
|
||||
<Valve className="org.keycloak.adapters.tomcat.KeycloakAuthenticatorValve"/>
|
||||
</Context>
|
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"realm" : "demo",
|
||||
"resource" : "input-portal",
|
||||
"realm-public-key" : "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
|
||||
"auth-server-url" : "http://${my.host.name}:8081/auth",
|
||||
"ssl-required" : "external",
|
||||
"credentials" : {
|
||||
"secret": "password"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
|
||||
version="3.0">
|
||||
|
||||
<module-name>adapter-test</module-name>
|
||||
|
||||
<servlet>
|
||||
<servlet-name>Servlet</servlet-name>
|
||||
<servlet-class>org.keycloak.testsuite.adapter.InputServlet</servlet-class>
|
||||
</servlet>
|
||||
|
||||
<servlet-mapping>
|
||||
<servlet-name>Servlet</servlet-name>
|
||||
<url-pattern>/*</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
<security-constraint>
|
||||
<web-resource-collection>
|
||||
<web-resource-name>Users</web-resource-name>
|
||||
<url-pattern>/secured/*</url-pattern>
|
||||
</web-resource-collection>
|
||||
<auth-constraint>
|
||||
<role-name>user</role-name>
|
||||
</auth-constraint>
|
||||
</security-constraint>
|
||||
|
||||
<login-config>
|
||||
<auth-method>BASIC</auth-method>
|
||||
<realm-name>demo</realm-name>
|
||||
</login-config>
|
||||
|
||||
<security-role>
|
||||
<role-name>admin</role-name>
|
||||
</security-role>
|
||||
<security-role>
|
||||
<role-name>user</role-name>
|
||||
</security-role>
|
||||
</web-app>
|
Loading…
Reference in a new issue