[java-support] branch master updated: IDP-627 - Support HSTS, CSP, X-Frame-Options, etc.

Scott Cantor cantor.2 at osu.edu
Fri Dec 9 20:54:54 EST 2016


This is an automated email from the git hooks/post-receive script.

scantor pushed a commit to branch master
in repository java-support.

View the commit online:
http://git.shibboleth.net/view/?p=java-support.git;a=commit;h=a54d171d42ba714fb7557d46fdf4ad7acaaca915

The following commit(s) were added to refs/heads/master by this push:
       new  a54d171   IDP-627 - Support HSTS, CSP, X-Frame-Options, etc.
a54d171 is described below

commit a54d171d42ba714fb7557d46fdf4ad7acaaca915
Author: Scott Cantor <cantor.2 at osu.edu>
AuthorDate: Fri Dec 9 20:54:51 2016 -0500

    IDP-627 - Support HSTS, CSP, X-Frame-Options, etc.
    
    https://issues.shibboleth.net/jira/browse/IDP-627
    
    Implement a filter to control response headers.
---
 pom.xml                                            |   4 +-
 .../support/net/DynamicResponseHeaderFilter.java   | 201 +++++++++++++++++++++
 2 files changed, 203 insertions(+), 2 deletions(-)

diff --git a/pom.xml b/pom.xml
index 0326e7a..125e3f2 100644
--- a/pom.xml
+++ b/pom.xml
@@ -7,13 +7,13 @@
     <parent>
         <groupId>net.shibboleth</groupId>
         <artifactId>parent-v3</artifactId>
-        <version>10</version>
+        <version>TRUNK-SNAPSHOT</version>
     </parent>
 
     <name>java-support</name>
     <groupId>net.shibboleth.utilities</groupId>
     <artifactId>java-support</artifactId>
-    <version>7.3.1-SNAPSHOT</version>
+    <version>7.4.0-SNAPSHOT</version>
     <packaging>jar</packaging>
 
     <repositories>
diff --git a/src/main/java/net/shibboleth/utilities/java/support/net/DynamicResponseHeaderFilter.java b/src/main/java/net/shibboleth/utilities/java/support/net/DynamicResponseHeaderFilter.java
new file mode 100644
index 0000000..7f4dfa7
--- /dev/null
+++ b/src/main/java/net/shibboleth/utilities/java/support/net/DynamicResponseHeaderFilter.java
@@ -0,0 +1,201 @@
+/*
+ * Licensed to the University Corporation for Advanced Internet Development,
+ * Inc. (UCAID) under one or more contributor license agreements.  See the
+ * NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The UCAID licenses this file to You under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.shibboleth.utilities.java.support.net;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletException;
+import javax.servlet.ServletOutputStream;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpServletResponseWrapper;
+
+import com.google.common.base.Function;
+import com.google.common.base.Predicates;
+import com.google.common.collect.Collections2;
+
+import net.shibboleth.utilities.java.support.annotation.constraint.NonnullElements;
+import net.shibboleth.utilities.java.support.collection.Pair;
+import net.shibboleth.utilities.java.support.primitive.StringSupport;
+
+/**
+ * Implementation of an HTTP servlet {@link Filter} which supports configurable response header
+ * injection, including via injected functions that can conditionally attach headers.
+ */
+public class DynamicResponseHeaderFilter implements Filter {
+    
+    /** Statically defined headers to return. */
+    @Nonnull @NonnullElements private Map<String,String> headers;
+
+    /** Callbacks to add headers dynamically. */
+    @Nonnull @NonnullElements
+    private Collection<Function<Pair<HttpServletRequest,HttpServletResponse>,Boolean>> callbacks;
+    
+    /** Constructor. */
+    public DynamicResponseHeaderFilter() {
+        headers = Collections.emptyMap();
+        callbacks = Collections.emptyList();
+    }
+    
+    /**
+     * Set the headers to statically attach to all responses.
+     * 
+     * @param map   header map
+     */
+    public void setHeaders(@Nullable @NonnullElements final Map<String,String> map) {
+        if (map != null) {
+            headers = new HashMap<>(map.size());
+            for (final Map.Entry<String,String> entry : map.entrySet()) {
+                final String trimmed = StringSupport.trimOrNull(entry.getKey());
+                if (trimmed != null && entry.getValue() != null) {
+                    headers.put(trimmed, entry.getValue());
+                }
+            }
+        } else {
+            headers = Collections.emptyMap();
+        }
+    }
+    
+    /**
+     * Set the callbacks to invoke to dynamically attach headers.
+     * 
+     * @param theCallbacks callback collection
+     */
+    public void setCallbacks(@Nullable @NonnullElements
+            final Collection<Function<Pair<HttpServletRequest,HttpServletResponse>,Boolean>> theCallbacks) {
+        if (theCallbacks != null) {
+            callbacks = new ArrayList<>(Collections2.filter(theCallbacks, Predicates.notNull()));
+        } else {
+            callbacks = Collections.emptyList();
+        }
+    }
+    
+    /** {@inheritDoc} */
+    public void init(final FilterConfig filterConfig) throws ServletException {
+    }
+
+    /** {@inheritDoc} */
+    public void destroy() {
+    }
+
+    /** {@inheritDoc} */
+    public void doFilter(final ServletRequest request, final ServletResponse response, final FilterChain chain)
+            throws IOException,
+            ServletException {
+        
+        if (headers.isEmpty() && callbacks.isEmpty()) {
+            chain.doFilter(request, response);
+            return;
+        }
+
+        if (!(request instanceof HttpServletRequest)) {
+            throw new ServletException("Request is not an instance of HttpServletRequest");
+        }
+
+        if (!(response instanceof HttpServletResponse)) {
+            throw new ServletException("Response is not an instance of HttpServletResponse");
+        }
+
+        chain.doFilter(request, new ResponseProxy((HttpServletRequest) request, (HttpServletResponse) response));
+    }
+
+    /**
+     * An implementation of {@link HttpServletResponse} which adds the response headers supplied by the outer class.
+     */
+    private class ResponseProxy extends HttpServletResponseWrapper {
+        
+        /** Request. */
+        @Nonnull private final HttpServletRequest request;
+        
+        /**
+         * Constructor.
+         *
+         * @param req the request
+         * @param response the response to delegate to
+         */
+        public ResponseProxy(@Nonnull final HttpServletRequest req, @Nonnull final HttpServletResponse response) {
+            super(response);
+            
+            request = req;
+        }
+    
+        /** {@inheritDoc} */
+        @Override
+        public ServletOutputStream getOutputStream() throws IOException {
+            addHeaders();
+            return super.getOutputStream();
+        }
+
+        /** {@inheritDoc} */
+        @Override
+        public PrintWriter getWriter() throws IOException {
+            addHeaders();
+            return super.getWriter();
+        }
+
+        /** {@inheritDoc} */
+        @Override
+        public void sendError(final int sc, final String msg) throws IOException {
+            addHeaders();
+            super.sendError(sc, msg);
+        }
+
+        /** {@inheritDoc} */
+        @Override
+        public void sendError(final int sc) throws IOException {
+            addHeaders();
+            super.sendError(sc);
+        }
+
+        /** {@inheritDoc} */
+        @Override
+        public void sendRedirect(final String location) throws IOException {
+            addHeaders();
+            super.sendRedirect(location);
+        }
+        
+        /** Add headers to response. */
+        private void addHeaders() {
+            for (final Map.Entry<String, String> header : headers.entrySet()) {
+                ((HttpServletResponse) getResponse()).addHeader(header.getKey(), header.getValue());
+            }
+            
+            if (!callbacks.isEmpty()) {
+                final Pair<HttpServletRequest,HttpServletResponse> p =
+                        new Pair<>(request, (HttpServletResponse) getResponse());
+                for (final Function<Pair<HttpServletRequest,HttpServletResponse>,Boolean> callback : callbacks) {
+                    callback.apply(p);
+                }
+            }
+        }
+    }
+    
+}
\ No newline at end of file

-- 
To stop receiving notification emails like this one, please contact
the administrator of this repository.


More information about the commits mailing list