Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: net/sf/acegisecurity/ui/x509/X509ProcessingFilter.java


1   /* Copyright 2004, 2005 Acegi Technology Pty Limited
2    *
3    * Licensed under the Apache License, Version 2.0 (the "License");
4    * you may not use this file except in compliance with the License.
5    * You may obtain a copy of the License at
6    *
7    *     http://www.apache.org/licenses/LICENSE-2.0
8    *
9    * Unless required by applicable law or agreed to in writing, software
10   * distributed under the License is distributed on an "AS IS" BASIS,
11   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12   * See the License for the specific language governing permissions and
13   * limitations under the License.
14   */
15  
16  package net.sf.acegisecurity.ui.x509;
17  
18  import net.sf.acegisecurity.ui.AbstractProcessingFilter;
19  import net.sf.acegisecurity.ui.WebAuthenticationDetails;
20  import net.sf.acegisecurity.Authentication;
21  import net.sf.acegisecurity.AuthenticationException;
22  import net.sf.acegisecurity.AuthenticationManager;
23  import net.sf.acegisecurity.context.ContextHolder;
24  import net.sf.acegisecurity.context.security.SecureContext;
25  import net.sf.acegisecurity.context.security.SecureContextUtils;
26  import net.sf.acegisecurity.providers.x509.X509AuthenticationToken;
27  
28  import javax.servlet.http.HttpServletRequest;
29  import javax.servlet.http.HttpServletResponse;
30  import javax.servlet.*;
31  import java.security.cert.X509Certificate;
32  import java.io.IOException;
33  
34  import org.apache.commons.logging.Log;
35  import org.apache.commons.logging.LogFactory;
36  import org.springframework.beans.factory.InitializingBean;
37  import org.springframework.util.Assert;
38  
39  /**
40   * Processes the X.509 certificate submitted by a client browser
41   * when HTTPS is used with client-authentication enabled.
42   * <p>
43   * An {@link X509AuthenticationToken} is created with the certificate
44   * as the credentials.
45   * </p>
46   * <p>
47   * The configured authentication manager is expected to supply a
48   * provider which can handle this token (usually an instance of
49   * {@link net.sf.acegisecurity.providers.x509.X509AuthenticationProvider}).
50   * </p>
51   *
52   * <p>
53   * <b>Do not use this class directly.</b> Instead configure
54   * <code>web.xml</code> to use the {@link
55   * net.sf.acegisecurity.util.FilterToBeanProxy}.
56   * </p>
57   *
58   * @author Luke Taylor
59   * @version $Id: X509ProcessingFilter.java,v 1.5 2005/03/18 01:00:34 luke_t Exp $
60   */
61  public class X509ProcessingFilter implements Filter, InitializingBean {
62      //~ Static fields/initializers =============================================
63  
64      private static final Log logger = LogFactory.getLog(X509ProcessingFilter.class);
65  
66      //~ Instance fields ========================================================
67  
68      private AuthenticationManager authenticationManager;
69  
70      //~ Methods ================================================================
71  
72      public void setAuthenticationManager(AuthenticationManager authenticationManager) {
73          this.authenticationManager = authenticationManager;
74      }
75  
76      public void afterPropertiesSet() throws Exception {
77          Assert.notNull(authenticationManager, "An AuthenticationManager must be set");
78      }
79  
80      /**
81       * This method first checks for an existing, non-null authentication in the
82       * secure context. If one is found it does nothing.
83       * <p>
84       * If no authentication object exists, it attempts to obtain the client
85       * authentication certificate from the request. If there is no certificate
86       * present then authentication is skipped. Otherwise a new authentication
87       * request containing the certificate will be passed to the configured
88       * {@link AuthenticationManager}.
89       * </p>
90       * <p>
91       * If authentication is successful the returned token will be stored in
92       * the secure context. Otherwise it will be set to null.
93       * In either case, the request proceeds through the filter chain.
94       * </p>
95       */
96      public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException {
97          if (!(request instanceof HttpServletRequest)) {
98              throw new ServletException("Can only process HttpServletRequest");
99          }
100 
101         if (!(response instanceof HttpServletResponse)) {
102             throw new ServletException("Can only process HttpServletResponse");
103         }
104 
105         HttpServletRequest httpRequest = (HttpServletRequest) request;
106         HttpServletResponse httpResponse = (HttpServletResponse) response;
107 
108         SecureContext ctx = SecureContextUtils.getSecureContext();
109 
110         logger.debug("Checking secure context token: " + ctx.getAuthentication());
111 
112         if (ctx.getAuthentication() == null) {
113 
114             Authentication authResult = null;
115             X509Certificate clientCertificate = extractClientCertificate(httpRequest);
116 
117             try {
118                 X509AuthenticationToken authRequest = new X509AuthenticationToken(clientCertificate);
119 
120                 authRequest.setDetails(new WebAuthenticationDetails(httpRequest));
121                 authResult = authenticationManager.authenticate(authRequest);
122                 successfulAuthentication(httpRequest, httpResponse, authResult);
123             } catch (AuthenticationException failed) {
124                 unsuccessfulAuthentication(httpRequest, httpResponse, failed);
125             }
126         }
127         filterChain.doFilter(request, response);
128     }
129 
130     private X509Certificate extractClientCertificate(HttpServletRequest request) {
131         X509Certificate[] certs = (X509Certificate[]) request.getAttribute("javax.servlet.request.X509Certificate");
132 
133         if (certs != null && certs.length > 0) {
134             return certs[0];
135         }
136 
137         if (logger.isDebugEnabled()) {
138             logger.debug("No client certificate found in request.");
139         }
140 
141         return null;
142     }
143 
144     /**
145      * Puts the <code>Authentication</code> instance returned by the authentication manager into
146      * the secure context.
147      */
148     protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, Authentication authResult)
149         throws IOException {
150 
151         if (logger.isDebugEnabled()) {
152             logger.debug("Authentication success: " + authResult);
153         }
154         SecureContext sc = SecureContextUtils.getSecureContext();
155         sc.setAuthentication(authResult);
156     }
157 
158     /**
159      * Ensures the authentication object in the secure context is set to null when authentication fails.
160      *
161      */
162     protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException failed) {
163         SecureContext sc = SecureContextUtils.getSecureContext();
164 
165         sc.setAuthentication(null);
166         ContextHolder.setContext(sc);
167 
168         if (logger.isDebugEnabled()) {
169             logger.debug("Updated ContextHolder to contain null Authentication");
170         }
171 
172         request.getSession().setAttribute(AbstractProcessingFilter.ACEGI_SECURITY_LAST_EXCEPTION_KEY, failed);
173     }
174 
175     public void init(FilterConfig filterConfig) throws ServletException { }
176 
177     public void destroy() { }
178 
179 }