484657 - Support HSTS rfc6797

This commit is contained in:
Greg Wilkins 2015-12-23 17:15:24 +11:00
parent f65a7db8c5
commit 19d6e36ab9
3 changed files with 124 additions and 6 deletions

View File

@ -97,7 +97,10 @@ public class ManyConnectors
// resolve the https connection before handing control over to the Jetty
// Server.
HttpConfiguration https_config = new HttpConfiguration(http_config);
https_config.addCustomizer(new SecureRequestCustomizer());
SecureRequestCustomizer src = new SecureRequestCustomizer();
src.setStsMaxAge(2000);
src.setStsIncludeSubDomains(true);
https_config.addCustomizer(src);
// HTTPS connector
// We create a second ServerConnector, passing in the http configuration

View File

@ -112,6 +112,8 @@ public enum HttpHeader
X_POWERED_BY("X-Powered-By"),
HTTP2_SETTINGS("HTTP2-Settings"),
STRICT_TRANSPORT_SECURITY("Strict-Transport-Security"),
/* ------------------------------------------------------------ */
/** HTTP2 Fields.
*/
@ -125,7 +127,7 @@ public enum HttpHeader
/* ------------------------------------------------------------ */
public final static Trie<HttpHeader> CACHE= new ArrayTrie<>(530);
public final static Trie<HttpHeader> CACHE= new ArrayTrie<>(560);
static
{
for (HttpHeader header : HttpHeader.values())

View File

@ -19,6 +19,7 @@
package org.eclipse.jetty.server;
import java.security.cert.X509Certificate;
import java.util.concurrent.TimeUnit;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLEngine;
@ -26,10 +27,14 @@ import javax.net.ssl.SSLSession;
import javax.servlet.ServletRequest;
import org.eclipse.jetty.http.BadMessageException;
import org.eclipse.jetty.http.HttpField;
import org.eclipse.jetty.http.HttpHeader;
import org.eclipse.jetty.http.HttpScheme;
import org.eclipse.jetty.http.PreEncodedHttpField;
import org.eclipse.jetty.io.ssl.SslConnection;
import org.eclipse.jetty.io.ssl.SslConnection.DecryptedEndPoint;
import org.eclipse.jetty.util.TypeUtil;
import org.eclipse.jetty.util.annotation.Name;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
import org.eclipse.jetty.util.ssl.SniX509ExtendedKeyManager;
@ -51,16 +56,104 @@ public class SecureRequestCustomizer implements HttpConfiguration.Customizer
public static final String CACHED_INFO_ATTR = CachedInfo.class.getName();
private boolean _sniHostCheck;
private long _stsMaxAge=-1;
private boolean _stsIncludeSubDomains;
private HttpField _stsField;
public SecureRequestCustomizer()
{
this(true);
}
public SecureRequestCustomizer(boolean sniHostCheck)
public SecureRequestCustomizer(@Name("sniHostCheck")boolean sniHostCheck)
{
this(sniHostCheck,-1,false);
}
/**
* @param sniHostCheck True if the SNI Host name must match.
* @param stsMaxAgeSeconds The max age in seconds for a Strict-Transport-Security response header. If set less than zero then no header is sent.
* @param stsIncludeSubdomains If true, a include subdomain property is sent with any Strict-Transport-Security header
*/
public SecureRequestCustomizer(
@Name("sniHostCheck")boolean sniHostCheck,
@Name("stsMaxAgeSeconds")long stsMaxAgeSeconds,
@Name("stsIncludeSubdomains")boolean stsIncludeSubdomains)
{
_sniHostCheck=sniHostCheck;
_stsMaxAge=stsMaxAgeSeconds;
_stsIncludeSubDomains=stsIncludeSubdomains;
formatSTS();
}
/**
* @return True if the SNI Host name must match.
*/
public boolean isSniHostCheck()
{
return _sniHostCheck;
}
/**
* @param sniHostCheck True if the SNI Host name must match.
*/
public void setSniHostCheck(boolean sniHostCheck)
{
_sniHostCheck = sniHostCheck;
}
/**
* @return The max age in seconds for a Strict-Transport-Security response header. If set less than zero then no header is sent.
*/
public long getStsMaxAge()
{
return _stsMaxAge;
}
/**
* Set the Strict-Transport-Security max age.
* @param stsMaxAgeSeconds The max age in seconds for a Strict-Transport-Security response header. If set less than zero then no header is sent.
*/
public void setStsMaxAge(long stsMaxAgeSeconds)
{
_stsMaxAge = stsMaxAgeSeconds;
formatSTS();
}
/**
* Convenience method to call {@link #setStsMaxAge(long)}
* @param period The period in units
* @param units The {@link TimeUnit} of the period
*/
public void setStsMaxAge(long period,TimeUnit units)
{
_stsMaxAge = units.toSeconds(period);
formatSTS();
}
/**
* @return true if a include subdomain property is sent with any Strict-Transport-Security header
*/
public boolean isStsIncludeSubDomains()
{
return _stsIncludeSubDomains;
}
/**
* @param stsIncludeSubDomains If true, a include subdomain property is sent with any Strict-Transport-Security header
*/
public void setStsIncludeSubDomains(boolean stsIncludeSubDomains)
{
_stsIncludeSubDomains = stsIncludeSubDomains;
formatSTS();
}
private void formatSTS()
{
if (_stsMaxAge<0)
_stsField=null;
else
_stsField=new PreEncodedHttpField(HttpHeader.STRICT_TRANSPORT_SECURITY,String.format("max-age=%d%s",_stsMaxAge,_stsIncludeSubDomains?"; includeSubDomains":""));
}
@Override
@ -68,7 +161,6 @@ public class SecureRequestCustomizer implements HttpConfiguration.Customizer
{
if (request.getHttpChannel().getEndPoint() instanceof DecryptedEndPoint)
{
request.setSecure(true);
if (request.getHttpURI().getScheme()==null)
request.setScheme(HttpScheme.HTTPS.asString());
@ -78,8 +170,29 @@ public class SecureRequestCustomizer implements HttpConfiguration.Customizer
SSLEngine sslEngine=sslConnection.getSSLEngine();
customize(sslEngine,request);
}
if (HttpScheme.HTTPS.is(request.getScheme()))
customizeSecure(request);
}
/**
* <p>
* Customizes the request attributes for general secure settings.
* The default impl calls {@link Request#setSecure(boolean)} with true
* and sets a response header if the Strict-Transport-Security options
* are set.
* </p>
*/
protected void customizeSecure(Request request)
{
request.setSecure(true);
if (_stsField!=null)
request.getResponse().getHttpFields().add(_stsField);
}
/**
* <p>
* Customizes the request attributes to be set for SSL requests.
@ -102,7 +215,7 @@ public class SecureRequestCustomizer implements HttpConfiguration.Customizer
* @param request
* HttpRequest to be customized.
*/
public void customize(SSLEngine sslEngine, Request request)
protected void customize(SSLEngine sslEngine, Request request)
{
request.setScheme(HttpScheme.HTTPS.asString());
SSLSession sslSession = sslEngine.getSession();