1   // ========================================================================
2   // Copyright 2002-2005 Mort Bay Consulting Pty. Ltd.
3   // ------------------------------------------------------------------------
4   // Licensed under the Apache License, Version 2.0 (the "License");
5   // you may not use this file except in compliance with the License.
6   // You may obtain a copy of the License at 
7   // http://www.apache.org/licenses/LICENSE-2.0
8   // Unless required by applicable law or agreed to in writing, software
9   // distributed under the License is distributed on an "AS IS" BASIS,
10  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11  // See the License for the specific language governing permissions and
12  // limitations under the License.
13  // ========================================================================
14  
15  package org.mortbay.jetty.ssl;
16  
17  import java.io.IOException;
18  import java.security.Principal;
19  
20  import javax.servlet.http.HttpServletResponse;
21  
22  import org.mortbay.jetty.Authenticator;
23  import org.mortbay.jetty.Request;
24  import org.mortbay.jetty.Response;
25  import org.mortbay.jetty.UserRealm;
26  import org.mortbay.jetty.security.Constraint;
27  
28  /* ------------------------------------------------------------ */
29  /** Client Certificate Authenticator.
30   * This Authenticator uses a client certificate to authenticate the user.
31   * Each client certificate supplied is tried against the realm using the
32   * Principal name as the username and a string representation of the
33   * certificate as the credential.
34   * @author Greg Wilkins (gregw)
35   */
36  public class ClientCertAuthenticator implements Authenticator
37  {
38      private int _maxHandShakeSeconds =60;
39      
40      /* ------------------------------------------------------------ */
41      public ClientCertAuthenticator()
42      {
43      }
44      
45      /* ------------------------------------------------------------ */
46      public int getMaxHandShakeSeconds()
47      {
48          return _maxHandShakeSeconds;
49      }
50      
51      /* ------------------------------------------------------------ */
52      /** 
53       * @param maxHandShakeSeconds Maximum time to wait for SSL handshake if
54       * Client certification is required.
55       */
56      public void setMaxHandShakeSeconds(int maxHandShakeSeconds)
57      {
58          _maxHandShakeSeconds = maxHandShakeSeconds;
59      }
60      
61      /* ------------------------------------------------------------ */
62      /** 
63       * @return UserPrinciple if authenticated or null if not. If
64       * Authentication fails, then the authenticator may have committed
65       * the response as an auth challenge or redirect.
66       * @exception IOException 
67       */
68      public Principal authenticate(UserRealm realm,
69              String pathInContext,
70              Request request,
71              Response response)
72          throws IOException
73      {
74          java.security.cert.X509Certificate[] certs =
75              (java.security.cert.X509Certificate[])
76              request.getAttribute("javax.servlet.request.X509Certificate");
77              
78          // Need certificates.
79          if (certs==null || certs.length==0 || certs[0]==null)
80          {
81              if (response != null)
82                  response.sendError(HttpServletResponse.SC_FORBIDDEN,"A client certificate is required for accessing this web application but the server's listener is not configured for mutual authentication (or the client did not provide a certificate).");
83              return null;
84          }
85          
86          Principal principal = certs[0].getSubjectDN();
87          if (principal==null)
88              principal=certs[0].getIssuerDN();
89          String username=principal==null?"clientcert":principal.getName();
90          
91          Principal user = realm.authenticate(username,certs,request);
92          if (user == null)
93          {
94              if (response != null)
95                  response.sendError(HttpServletResponse.SC_FORBIDDEN,"The provided client certificate does not correspond to a trusted user.");
96              return null;
97          }
98          
99          request.setAuthType(Constraint.__CERT_AUTH);
100         request.setUserPrincipal(user);                
101         return user;
102     }
103     
104     /* ------------------------------------------------------------ */
105     public String getAuthMethod()
106     {
107         return Constraint.__CERT_AUTH;
108     }
109 
110 }