View Javadoc

1   //
2   //  ========================================================================
3   //  Copyright (c) 1995-2013 Mort Bay Consulting Pty. Ltd.
4   //  ------------------------------------------------------------------------
5   //  All rights reserved. This program and the accompanying materials
6   //  are made available under the terms of the Eclipse Public License v1.0
7   //  and Apache License v2.0 which accompanies this distribution.
8   //
9   //      The Eclipse Public License is available at
10  //      http://www.eclipse.org/legal/epl-v10.html
11  //
12  //      The Apache License v2.0 is available at
13  //      http://www.opensource.org/licenses/apache2.0.php
14  //
15  //  You may elect to redistribute this code under either of these licenses.
16  //  ========================================================================
17  //
18  
19  package org.eclipse.jetty.server;
20  
21  import java.security.cert.X509Certificate;
22  
23  import javax.net.ssl.SSLEngine;
24  import javax.net.ssl.SSLSession;
25  
26  import org.eclipse.jetty.http.HttpScheme;
27  import org.eclipse.jetty.io.ssl.SslConnection;
28  import org.eclipse.jetty.io.ssl.SslConnection.DecryptedEndPoint;
29  import org.eclipse.jetty.util.TypeUtil;
30  import org.eclipse.jetty.util.log.Log;
31  import org.eclipse.jetty.util.log.Logger;
32  import org.eclipse.jetty.util.ssl.SslContextFactory;
33  
34  public class SecureRequestCustomizer implements HttpConfiguration.Customizer
35  {
36      private static final Logger LOG = Log.getLogger(SecureRequestCustomizer.class);
37      
38      /**
39       * The name of the SSLSession attribute that will contain any cached information.
40       */
41      public static final String CACHED_INFO_ATTR = CachedInfo.class.getName();
42  
43  
44      @Override
45      public void customize(Connector connector, HttpConfiguration channelConfig, Request request)
46      {
47          if (request.getHttpChannel().getEndPoint() instanceof DecryptedEndPoint)
48          {
49              request.setScheme(HttpScheme.HTTPS.asString());
50              request.setSecure(true);
51              SslConnection.DecryptedEndPoint ssl_endp = (DecryptedEndPoint)request.getHttpChannel().getEndPoint();
52              SslConnection sslConnection = ssl_endp.getSslConnection();
53              SSLEngine sslEngine=sslConnection.getSSLEngine();
54              customize(sslEngine,request);
55          }
56  
57      }
58  
59      /* ------------------------------------------------------------ */
60      /*
61       * Allow the Listener a chance to customise the request. before the server
62       * does its stuff. <br>
63       * This allows the required attributes to be set for SSL requests. <br>
64       * The requirements of the Servlet specs are:
65       * <ul>
66       * <li> an attribute named "javax.servlet.request.ssl_session_id" of type
67       * String (since Servlet Spec 3.0).</li>
68       * <li> an attribute named "javax.servlet.request.cipher_suite" of type
69       * String.</li>
70       * <li> an attribute named "javax.servlet.request.key_size" of type Integer.</li>
71       * <li> an attribute named "javax.servlet.request.X509Certificate" of type
72       * java.security.cert.X509Certificate[]. This is an array of objects of type
73       * X509Certificate, the order of this array is defined as being in ascending
74       * order of trust. The first certificate in the chain is the one set by the
75       * client, the next is the one used to authenticate the first, and so on.
76       * </li>
77       * </ul>
78       *
79       * @param request
80       *                HttpRequest to be customised.
81       */
82      public void customize(SSLEngine sslEngine, Request request)
83      {
84          request.setScheme(HttpScheme.HTTPS.asString());
85          SSLSession sslSession = sslEngine.getSession();
86  
87          try
88          {
89              String cipherSuite=sslSession.getCipherSuite();
90              Integer keySize;
91              X509Certificate[] certs;
92              String idStr;
93  
94              CachedInfo cachedInfo=(CachedInfo)sslSession.getValue(CACHED_INFO_ATTR);
95              if (cachedInfo!=null)
96              {
97                  keySize=cachedInfo.getKeySize();
98                  certs=cachedInfo.getCerts();
99                  idStr=cachedInfo.getIdStr();
100             }
101             else 
102             {
103                 keySize=new Integer(SslContextFactory.deduceKeyLength(cipherSuite));
104                 certs=SslContextFactory.getCertChain(sslSession);
105                 byte[] bytes = sslSession.getId();
106                 idStr = TypeUtil.toHexString(bytes);
107                 cachedInfo=new CachedInfo(keySize,certs,idStr);
108                 sslSession.putValue(CACHED_INFO_ATTR,cachedInfo);
109             }
110 
111             if (certs!=null)
112                 request.setAttribute("javax.servlet.request.X509Certificate",certs);
113 
114             request.setAttribute("javax.servlet.request.cipher_suite",cipherSuite);
115             request.setAttribute("javax.servlet.request.key_size",keySize);
116             request.setAttribute("javax.servlet.request.ssl_session_id", idStr);
117         }
118         catch (Exception e)
119         {
120             LOG.warn(Log.EXCEPTION,e);
121         }
122     }
123 
124     @Override
125     public String toString()
126     {
127         return String.format("%s@%x",this.getClass().getSimpleName(),hashCode());
128     }
129     
130     /* ------------------------------------------------------------ */
131     /* ------------------------------------------------------------ */
132     /* ------------------------------------------------------------ */
133     /**
134      * Simple bundle of information that is cached in the SSLSession. Stores the
135      * effective keySize and the client certificate chain.
136      */
137     private static class CachedInfo
138     {
139         private final X509Certificate[] _certs;
140         private final Integer _keySize;
141         private final String _idStr;
142 
143         CachedInfo(Integer keySize, X509Certificate[] certs,String idStr)
144         {
145             this._keySize=keySize;
146             this._certs=certs;
147             this._idStr=idStr;
148         }
149 
150         X509Certificate[] getCerts()
151         {
152             return _certs;
153         }
154 
155         Integer getKeySize()
156         {
157             return _keySize;
158         }
159 
160         String getIdStr()
161         {
162             return _idStr;
163         }
164     }
165 
166 
167 
168 }