[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