View Javadoc

1   //
2   //  ========================================================================
3   //  Copyright (c) 1995-2015 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      @Override
52      public void customize(Connector connector, HttpConfiguration channelConfig, Request request)
53      {
54          if (request.getHttpChannel().getEndPoint() instanceof DecryptedEndPoint)
55          {
56              request.setScheme(HttpScheme.HTTPS.asString());
57              request.setSecure(true);
58              SslConnection.DecryptedEndPoint ssl_endp = (DecryptedEndPoint)request.getHttpChannel().getEndPoint();
59              SslConnection sslConnection = ssl_endp.getSslConnection();
60              SSLEngine sslEngine=sslConnection.getSSLEngine();
61              customize(sslEngine,request);
62          }
63      }
64  
65      /* ------------------------------------------------------------ */
66      /*
67       * Customise the request attributes to be set for SSL requests. <br>
68       * The requirements of the Servlet specs are:
69       * <ul>
70       * <li> an attribute named "javax.servlet.request.ssl_session_id" of type
71       * String (since Servlet Spec 3.0).</li>
72       * <li> an attribute named "javax.servlet.request.cipher_suite" of type
73       * String.</li>
74       * <li> an attribute named "javax.servlet.request.key_size" of type Integer.</li>
75       * <li> an attribute named "javax.servlet.request.X509Certificate" of type
76       * java.security.cert.X509Certificate[]. This is an array of objects of type
77       * X509Certificate, the order of this array is defined as being in ascending
78       * order of trust. The first certificate in the chain is the one set by the
79       * client, the next is the one used to authenticate the first, and so on.
80       * </li>
81       * </ul>
82       *
83       * @param request
84       *                HttpRequest to be customised.
85       */
86      public void customize(SSLEngine sslEngine, Request request)
87      {
88          request.setScheme(HttpScheme.HTTPS.asString());
89          SSLSession sslSession = sslEngine.getSession();
90  
91          try
92          {
93              String cipherSuite=sslSession.getCipherSuite();
94              Integer keySize;
95              X509Certificate[] certs;
96              String idStr;
97  
98              CachedInfo cachedInfo=(CachedInfo)sslSession.getValue(CACHED_INFO_ATTR);
99              if (cachedInfo!=null)
100             {
101                 keySize=cachedInfo.getKeySize();
102                 certs=cachedInfo.getCerts();
103                 idStr=cachedInfo.getIdStr();
104             }
105             else 
106             {
107                 keySize=new Integer(SslContextFactory.deduceKeyLength(cipherSuite));
108                 certs=SslContextFactory.getCertChain(sslSession);
109                 byte[] bytes = sslSession.getId();
110                 idStr = TypeUtil.toHexString(bytes);
111                 cachedInfo=new CachedInfo(keySize,certs,idStr);
112                 sslSession.putValue(CACHED_INFO_ATTR,cachedInfo);
113             }
114 
115             if (certs!=null)
116                 request.setAttribute("javax.servlet.request.X509Certificate",certs);
117 
118             request.setAttribute("javax.servlet.request.cipher_suite",cipherSuite);
119             request.setAttribute("javax.servlet.request.key_size",keySize);
120             request.setAttribute("javax.servlet.request.ssl_session_id", idStr);
121         }
122         catch (Exception e)
123         {
124             LOG.warn(Log.EXCEPTION,e);
125         }
126     }
127 
128     @Override
129     public String toString()
130     {
131         return String.format("%s@%x",this.getClass().getSimpleName(),hashCode());
132     }
133     
134     /* ------------------------------------------------------------ */
135     /* ------------------------------------------------------------ */
136     /* ------------------------------------------------------------ */
137     /**
138      * Simple bundle of information that is cached in the SSLSession. Stores the
139      * effective keySize and the client certificate chain.
140      */
141     private static class CachedInfo
142     {
143         private final X509Certificate[] _certs;
144         private final Integer _keySize;
145         private final String _idStr;
146 
147         CachedInfo(Integer keySize, X509Certificate[] certs,String idStr)
148         {
149             this._keySize=keySize;
150             this._certs=certs;
151             this._idStr=idStr;
152         }
153 
154         X509Certificate[] getCerts()
155         {
156             return _certs;
157         }
158 
159         Integer getKeySize()
160         {
161             return _keySize;
162         }
163 
164         String getIdStr()
165         {
166             return _idStr;
167         }
168     }
169 
170 
171 
172 }