You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@shiro.apache.org by fp...@apache.org on 2020/10/20 19:16:37 UTC

[shiro] 01/03: SslFilter with HTTP Strict Transport Security (HSTS)

This is an automated email from the ASF dual-hosted git repository.

fpapon pushed a commit to branch 1.7.x
in repository https://gitbox.apache.org/repos/asf/shiro.git

commit 243e8924420518348141644175fb3dbfe0335f47
Author: Björn Raupach <ra...@e2n.de>
AuthorDate: Tue Jan 10 10:03:36 2017 +0100

    SslFilter with HTTP Strict Transport Security (HSTS)
---
 .../apache/shiro/web/filter/authz/SslFilter.java   | 84 +++++++++++++++++++++-
 1 file changed, 82 insertions(+), 2 deletions(-)

diff --git a/web/src/main/java/org/apache/shiro/web/filter/authz/SslFilter.java b/web/src/main/java/org/apache/shiro/web/filter/authz/SslFilter.java
index 3a6ab7a..d85bb23 100644
--- a/web/src/main/java/org/apache/shiro/web/filter/authz/SslFilter.java
+++ b/web/src/main/java/org/apache/shiro/web/filter/authz/SslFilter.java
@@ -20,6 +20,7 @@ package org.apache.shiro.web.filter.authz;
 
 import javax.servlet.ServletRequest;
 import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletResponse;
 
 /**
  * Filter which requires a request to be over SSL.  Access is allowed if the request is received on the configured
@@ -30,21 +31,46 @@ import javax.servlet.ServletResponse;
  * The {@link #getPort() port} property defaults to {@code 443} and also additionally guarantees that the
  * request scheme is always 'https' (except for port 80, which retains the 'http' scheme).
  * <p/>
- * Example config:
+ * In addition the filter allows enabling HTTP Strict Transport Security (HSTS).
+ * This feature is opt-in and disabled by default. If enabled HSTS
+ * will prevent <b>any</b> communications from being sent over HTTP to the 
+ * specified domain and will instead send all communications over HTTPS.
+ * </p>
+ * <b>Warning:</b> Use this setting only if you plan to enable SSL on every path.
+ * </p>
+ * Example configs:
  * <pre>
  * [urls]
  * /secure/path/** = ssl
  * </pre>
- *
+ * with HSTS enabled
+ * <pre>
+ * [main]
+ * ssl.hsts.enabled = true
+ * [urls]
+ * /** = ssl
+ * </pre>
  * @since 1.0
+ * @see <a href="https://tools.ietf.org/html/rfc6797">HTTP Strict Transport Security (HSTS)</a>
  */
 public class SslFilter extends PortFilter {
 
     public static final int DEFAULT_HTTPS_PORT = 443;
     public static final String HTTPS_SCHEME = "https";
+    
+    private HSTS hsts;
 
     public SslFilter() {
         setPort(DEFAULT_HTTPS_PORT);
+        this.hsts = new HSTS();
+    }
+
+    public HSTS getHsts() {
+        return hsts;
+    }
+
+    public void setHsts(HSTS hsts) {
+        this.hsts = hsts;
     }
 
     @Override
@@ -73,4 +99,58 @@ public class SslFilter extends PortFilter {
     protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) throws Exception {
         return super.isAccessAllowed(request, response, mappedValue) && request.isSecure();
     }
+
+    @Override
+    protected void postHandle(ServletRequest request, ServletResponse response) throws Exception {
+        if (hsts.enabled) {
+            StringBuilder directives = new StringBuilder(64);
+            directives.append("max-age=").append(hsts.getMaxAge());
+            if (hsts.includeSubDomains) {
+                directives.append("; includeSubDomains");
+            }
+            HttpServletResponse resp = (HttpServletResponse) response;
+            resp.addHeader("Strict-Transport-Security", directives.toString());
+        }
+    }
+    
+    public class HSTS {
+        
+        static final boolean DEFAULT_ENABLED = false;
+        public static final int DEFAULT_EXPIRE_TIME = 31536000; // approx. one year in seconds
+        public static final boolean DEFAULT_INCLUDE_SUB_DOMAINS = false;
+        
+        private boolean enabled;
+        private int maxAge;
+        private boolean includeSubDomains;
+        
+        public HSTS() {
+            this.maxAge = DEFAULT_EXPIRE_TIME;
+            this.includeSubDomains = DEFAULT_INCLUDE_SUB_DOMAINS;
+        }
+
+        public boolean isEnabled() {
+            return enabled;
+        }
+
+        public void setEnabled(boolean enabled) {
+            this.enabled = enabled;
+        }
+
+        public int getMaxAge() {
+            return maxAge;
+        }
+
+        public void setMaxAge(int maxAge) {
+            this.maxAge = maxAge;
+        }
+
+        public boolean isIncludeSubDomains() {
+            return includeSubDomains;
+        }
+
+        public void setIncludeSubDomains(boolean includeSubDomains) {
+            this.includeSubDomains = includeSubDomains;
+        }
+        
+    }
 }