mirror of
https://github.com/keycloak/keycloak.git
synced 2026-01-30 11:29:27 -06:00
error page adapter support
This commit is contained in:
@@ -11,4 +11,11 @@ public interface AuthChallenge {
|
||||
* @return challenge sent
|
||||
*/
|
||||
boolean challenge(HttpFacade exchange);
|
||||
|
||||
/**
|
||||
* Whether or not an error page should be displayed if possible
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
boolean errorPage();
|
||||
}
|
||||
|
||||
@@ -109,6 +109,11 @@ public class BearerTokenRequestAuthenticator {
|
||||
|
||||
protected AuthChallenge clientCertChallenge() {
|
||||
return new AuthChallenge() {
|
||||
@Override
|
||||
public boolean errorPage() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean challenge(HttpFacade exchange) {
|
||||
// do the same thing as client cert auth
|
||||
@@ -129,6 +134,11 @@ public class BearerTokenRequestAuthenticator {
|
||||
}
|
||||
final String challenge = header.toString();
|
||||
return new AuthChallenge() {
|
||||
@Override
|
||||
public boolean errorPage() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean challenge(HttpFacade facade) {
|
||||
facade.getResponse().setStatus(401);
|
||||
|
||||
@@ -146,13 +146,29 @@ public class OAuthRequestAuthenticator {
|
||||
protected AuthChallenge loginRedirect() {
|
||||
final String state = getStateCode();
|
||||
final String redirect = getRedirectUri(state);
|
||||
return new AuthChallenge() {
|
||||
@Override
|
||||
public boolean challenge(HttpFacade exchange) {
|
||||
if (redirect == null) {
|
||||
if (redirect == null) {
|
||||
return new AuthChallenge() {
|
||||
@Override
|
||||
public boolean challenge(HttpFacade exchange) {
|
||||
exchange.getResponse().setStatus(403);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean errorPage() {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
}
|
||||
return new AuthChallenge() {
|
||||
|
||||
@Override
|
||||
public boolean errorPage() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean challenge(HttpFacade exchange) {
|
||||
tokenStore.saveRequest();
|
||||
log.debug("Sending redirect to login page: " + redirect);
|
||||
exchange.getResponse().setStatus(302);
|
||||
@@ -218,6 +234,11 @@ public class OAuthRequestAuthenticator {
|
||||
|
||||
protected AuthChallenge challenge(final int code) {
|
||||
return new AuthChallenge() {
|
||||
@Override
|
||||
public boolean errorPage() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean challenge(HttpFacade exchange) {
|
||||
exchange.getResponse().setStatus(code);
|
||||
|
||||
@@ -11,6 +11,7 @@ import org.keycloak.adapters.tomcat.GenericPrincipalFactory;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.security.Principal;
|
||||
import java.util.List;
|
||||
|
||||
@@ -22,9 +23,19 @@ import java.util.List;
|
||||
*/
|
||||
public class KeycloakAuthenticatorValve extends AbstractKeycloakAuthenticatorValve {
|
||||
public boolean authenticate(Request request, HttpServletResponse response, LoginConfig config) throws java.io.IOException {
|
||||
return authenticateInternal(request, response);
|
||||
return authenticateInternal(request, response, config);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean forwardToErrorPageInternal(Request request, HttpServletResponse response, Object loginConfig) throws IOException {
|
||||
if (loginConfig == null) return false;
|
||||
LoginConfig config = (LoginConfig)loginConfig;
|
||||
if (config.getErrorPage() == null) return false;
|
||||
forwardToErrorPage(request, (Response)response, config);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void start() throws LifecycleException {
|
||||
StandardContext standardContext = (StandardContext) context;
|
||||
|
||||
@@ -1,14 +1,18 @@
|
||||
package org.keycloak.adapters.jetty;
|
||||
|
||||
import org.apache.http.HttpVersion;
|
||||
import org.eclipse.jetty.security.DefaultUserIdentity;
|
||||
import org.eclipse.jetty.security.ServerAuthException;
|
||||
import org.eclipse.jetty.security.UserAuthentication;
|
||||
import org.eclipse.jetty.security.authentication.DeferredAuthentication;
|
||||
import org.eclipse.jetty.security.authentication.FormAuthenticator;
|
||||
import org.eclipse.jetty.security.authentication.LoginAuthenticator;
|
||||
import org.eclipse.jetty.server.Authentication;
|
||||
import org.eclipse.jetty.server.Request;
|
||||
import org.eclipse.jetty.server.Response;
|
||||
import org.eclipse.jetty.server.UserIdentity;
|
||||
import org.eclipse.jetty.server.handler.ContextHandler;
|
||||
import org.eclipse.jetty.util.URIUtil;
|
||||
import org.jboss.logging.Logger;
|
||||
import org.keycloak.KeycloakPrincipal;
|
||||
import org.keycloak.KeycloakSecurityContext;
|
||||
@@ -37,6 +41,7 @@ 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.HashSet;
|
||||
import java.util.Set;
|
||||
@@ -52,6 +57,7 @@ public abstract class AbstractKeycloakJettyAuthenticator extends LoginAuthentica
|
||||
protected NodesRegistrationManagement nodesRegistrationManagement;
|
||||
protected AdapterConfig adapterConfig;
|
||||
protected KeycloakConfigResolver configResolver;
|
||||
protected String errorPage;
|
||||
|
||||
public AbstractKeycloakJettyAuthenticator() {
|
||||
super();
|
||||
@@ -66,7 +72,7 @@ public abstract class AbstractKeycloakJettyAuthenticator extends LoginAuthentica
|
||||
}
|
||||
|
||||
public AdapterTokenStore getTokenStore(Request request, HttpFacade facade, KeycloakDeployment resolvedDeployment) {
|
||||
AdapterTokenStore store = (AdapterTokenStore)request.getAttribute(TOKEN_STORE_NOTE);
|
||||
AdapterTokenStore store = (AdapterTokenStore) request.getAttribute(TOKEN_STORE_NOTE);
|
||||
if (store != null) {
|
||||
return store;
|
||||
}
|
||||
@@ -84,8 +90,8 @@ public abstract class AbstractKeycloakJettyAuthenticator extends LoginAuthentica
|
||||
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());
|
||||
AdapterDeploymentContext deploymentContext = (AdapterDeploymentContext) request.getAttribute(AdapterDeploymentContext.class.getName());
|
||||
KeycloakSecurityContext ksc = (KeycloakSecurityContext) request.getAttribute(KeycloakSecurityContext.class.getName());
|
||||
if (ksc != null) {
|
||||
JettyHttpFacade facade = new JettyHttpFacade(request, null);
|
||||
KeycloakDeployment deployment = deploymentContext.resolveDeployment(facade);
|
||||
@@ -115,11 +121,25 @@ public abstract class AbstractKeycloakJettyAuthenticator extends LoginAuthentica
|
||||
public void setConfiguration(AuthConfiguration configuration) {
|
||||
//super.setConfiguration(configuration);
|
||||
initializeKeycloak();
|
||||
String error = configuration.getInitParameter(FormAuthenticator.__FORM_ERROR_PAGE);
|
||||
setErrorPage(error);
|
||||
}
|
||||
|
||||
private void setErrorPage(String path) {
|
||||
if (path == null || path.trim().length() == 0) {
|
||||
} else {
|
||||
if (!path.startsWith("/")) {
|
||||
path = "/" + path;
|
||||
}
|
||||
errorPage = path;
|
||||
|
||||
if (errorPage.indexOf('?') > 0)
|
||||
errorPage = errorPage.substring(0, errorPage.indexOf('?'));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean secureResponse(ServletRequest req, ServletResponse res, boolean mandatory, Authentication.User validatedUser) throws ServerAuthException
|
||||
{
|
||||
public boolean secureResponse(ServletRequest req, ServletResponse res, boolean mandatory, Authentication.User validatedUser) throws ServerAuthException {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -167,12 +187,13 @@ public abstract class AbstractKeycloakJettyAuthenticator extends LoginAuthentica
|
||||
InputStream configInputStream = getConfigInputStream(theServletContext);
|
||||
if (configInputStream != null) {
|
||||
deploymentContext = new AdapterDeploymentContext(KeycloakDeploymentBuilder.build(configInputStream));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (deploymentContext == null) {
|
||||
deploymentContext = new AdapterDeploymentContext(new KeycloakDeployment());
|
||||
}
|
||||
if (theServletContext != null) theServletContext.setAttribute(AdapterDeploymentContext.class.getName(), deploymentContext);
|
||||
if (theServletContext != null)
|
||||
theServletContext.setAttribute(AdapterDeploymentContext.class.getName(), deploymentContext);
|
||||
}
|
||||
|
||||
private InputStream getConfigInputStream(ServletContext servletContext) {
|
||||
@@ -198,7 +219,7 @@ public abstract class AbstractKeycloakJettyAuthenticator extends LoginAuthentica
|
||||
log.trace("*** authenticate");
|
||||
}
|
||||
Request request = resolveRequest(req);
|
||||
JettyHttpFacade facade = new JettyHttpFacade(request, (HttpServletResponse)res);
|
||||
JettyHttpFacade facade = new JettyHttpFacade(request, (HttpServletResponse) res);
|
||||
KeycloakDeployment deployment = deploymentContext.resolveDeployment(facade);
|
||||
if (deployment == null || !deployment.isConfigured()) {
|
||||
log.debug("*** deployment isn't configured return false");
|
||||
@@ -231,17 +252,25 @@ public abstract class AbstractKeycloakJettyAuthenticator extends LoginAuthentica
|
||||
}
|
||||
AuthChallenge challenge = authenticator.getChallenge();
|
||||
if (challenge != null) {
|
||||
if (challenge.errorPage() && errorPage != null) {
|
||||
Response response = (Response)res;
|
||||
try {
|
||||
response.sendRedirect(response.encodeRedirectURL(URIUtil.addPaths(request.getContextPath(), errorPage)));
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
}
|
||||
challenge.challenge(facade);
|
||||
}
|
||||
return Authentication.SEND_CONTINUE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
protected abstract Request resolveRequest(ServletRequest req);
|
||||
|
||||
protected JettyRequestAuthenticator createRequestAuthenticator(Request request, JettyHttpFacade facade,
|
||||
KeycloakDeployment deployment, AdapterTokenStore tokenStore) {
|
||||
KeycloakDeployment deployment, AdapterTokenStore tokenStore) {
|
||||
return new JettyRequestAuthenticator(facade, deployment, tokenStore, -1, request);
|
||||
}
|
||||
|
||||
@@ -263,8 +292,7 @@ public abstract class AbstractKeycloakJettyAuthenticator extends LoginAuthentica
|
||||
|
||||
protected abstract Authentication createAuthentication(UserIdentity userIdentity);
|
||||
|
||||
public static abstract class KeycloakAuthentication extends UserAuthentication
|
||||
{
|
||||
public static abstract class KeycloakAuthentication extends UserAuthentication {
|
||||
public KeycloakAuthentication(String method, UserIdentity userIdentity) {
|
||||
super(method, userIdentity);
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ 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.catalina.deploy.LoginConfig;
|
||||
import org.apache.tomcat.util.buf.ByteChunk;
|
||||
import org.keycloak.KeycloakSecurityContext;
|
||||
import org.keycloak.constants.AdapterConstants;
|
||||
@@ -175,8 +176,9 @@ public abstract class AbstractKeycloakAuthenticatorValve extends FormAuthenticat
|
||||
}
|
||||
|
||||
protected abstract GenericPrincipalFactory createPrincipalFactory();
|
||||
protected abstract boolean forwardToErrorPageInternal(Request request, HttpServletResponse response, Object loginConfig) throws IOException;
|
||||
|
||||
protected boolean authenticateInternal(Request request, HttpServletResponse response) {
|
||||
protected boolean authenticateInternal(Request request, HttpServletResponse response, Object loginConfig) throws IOException {
|
||||
CatalinaHttpFacade facade = new CatalinaHttpFacade(request, response);
|
||||
KeycloakDeployment deployment = deploymentContext.resolveDeployment(facade);
|
||||
if (deployment == null || !deployment.isConfigured()) {
|
||||
@@ -196,6 +198,12 @@ public abstract class AbstractKeycloakAuthenticatorValve extends FormAuthenticat
|
||||
}
|
||||
AuthChallenge challenge = authenticator.getChallenge();
|
||||
if (challenge != null) {
|
||||
if (loginConfig == null) {
|
||||
loginConfig = request.getContext().getLoginConfig();
|
||||
}
|
||||
if (challenge.errorPage()) {
|
||||
if (forwardToErrorPageInternal(request, response, loginConfig))return false;
|
||||
}
|
||||
challenge.challenge(facade);
|
||||
}
|
||||
return false;
|
||||
|
||||
@@ -8,6 +8,8 @@ import org.apache.catalina.deploy.LoginConfig;
|
||||
import org.apache.catalina.realm.GenericPrincipal;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.security.Principal;
|
||||
import java.util.List;
|
||||
|
||||
@@ -20,9 +22,19 @@ import java.util.List;
|
||||
public class KeycloakAuthenticatorValve extends AbstractKeycloakAuthenticatorValve {
|
||||
@Override
|
||||
public boolean authenticate(Request request, Response response, LoginConfig config) throws java.io.IOException {
|
||||
return authenticateInternal(request, response);
|
||||
return authenticateInternal(request, response, config);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean forwardToErrorPageInternal(Request request, HttpServletResponse response, Object loginConfig) throws IOException {
|
||||
if (loginConfig == null) return false;
|
||||
LoginConfig config = (LoginConfig)loginConfig;
|
||||
if (config.getErrorPage() == null) return false;
|
||||
forwardToErrorPage(request, (Response)response, config);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void start() throws LifecycleException {
|
||||
StandardContext standardContext = (StandardContext) context;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package org.keycloak.adapters.tomcat;
|
||||
|
||||
import org.apache.catalina.connector.Request;
|
||||
import org.apache.catalina.connector.Response;
|
||||
import org.apache.catalina.core.StandardContext;
|
||||
import org.apache.catalina.deploy.LoginConfig;
|
||||
import org.apache.catalina.realm.GenericPrincipal;
|
||||
@@ -19,9 +20,19 @@ import java.util.List;
|
||||
*/
|
||||
public class KeycloakAuthenticatorValve extends AbstractKeycloakAuthenticatorValve {
|
||||
public boolean authenticate(Request request, HttpServletResponse response, LoginConfig config) throws IOException {
|
||||
return authenticateInternal(request, response);
|
||||
return authenticateInternal(request, response, config);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean forwardToErrorPageInternal(Request request, HttpServletResponse response, Object loginConfig) throws IOException {
|
||||
if (loginConfig == null) return false;
|
||||
LoginConfig config = (LoginConfig)loginConfig;
|
||||
if (config.getErrorPage() == null) return false;
|
||||
forwardToErrorPage(request, (Response)response, config);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
protected void initInternal() {
|
||||
StandardContext standardContext = (StandardContext) context;
|
||||
standardContext.addLifecycleListener(this);
|
||||
|
||||
@@ -32,6 +32,19 @@
|
||||
<artifactId>keycloak-adapter-core</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.tomcat</groupId>
|
||||
<artifactId>tomcat-servlet-api</artifactId>
|
||||
<version>${tomcat.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.tomcat</groupId>
|
||||
<artifactId>tomcat-catalina</artifactId>
|
||||
<version>${tomcat.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-tomcat-core-adapter</artifactId>
|
||||
|
||||
@@ -1,12 +1,19 @@
|
||||
package org.keycloak.adapters.tomcat;
|
||||
|
||||
import org.apache.catalina.authenticator.FormAuthenticator;
|
||||
import org.apache.catalina.connector.Request;
|
||||
import org.apache.catalina.connector.Response;
|
||||
import org.apache.catalina.core.StandardContext;
|
||||
import org.apache.catalina.realm.GenericPrincipal;
|
||||
import org.apache.tomcat.util.ExceptionUtils;
|
||||
import org.apache.tomcat.util.descriptor.web.LoginConfig;
|
||||
|
||||
import javax.servlet.RequestDispatcher;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.security.Principal;
|
||||
import java.util.List;
|
||||
|
||||
@@ -18,7 +25,32 @@ import java.util.List;
|
||||
*/
|
||||
public class KeycloakAuthenticatorValve extends AbstractKeycloakAuthenticatorValve {
|
||||
public boolean authenticate(Request request, HttpServletResponse response) throws IOException {
|
||||
return authenticateInternal(request, response);
|
||||
return authenticateInternal(request, response, request.getContext().getLoginConfig());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean forwardToErrorPageInternal(Request request, HttpServletResponse response, Object loginConfig) throws IOException {
|
||||
if (loginConfig == null) return false;
|
||||
LoginConfig config = (LoginConfig)loginConfig;
|
||||
if (config.getErrorPage() == null) return false;
|
||||
// had to do this to get around compiler/IDE issues :(
|
||||
try {
|
||||
Method method = null;
|
||||
/*
|
||||
for (Method m : getClass().getDeclaredMethods()) {
|
||||
if (m.getName().equals("forwardToErrorPage")) {
|
||||
method = m;
|
||||
break;
|
||||
}
|
||||
}
|
||||
*/
|
||||
method = FormAuthenticator.class.getDeclaredMethod("forwardToErrorPage", Request.class, HttpServletResponse.class, LoginConfig.class);
|
||||
method.setAccessible(true);
|
||||
method.invoke(this, request, response, config);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
protected void initInternal() {
|
||||
|
||||
@@ -23,7 +23,9 @@ import io.undertow.security.api.SecurityNotification;
|
||||
import io.undertow.server.HttpServerExchange;
|
||||
import io.undertow.server.session.Session;
|
||||
import io.undertow.util.AttachmentKey;
|
||||
import io.undertow.util.Headers;
|
||||
import io.undertow.util.Sessions;
|
||||
import io.undertow.util.StatusCodes;
|
||||
import org.keycloak.KeycloakPrincipal;
|
||||
import org.keycloak.KeycloakSecurityContext;
|
||||
import org.keycloak.adapters.AdapterDeploymentContext;
|
||||
@@ -46,16 +48,22 @@ public abstract class AbstractUndertowKeycloakAuthMech implements Authentication
|
||||
public static final AttachmentKey<AuthChallenge> KEYCLOAK_CHALLENGE_ATTACHMENT_KEY = AttachmentKey.create(AuthChallenge.class);
|
||||
protected AdapterDeploymentContext deploymentContext;
|
||||
protected UndertowUserSessionManagement sessionManagement;
|
||||
protected String errorPage;
|
||||
|
||||
public AbstractUndertowKeycloakAuthMech(AdapterDeploymentContext deploymentContext, UndertowUserSessionManagement sessionManagement) {
|
||||
public AbstractUndertowKeycloakAuthMech(AdapterDeploymentContext deploymentContext, UndertowUserSessionManagement sessionManagement, String errorPage) {
|
||||
this.deploymentContext = deploymentContext;
|
||||
this.sessionManagement = sessionManagement;
|
||||
this.errorPage = errorPage;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChallengeResult sendChallenge(HttpServerExchange exchange, SecurityContext securityContext) {
|
||||
AuthChallenge challenge = exchange.getAttachment(KEYCLOAK_CHALLENGE_ATTACHMENT_KEY);
|
||||
if (challenge != null) {
|
||||
if (challenge.errorPage() && errorPage != null) {
|
||||
Integer code = servePage(exchange, errorPage);
|
||||
return new ChallengeResult(true, code);
|
||||
}
|
||||
UndertowHttpFacade facade = new UndertowHttpFacade(exchange);
|
||||
if (challenge.challenge(facade)) {
|
||||
return new ChallengeResult(true, exchange.getResponseCode());
|
||||
@@ -64,6 +72,19 @@ public abstract class AbstractUndertowKeycloakAuthMech implements Authentication
|
||||
return new ChallengeResult(false);
|
||||
}
|
||||
|
||||
protected Integer servePage(final HttpServerExchange exchange, final String location) {
|
||||
sendRedirect(exchange, location);
|
||||
return StatusCodes.TEMPORARY_REDIRECT;
|
||||
}
|
||||
|
||||
static void sendRedirect(final HttpServerExchange exchange, final String location) {
|
||||
// TODO - String concatenation to construct URLS is extremely error prone - switch to a URI which will better handle this.
|
||||
String loc = exchange.getRequestScheme() + "://" + exchange.getHostAndPort() + location;
|
||||
exchange.getResponseHeaders().put(Headers.LOCATION, loc);
|
||||
}
|
||||
|
||||
|
||||
|
||||
protected void registerNotifications(final SecurityContext securityContext) {
|
||||
|
||||
final NotificationReceiver logoutReceiver = new NotificationReceiver() {
|
||||
|
||||
@@ -32,11 +32,12 @@ import io.undertow.servlet.api.LoginConfig;
|
||||
import io.undertow.servlet.api.ServletSessionConfig;
|
||||
import io.undertow.servlet.util.ImmediateInstanceHandle;
|
||||
import org.jboss.logging.Logger;
|
||||
import org.keycloak.constants.AdapterConstants;
|
||||
import org.keycloak.adapters.AdapterDeploymentContext;
|
||||
import org.keycloak.adapters.KeycloakConfigResolver;
|
||||
import org.keycloak.adapters.KeycloakDeployment;
|
||||
import org.keycloak.adapters.KeycloakDeploymentBuilder;
|
||||
import org.keycloak.adapters.NodesRegistrationManagement;
|
||||
import org.keycloak.constants.AdapterConstants;
|
||||
|
||||
import javax.servlet.ServletContext;
|
||||
import java.io.ByteArrayInputStream;
|
||||
@@ -44,7 +45,6 @@ import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Map;
|
||||
import org.keycloak.adapters.KeycloakConfigResolver;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
@@ -57,9 +57,9 @@ public class KeycloakServletExtension implements ServletExtension {
|
||||
// todo when this DeploymentInfo method of the same name is fixed.
|
||||
public boolean isAuthenticationMechanismPresent(DeploymentInfo deploymentInfo, final String mechanismName) {
|
||||
LoginConfig loginConfig = deploymentInfo.getLoginConfig();
|
||||
if(loginConfig != null) {
|
||||
for(AuthMethodConfig method : loginConfig.getAuthMethods()) {
|
||||
if(method.getName().equalsIgnoreCase(mechanismName)) {
|
||||
if (loginConfig != null) {
|
||||
for (AuthMethodConfig method : loginConfig.getAuthMethods()) {
|
||||
if (method.getName().equalsIgnoreCase(mechanismName)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -191,7 +191,17 @@ public class KeycloakServletExtension implements ServletExtension {
|
||||
|
||||
protected ServletKeycloakAuthMech createAuthenticationMechanism(DeploymentInfo deploymentInfo, AdapterDeploymentContext deploymentContext, UndertowUserSessionManagement userSessionManagement,
|
||||
NodesRegistrationManagement nodesRegistrationManagement) {
|
||||
log.debug("creating ServletKeycloakAuthMech");
|
||||
return new ServletKeycloakAuthMech(deploymentContext, userSessionManagement, nodesRegistrationManagement, deploymentInfo.getConfidentialPortManager());
|
||||
log.debug("creating ServletKeycloakAuthMech");
|
||||
String errorPage = getErrorPage(deploymentInfo);
|
||||
return new ServletKeycloakAuthMech(deploymentContext, userSessionManagement, nodesRegistrationManagement, deploymentInfo.getConfidentialPortManager(), errorPage);
|
||||
}
|
||||
|
||||
protected String getErrorPage(DeploymentInfo deploymentInfo) {
|
||||
LoginConfig loginConfig = deploymentInfo.getLoginConfig();
|
||||
String errorPage = null;
|
||||
if (loginConfig != null) {
|
||||
errorPage = loginConfig.getErrorPage();
|
||||
}
|
||||
return errorPage;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,18 +16,28 @@
|
||||
*/
|
||||
package org.keycloak.adapters.undertow;
|
||||
|
||||
import io.undertow.security.api.AuthenticationMechanism;
|
||||
import io.undertow.security.api.SecurityContext;
|
||||
import io.undertow.server.HttpServerExchange;
|
||||
import io.undertow.servlet.api.ConfidentialPortManager;
|
||||
import io.undertow.servlet.handlers.ServletRequestContext;
|
||||
import io.undertow.util.Headers;
|
||||
import org.jboss.logging.Logger;
|
||||
import org.keycloak.adapters.AdapterDeploymentContext;
|
||||
import org.keycloak.adapters.AdapterTokenStore;
|
||||
import org.keycloak.adapters.AuthChallenge;
|
||||
import org.keycloak.adapters.HttpFacade;
|
||||
import org.keycloak.adapters.KeycloakDeployment;
|
||||
import org.keycloak.adapters.NodesRegistrationManagement;
|
||||
import org.keycloak.adapters.RequestAuthenticator;
|
||||
import org.keycloak.enums.TokenStore;
|
||||
|
||||
import javax.servlet.RequestDispatcher;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @author Stan Silvert ssilvert@redhat.com (C) 2014 Red Hat Inc.
|
||||
@@ -39,12 +49,36 @@ public class ServletKeycloakAuthMech extends AbstractUndertowKeycloakAuthMech {
|
||||
protected NodesRegistrationManagement nodesRegistrationManagement;
|
||||
protected ConfidentialPortManager portManager;
|
||||
|
||||
public ServletKeycloakAuthMech(AdapterDeploymentContext deploymentContext, UndertowUserSessionManagement userSessionManagement, NodesRegistrationManagement nodesRegistrationManagement, ConfidentialPortManager portManager) {
|
||||
super(deploymentContext, userSessionManagement);
|
||||
public ServletKeycloakAuthMech(AdapterDeploymentContext deploymentContext, UndertowUserSessionManagement userSessionManagement,
|
||||
NodesRegistrationManagement nodesRegistrationManagement, ConfidentialPortManager portManager,
|
||||
String errorPage) {
|
||||
super(deploymentContext, userSessionManagement, errorPage);
|
||||
this.nodesRegistrationManagement = nodesRegistrationManagement;
|
||||
this.portManager = portManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Integer servePage(HttpServerExchange exchange, String location) {
|
||||
final ServletRequestContext servletRequestContext = exchange.getAttachment(ServletRequestContext.ATTACHMENT_KEY);
|
||||
ServletRequest req = servletRequestContext.getServletRequest();
|
||||
ServletResponse resp = servletRequestContext.getServletResponse();
|
||||
RequestDispatcher disp = req.getRequestDispatcher(location);
|
||||
//make sure the login page is never cached
|
||||
exchange.getResponseHeaders().add(Headers.CACHE_CONTROL, "no-cache, no-store, must-revalidate");
|
||||
exchange.getResponseHeaders().add(Headers.PRAGMA, "no-cache");
|
||||
exchange.getResponseHeaders().add(Headers.EXPIRES, "0");
|
||||
|
||||
|
||||
try {
|
||||
disp.forward(req, resp);
|
||||
} catch (ServletException e) {
|
||||
throw new RuntimeException(e);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AuthenticationMechanismOutcome authenticate(HttpServerExchange exchange, SecurityContext securityContext) {
|
||||
UndertowHttpFacade facade = new UndertowHttpFacade(exchange);
|
||||
|
||||
@@ -17,8 +17,8 @@ public class UndertowAuthenticationMechanism extends AbstractUndertowKeycloakAut
|
||||
protected int confidentialPort;
|
||||
|
||||
public UndertowAuthenticationMechanism(AdapterDeploymentContext deploymentContext, UndertowUserSessionManagement sessionManagement,
|
||||
NodesRegistrationManagement nodesRegistrationManagement, int confidentialPort) {
|
||||
super(deploymentContext, sessionManagement);
|
||||
NodesRegistrationManagement nodesRegistrationManagement, int confidentialPort, String errorPage) {
|
||||
super(deploymentContext, sessionManagement, errorPage);
|
||||
this.nodesRegistrationManagement = nodesRegistrationManagement;
|
||||
this.confidentialPort = confidentialPort;
|
||||
}
|
||||
|
||||
@@ -21,8 +21,8 @@ public class WildflyAuthenticationMechanism extends ServletKeycloakAuthMech {
|
||||
public WildflyAuthenticationMechanism(AdapterDeploymentContext deploymentContext,
|
||||
UndertowUserSessionManagement userSessionManagement,
|
||||
NodesRegistrationManagement nodesRegistrationManagement,
|
||||
ConfidentialPortManager portManager) {
|
||||
super(deploymentContext, userSessionManagement, nodesRegistrationManagement, portManager);
|
||||
ConfidentialPortManager portManager, String errorPage) {
|
||||
super(deploymentContext, userSessionManagement, nodesRegistrationManagement, portManager, errorPage);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -19,7 +19,7 @@ public class WildflyKeycloakServletExtension extends KeycloakServletExtension {
|
||||
protected ServletKeycloakAuthMech createAuthenticationMechanism(DeploymentInfo deploymentInfo, AdapterDeploymentContext deploymentContext,
|
||||
UndertowUserSessionManagement userSessionManagement, NodesRegistrationManagement nodesRegistrationManagement) {
|
||||
log.debug("creating WildflyAuthenticationMechanism");
|
||||
return new WildflyAuthenticationMechanism(deploymentContext, userSessionManagement, nodesRegistrationManagement, deploymentInfo.getConfidentialPortManager());
|
||||
return new WildflyAuthenticationMechanism(deploymentContext, userSessionManagement, nodesRegistrationManagement, deploymentInfo.getConfidentialPortManager(), getErrorPage(deploymentInfo));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -229,7 +229,7 @@ public class ProxyServerBuilder {
|
||||
handler = new ConstraintMatcherHandler(matches, handler, toWrap, errorPage);
|
||||
final List<AuthenticationMechanism> mechanisms = new LinkedList<AuthenticationMechanism>();
|
||||
mechanisms.add(new CachedAuthenticatedSessionMechanism());
|
||||
mechanisms.add(new UndertowAuthenticationMechanism(deploymentContext, userSessionManagement, nodesRegistrationManagement, -1));
|
||||
mechanisms.add(new UndertowAuthenticationMechanism(deploymentContext, userSessionManagement, nodesRegistrationManagement, -1, null));
|
||||
handler = new AuthenticationMechanismsHandler(handler, mechanisms);
|
||||
IdentityManager identityManager = new IdentityManager() {
|
||||
@Override
|
||||
|
||||
@@ -224,6 +224,9 @@ public class AdapterTestStrategy extends ExternalResource {
|
||||
Assert.assertTrue(driver.getCurrentUrl().startsWith(LOGIN_URL));
|
||||
driver.navigate().to(APP_SERVER_BASE_URL + "/customer-portal");
|
||||
Assert.assertTrue(driver.getCurrentUrl().startsWith(LOGIN_URL));
|
||||
loginPage.cancel();
|
||||
System.out.println(driver.getPageSource());
|
||||
Assert.assertTrue(driver.getPageSource().contains("Error Page"));
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import io.undertow.servlet.api.DeploymentInfo;
|
||||
import io.undertow.servlet.api.FilterInfo;
|
||||
import io.undertow.servlet.api.LoginConfig;
|
||||
import io.undertow.servlet.api.SecurityConstraint;
|
||||
import io.undertow.servlet.api.SecurityInfo;
|
||||
import io.undertow.servlet.api.ServletInfo;
|
||||
import io.undertow.servlet.api.WebResourceCollection;
|
||||
import org.jboss.resteasy.plugins.server.undertow.UndertowJaxrsServer;
|
||||
@@ -126,6 +127,7 @@ public abstract class AbstractKeycloakRule extends ExternalResource {
|
||||
server.getServer().deploy(deploymentInfo);
|
||||
}
|
||||
|
||||
|
||||
private DeploymentInfo createDeploymentInfo(String name, String contextPath, Class<? extends Servlet> servletClass) {
|
||||
DeploymentInfo deploymentInfo = new DeploymentInfo();
|
||||
deploymentInfo.setClassLoader(getClass().getClassLoader());
|
||||
@@ -168,11 +170,25 @@ public abstract class AbstractKeycloakRule extends ExternalResource {
|
||||
constraint.addRoleAllowed(role);
|
||||
di.addSecurityConstraint(constraint);
|
||||
}
|
||||
LoginConfig loginConfig = new LoginConfig("KEYCLOAK", "demo");
|
||||
LoginConfig loginConfig = new LoginConfig("KEYCLOAK", "demo", null, "/error.html");
|
||||
di.setLoginConfig(loginConfig);
|
||||
addErrorPage(di);
|
||||
|
||||
server.getServer().deploy(di);
|
||||
}
|
||||
|
||||
public void addErrorPage(DeploymentInfo di) {
|
||||
ServletInfo servlet = new ServletInfo("Error Page", ErrorServlet.class);
|
||||
servlet.addMapping("/error.html");
|
||||
SecurityConstraint constraint = new SecurityConstraint();
|
||||
WebResourceCollection collection = new WebResourceCollection();
|
||||
collection.addUrlPattern("/error.html");
|
||||
constraint.addWebResourceCollection(collection);
|
||||
constraint.setEmptyRoleSemantic(SecurityInfo.EmptyRoleSemantic.PERMIT);
|
||||
di.addSecurityConstraint(constraint);
|
||||
di.addServlet(servlet);
|
||||
}
|
||||
|
||||
public void deployJaxrsApplication(String name, String contextPath, Class<? extends Application> applicationClass, Map<String,String> initParams) {
|
||||
ResteasyDeployment deployment = new ResteasyDeployment();
|
||||
deployment.setApplicationClass(applicationClass.getName());
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
package org.keycloak.testsuite.rule;
|
||||
|
||||
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:mposolda@redhat.com">Marek Posolda</a>
|
||||
*/
|
||||
public class ErrorServlet extends HttpServlet {
|
||||
|
||||
@Override
|
||||
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
|
||||
|
||||
|
||||
resp.setContentType("text/html");
|
||||
PrintWriter pw = resp.getWriter();
|
||||
pw.printf("<html><head><title>%s</title></head><body>", "Error Page");
|
||||
pw.print("<h1>There was an error</h1></body></html>");
|
||||
pw.flush();
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -10,12 +10,21 @@
|
||||
<servlet-name>Servlet</servlet-name>
|
||||
<servlet-class>org.keycloak.testsuite.adapter.CustomerServlet</servlet-class>
|
||||
</servlet>
|
||||
<servlet>
|
||||
<servlet-name>Error Servlet</servlet-name>
|
||||
<servlet-class>org.keycloak.testsuite.rule.ErrorServlet</servlet-class>
|
||||
</servlet>
|
||||
|
||||
<servlet-mapping>
|
||||
<servlet-name>Servlet</servlet-name>
|
||||
<url-pattern>/*</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
<servlet-mapping>
|
||||
<servlet-name>Error Servlet</servlet-name>
|
||||
<url-pattern>/error.html</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
<security-constraint>
|
||||
<web-resource-collection>
|
||||
<web-resource-name>Users</web-resource-name>
|
||||
@@ -25,12 +34,23 @@
|
||||
<role-name>user</role-name>
|
||||
</auth-constraint>
|
||||
</security-constraint>
|
||||
<security-constraint>
|
||||
<web-resource-collection>
|
||||
<web-resource-name>Errors</web-resource-name>
|
||||
<url-pattern>/error.html</url-pattern>
|
||||
</web-resource-collection>
|
||||
</security-constraint>
|
||||
|
||||
<login-config>
|
||||
<auth-method>BASIC</auth-method>
|
||||
<auth-method>FORM</auth-method>
|
||||
<realm-name>demo</realm-name>
|
||||
<form-login-config>
|
||||
<form-login-page>/error.html</form-login-page>
|
||||
<form-error-page>/error.html</form-error-page>
|
||||
</form-login-config>
|
||||
</login-config>
|
||||
|
||||
♦
|
||||
<security-role>
|
||||
<role-name>admin</role-name>
|
||||
</security-role>
|
||||
|
||||
@@ -10,12 +10,21 @@
|
||||
<servlet-name>Servlet</servlet-name>
|
||||
<servlet-class>org.keycloak.testsuite.adapter.CustomerServlet</servlet-class>
|
||||
</servlet>
|
||||
<servlet>
|
||||
<servlet-name>Error Servlet</servlet-name>
|
||||
<servlet-class>org.keycloak.testsuite.rule.ErrorServlet</servlet-class>
|
||||
</servlet>
|
||||
|
||||
<servlet-mapping>
|
||||
<servlet-name>Servlet</servlet-name>
|
||||
<url-pattern>/*</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
<servlet-mapping>
|
||||
<servlet-name>Error Servlet</servlet-name>
|
||||
<url-pattern>/error.html</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
<security-constraint>
|
||||
<web-resource-collection>
|
||||
<web-resource-name>Users</web-resource-name>
|
||||
@@ -25,10 +34,20 @@
|
||||
<role-name>user</role-name>
|
||||
</auth-constraint>
|
||||
</security-constraint>
|
||||
<security-constraint>
|
||||
<web-resource-collection>
|
||||
<web-resource-name>Errors</web-resource-name>
|
||||
<url-pattern>/error.html</url-pattern>
|
||||
</web-resource-collection>
|
||||
</security-constraint>
|
||||
|
||||
<login-config>
|
||||
<auth-method>BASIC</auth-method>
|
||||
<auth-method>FORM</auth-method>
|
||||
<realm-name>demo</realm-name>
|
||||
<form-login-config>
|
||||
<form-login-page>/error.html</form-login-page>
|
||||
<form-error-page>/error.html</form-error-page>
|
||||
</form-login-config>
|
||||
</login-config>
|
||||
|
||||
<security-role>
|
||||
|
||||
@@ -10,12 +10,21 @@
|
||||
<servlet-name>Servlet</servlet-name>
|
||||
<servlet-class>org.keycloak.testsuite.adapter.CustomerServlet</servlet-class>
|
||||
</servlet>
|
||||
<servlet>
|
||||
<servlet-name>Error Servlet</servlet-name>
|
||||
<servlet-class>org.keycloak.testsuite.rule.ErrorServlet</servlet-class>
|
||||
</servlet>
|
||||
|
||||
<servlet-mapping>
|
||||
<servlet-name>Servlet</servlet-name>
|
||||
<url-pattern>/*</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
<servlet-mapping>
|
||||
<servlet-name>Error Servlet</servlet-name>
|
||||
<url-pattern>/error.html</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
<security-constraint>
|
||||
<web-resource-collection>
|
||||
<web-resource-name>Users</web-resource-name>
|
||||
@@ -25,10 +34,20 @@
|
||||
<role-name>user</role-name>
|
||||
</auth-constraint>
|
||||
</security-constraint>
|
||||
<security-constraint>
|
||||
<web-resource-collection>
|
||||
<web-resource-name>Errors</web-resource-name>
|
||||
<url-pattern>/error.html</url-pattern>
|
||||
</web-resource-collection>
|
||||
</security-constraint>
|
||||
|
||||
<login-config>
|
||||
<auth-method>BASIC</auth-method>
|
||||
<auth-method>FORM</auth-method>
|
||||
<realm-name>demo</realm-name>
|
||||
<form-login-config>
|
||||
<form-login-page>/error.html</form-login-page>
|
||||
<form-error-page>/error.html</form-error-page>
|
||||
</form-login-config>
|
||||
</login-config>
|
||||
|
||||
<security-role>
|
||||
|
||||
@@ -10,12 +10,21 @@
|
||||
<servlet-name>Servlet</servlet-name>
|
||||
<servlet-class>org.keycloak.testsuite.adapter.CustomerServlet</servlet-class>
|
||||
</servlet>
|
||||
<servlet>
|
||||
<servlet-name>Error Servlet</servlet-name>
|
||||
<servlet-class>org.keycloak.testsuite.rule.ErrorServlet</servlet-class>
|
||||
</servlet>
|
||||
|
||||
<servlet-mapping>
|
||||
<servlet-name>Servlet</servlet-name>
|
||||
<url-pattern>/*</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
<servlet-mapping>
|
||||
<servlet-name>Error Servlet</servlet-name>
|
||||
<url-pattern>/error.html</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
<security-constraint>
|
||||
<web-resource-collection>
|
||||
<web-resource-name>Users</web-resource-name>
|
||||
@@ -25,10 +34,20 @@
|
||||
<role-name>user</role-name>
|
||||
</auth-constraint>
|
||||
</security-constraint>
|
||||
<security-constraint>
|
||||
<web-resource-collection>
|
||||
<web-resource-name>Errors</web-resource-name>
|
||||
<url-pattern>/error.html</url-pattern>
|
||||
</web-resource-collection>
|
||||
</security-constraint>
|
||||
|
||||
<login-config>
|
||||
<auth-method>BASIC</auth-method>
|
||||
<realm-name>demo</realm-name>
|
||||
<form-login-config>
|
||||
<form-login-page>/error.html</form-login-page>
|
||||
<form-error-page>/error.html</form-error-page>
|
||||
</form-login-config>
|
||||
</login-config>
|
||||
|
||||
<security-role>
|
||||
|
||||
@@ -10,12 +10,21 @@
|
||||
<servlet-name>Servlet</servlet-name>
|
||||
<servlet-class>org.keycloak.testsuite.adapter.CustomerServlet</servlet-class>
|
||||
</servlet>
|
||||
<servlet>
|
||||
<servlet-name>Error Servlet</servlet-name>
|
||||
<servlet-class>org.keycloak.testsuite.rule.ErrorServlet</servlet-class>
|
||||
</servlet>
|
||||
|
||||
<servlet-mapping>
|
||||
<servlet-name>Servlet</servlet-name>
|
||||
<url-pattern>/*</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
<servlet-mapping>
|
||||
<servlet-name>Error Servlet</servlet-name>
|
||||
<url-pattern>/error.html</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
<security-constraint>
|
||||
<web-resource-collection>
|
||||
<web-resource-name>Users</web-resource-name>
|
||||
@@ -25,10 +34,20 @@
|
||||
<role-name>user</role-name>
|
||||
</auth-constraint>
|
||||
</security-constraint>
|
||||
<security-constraint>
|
||||
<web-resource-collection>
|
||||
<web-resource-name>Errors</web-resource-name>
|
||||
<url-pattern>/error.html</url-pattern>
|
||||
</web-resource-collection>
|
||||
</security-constraint>
|
||||
|
||||
<login-config>
|
||||
<auth-method>BASIC</auth-method>
|
||||
<realm-name>demo</realm-name>
|
||||
<form-login-config>
|
||||
<form-login-page>/error.html</form-login-page>
|
||||
<form-error-page>/error.html</form-error-page>
|
||||
</form-login-config>
|
||||
</login-config>
|
||||
|
||||
<security-role>
|
||||
|
||||
@@ -10,12 +10,21 @@
|
||||
<servlet-name>Servlet</servlet-name>
|
||||
<servlet-class>org.keycloak.testsuite.adapter.CustomerServlet</servlet-class>
|
||||
</servlet>
|
||||
<servlet>
|
||||
<servlet-name>Error Servlet</servlet-name>
|
||||
<servlet-class>org.keycloak.testsuite.rule.ErrorServlet</servlet-class>
|
||||
</servlet>
|
||||
|
||||
<servlet-mapping>
|
||||
<servlet-name>Servlet</servlet-name>
|
||||
<url-pattern>/*</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
<servlet-mapping>
|
||||
<servlet-name>Error Servlet</servlet-name>
|
||||
<url-pattern>/error.html</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
<security-constraint>
|
||||
<web-resource-collection>
|
||||
<web-resource-name>Users</web-resource-name>
|
||||
@@ -25,10 +34,20 @@
|
||||
<role-name>user</role-name>
|
||||
</auth-constraint>
|
||||
</security-constraint>
|
||||
<security-constraint>
|
||||
<web-resource-collection>
|
||||
<web-resource-name>Errors</web-resource-name>
|
||||
<url-pattern>/error.html</url-pattern>
|
||||
</web-resource-collection>
|
||||
</security-constraint>
|
||||
|
||||
<login-config>
|
||||
<auth-method>BASIC</auth-method>
|
||||
<realm-name>demo</realm-name>
|
||||
<form-login-config>
|
||||
<form-login-page>/error.html</form-login-page>
|
||||
<form-error-page>/error.html</form-error-page>
|
||||
</form-login-config>
|
||||
</login-config>
|
||||
|
||||
<security-role>
|
||||
|
||||
Reference in New Issue
Block a user