diff --git a/core/src/main/java/org/acegisecurity/ui/x509/X509ProcessingFilter.java b/core/src/main/java/org/acegisecurity/ui/x509/X509ProcessingFilter.java index 5b909b40be..65c59b8f26 100644 --- a/core/src/main/java/org/acegisecurity/ui/x509/X509ProcessingFilter.java +++ b/core/src/main/java/org/acegisecurity/ui/x509/X509ProcessingFilter.java @@ -9,7 +9,6 @@ import net.sf.acegisecurity.context.ContextHolder; import net.sf.acegisecurity.context.security.SecureContext; import net.sf.acegisecurity.context.security.SecureContextUtils; import net.sf.acegisecurity.providers.x509.X509AuthenticationToken; -import net.sf.acegisecurity.providers.x509.X509AuthenticationProvider; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @@ -22,8 +21,8 @@ import org.apache.commons.logging.LogFactory; import org.springframework.beans.factory.InitializingBean; /** - * Processes the X.509 certificate submitted by a client - typically - * when HTTPS is used with client-authentiction enabled. + * Processes the X.509 certificate submitted by a client browser + * when HTTPS is used with client-authentication enabled. *
* An {@link X509AuthenticationToken} is created with the certificate * as the credentials. @@ -47,8 +46,11 @@ public class X509ProcessingFilter implements Filter, InitializingBean { private static final Log logger = LogFactory.getLog(X509ProcessingFilter.class); + //~ Instance fields ======================================================== + private AuthenticationManager authenticationManager; + //~ Methods ================================================================ public void setAuthenticationManager(AuthenticationManager authenticationManager) { this.authenticationManager = authenticationManager; @@ -59,6 +61,22 @@ public class X509ProcessingFilter implements Filter, InitializingBean { throw new IllegalArgumentException("An AuthenticationManager must be set"); } + /** + * This method first checks for an existing, non-null authentication in the + * secure context. If one is found it does nothing. + *
+ * If no authentication object exists, it attempts to obtain the client + * authentication certificate from the request. If there is no certificate + * present then authentication is skipped. Otherwise a new authentication + * request containing the certificate will be passed to the configured + * {@link AuthenticationManager}. + *
+ *+ * If authentication is successful the returned token will be stored in + * the secure context. Otherwise it will be set to null. + * In either case, the request proceeds through the filter chain. + *
+ */ public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException { if (!(request instanceof HttpServletRequest)) { throw new ServletException("Can only process HttpServletRequest"); @@ -68,44 +86,77 @@ public class X509ProcessingFilter implements Filter, InitializingBean { throw new ServletException("Can only process HttpServletResponse"); } + HttpServletRequest httpRequest = (HttpServletRequest) request; + HttpServletResponse httpResponse = (HttpServletResponse) response; SecureContext ctx = SecureContextUtils.getSecureContext(); - logger.debug("Checking secure context: " + ctx); + logger.debug("Checking secure context token: " + ctx.getAuthentication()); + if(ctx.getAuthentication() == null) { - attemptAuthentication((HttpServletRequest)request); - } + Authentication authResult = null; + X509Certificate clientCertificate = extractClientCertificate(httpRequest); + + try { + X509AuthenticationToken authRequest = new X509AuthenticationToken(clientCertificate); + // authRequest.setDetails(new WebAuthenticationDetails(request)); + authResult = authenticationManager.authenticate(authRequest); + successfulAuthentication(httpRequest, httpResponse, authResult); + } catch (AuthenticationException failed) { + unsuccessfulAuthentication(httpRequest, httpResponse, failed); + } + } filterChain.doFilter(request, response); } - /** - * - * @param request the request containing the client certificate - * @return - * @throws AuthenticationException if the authentication manager rejects the certificate for some reason. - */ - public Authentication attemptAuthentication(HttpServletRequest request) throws AuthenticationException { + private X509Certificate extractClientCertificate(HttpServletRequest request) { X509Certificate[] certs = (X509Certificate[]) request.getAttribute("javax.servlet.request.X509Certificate"); - X509Certificate clientCertificate = null; - if(certs != null && certs.length > 0) { - clientCertificate = certs[0]; - logger.debug("Authenticating with certificate " + clientCertificate); - } else { - logger.warn("No client certificate found in Request."); + return certs[0]; + } + + if(logger.isDebugEnabled()) + logger.debug("No client certificate found in request, authentication will fail."); + + return null; + } + + /** + * Puts theAuthentication instance returned by the authentication manager into
+ * the secure context.
+ */
+ protected void successfulAuthentication(HttpServletRequest request,
+ HttpServletResponse response, Authentication authResult)
+ throws IOException {
+
+ if (logger.isDebugEnabled()) {
+ logger.debug("Authentication success: " + authResult);
}
- // TODO: warning is probably superfluous, as it may get called when a non-protected URL is used and no certificate is present.
+ SecureContext sc = SecureContextUtils.getSecureContext();
+ sc.setAuthentication(authResult);
+ }
- X509AuthenticationToken authRequest = new X509AuthenticationToken(clientCertificate);
+ /**
+ * Ensures the authentication object in the secure context is set to null when authentication fails.
+ *
+ */
+ protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException failed) {
+ SecureContext sc = SecureContextUtils.getSecureContext();
- // authRequest.setDetails(new WebAuthenticationDetails(request));
+ sc.setAuthentication(null);
+ ContextHolder.setContext(sc);
- return authenticationManager.authenticate(authRequest);
+ if (logger.isDebugEnabled()) {
+ logger.debug("Updated ContextHolder to contain null Authentication");
+ }
+
+ request.getSession().setAttribute(AbstractProcessingFilter.ACEGI_SECURITY_LAST_EXCEPTION_KEY, failed);
}
+
public void init(FilterConfig filterConfig) throws ServletException { }