Selaa lähdekoodia

First version that works.

Luke Taylor 20 vuotta sitten
vanhempi
commit
af02c42e9f

+ 74 - 23
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.
  * <p>
  * 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.
+     * <p>
+     * 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}.
+     * </p>
+     * <p>
+     * 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.
+     * </p>
+     */
     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 the <code>Authentication</code> 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 { }