View Javadoc

1   //
2   //  ========================================================================
3   //  Copyright (c) 1995-2016 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.SSLContext;
24  import javax.net.ssl.SSLEngine;
25  import javax.net.ssl.SSLSession;
26  import javax.servlet.ServletRequest;
27  
28  import org.eclipse.jetty.http.HttpScheme;
29  import org.eclipse.jetty.io.ssl.SslConnection;
30  import org.eclipse.jetty.io.ssl.SslConnection.DecryptedEndPoint;
31  import org.eclipse.jetty.util.TypeUtil;
32  import org.eclipse.jetty.util.log.Log;
33  import org.eclipse.jetty.util.log.Logger;
34  import org.eclipse.jetty.util.ssl.SslContextFactory;
35  
36  
37  /* ------------------------------------------------------------ */
38  /** Customizer that extracts the attribute from an {@link SSLContext}
39   * and sets them on the request with {@link ServletRequest#setAttribute(String, Object)}
40   * according to Servlet Specification Requirements.
41   */
42  public class SecureRequestCustomizer implements HttpConfiguration.Customizer
43  {
44      private static final Logger LOG = Log.getLogger(SecureRequestCustomizer.class);
45      
46      /**
47       * The name of the SSLSession attribute that will contain any cached information.
48       */
49      public static final String CACHED_INFO_ATTR = CachedInfo.class.getName();
50  
51      private String sslSessionAttribute = "org.eclipse.jetty.servlet.request.ssl_session";
52  
53      @Override
54      public void customize(Connector connector, HttpConfiguration channelConfig, Request request)
55      {
56          if (request.getHttpChannel().getEndPoint() instanceof DecryptedEndPoint)
57          {
58              request.setScheme(HttpScheme.HTTPS.asString());
59              request.setSecure(true);
60              SslConnection.DecryptedEndPoint ssl_endp = (DecryptedEndPoint)request.getHttpChannel().getEndPoint();
61              SslConnection sslConnection = ssl_endp.getSslConnection();
62              SSLEngine sslEngine=sslConnection.getSSLEngine();
63              customize(sslEngine,request);
64          }
65      }
66  
67      /* ------------------------------------------------------------ */
68      /*
69       * Customise the request attributes to be set for SSL requests. <br>
70       * The requirements of the Servlet specs are:
71       * <ul>
72       * <li> an attribute named "javax.servlet.request.ssl_session_id" of type
73       * String (since Servlet Spec 3.0).</li>
74       * <li> an attribute named "javax.servlet.request.cipher_suite" of type
75       * String.</li>
76       * <li> an attribute named "javax.servlet.request.key_size" of type Integer.</li>
77       * <li> an attribute named "javax.servlet.request.X509Certificate" of type
78       * java.security.cert.X509Certificate[]. This is an array of objects of type
79       * X509Certificate, the order of this array is defined as being in ascending
80       * order of trust. The first certificate in the chain is the one set by the
81       * client, the next is the one used to authenticate the first, and so on.
82       * </li>
83       * </ul>
84       *
85       * @param request
86       *                HttpRequest to be customised.
87       */
88      public void customize(SSLEngine sslEngine, Request request)
89      {
90          request.setScheme(HttpScheme.HTTPS.asString());
91          SSLSession sslSession = sslEngine.getSession();
92  
93          try
94          {
95              String cipherSuite=sslSession.getCipherSuite();
96              Integer keySize;
97              X509Certificate[] certs;
98              String idStr;
99  
100             CachedInfo cachedInfo=(CachedInfo)sslSession.getValue(CACHED_INFO_ATTR);
101             if (cachedInfo!=null)
102             {
103                 keySize=cachedInfo.getKeySize();
104                 certs=cachedInfo.getCerts();
105                 idStr=cachedInfo.getIdStr();
106             }
107             else 
108             {
109                 keySize=new Integer(SslContextFactory.deduceKeyLength(cipherSuite));
110                 certs=SslContextFactory.getCertChain(sslSession);
111                 byte[] bytes = sslSession.getId();
112                 idStr = TypeUtil.toHexString(bytes);
113                 cachedInfo=new CachedInfo(keySize,certs,idStr);
114                 sslSession.putValue(CACHED_INFO_ATTR,cachedInfo);
115             }
116 
117             if (certs!=null)
118                 request.setAttribute("javax.servlet.request.X509Certificate",certs);
119 
120             request.setAttribute("javax.servlet.request.cipher_suite",cipherSuite);
121             request.setAttribute("javax.servlet.request.key_size",keySize);
122             request.setAttribute("javax.servlet.request.ssl_session_id", idStr);
123             request.setAttribute(getSslSessionAttribute(), sslSession);
124         }
125         catch (Exception e)
126         {
127             LOG.warn(Log.EXCEPTION,e);
128         }
129     }
130     
131     public void setSslSessionAttribute(String attribute)
132     {
133         this.sslSessionAttribute = attribute;
134     }
135 
136     public String getSslSessionAttribute()
137     {
138         return sslSessionAttribute;
139     }
140 
141     @Override
142     public String toString()
143     {
144         return String.format("%s@%x",this.getClass().getSimpleName(),hashCode());
145     }
146     
147     /* ------------------------------------------------------------ */
148     /* ------------------------------------------------------------ */
149     /* ------------------------------------------------------------ */
150     /**
151      * Simple bundle of information that is cached in the SSLSession. Stores the
152      * effective keySize and the client certificate chain.
153      */
154     private static class CachedInfo
155     {
156         private final X509Certificate[] _certs;
157         private final Integer _keySize;
158         private final String _idStr;
159 
160         CachedInfo(Integer keySize, X509Certificate[] certs,String idStr)
161         {
162             this._keySize=keySize;
163             this._certs=certs;
164             this._idStr=idStr;
165         }
166 
167         X509Certificate[] getCerts()
168         {
169             return _certs;
170         }
171 
172         Integer getKeySize()
173         {
174             return _keySize;
175         }
176 
177         String getIdStr()
178         {
179             return _idStr;
180         }
181     }
182 
183 
184 
185 }