[java-opensaml] 02/02: OSJ-393 - Add CSP protection to OpenSAML messaging templates

Scott Cantor cantor.2 at osu.edu
Tue Oct 31 20:03:49 UTC 2023


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

scantor pushed a commit to branch dev/OSJ-393
in repository java-opensaml.

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

commit e633037c0a681dc54c03eb79eb51a8ff89b4d750
Author: Scott Cantor <cantor.2 at osu.edu>
AuthorDate: Tue Oct 31 16:03:09 2023 -0400

    OSJ-393 - Add CSP protection to OpenSAML messaging templates
    
    https://shibboleth.atlassian.net/browse/OSJ-393
    
    New interface added for injection of CSP objects.
    Conditional logic used to apply the changes.
    Tests updated.
---
 .../messaging/encoder/HTMLMessageEncoder.java      | 47 ++++++++++++++++++++++
 .../binding/encoding/impl/HTTPPostEncoder.java     | 38 ++++++++++++++++-
 .../binding/encoding/impl/HTTPArtifactEncoder.java | 36 ++++++++++++++++-
 .../binding/encoding/impl/HTTPPostEncoder.java     | 35 +++++++++++++++-
 .../main/resources/templates/saml1-post-binding.vm |  7 +++-
 .../templates/saml2-post-artifact-binding.vm       |  7 +++-
 .../main/resources/templates/saml2-post-binding.vm |  7 +++-
 .../templates/saml2-post-simplesign-binding.vm     |  7 +++-
 .../binding/encoding/impl/HTTPPostEncoderTest.java |  9 ++++-
 .../binding/encoding/impl/HTTPPostEncoderTest.java | 12 ++++++
 .../impl/HTTPPostSimpleSignEncoderTest.java        | 17 ++++++++
 11 files changed, 211 insertions(+), 11 deletions(-)

diff --git a/opensaml-messaging-api/src/main/java/org/opensaml/messaging/encoder/HTMLMessageEncoder.java b/opensaml-messaging-api/src/main/java/org/opensaml/messaging/encoder/HTMLMessageEncoder.java
new file mode 100644
index 000000000..de534a8c6
--- /dev/null
+++ b/opensaml-messaging-api/src/main/java/org/opensaml/messaging/encoder/HTMLMessageEncoder.java
@@ -0,0 +1,47 @@
+/*
+ * Licensed 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 org.opensaml.messaging.encoder;
+
+import javax.annotation.Nullable;
+
+import net.shibboleth.shared.codec.StringDigester;
+import net.shibboleth.shared.security.IdentifierGenerationStrategy;
+
+/**
+ * Interface for a {@link MessageEncoder} that relies on HTML output, and thus requires CSP considerations.
+ * 
+ * @since 5.1.0
+ */
+public interface HTMLMessageEncoder extends MessageEncoder {
+    
+    /**
+     * Set a {@link StringDigester} to use to generate CSP hashes.
+     * 
+     * @param digester string digester
+     * 
+     * @since 5.1.0
+     */
+    void setCSPDigester(@Nullable final StringDigester digester);
+    
+    /**
+     * Set a {@link IdentifierGenerationStrategy} to use to generate CSP nonces.
+     * 
+     * @param strategy nonce strategy
+     * 
+     * @since 5.1.0
+     */
+    void setCSPNonceGenerator(@Nullable final IdentifierGenerationStrategy strategy);
+
+}
\ No newline at end of file
diff --git a/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml1/binding/encoding/impl/HTTPPostEncoder.java b/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml1/binding/encoding/impl/HTTPPostEncoder.java
index 24a0984f5..825ccdee1 100644
--- a/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml1/binding/encoding/impl/HTTPPostEncoder.java
+++ b/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml1/binding/encoding/impl/HTTPPostEncoder.java
@@ -23,8 +23,11 @@ import javax.annotation.Nullable;
 
 import org.apache.velocity.VelocityContext;
 import org.apache.velocity.app.VelocityEngine;
+import org.opensaml.core.config.ConfigurationProperties;
+import org.opensaml.core.config.ConfigurationService;
 import org.opensaml.core.xml.XMLObject;
 import org.opensaml.messaging.context.MessageContext;
+import org.opensaml.messaging.encoder.HTMLMessageEncoder;
 import org.opensaml.messaging.encoder.MessageEncodingException;
 import org.opensaml.saml.common.SAMLObject;
 import org.opensaml.saml.common.binding.SAMLBindingSupport;
@@ -36,8 +39,10 @@ import net.shibboleth.shared.annotation.constraint.NotEmpty;
 import net.shibboleth.shared.codec.Base64Support;
 import net.shibboleth.shared.codec.EncodingException;
 import net.shibboleth.shared.codec.HTMLEncoder;
+import net.shibboleth.shared.codec.StringDigester;
 import net.shibboleth.shared.component.ComponentInitializationException;
 import net.shibboleth.shared.primitive.LoggerFactory;
+import net.shibboleth.shared.security.IdentifierGenerationStrategy;
 import net.shibboleth.shared.servlet.HttpServletSupport;
 import net.shibboleth.shared.xml.SerializeSupport;
 
@@ -46,7 +51,7 @@ import jakarta.servlet.http.HttpServletResponse;
 /**
  * SAML 1.X HTTP POST message encoder.
  */
-public class HTTPPostEncoder extends BaseSAML1MessageEncoder {
+public class HTTPPostEncoder extends BaseSAML1MessageEncoder implements HTMLMessageEncoder {
     
     /** Default template ID. */
     @Nonnull @NotEmpty public static final String DEFAULT_TEMPLATE_ID = "/templates/saml1-post-binding.vm";
@@ -60,6 +65,12 @@ public class HTTPPostEncoder extends BaseSAML1MessageEncoder {
     /** ID of the velocity template used when performing POST encoding. */
     @NonnullAfterInit private String velocityTemplateId;
     
+    /** Digester for CSP hashes. */
+    @Nullable private StringDigester cspDigester;
+
+    /** Generator for CSP nonces. */
+    @Nullable private IdentifierGenerationStrategy cspNonceGenerator;
+    
     /** Constructor. */
     public HTTPPostEncoder() {
         setVelocityTemplateId(DEFAULT_TEMPLATE_ID);
@@ -111,6 +122,18 @@ public class HTTPPostEncoder extends BaseSAML1MessageEncoder {
         checkSetterPreconditions();
         velocityTemplateId = newVelocityTemplateId;
     }
+    
+    /** {@inheritDoc} */
+    public void setCSPDigester(@Nullable final StringDigester digester) {
+        checkSetterPreconditions();
+        cspDigester = digester;
+    }
+    
+    /** {@inheritDoc} */
+    public void setCSPNonceGenerator(@Nullable final IdentifierGenerationStrategy strategy) {
+        checkSetterPreconditions();
+        cspNonceGenerator = strategy;
+    }
 
     /** {@inheritDoc} */
     protected void doInitialize() throws ComponentInitializationException {
@@ -157,6 +180,15 @@ public class HTTPPostEncoder extends BaseSAML1MessageEncoder {
             log.debug("Encoding action url of '{}' with encoded value '{}'", endpointURL, encodedEndpointURL);
             context.put("action", encodedEndpointURL);
             context.put("binding", getBindingURI());
+            
+            if (cspDigester != null) {
+                log.trace("Adding CSP digester to context");
+                context.put("cspDigester", cspDigester);
+            }
+            if (cspNonceGenerator != null) {
+                log.trace("Adding CSP nonce generator to context");
+                context.put("cspNonce", cspNonceGenerator);
+            }
 
             log.debug("Marshalling and Base64 encoding SAML message");
             final String messageXML = SerializeSupport.nodeToString(marshallMessage(message));
@@ -172,6 +204,7 @@ public class HTTPPostEncoder extends BaseSAML1MessageEncoder {
             
             final HttpServletResponse response = getHttpServletResponse();
             assert response != null;
+            context.put("response", response);
             
             HttpServletSupport.addNoCacheHeaders(response);
             HttpServletSupport.setUTF8Encoding(response);
@@ -192,4 +225,5 @@ public class HTTPPostEncoder extends BaseSAML1MessageEncoder {
             throw new MessageEncodingException("Error creating output document", e);
         }
     }
-}
+
+}
\ No newline at end of file
diff --git a/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/binding/encoding/impl/HTTPArtifactEncoder.java b/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/binding/encoding/impl/HTTPArtifactEncoder.java
index 13f4ab394..20cd05454 100644
--- a/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/binding/encoding/impl/HTTPArtifactEncoder.java
+++ b/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/binding/encoding/impl/HTTPArtifactEncoder.java
@@ -25,6 +25,7 @@ import javax.annotation.Nullable;
 import org.apache.velocity.VelocityContext;
 import org.apache.velocity.app.VelocityEngine;
 import org.opensaml.messaging.context.MessageContext;
+import org.opensaml.messaging.encoder.HTMLMessageEncoder;
 import org.opensaml.messaging.encoder.MessageEncodingException;
 import org.opensaml.saml.common.SAMLObject;
 import org.opensaml.saml.common.binding.SAMLBindingSupport;
@@ -46,17 +47,19 @@ import net.shibboleth.shared.annotation.constraint.NotEmpty;
 import net.shibboleth.shared.codec.Base64Support;
 import net.shibboleth.shared.codec.EncodingException;
 import net.shibboleth.shared.codec.HTMLEncoder;
+import net.shibboleth.shared.codec.StringDigester;
 import net.shibboleth.shared.collection.Pair;
 import net.shibboleth.shared.component.ComponentInitializationException;
 import net.shibboleth.shared.logic.Constraint;
 import net.shibboleth.shared.net.URLBuilder;
 import net.shibboleth.shared.primitive.LoggerFactory;
 import net.shibboleth.shared.primitive.StringSupport;
+import net.shibboleth.shared.security.IdentifierGenerationStrategy;
 
 /**
  * SAML 2 Artifact Binding encoder, support both HTTP GET and POST.
  */
-public class HTTPArtifactEncoder extends BaseSAML2MessageEncoder {
+public class HTTPArtifactEncoder extends BaseSAML2MessageEncoder implements HTMLMessageEncoder {
     
     /** Default template ID. */
     @Nonnull @NotEmpty public static final String DEFAULT_TEMPLATE_ID = "/templates/saml2-post-artifact-binding.vm";
@@ -73,6 +76,12 @@ public class HTTPArtifactEncoder extends BaseSAML2MessageEncoder {
     /** ID of the velocity template used when performing POST encoding. */
     @Nonnull @NotEmpty private String velocityTemplateId;
 
+    /** Digester for CSP hashes. */
+    @Nullable private StringDigester cspDigester;
+
+    /** Generator for CSP nonces. */
+    @Nullable private IdentifierGenerationStrategy cspNonceGenerator;
+    
     /** SAML artifact map used to store created artifacts for later retrieval. */
     @NonnullAfterInit private SAMLArtifactMap artifactMap;
 
@@ -154,6 +163,18 @@ public class HTTPArtifactEncoder extends BaseSAML2MessageEncoder {
         velocityTemplateId = Constraint.isNotNull(StringSupport.trimOrNull(newVelocityTemplateId),
                 "Velocity template ID cannot be null or empty");
     }
+    
+    /** {@inheritDoc} */
+    public void setCSPDigester(@Nullable final StringDigester digester) {
+        checkSetterPreconditions();
+        cspDigester = digester;
+    }
+    
+    /** {@inheritDoc} */
+    public void setCSPNonceGenerator(@Nullable final IdentifierGenerationStrategy strategy) {
+        checkSetterPreconditions();
+        cspNonceGenerator = strategy;
+    }
 
     /**
      * Get the SAML artifact map to use.
@@ -228,6 +249,15 @@ public class HTTPArtifactEncoder extends BaseSAML2MessageEncoder {
             throw new MessageEncodingException("Unable to base64 encode SAML 2 artifact when creating POST form",e);
         }
         context.put("binding", getBindingURI());
+        
+        if (cspDigester != null) {
+            log.trace("Adding CSP digester to context");
+            context.put("cspDigester", cspDigester);
+        }
+        if (cspNonceGenerator != null) {
+            log.trace("Adding CSP nonce generator to context");
+            context.put("cspNonce", cspNonceGenerator);
+        }
 
         final String relayState = SAMLBindingSupport.getRelayState(messageContext);
         if (SAMLBindingSupport.checkRelayState(relayState)) {
@@ -236,9 +266,11 @@ public class HTTPArtifactEncoder extends BaseSAML2MessageEncoder {
             context.put("RelayState", encodedRelayState);
         }
 
+        final HttpServletResponse response = getHttpServletResponse();
+        context.put("response", response);
+
         try {
             log.debug("Invoking velocity template");
-            final HttpServletResponse response = getHttpServletResponse();
             try (final OutputStreamWriter outWriter = new OutputStreamWriter(response.getOutputStream())) {
                 assert velocityEngine != null;
                 velocityEngine.mergeTemplate(velocityTemplateId, "UTF-8", context, outWriter);
diff --git a/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/binding/encoding/impl/HTTPPostEncoder.java b/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/binding/encoding/impl/HTTPPostEncoder.java
index dd6bc4986..1dd9840a2 100644
--- a/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/binding/encoding/impl/HTTPPostEncoder.java
+++ b/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/binding/encoding/impl/HTTPPostEncoder.java
@@ -24,6 +24,7 @@ import javax.annotation.Nullable;
 import org.apache.velocity.VelocityContext;
 import org.apache.velocity.app.VelocityEngine;
 import org.opensaml.messaging.context.MessageContext;
+import org.opensaml.messaging.encoder.HTMLMessageEncoder;
 import org.opensaml.messaging.encoder.MessageEncodingException;
 import org.opensaml.saml.common.SAMLObject;
 import org.opensaml.saml.common.binding.SAMLBindingSupport;
@@ -38,10 +39,12 @@ import net.shibboleth.shared.annotation.constraint.NotEmpty;
 import net.shibboleth.shared.codec.Base64Support;
 import net.shibboleth.shared.codec.EncodingException;
 import net.shibboleth.shared.codec.HTMLEncoder;
+import net.shibboleth.shared.codec.StringDigester;
 import net.shibboleth.shared.component.ComponentInitializationException;
 import net.shibboleth.shared.logic.Constraint;
 import net.shibboleth.shared.primitive.LoggerFactory;
 import net.shibboleth.shared.primitive.StringSupport;
+import net.shibboleth.shared.security.IdentifierGenerationStrategy;
 import net.shibboleth.shared.servlet.HttpServletSupport;
 import net.shibboleth.shared.xml.SerializeSupport;
 
@@ -50,7 +53,7 @@ import jakarta.servlet.http.HttpServletResponse;
 /**
  * SAML 2.0 HTTP Post binding message encoder.
  */
-public class HTTPPostEncoder extends BaseSAML2MessageEncoder {
+public class HTTPPostEncoder extends BaseSAML2MessageEncoder implements HTMLMessageEncoder {
     
     /** Default template ID. */
     @Nonnull @NotEmpty public static final String DEFAULT_TEMPLATE_ID = "/templates/saml2-post-binding.vm";
@@ -64,6 +67,12 @@ public class HTTPPostEncoder extends BaseSAML2MessageEncoder {
     /** ID of the Velocity template used when performing POST encoding. */
     @Nonnull private String velocityTemplateId;
     
+    /** Digester for CSP hashes. */
+    @Nullable private StringDigester cspDigester;
+
+    /** Generator for CSP nonces. */
+    @Nullable private IdentifierGenerationStrategy cspNonceGenerator;
+    
     /** Constructor. */
     public HTTPPostEncoder() {
         velocityTemplateId = DEFAULT_TEMPLATE_ID;
@@ -116,7 +125,19 @@ public class HTTPPostEncoder extends BaseSAML2MessageEncoder {
         velocityTemplateId = Constraint.isNotNull(StringSupport.trimOrNull(newVelocityTemplateId),
                 "Velocity template ID cannot be null or empty");
     }
-
+    
+    /** {@inheritDoc} */
+    public void setCSPDigester(@Nullable final StringDigester digester) {
+        checkSetterPreconditions();
+        cspDigester = digester;
+    }
+    
+    /** {@inheritDoc} */
+    public void setCSPNonceGenerator(@Nullable final IdentifierGenerationStrategy strategy) {
+        checkSetterPreconditions();
+        cspNonceGenerator = strategy;
+    }
+    
     /** {@inheritDoc} */
     protected void doInitialize() throws ComponentInitializationException {
         super.doInitialize();
@@ -159,6 +180,7 @@ public class HTTPPostEncoder extends BaseSAML2MessageEncoder {
 
             final HttpServletResponse response = getHttpServletResponse();
             assert response != null;
+            context.put("response", response);
             
             HttpServletSupport.addNoCacheHeaders(response);
             HttpServletSupport.setUTF8Encoding(response);
@@ -191,6 +213,15 @@ public class HTTPPostEncoder extends BaseSAML2MessageEncoder {
         velocityContext.put("action", encodedEndpointURL);
         velocityContext.put("binding", getBindingURI());
         
+        if (cspDigester != null) {
+            log.trace("Adding CSP digester to context");
+            velocityContext.put("cspDigester", cspDigester);
+        }
+        if (cspNonceGenerator != null) {
+            log.trace("Adding CSP nonce generator to context");
+            velocityContext.put("cspNonce", cspNonceGenerator);
+        }
+        
         final SAMLObject outboundMessage = (SAMLObject) messageContext.getMessage();
         // Checked above.
         assert outboundMessage != null;
diff --git a/opensaml-saml-impl/src/main/resources/templates/saml1-post-binding.vm b/opensaml-saml-impl/src/main/resources/templates/saml1-post-binding.vm
index f4807d3e0..7abc5427a 100644
--- a/opensaml-saml-impl/src/main/resources/templates/saml1-post-binding.vm
+++ b/opensaml-saml-impl/src/main/resources/templates/saml1-post-binding.vm
@@ -2,11 +2,16 @@
 ## Velocity Template for SAML 1 HTTP-POST binding
 ##
 ## Velocity context may contain the following properties
+## response - HttpServletResponse
+## cspDigester - Calculates base64-encoded SHA-2 hashes (call apply)
+## cspNonce - Calculates secure nonces (call generateIdentifier)
 ## action - String - the action URL for the form
 ## binding - String - the SAML binding type in use
 ## TARGET - String - the relay state for the message
 ## SAMLResponse - String - the Base64 encoded SAML Response
 ##
+#set ($onLoad="document.forms[0].submit()")
+#if ($cspDigester)$response.addHeader("Content-Security-Policy", "script-src-attr 'unsafe-hashes' 'sha256-$cspDigester.apply($onLoad)'")#end
 <!DOCTYPE html>
 <html>
 
@@ -15,7 +20,7 @@
         #parse ( "/templates/add-html-head-content.vm" )
     </head>
 
-    <body onload="document.forms[0].submit()">
+    <body onload="$onLoad">
         <noscript>
             <p>
                 <strong>Note:</strong> Since your browser does not support JavaScript,
diff --git a/opensaml-saml-impl/src/main/resources/templates/saml2-post-artifact-binding.vm b/opensaml-saml-impl/src/main/resources/templates/saml2-post-artifact-binding.vm
index 25a91ebdf..0d294ba29 100644
--- a/opensaml-saml-impl/src/main/resources/templates/saml2-post-artifact-binding.vm
+++ b/opensaml-saml-impl/src/main/resources/templates/saml2-post-artifact-binding.vm
@@ -2,18 +2,23 @@
 ## Velocity Template for SAML 2 HTTP-POST binding
 ##
 ## Velocity context may contain the following properties
+## response - HttpServletResponse
+## cspDigester - Calculates base64-encoded SHA-2 hashes (call apply)
+## cspNonce - Calculates secure nonces (call generateIdentifier)
 ## action - String - the action URL for the form
 ## binding - String - the SAML binding type in use
 ## RelayState - String - the relay state for the message
 ## SAMLArt - String - SAML 2 artifact
 ##
+#set ($onLoad="document.forms[0].submit()")
+#if ($cspDigester)$response.addHeader("Content-Security-Policy", "script-src-attr 'unsafe-hashes' 'sha256-$cspDigester.apply($onLoad)'")#end
 <!DOCTYPE html>
 <html>
     <head>
         <meta charset="utf-8" />
         #parse ( "/templates/add-html-head-content.vm" )
     </head>
-    <body onload="document.forms[0].submit()">
+    <body onload="$onLoad">
         <noscript>
             <p>
                 <strong>Note:</strong> Since your browser does not support JavaScript,
diff --git a/opensaml-saml-impl/src/main/resources/templates/saml2-post-binding.vm b/opensaml-saml-impl/src/main/resources/templates/saml2-post-binding.vm
index c0473e0a6..45dd1966d 100644
--- a/opensaml-saml-impl/src/main/resources/templates/saml2-post-binding.vm
+++ b/opensaml-saml-impl/src/main/resources/templates/saml2-post-binding.vm
@@ -2,19 +2,24 @@
 ## Velocity Template for SAML 2 HTTP-POST binding
 ##
 ## Velocity context may contain the following properties
+## response - HttpServletResponse
+## cspDigester - Calculates base64-encoded SHA-2 hashes (call apply)
+## cspNonce - Calculates secure nonces (call generateIdentifier)
 ## action - String - the action URL for the form
 ## binding - String - the SAML binding type in use
 ## RelayState - String - the relay state for the message
 ## SAMLRequest - String - the Base64 encoded SAML Request
 ## SAMLResponse - String - the Base64 encoded SAML Response
 ##
+#set ($onLoad="document.forms[0].submit()")
+#if ($cspDigester)$response.addHeader("Content-Security-Policy", "script-src-attr 'unsafe-hashes' 'sha256-$cspDigester.apply($onLoad)'")#end
 <!DOCTYPE html>
 <html>
     <head>
         <meta charset="utf-8" />
         #parse ( "/templates/add-html-head-content.vm" )
     </head>
-    <body onload="document.forms[0].submit()">
+    <body onload="$onLoad">
         <noscript>
             <p>
                 <strong>Note:</strong> Since your browser does not support JavaScript,
diff --git a/opensaml-saml-impl/src/main/resources/templates/saml2-post-simplesign-binding.vm b/opensaml-saml-impl/src/main/resources/templates/saml2-post-simplesign-binding.vm
index 0c7b7df24..f4917df5b 100644
--- a/opensaml-saml-impl/src/main/resources/templates/saml2-post-simplesign-binding.vm
+++ b/opensaml-saml-impl/src/main/resources/templates/saml2-post-simplesign-binding.vm
@@ -2,6 +2,9 @@
 ## Velocity Template for SAML 2 HTTP-POST-SimpleSign binding
 ##
 ## Velocity context may contain the following properties
+## response - HttpServletResponse
+## cspDigester - Calculates base64-encoded SHA-2 hashes (call apply)
+## cspNonce - Calculates secure nonces (call generateIdentifier)
 ## action - String - the action URL for the form
 ## binding - String - the SAML binding type in use
 ## RelayState - String - the relay state for the message
@@ -11,13 +14,15 @@
 ## SigAlg - String - the signature algorithm URI
 ## KeyInfo - String - the Base64 encoded ds:KeyInfo (optional)
 ##
+#set ($onLoad="document.forms[0].submit()")
+#if ($cspDigester)$response.addHeader("Content-Security-Policy", "script-src-attr 'unsafe-hashes' 'sha256-$cspDigester.apply($onLoad)'")#end
 <!DOCTYPE html>
 <html>
     <head>
         <meta charset="utf-8" />
         #parse ( "/templates/add-html-head-content.vm" )
     </head>
-    <body onload="document.forms[0].submit()">
+    <body onload="$onLoad">
         <noscript>
             <p>
                 <strong>Note:</strong> Since your browser does not support JavaScript,
diff --git a/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml1/binding/encoding/impl/HTTPPostEncoderTest.java b/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml1/binding/encoding/impl/HTTPPostEncoderTest.java
index 8409f2cf3..1053de5a6 100644
--- a/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml1/binding/encoding/impl/HTTPPostEncoderTest.java
+++ b/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml1/binding/encoding/impl/HTTPPostEncoderTest.java
@@ -44,6 +44,8 @@ import org.testng.annotations.BeforeMethod;
 import org.testng.annotations.Test;
 
 import net.shibboleth.shared.codec.Base64Support;
+import net.shibboleth.shared.codec.StringDigester;
+import net.shibboleth.shared.codec.StringDigester.OutputFormat;
 import net.shibboleth.shared.testing.ConstantSupplier;
 
 /**
@@ -59,7 +61,7 @@ public class HTTPPostEncoderTest extends XMLObjectBaseTestCase {
     public void setUp() throws Exception {
         velocityEngine = new VelocityEngine();
         velocityEngine.setProperty(RuntimeConstants.RESOURCE_LOADERS, "classpath");
-        velocityEngine.setProperty("classpath.resource.loader.class",
+        velocityEngine.setProperty("resource.loader.classpath.class",
                 "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader");
         velocityEngine.init();
     }
@@ -96,6 +98,8 @@ public class HTTPPostEncoderTest extends XMLObjectBaseTestCase {
         encoder.setHttpServletResponseSupplier(new ConstantSupplier<>(response));
         
         encoder.setVelocityEngine(velocityEngine);
+        
+        encoder.setCSPDigester(new StringDigester("SHA-256", OutputFormat.HEX_LOWER));
 
         encoder.initialize();
         encoder.prepareContext();
@@ -105,6 +109,9 @@ public class HTTPPostEncoderTest extends XMLObjectBaseTestCase {
         Assert.assertEquals("UTF-8", response.getCharacterEncoding(), "Unexpected character encoding");
         Assert.assertEquals(response.getHeader("Cache-control"), "no-cache, no-store", "Unexpected cache controls");
         
+        final String csp = response.getHeader("Content-Security-Policy");
+        Assert.assertTrue(csp != null && csp.contains("script-src-attr 'unsafe-hashes' 'sha256-78f9e25449128af5ff73b5d604669faa1f2d4a9891aca8aa61ea9b1bb3754ce1"));
+        
         Document webDoc = Jsoup.parse(response.getContentAsString());
         
         boolean sawDocType = false;
diff --git a/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml2/binding/encoding/impl/HTTPPostEncoderTest.java b/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml2/binding/encoding/impl/HTTPPostEncoderTest.java
index e18057e78..ba02a8fd9 100644
--- a/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml2/binding/encoding/impl/HTTPPostEncoderTest.java
+++ b/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml2/binding/encoding/impl/HTTPPostEncoderTest.java
@@ -47,6 +47,8 @@ import org.testng.annotations.BeforeMethod;
 import org.testng.annotations.Test;
 
 import net.shibboleth.shared.codec.Base64Support;
+import net.shibboleth.shared.codec.StringDigester;
+import net.shibboleth.shared.codec.StringDigester.OutputFormat;
 import net.shibboleth.shared.testing.ConstantSupplier;
 
 /**
@@ -118,10 +120,15 @@ public class HTTPPostEncoderTest extends XMLObjectBaseTestCase {
         
         encoder.setVelocityEngine(velocityEngine);
         
+        encoder.setCSPDigester(new StringDigester("SHA-256", OutputFormat.HEX_LOWER));
+        
         encoder.initialize();
         encoder.prepareContext();
         encoder.encode();
 
+        final String csp = response.getHeader("Content-Security-Policy");
+        Assert.assertTrue(csp != null && csp.contains("script-src-attr 'unsafe-hashes' 'sha256-78f9e25449128af5ff73b5d604669faa1f2d4a9891aca8aa61ea9b1bb3754ce1"));
+
         Assert.assertEquals(response.getContentType(), "text/html;charset=UTF-8", "Unexpected content type");
         Assert.assertEquals("UTF-8", response.getCharacterEncoding(), "Unexpected character encoding");
         Assert.assertEquals(response.getHeader("Cache-control"), "no-cache, no-store", "Unexpected cache controls");
@@ -212,10 +219,15 @@ public class HTTPPostEncoderTest extends XMLObjectBaseTestCase {
         
         encoder.setVelocityEngine(velocityEngine);
         
+        encoder.setCSPDigester(new StringDigester("SHA-256", OutputFormat.HEX_LOWER));
+
         encoder.initialize();
         encoder.prepareContext();
         encoder.encode();
 
+        final String csp = response.getHeader("Content-Security-Policy");
+        Assert.assertTrue(csp != null && csp.contains("script-src-attr 'unsafe-hashes' 'sha256-78f9e25449128af5ff73b5d604669faa1f2d4a9891aca8aa61ea9b1bb3754ce1"));
+        
         Assert.assertEquals(response.getContentType(), "text/html;charset=UTF-8", "Unexpected content type");
         Assert.assertEquals("UTF-8", response.getCharacterEncoding(), "Unexpected character encoding");
         Assert.assertEquals(response.getHeader("Cache-control"), "no-cache, no-store", "Unexpected cache controls");
diff --git a/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml2/binding/encoding/impl/HTTPPostSimpleSignEncoderTest.java b/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml2/binding/encoding/impl/HTTPPostSimpleSignEncoderTest.java
index 649c1bef1..8c1667245 100644
--- a/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml2/binding/encoding/impl/HTTPPostSimpleSignEncoderTest.java
+++ b/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml2/binding/encoding/impl/HTTPPostSimpleSignEncoderTest.java
@@ -59,6 +59,8 @@ import org.testng.annotations.BeforeMethod;
 import org.testng.annotations.Test;
 
 import net.shibboleth.shared.codec.Base64Support;
+import net.shibboleth.shared.codec.StringDigester;
+import net.shibboleth.shared.codec.StringDigester.OutputFormat;
 import net.shibboleth.shared.testing.ConstantSupplier;
 
 /**
@@ -130,10 +132,15 @@ public class HTTPPostSimpleSignEncoderTest extends XMLObjectBaseTestCase {
         
         encoder.setVelocityEngine(velocityEngine);
         
+        encoder.setCSPDigester(new StringDigester("SHA-256", OutputFormat.HEX_LOWER));
+
         encoder.initialize();
         encoder.prepareContext();
         encoder.encode();
 
+        final String csp = response.getHeader("Content-Security-Policy");
+        Assert.assertTrue(csp != null && csp.contains("script-src-attr 'unsafe-hashes' 'sha256-78f9e25449128af5ff73b5d604669faa1f2d4a9891aca8aa61ea9b1bb3754ce1"));
+
         Assert.assertEquals(response.getContentType(), "text/html;charset=UTF-8", "Unexpected content type");
         Assert.assertEquals("UTF-8", response.getCharacterEncoding(), "Unexpected character encoding");
         Assert.assertEquals(response.getHeader("Cache-control"), "no-cache, no-store", "Unexpected cache controls");
@@ -223,10 +230,15 @@ public class HTTPPostSimpleSignEncoderTest extends XMLObjectBaseTestCase {
         
         encoder.setVelocityEngine(velocityEngine);
         
+        encoder.setCSPDigester(new StringDigester("SHA-256", OutputFormat.HEX_LOWER));
+
         encoder.initialize();
         encoder.prepareContext();
         encoder.encode();
 
+        final String csp = response.getHeader("Content-Security-Policy");
+        Assert.assertTrue(csp != null && csp.contains("script-src-attr 'unsafe-hashes' 'sha256-78f9e25449128af5ff73b5d604669faa1f2d4a9891aca8aa61ea9b1bb3754ce1"));
+        
         Assert.assertEquals(response.getContentType(), "text/html;charset=UTF-8", "Unexpected content type");
         Assert.assertEquals("UTF-8", response.getCharacterEncoding(), "Unexpected character encoding");
         Assert.assertEquals(response.getHeader("Cache-control"), "no-cache, no-store", "Unexpected cache controls");
@@ -325,10 +337,15 @@ public class HTTPPostSimpleSignEncoderTest extends XMLObjectBaseTestCase {
         
         encoder.setVelocityEngine(velocityEngine);
         
+        encoder.setCSPDigester(new StringDigester("SHA-256", OutputFormat.HEX_LOWER));
+        
         encoder.initialize();
         encoder.prepareContext();
         encoder.encode();
         
+        final String csp = response.getHeader("Content-Security-Policy");
+        Assert.assertTrue(csp != null && csp.contains("script-src-attr 'unsafe-hashes' 'sha256-78f9e25449128af5ff73b5d604669faa1f2d4a9891aca8aa61ea9b1bb3754ce1"));
+
         Document webDoc = Jsoup.parse(response.getContentAsString());
         
         boolean sawDocType = false;

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


More information about the commits mailing list