Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGreg Wilkins2015-12-23 06:15:24 +0000
committerGreg Wilkins2015-12-23 06:15:24 +0000
commit19d6e36ab961b9b8db97c66ebde973f36e37f959 (patch)
tree4b4a956dcfb6a17f2c0d12220728c0c0d1e82d58
parentf65a7db8c53113c25635b7f46567abce6a88e559 (diff)
downloadorg.eclipse.jetty.project-19d6e36ab961b9b8db97c66ebde973f36e37f959.tar.gz
org.eclipse.jetty.project-19d6e36ab961b9b8db97c66ebde973f36e37f959.tar.xz
org.eclipse.jetty.project-19d6e36ab961b9b8db97c66ebde973f36e37f959.zip
484657 - Support HSTS rfc6797
-rw-r--r--examples/embedded/src/main/java/org/eclipse/jetty/embedded/ManyConnectors.java5
-rw-r--r--jetty-http/src/main/java/org/eclipse/jetty/http/HttpHeader.java4
-rw-r--r--jetty-server/src/main/java/org/eclipse/jetty/server/SecureRequestCustomizer.java121
3 files changed, 124 insertions, 6 deletions
diff --git a/examples/embedded/src/main/java/org/eclipse/jetty/embedded/ManyConnectors.java b/examples/embedded/src/main/java/org/eclipse/jetty/embedded/ManyConnectors.java
index 34a12c09cb..53758ef75c 100644
--- a/examples/embedded/src/main/java/org/eclipse/jetty/embedded/ManyConnectors.java
+++ b/examples/embedded/src/main/java/org/eclipse/jetty/embedded/ManyConnectors.java
@@ -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
diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpHeader.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpHeader.java
index 54735cb57a..0772da4682 100644
--- a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpHeader.java
+++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpHeader.java
@@ -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())
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/SecureRequestCustomizer.java b/jetty-server/src/main/java/org/eclipse/jetty/server/SecureRequestCustomizer.java
index 7dc74588d8..c7409aaf93 100644
--- a/jetty-server/src/main/java/org/eclipse/jetty/server/SecureRequestCustomizer.java
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/SecureRequestCustomizer.java
@@ -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();

Back to the top