Merge remote-tracking branch 'upstream/master'
This commit is contained in:
commit
1cbf5a5d99
93 changed files with 1583 additions and 484 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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,17 +1,15 @@
|
|||
<section id="javascript-adapter">
|
||||
<title>Pure Client Javascript Adapter</title>
|
||||
<title>Javascript Adapter</title>
|
||||
<para>
|
||||
The Keycloak Server comes with a Javascript library you can use to secure pure HTML/Javascript applications. This
|
||||
The Keycloak Server comes with a Javascript library you can use to secure HTML/Javascript applications. This
|
||||
library is referencable directly from the keycloak server. You can also download the adapter from Keycloak's download
|
||||
site if you want a static copy of this library. It
|
||||
works in the same way as other application adapters except that your browser is driving the OAuth redirect protocol
|
||||
rather than the server.
|
||||
</para>
|
||||
<para>
|
||||
The
|
||||
disadvantage of using this approach is that you end up having a non-confidential, public client. This can be mitigated
|
||||
by registering valid redirect URLs. You are still vulnerable if somebody hijacks the IP/DNS name of your pure
|
||||
HTML/Javascript application though.
|
||||
The disadvantage of using this approach is that you have a non-confidential, public client. This makes it more
|
||||
important that you register valid redirect URLs and make sure your domain name is secured.
|
||||
</para>
|
||||
<para>
|
||||
To use this adapter, you must first configure an application (or client) through the <literal>Keycloak Admin Console</literal>.
|
||||
|
@ -138,6 +136,21 @@ keycloak.updateToken(30).success(function() {
|
|||
</para>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>Older browsers</title>
|
||||
|
||||
<para>
|
||||
The JavaScript adapter depends on Base64 (window.btoa and window.atob) and HTML5 History API. If you need to
|
||||
support browsers that don't provide those (for example IE9) you'll need to add polyfillers. Example polyfill
|
||||
libraries:
|
||||
|
||||
<itemizedlist>
|
||||
<listitem>Base64 - <ulink url="https://github.com/davidchambers/Base64.js">https://github.com/davidchambers/Base64.js</ulink></listitem>
|
||||
<listitem>HTML5 History - <ulink url="https://github.com/devote/HTML5-History-API">https://github.com/devote/HTML5-History-API</ulink></listitem>
|
||||
</itemizedlist>
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>JavaScript Adapter reference</title>
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@ public class EventEntity {
|
|||
@Column(name="ID", length = 36)
|
||||
private String id;
|
||||
|
||||
@Column(name="TIME")
|
||||
@Column(name="\"TIME\"")
|
||||
private long time;
|
||||
|
||||
@Column(name="TYPE")
|
||||
|
|
|
@ -71,7 +71,6 @@
|
|||
<span>Loading...</span>
|
||||
</div>
|
||||
</div>
|
||||
<div id="serverInfo">Keycloak {{serverInfo.version}}</div>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
|
|
|
@ -863,6 +863,9 @@ module.config([ '$routeProvider', function($routeProvider) {
|
|||
},
|
||||
controller : 'RealmBruteForceCtrl'
|
||||
})
|
||||
.when('/server-info', {
|
||||
templateUrl : 'partials/server-info.html'
|
||||
})
|
||||
.when('/logout', {
|
||||
templateUrl : 'partials/home.html',
|
||||
controller : 'LogoutCtrl'
|
||||
|
|
|
@ -6,6 +6,9 @@ module.controller('GlobalCtrl', function($scope, $http, Auth, WhoAmI, Current, $
|
|||
$scope.authUrl = authUrl;
|
||||
$scope.auth = Auth;
|
||||
$scope.serverInfo = ServerInfo.get();
|
||||
$scope.serverInfoUpdate = function() {
|
||||
$scope.serverInfo = ServerInfo.get();
|
||||
};
|
||||
|
||||
WhoAmI.get(function (data) {
|
||||
Auth.user = data;
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
</a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a href="{{authUrl}}/realms/{{auth.user.realm}}/account?referrer=security-admin-console">Manage Account</a></li>
|
||||
<li><a href="#/server-info">Server Info</a></li>
|
||||
<li class="separator"><a href="" ng-click="auth.authz.logout()">Sign Out</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
<div id="content-area" class="col-sm-12" role="main">
|
||||
<h2></h2>
|
||||
|
||||
<div id="content">
|
||||
|
||||
<h2>Server Info</h2>
|
||||
|
||||
<table class="table table-striped table-bordered">
|
||||
<tr>
|
||||
<td>Version</td>
|
||||
<td>{{serverInfo.version}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Server Time</td>
|
||||
<td>{{serverInfo.serverTime}} (<a data-ng-click="serverInfoUpdate()">update</a>)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Providers</td>
|
||||
<td>
|
||||
<table class="table table-striped table-bordered">
|
||||
<tr data-ng-repeat="(spi, providers) in serverInfo.providers">
|
||||
<td>{{spi}}</td>
|
||||
<td>{{providers.sort().join(', ')}}</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
|
@ -837,10 +837,3 @@ legend .kc-icon-collapse {
|
|||
table table {
|
||||
margin-bottom: 0 !important;
|
||||
}
|
||||
|
||||
#serverInfo {
|
||||
color: #666;
|
||||
position: absolute;
|
||||
bottom: 10px;
|
||||
right: 10px;
|
||||
}
|
|
@ -33,3 +33,8 @@
|
|||
border-top-color: rgba(255,255,255,0.05);
|
||||
}
|
||||
|
||||
.dropdown-menu .separator {
|
||||
border-top: 1px solid #ddd;
|
||||
margin-top: 5px;
|
||||
padding-top: 5px;
|
||||
}
|
||||
|
|
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,6 +1,8 @@
|
|||
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;
|
||||
|
@ -10,6 +12,7 @@ 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;
|
||||
|
||||
|
@ -18,14 +21,15 @@ import javax.servlet.http.HttpSession;
|
|||
*
|
||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
*/
|
||||
public class JettySessionTokenStore implements AdapterTokenStore {
|
||||
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(JettySessionTokenStore.class);
|
||||
private static final Logger log = Logger.getLogger(AbstractJettySessionTokenStore.class);
|
||||
|
||||
private Request request;
|
||||
private KeycloakDeployment deployment;
|
||||
protected KeycloakDeployment deployment;
|
||||
|
||||
public JettySessionTokenStore(Request request, KeycloakDeployment deployment) {
|
||||
public AbstractJettySessionTokenStore(Request request, KeycloakDeployment deployment) {
|
||||
this.request = request;
|
||||
this.deployment = deployment;
|
||||
}
|
||||
|
@ -66,10 +70,10 @@ public class JettySessionTokenStore implements AdapterTokenStore {
|
|||
securityContext.setCurrentRequestInfo(deployment, this);
|
||||
request.setAttribute(KeycloakSecurityContext.class.getName(), securityContext);
|
||||
|
||||
AbstractJettyRequestAuthenticator jettyAuthenticator = (AbstractJettyRequestAuthenticator) authenticator;
|
||||
JettyRequestAuthenticator jettyAuthenticator = (JettyRequestAuthenticator) authenticator;
|
||||
KeycloakPrincipal<RefreshableKeycloakSecurityContext> principal = AdapterUtils.createPrincipal(deployment, securityContext);
|
||||
jettyAuthenticator.principal = principal;
|
||||
jettyAuthenticator.restoreRequest();
|
||||
restoreRequest();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -91,4 +95,5 @@ public class JettySessionTokenStore implements AdapterTokenStore {
|
|||
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,11 +20,6 @@ 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
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -619,7 +619,7 @@
|
|||
if (event.origin !== loginIframe.iframeOrigin) {
|
||||
return;
|
||||
}
|
||||
var data = event.data;
|
||||
var data = JSON.parse(event.data);
|
||||
var promise = loginIframe.callbackMap[data.callbackId];
|
||||
delete loginIframe.callbackMap[data.callbackId];
|
||||
|
||||
|
@ -652,7 +652,7 @@
|
|||
msg.callbackId = createCallbackId();
|
||||
loginIframe.callbackMap[msg.callbackId] = promise;
|
||||
var origin = loginIframe.iframeOrigin;
|
||||
loginIframe.iframe.contentWindow.postMessage(msg, origin);
|
||||
loginIframe.iframe.contentWindow.postMessage(JSON.stringify(msg), origin);
|
||||
} else {
|
||||
promise.setSuccess();
|
||||
}
|
||||
|
|
|
@ -17,14 +17,15 @@
|
|||
return;
|
||||
|
||||
}
|
||||
event.data.loggedIn = false;
|
||||
var data = JSON.parse(event.data);
|
||||
data.loggedIn = false;
|
||||
var cookie = getCookie('KEYCLOAK_SESSION');
|
||||
if (cookie) {
|
||||
event.data.loggedIn = true;
|
||||
event.data.session = cookie;
|
||||
data.loggedIn = true;
|
||||
data.session = cookie;
|
||||
}
|
||||
|
||||
event.source.postMessage(event.data,
|
||||
event.source.postMessage(JSON.stringify(data),
|
||||
event.origin);
|
||||
}
|
||||
window.addEventListener("message", receiveMessage, false);
|
||||
|
|
|
@ -40,7 +40,7 @@ public class CredentialAddHandler extends AbstractAddStepHandlerWithAttributes {
|
|||
@Override
|
||||
protected void performRuntime(OperationContext context, ModelNode operation, ModelNode model, ServiceVerificationHandler verificationHandler, List<ServiceController<?>> newControllers) throws OperationFailedException {
|
||||
KeycloakAdapterConfigService ckService = KeycloakAdapterConfigService.find(context);
|
||||
ckService.addCredential(operation, model);
|
||||
ckService.addCredential(operation, context.resolveExpressions(model));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -61,6 +61,6 @@ public final class RealmAddHandler extends AbstractAddStepHandler {
|
|||
@Override
|
||||
protected void performRuntime(OperationContext context, ModelNode operation, ModelNode model, ServiceVerificationHandler verificationHandler, List<ServiceController<?>> newControllers) throws OperationFailedException {
|
||||
KeycloakAdapterConfigService ckService = KeycloakAdapterConfigService.find(context);
|
||||
ckService.addRealm(operation, model);
|
||||
ckService.addRealm(operation, context.resolveExpressions(model));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -56,6 +56,6 @@ public final class SecureDeploymentAddHandler extends AbstractAddStepHandler {
|
|||
@Override
|
||||
protected void performRuntime(OperationContext context, ModelNode operation, ModelNode model, ServiceVerificationHandler verificationHandler, List<ServiceController<?>> newControllers) throws OperationFailedException {
|
||||
KeycloakAdapterConfigService ckService = KeycloakAdapterConfigService.find(context);
|
||||
ckService.addSecureDeployment(operation, model);
|
||||
ckService.addSecureDeployment(operation, context.resolveExpressions(model));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -41,7 +41,7 @@ public class CredentialAddHandler extends AbstractAddStepHandler {
|
|||
@Override
|
||||
protected void performRuntime(OperationContext context, ModelNode operation, ModelNode model, ServiceVerificationHandler verificationHandler, List<ServiceController<?>> newControllers) throws OperationFailedException {
|
||||
KeycloakAdapterConfigService ckService = KeycloakAdapterConfigService.find(context);
|
||||
ckService.addCredential(operation, model);
|
||||
ckService.addCredential(operation, context.resolveExpressions(model));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -35,15 +35,15 @@ import java.util.List;
|
|||
|
||||
/**
|
||||
* Pass authentication data (keycloak.json) as a servlet context param so it can be read by the KeycloakServletExtension.
|
||||
* This is used for AS7/EAP6.
|
||||
* This is used for EAP6.
|
||||
*
|
||||
* @author Stan Silvert ssilvert@redhat.com (C) 2014 Red Hat Inc.
|
||||
*/
|
||||
|
||||
// Note: Even though this class closely resembles the WildFly KeycloakAdapterConfigDeploymentProcessor
|
||||
// it can not be easily refactored because the WarMetaData classes are of different types.
|
||||
public class KeycloakAdapterConfigDeploymentProcessorAS7 implements DeploymentUnitProcessor {
|
||||
protected Logger log = Logger.getLogger(KeycloakAdapterConfigDeploymentProcessorAS7.class);
|
||||
public class KeycloakAdapterConfigDeploymentProcessorEAP6 implements DeploymentUnitProcessor {
|
||||
protected Logger log = Logger.getLogger(KeycloakAdapterConfigDeploymentProcessorEAP6.class);
|
||||
|
||||
@Override
|
||||
public void deploy(DeploymentPhaseContext phaseContext) throws DeploymentUnitProcessingException {
|
|
@ -23,11 +23,11 @@ import org.jboss.modules.ModuleIdentifier;
|
|||
import org.jboss.modules.ModuleLoader;
|
||||
|
||||
/**
|
||||
* Adds platform-specific modules for AS7
|
||||
* Adds platform-specific modules for EAP6
|
||||
*
|
||||
* @author Stan Silvert ssilvert@redhat.com (C) 2014 Red Hat Inc.
|
||||
*/
|
||||
public class KeycloakDependencyProcessorAS7 extends KeycloakDependencyProcessor {
|
||||
public class KeycloakDependencyProcessorEAP6 extends KeycloakDependencyProcessor {
|
||||
|
||||
private static final ModuleIdentifier KEYCLOAK_AS7_ADAPTER = ModuleIdentifier.create("org.keycloak.keycloak-as7-adapter");
|
||||
|
|
@ -70,7 +70,7 @@ class KeycloakSubsystemAdd extends AbstractBoottimeAddStepHandler {
|
|||
if (Environment.isWildFly()) {
|
||||
return new KeycloakDependencyProcessorWildFly();
|
||||
} else {
|
||||
return new KeycloakDependencyProcessorAS7();
|
||||
return new KeycloakDependencyProcessorEAP6();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -78,7 +78,7 @@ class KeycloakSubsystemAdd extends AbstractBoottimeAddStepHandler {
|
|||
if (Environment.isWildFly()) {
|
||||
return new KeycloakAdapterConfigDeploymentProcessor();
|
||||
} else {
|
||||
return new KeycloakAdapterConfigDeploymentProcessorAS7();
|
||||
return new KeycloakAdapterConfigDeploymentProcessorEAP6();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -61,6 +61,6 @@ public final class RealmAddHandler extends AbstractAddStepHandler {
|
|||
@Override
|
||||
protected void performRuntime(OperationContext context, ModelNode operation, ModelNode model, ServiceVerificationHandler verificationHandler, List<ServiceController<?>> newControllers) throws OperationFailedException {
|
||||
KeycloakAdapterConfigService ckService = KeycloakAdapterConfigService.find(context);
|
||||
ckService.addRealm(operation, model);
|
||||
ckService.addRealm(operation, context.resolveExpressions(model));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -56,6 +56,6 @@ public final class SecureDeploymentAddHandler extends AbstractAddStepHandler {
|
|||
@Override
|
||||
protected void performRuntime(OperationContext context, ModelNode operation, ModelNode model, ServiceVerificationHandler verificationHandler, List<ServiceController<?>> newControllers) throws OperationFailedException {
|
||||
KeycloakAdapterConfigService ckService = KeycloakAdapterConfigService.find(context);
|
||||
ckService.addSecureDeployment(operation, model);
|
||||
ckService.addSecureDeployment(operation, context.resolveExpressions(model));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -51,6 +51,7 @@ public final class AuthServerAddHandler extends AbstractAddStepHandler {
|
|||
for (AttributeDefinition attr : AuthServerDefinition.ALL_ATTRIBUTES) {
|
||||
attr.validateAndSet(operation, model);
|
||||
}
|
||||
model = context.resolveExpressions(model);
|
||||
|
||||
// returns early if on domain controller
|
||||
if (!requiresRuntime(context)) return;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -56,6 +56,7 @@ import org.keycloak.services.managers.AppAuthManager;
|
|||
import org.keycloak.services.managers.Auth;
|
||||
import org.keycloak.services.managers.AuthenticationManager;
|
||||
import org.keycloak.services.managers.ClientSessionCode;
|
||||
import org.keycloak.services.managers.ResourceAdminManager;
|
||||
import org.keycloak.services.messages.Messages;
|
||||
import org.keycloak.services.resources.flows.Flows;
|
||||
import org.keycloak.services.resources.flows.OAuthRedirect;
|
||||
|
@ -624,6 +625,14 @@ public class AccountService {
|
|||
return account.setError(ape.getMessage()).createResponse(AccountPages.PASSWORD);
|
||||
}
|
||||
|
||||
List<UserSessionModel> sessions = session.sessions().getUserSessions(realm, user);
|
||||
for (UserSessionModel s : sessions) {
|
||||
if (!s.getId().equals(auth.getSession().getId())) {
|
||||
new ResourceAdminManager().logoutSession(uriInfo.getRequestUri(), realm, s);
|
||||
session.sessions().removeUserSession(realm, s);
|
||||
}
|
||||
}
|
||||
|
||||
event.event(EventType.UPDATE_PASSWORD).client(auth.getClient()).user(auth.getUser()).success();
|
||||
|
||||
setReferrerOnPage();
|
||||
|
|
|
@ -9,17 +9,21 @@ import org.keycloak.freemarker.ThemeProvider;
|
|||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.protocol.LoginProtocol;
|
||||
import org.keycloak.protocol.LoginProtocolFactory;
|
||||
import org.keycloak.provider.Provider;
|
||||
import org.keycloak.provider.ProviderFactory;
|
||||
import org.keycloak.provider.Spi;
|
||||
import org.keycloak.social.SocialProvider;
|
||||
import org.keycloak.util.ProviderLoader;
|
||||
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.core.Context;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.ServiceLoader;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
|
@ -38,15 +42,25 @@ public class ServerInfoAdminResource {
|
|||
@GET
|
||||
public ServerInfoRepresentation getInfo() {
|
||||
ServerInfoRepresentation info = new ServerInfoRepresentation();
|
||||
info.setVersion(Version.VERSION);
|
||||
info.version = Version.VERSION;
|
||||
info.serverTime = new Date().toString();
|
||||
setSocialProviders(info);
|
||||
setThemes(info);
|
||||
setEventListeners(info);
|
||||
setProtocols(info);
|
||||
setApplicationImporters(info);
|
||||
setProviders(info);
|
||||
return info;
|
||||
}
|
||||
|
||||
private void setProviders(ServerInfoRepresentation info) {
|
||||
Map<String, Set<String>> providers = new HashMap<String, Set<String>>();
|
||||
for (Spi spi : ServiceLoader.load(Spi.class)) {
|
||||
providers.put(spi.getName(), session.listProviderIds(spi.getProviderClass()));
|
||||
}
|
||||
info.providers = providers;
|
||||
}
|
||||
|
||||
private void setThemes(ServerInfoRepresentation info) {
|
||||
ThemeProvider themeProvider = session.getProvider(ThemeProvider.class, "extending");
|
||||
info.themes = new HashMap<String, List<String>>();
|
||||
|
@ -100,24 +114,27 @@ public class ServerInfoAdminResource {
|
|||
|
||||
private String version;
|
||||
|
||||
private String serverTime;
|
||||
|
||||
private Map<String, List<String>> themes;
|
||||
|
||||
private List<String> socialProviders;
|
||||
private List<String> protocols;
|
||||
private List<Map<String, String>> applicationImporters;
|
||||
|
||||
private Map<String, Set<String>> providers;
|
||||
|
||||
private List<String> eventListeners;
|
||||
|
||||
public ServerInfoRepresentation() {
|
||||
}
|
||||
|
||||
public String getVersion() {
|
||||
return version;
|
||||
public String getServerTime() {
|
||||
return serverTime;
|
||||
}
|
||||
|
||||
public void setVersion(String version) {
|
||||
this.version = version;
|
||||
public String getVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
public Map<String, List<String>> getThemes() {
|
||||
|
@ -139,6 +156,10 @@ public class ServerInfoAdminResource {
|
|||
public List<Map<String, String>> getApplicationImporters() {
|
||||
return applicationImporters;
|
||||
}
|
||||
|
||||
public Map<String, Set<String>> getProviders() {
|
||||
return providers;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
0
testsuite/integration/src/test/java/org/keycloak/testsuite/adapter/SessionServlet.java
Normal file → Executable file
0
testsuite/integration/src/test/java/org/keycloak/testsuite/adapter/SessionServlet.java
Normal file → Executable file
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