484657 - Support HSTS rfc6797
This commit is contained in:
parent
f65a7db8c5
commit
19d6e36ab9
|
@ -97,7 +97,10 @@ public class ManyConnectors
|
||||||
// resolve the https connection before handing control over to the Jetty
|
// resolve the https connection before handing control over to the Jetty
|
||||||
// Server.
|
// Server.
|
||||||
HttpConfiguration https_config = new HttpConfiguration(http_config);
|
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
|
// HTTPS connector
|
||||||
// We create a second ServerConnector, passing in the http configuration
|
// We create a second ServerConnector, passing in the http configuration
|
||||||
|
|
|
@ -112,6 +112,8 @@ public enum HttpHeader
|
||||||
X_POWERED_BY("X-Powered-By"),
|
X_POWERED_BY("X-Powered-By"),
|
||||||
HTTP2_SETTINGS("HTTP2-Settings"),
|
HTTP2_SETTINGS("HTTP2-Settings"),
|
||||||
|
|
||||||
|
STRICT_TRANSPORT_SECURITY("Strict-Transport-Security"),
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
/** HTTP2 Fields.
|
/** 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
|
static
|
||||||
{
|
{
|
||||||
for (HttpHeader header : HttpHeader.values())
|
for (HttpHeader header : HttpHeader.values())
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
package org.eclipse.jetty.server;
|
package org.eclipse.jetty.server;
|
||||||
|
|
||||||
import java.security.cert.X509Certificate;
|
import java.security.cert.X509Certificate;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
import javax.net.ssl.SSLContext;
|
import javax.net.ssl.SSLContext;
|
||||||
import javax.net.ssl.SSLEngine;
|
import javax.net.ssl.SSLEngine;
|
||||||
|
@ -26,10 +27,14 @@ import javax.net.ssl.SSLSession;
|
||||||
import javax.servlet.ServletRequest;
|
import javax.servlet.ServletRequest;
|
||||||
|
|
||||||
import org.eclipse.jetty.http.BadMessageException;
|
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.HttpScheme;
|
||||||
|
import org.eclipse.jetty.http.PreEncodedHttpField;
|
||||||
import org.eclipse.jetty.io.ssl.SslConnection;
|
import org.eclipse.jetty.io.ssl.SslConnection;
|
||||||
import org.eclipse.jetty.io.ssl.SslConnection.DecryptedEndPoint;
|
import org.eclipse.jetty.io.ssl.SslConnection.DecryptedEndPoint;
|
||||||
import org.eclipse.jetty.util.TypeUtil;
|
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.Log;
|
||||||
import org.eclipse.jetty.util.log.Logger;
|
import org.eclipse.jetty.util.log.Logger;
|
||||||
import org.eclipse.jetty.util.ssl.SniX509ExtendedKeyManager;
|
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();
|
public static final String CACHED_INFO_ATTR = CachedInfo.class.getName();
|
||||||
|
|
||||||
private boolean _sniHostCheck;
|
private boolean _sniHostCheck;
|
||||||
|
private long _stsMaxAge=-1;
|
||||||
|
private boolean _stsIncludeSubDomains;
|
||||||
|
private HttpField _stsField;
|
||||||
|
|
||||||
public SecureRequestCustomizer()
|
public SecureRequestCustomizer()
|
||||||
{
|
{
|
||||||
this(true);
|
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;
|
_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
|
@Override
|
||||||
|
@ -68,7 +161,6 @@ public class SecureRequestCustomizer implements HttpConfiguration.Customizer
|
||||||
{
|
{
|
||||||
if (request.getHttpChannel().getEndPoint() instanceof DecryptedEndPoint)
|
if (request.getHttpChannel().getEndPoint() instanceof DecryptedEndPoint)
|
||||||
{
|
{
|
||||||
request.setSecure(true);
|
|
||||||
|
|
||||||
if (request.getHttpURI().getScheme()==null)
|
if (request.getHttpURI().getScheme()==null)
|
||||||
request.setScheme(HttpScheme.HTTPS.asString());
|
request.setScheme(HttpScheme.HTTPS.asString());
|
||||||
|
@ -78,8 +170,29 @@ public class SecureRequestCustomizer implements HttpConfiguration.Customizer
|
||||||
SSLEngine sslEngine=sslConnection.getSSLEngine();
|
SSLEngine sslEngine=sslConnection.getSSLEngine();
|
||||||
customize(sslEngine,request);
|
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>
|
* <p>
|
||||||
* Customizes the request attributes to be set for SSL requests.
|
* Customizes the request attributes to be set for SSL requests.
|
||||||
|
@ -102,7 +215,7 @@ public class SecureRequestCustomizer implements HttpConfiguration.Customizer
|
||||||
* @param request
|
* @param request
|
||||||
* HttpRequest to be customized.
|
* HttpRequest to be customized.
|
||||||
*/
|
*/
|
||||||
public void customize(SSLEngine sslEngine, Request request)
|
protected void customize(SSLEngine sslEngine, Request request)
|
||||||
{
|
{
|
||||||
request.setScheme(HttpScheme.HTTPS.asString());
|
request.setScheme(HttpScheme.HTTPS.asString());
|
||||||
SSLSession sslSession = sslEngine.getSession();
|
SSLSession sslSession = sslEngine.getSession();
|
||||||
|
|
Loading…
Reference in New Issue