1 //
2 // ========================================================================
3 // Copyright (c) 1995-2014 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 }