[java-identity-provider] 01/01: IDP-2183 - Use of JS in views needs to be hardened via CSP

Scott Cantor cantor.2 at osu.edu
Tue Oct 24 18:28:47 UTC 2023


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

scantor pushed a commit to branch dev/IDP-2183
in repository java-identity-provider.

View the commit online:
http://git.shibboleth.net/view/?p=java-identity-provider.git;a=commit;h=462521ad28548639c84325671e77558f0adf1817

commit 462521ad28548639c84325671e77558f0adf1817
Author: Scott Cantor <cantor.2 at osu.edu>
AuthorDate: Tue Oct 24 14:28:42 2023 -0400

    IDP-2183 - Use of JS in views needs to be hardened via CSP
    
    https://shibboleth.atlassian.net/browse/IDP-2183
    
    Add beans to support hashing and nonce generation.
    Initial CSP support to limit Javascript in views.
---
 idp-authn-impl/pom.xml                             |  9 +++---
 .../authn/spnego/impl/SPNEGOAuthnController.java   | 33 +++++++++++++++++++++-
 .../net/shibboleth/idp/conf/mvc-beans.xml          |  4 ++-
 .../net/shibboleth/idp/conf/primitives.xml         | 25 ++++++++++++++++
 .../net/shibboleth/idp/flows/admin/hello-flow.xml  |  2 ++
 .../shibboleth/idp/flows/admin/mdquery-flow.xml    |  2 ++
 .../idp/flows/admin/resolvertest-flow.xml          |  2 ++
 .../net/shibboleth/idp/flows/admin/status-flow.xml |  2 ++
 .../idp/flows/admin/unlock-keys-flow.xml           |  4 +++
 .../idp/flows/authn/password-authn-flow.xml        |  2 ++
 .../shibboleth/idp/flows/cas/cas-abstract-flow.xml |  2 ++
 .../client-storage/client-storage-read-flow.xml    |  2 ++
 .../client-storage/client-storage-write-flow.xml   |  2 ++
 .../idp/flows/intercept/attribute-release-flow.xml |  2 ++
 .../idp/flows/intercept/expiring-password-flow.xml |  2 ++
 .../idp/flows/intercept/impersonate-flow.xml       |  2 ++
 .../idp/flows/intercept/terms-of-use-flow.xml      |  4 ++-
 .../idp/flows/intercept/warning-flow.xml           |  2 ++
 .../shibboleth/idp/flows/logout/logout-flow.xml    | 10 +++++++
 .../idp/flows/logout/logout-propagation-flow.xml   |  2 ++
 .../idp/flows/saml/saml-abstract-flow.xml          |  4 +++
 .../idp/flows/saml/saml2/slo-back-flow.xml         |  2 ++
 .../flows/saml/saml2/slo-front-abstract-flow.xml   | 10 +++++++
 .../idp/module/flows/user/prefs/prefs-flow.xml     |  2 ++
 .../net/shibboleth/idp/module/views/admin/hello.vm |  1 +
 .../idp/module/views/admin/unlock-keys.vm          |  1 +
 .../views/client-storage/client-storage-read.vm    | 15 ++++++----
 .../views/client-storage/client-storage-write.vm   | 15 ++++++----
 .../net/shibboleth/idp/module/views/error.vm       |  3 ++
 .../module/views/intercept/attribute-release.vm    |  1 +
 .../module/views/intercept/expiring-password.vm    |  1 +
 .../idp/module/views/intercept/impersonate.vm      |  1 +
 .../idp/module/views/intercept/terms-of-use.vm     |  1 +
 .../net/shibboleth/idp/module/views/login.vm       |  7 +++--
 .../shibboleth/idp/module/views/logout-complete.vm |  3 ++
 .../idp/module/views/logout-propagate.vm           |  3 ++
 .../net/shibboleth/idp/module/views/logout.vm      |  3 ++
 .../idp/module/views/spnego-unavailable.vm         |  6 +++-
 .../net/shibboleth/idp/module/views/user-prefs.js  |  2 ++
 .../net/shibboleth/idp/module/views/user-prefs.vm  | 18 +++++++-----
 .../shibboleth/idp/views/client-storage/read.vm    |  6 ++--
 .../shibboleth/idp/views/client-storage/write.vm   |  4 ++-
 .../net/shibboleth/idp/views/logout/propagate.vm   |  4 ++-
 .../net/shibboleth/idp/views/logout/saml-async.vm  |  1 +
 44 files changed, 195 insertions(+), 34 deletions(-)

diff --git a/idp-authn-impl/pom.xml b/idp-authn-impl/pom.xml
index 53b0f3f55..c763c2a88 100644
--- a/idp-authn-impl/pom.xml
+++ b/idp-authn-impl/pom.xml
@@ -104,6 +104,10 @@
             <groupId>${shib-shared.groupId}</groupId>
             <artifactId>shib-networking</artifactId>
         </dependency>
+        <dependency>
+            <groupId>${shib-shared.groupId}</groupId>
+            <artifactId>shib-security</artifactId>
+        </dependency>
         <dependency>
             <groupId>${shib-shared.groupId}</groupId>
             <artifactId>shib-service</artifactId>
@@ -264,11 +268,6 @@
             <scope>test</scope>
         </dependency>
 
-        <dependency>
-            <groupId>${shib-shared.groupId}</groupId>
-            <artifactId>shib-security</artifactId>
-            <scope>test</scope>
-        </dependency>
         <dependency>
             <groupId>${shib-shared.groupId}</groupId>
             <artifactId>shib-testing</artifactId>
diff --git a/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/spnego/impl/SPNEGOAuthnController.java b/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/spnego/impl/SPNEGOAuthnController.java
index f9484960f..43e677fb6 100644
--- a/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/spnego/impl/SPNEGOAuthnController.java
+++ b/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/spnego/impl/SPNEGOAuthnController.java
@@ -43,8 +43,9 @@ import net.shibboleth.idp.authn.context.AuthenticationContext;
 import net.shibboleth.idp.authn.principal.UsernamePrincipal;
 import net.shibboleth.shared.annotation.constraint.NotEmpty;
 import net.shibboleth.shared.codec.HTMLEncoder;
+import net.shibboleth.shared.codec.StringDigester;
 import net.shibboleth.shared.primitive.LoggerFactory;
-
+import net.shibboleth.shared.security.IdentifierGenerationStrategy;
 import jakarta.servlet.http.HttpServletRequest;
 import jakarta.servlet.http.HttpServletResponse;
 
@@ -70,6 +71,34 @@ public class SPNEGOAuthnController {
 
     /** Class logger. */
     @Nonnull private final Logger log = LoggerFactory.getLogger(SPNEGOAuthnController.class);
+    
+    /** CSP digest computation bean. */
+    @Nullable private StringDigester cspDigester;
+    
+    /** CSP nonce generator bean. */
+    @Nullable private IdentifierGenerationStrategy cspNonceGenerator;
+    
+    /**
+     * Sets a {@link StringDigester} to use in computing CSP digests in views.
+     * 
+     * @param digester digester to set
+     * 
+     * @since 5.1.0
+     */
+    public void setCSPDigester(@Nullable final StringDigester digester) {
+        cspDigester = digester;
+    }
+    
+    /**
+     * Sets an {@link IdentifierGenerationStrategy} to use in computing CSP nonces in views.
+     * 
+     * @param strategy nonce strategy
+     * 
+     * @since 5.1.0
+     */
+    public void setCSPNonceGenerator(@Nullable final IdentifierGenerationStrategy strategy) {
+        cspNonceGenerator = strategy;
+    }
 
     /**
      * Handle initial request that starts SPNEGO.
@@ -390,6 +419,8 @@ public class SPNEGOAuthnController {
         modelAndView.addObject("request", httpRequest);
         modelAndView.addObject("response", httpResponse);
         modelAndView.addObject("encoder", HTMLEncoder.class);
+        modelAndView.addObject("cspDigester", cspDigester);
+        modelAndView.addObject("cspNonce", cspNonceGenerator);
         final StringBuffer errorUrl = httpRequest.getRequestURL();
         errorUrl.append("/error");
         final String queryString = httpRequest.getQueryString();
diff --git a/idp-conf-impl/src/main/resources/net/shibboleth/idp/conf/mvc-beans.xml b/idp-conf-impl/src/main/resources/net/shibboleth/idp/conf/mvc-beans.xml
index 86e2104f7..35e087f1c 100644
--- a/idp-conf-impl/src/main/resources/net/shibboleth/idp/conf/mvc-beans.xml
+++ b/idp-conf-impl/src/main/resources/net/shibboleth/idp/conf/mvc-beans.xml
@@ -56,7 +56,9 @@
     
     <!-- Additional MVC controllers scanned for annotations. -->
     
-    <bean id="shibboleth.SPNEGOAuthnController" class="net.shibboleth.idp.authn.spnego.impl.SPNEGOAuthnController" />
+    <bean id="shibboleth.SPNEGOAuthnController" class="net.shibboleth.idp.authn.spnego.impl.SPNEGOAuthnController"
+        p:cSPDigester-ref="shibboleth.CSPDigester"
+        p:cSPNonceGenerator-ref="shibboleth.CSPNonce" />
     <bean id="shibboleth.SAMLAuthnPOSTController" class="net.shibboleth.idp.saml.saml2.profile.impl.SAMLAuthnController"
         p:inboundBindings-ref="shibboleth.OutgoingSAML2SSOBindings" />
     <bean id="shibboleth.RaiseErrorController" class="net.shibboleth.shared.spring.error.ErrorRaisingController" />
diff --git a/idp-conf-impl/src/main/resources/net/shibboleth/idp/conf/primitives.xml b/idp-conf-impl/src/main/resources/net/shibboleth/idp/conf/primitives.xml
index 18ccdc95e..228fc03f4 100644
--- a/idp-conf-impl/src/main/resources/net/shibboleth/idp/conf/primitives.xml
+++ b/idp-conf-impl/src/main/resources/net/shibboleth/idp/conf/primitives.xml
@@ -49,6 +49,31 @@
     <bean id="shibboleth.X509TrustManager" abstract="true"
         class="org.opensaml.security.trust.impl.TrustEngineX509TrustManager" />
 
+    <!-- Used in views to calculate CSP hashes and nonces. -->
+    
+    <bean id="shibboleth.CSPDigester" class="net.shibboleth.shared.codec.StringDigester"
+        c:algorithm="SHA256" c:format="BASE64" />
+
+    <bean id="shibboleth.CSPNonce" destroy-method=""
+            class="net.shibboleth.shared.security.IdentifierGenerationStrategy" factory-method="getInstance">
+        <constructor-arg>
+            <util:constant
+                static-field="net.shibboleth.shared.security.IdentifierGenerationStrategy.ProviderType.SECURE" />
+        </constructor-arg>
+        <constructor-arg>
+            <bean class="net.shibboleth.shared.security.RandomIdentifierParameterSpec"
+                    c:identifierSize="16">
+                <constructor-arg name="source">
+                    <null/>
+                </constructor-arg>
+                <constructor-arg name="identifierEncoder">
+                    <null/>
+                </constructor-arg>
+            </bean>
+        </constructor-arg>
+    </bean>
+    
+
     <!-- Beans for user-visible metadata configuration usage. -->
 
     <!-- Secondary indexing support -->
diff --git a/idp-conf-impl/src/main/resources/net/shibboleth/idp/flows/admin/hello-flow.xml b/idp-conf-impl/src/main/resources/net/shibboleth/idp/flows/admin/hello-flow.xml
index aba96d022..b71d8e7d8 100644
--- a/idp-conf-impl/src/main/resources/net/shibboleth/idp/flows/admin/hello-flow.xml
+++ b/idp-conf-impl/src/main/resources/net/shibboleth/idp/flows/admin/hello-flow.xml
@@ -34,6 +34,8 @@
             <evaluate expression="opensamlProfileRequestContext.getSubcontext(T(net.shibboleth.idp.authn.context.SubjectContext))" result="requestScope.subjectContext" />
             <evaluate expression="opensamlProfileRequestContext.getSubcontext(T(net.shibboleth.profile.context.RelyingPartyContext)).getSubcontext(T(net.shibboleth.idp.attribute.context.AttributeContext))" result="requestScope.attributeContext" />
             <evaluate expression="T(net.shibboleth.shared.codec.HTMLEncoder)" result="requestScope.encoder" />
+            <evaluate expression="flowRequestContext.getActiveFlow().getApplicationContext().getBean('shibboleth.CSPDigester')" result="requestScope.cspDigester" />
+            <evaluate expression="flowRequestContext.getActiveFlow().getApplicationContext().getBean('shibboleth.CSPNonce')" result="requestScope.cspNonce" />
             <evaluate expression="flowRequestContext.getExternalContext().getNativeRequest()" result="requestScope.request" />
             <evaluate expression="flowRequestContext.getExternalContext().getNativeResponse()" result="requestScope.response" />
             <evaluate expression="flowRequestContext.getActiveFlow().getApplicationContext().containsBean('shibboleth.CustomViewContext') ? flowRequestContext.getActiveFlow().getApplicationContext().getBean('shibboleth.CustomViewContext') : null" result="requestScope.custom" />
diff --git a/idp-conf-impl/src/main/resources/net/shibboleth/idp/flows/admin/mdquery-flow.xml b/idp-conf-impl/src/main/resources/net/shibboleth/idp/flows/admin/mdquery-flow.xml
index e1e7bb02e..4f2c4cf47 100644
--- a/idp-conf-impl/src/main/resources/net/shibboleth/idp/flows/admin/mdquery-flow.xml
+++ b/idp-conf-impl/src/main/resources/net/shibboleth/idp/flows/admin/mdquery-flow.xml
@@ -44,6 +44,8 @@
             <evaluate expression="T(org.opensaml.core.xml.util.XMLObjectSupport)" result="requestScope.XMLObjectSupport" />
             <evaluate expression="T(net.shibboleth.shared.xml.SerializeSupport)" result="requestScope.SerializeSupport" />
             <evaluate expression="T(net.shibboleth.shared.codec.HTMLEncoder)" result="requestScope.encoder" />
+            <evaluate expression="flowRequestContext.getActiveFlow().getApplicationContext().getBean('shibboleth.CSPDigester')" result="requestScope.cspDigester" />
+            <evaluate expression="flowRequestContext.getActiveFlow().getApplicationContext().getBean('shibboleth.CSPNonce')" result="requestScope.cspNonce" />
             <evaluate expression="flowRequestContext.getExternalContext().getNativeRequest()" result="requestScope.request" />
             <evaluate expression="flowRequestContext.getExternalContext().getNativeResponse()" result="requestScope.response" />
             <evaluate expression="flowRequestContext.getActiveFlow().getApplicationContext().containsBean('shibboleth.CustomViewContext') ? flowRequestContext.getActiveFlow().getApplicationContext().getBean('shibboleth.CustomViewContext') : null" result="requestScope.custom" />
diff --git a/idp-conf-impl/src/main/resources/net/shibboleth/idp/flows/admin/resolvertest-flow.xml b/idp-conf-impl/src/main/resources/net/shibboleth/idp/flows/admin/resolvertest-flow.xml
index 0619eadbe..f241a59dc 100644
--- a/idp-conf-impl/src/main/resources/net/shibboleth/idp/flows/admin/resolvertest-flow.xml
+++ b/idp-conf-impl/src/main/resources/net/shibboleth/idp/flows/admin/resolvertest-flow.xml
@@ -103,6 +103,8 @@
             <evaluate expression="T(org.opensaml.core.xml.util.XMLObjectSupport)" result="requestScope.XMLObjectSupport" />
             <evaluate expression="T(net.shibboleth.shared.xml.SerializeSupport)" result="requestScope.SerializeSupport" />
             <evaluate expression="T(net.shibboleth.shared.codec.HTMLEncoder)" result="requestScope.encoder" />
+            <evaluate expression="flowRequestContext.getActiveFlow().getApplicationContext().getBean('shibboleth.CSPDigester')" result="requestScope.cspDigester" />
+            <evaluate expression="flowRequestContext.getActiveFlow().getApplicationContext().getBean('shibboleth.CSPNonce')" result="requestScope.cspNonce" />
             <evaluate expression="flowRequestContext.getExternalContext().getNativeRequest()" result="requestScope.request" />
             <evaluate expression="flowRequestContext.getExternalContext().getNativeResponse()" result="requestScope.response" />
             <evaluate expression="flowRequestContext.getActiveFlow().getApplicationContext().containsBean('shibboleth.CustomViewContext') ? flowRequestContext.getActiveFlow().getApplicationContext().getBean('shibboleth.CustomViewContext') : null" result="requestScope.custom" />
diff --git a/idp-conf-impl/src/main/resources/net/shibboleth/idp/flows/admin/status-flow.xml b/idp-conf-impl/src/main/resources/net/shibboleth/idp/flows/admin/status-flow.xml
index cd8d76ffe..ddb4e075b 100644
--- a/idp-conf-impl/src/main/resources/net/shibboleth/idp/flows/admin/status-flow.xml
+++ b/idp-conf-impl/src/main/resources/net/shibboleth/idp/flows/admin/status-flow.xml
@@ -34,6 +34,8 @@
             <evaluate expression="flowRequestContext.getActiveFlow().getApplicationContext().getBean('shibboleth.metrics.MetadataGaugeSet')" result="requestScope.metadataResolverGaugeSet" />            
             <evaluate expression="opensamlProfileRequestContext" result="requestScope.profileRequestContext" />
             <evaluate expression="T(net.shibboleth.shared.codec.HTMLEncoder)" result="requestScope.encoder" />
+            <evaluate expression="flowRequestContext.getActiveFlow().getApplicationContext().getBean('shibboleth.CSPDigester')" result="requestScope.cspDigester" />
+            <evaluate expression="flowRequestContext.getActiveFlow().getApplicationContext().getBean('shibboleth.CSPNonce')" result="requestScope.cspNonce" />
             <evaluate expression="flowRequestContext.getExternalContext().getNativeRequest()" result="requestScope.request" />
             <evaluate expression="flowRequestContext.getExternalContext().getNativeResponse()" result="requestScope.response" />
             <evaluate expression="flowRequestContext.getActiveFlow().getApplicationContext().containsBean('shibboleth.CustomViewContext') ? flowRequestContext.getActiveFlow().getApplicationContext().getBean('shibboleth.CustomViewContext') : null" result="requestScope.custom" />
diff --git a/idp-conf-impl/src/main/resources/net/shibboleth/idp/flows/admin/unlock-keys-flow.xml b/idp-conf-impl/src/main/resources/net/shibboleth/idp/flows/admin/unlock-keys-flow.xml
index 7f79ddf3e..e92bffffc 100644
--- a/idp-conf-impl/src/main/resources/net/shibboleth/idp/flows/admin/unlock-keys-flow.xml
+++ b/idp-conf-impl/src/main/resources/net/shibboleth/idp/flows/admin/unlock-keys-flow.xml
@@ -37,6 +37,8 @@
             <evaluate expression="environment" result="viewScope.environment" />
             <evaluate expression="opensamlProfileRequestContext" result="viewScope.profileRequestContext" />
             <evaluate expression="T(net.shibboleth.shared.codec.HTMLEncoder)" result="viewScope.encoder" />
+            <evaluate expression="flowRequestContext.getActiveFlow().getApplicationContext().getBean('shibboleth.CSPDigester')" result="viewScope.cspDigester" />
+            <evaluate expression="flowRequestContext.getActiveFlow().getApplicationContext().getBean('shibboleth.CSPNonce')" result="viewScope.cspNonce" />
             <evaluate expression="flowRequestContext.getExternalContext().getNativeRequest()" result="viewScope.request" />
             <evaluate expression="flowRequestContext.getExternalContext().getNativeResponse()" result="viewScope.response" />
             <evaluate expression="flowRequestContext.getActiveFlow().getApplicationContext().containsBean('shibboleth.CustomViewContext') ? flowRequestContext.getActiveFlow().getApplicationContext().getBean('shibboleth.CustomViewContext') : null" result="viewScope.custom" />
@@ -64,6 +66,8 @@
             <evaluate expression="environment" result="requestScope.environment" />
             <evaluate expression="opensamlProfileRequestContext" result="requestScope.profileRequestContext" />
             <evaluate expression="T(net.shibboleth.shared.codec.HTMLEncoder)" result="requestScope.encoder" />
+            <evaluate expression="flowRequestContext.getActiveFlow().getApplicationContext().getBean('shibboleth.CSPDigester')" result="requestScope.cspDigester" />
+            <evaluate expression="flowRequestContext.getActiveFlow().getApplicationContext().getBean('shibboleth.CSPNonce')" result="requestScope.cspNonce" />
             <evaluate expression="flowRequestContext.getExternalContext().getNativeRequest()" result="requestScope.request" />
             <evaluate expression="flowRequestContext.getExternalContext().getNativeResponse()" result="requestScope.response" />
             <evaluate expression="flowRequestContext.getActiveFlow().getApplicationContext().containsBean('shibboleth.CustomViewContext') ? flowRequestContext.getActiveFlow().getApplicationContext().getBean('shibboleth.CustomViewContext') : null" result="requestScope.custom" />
diff --git a/idp-conf-impl/src/main/resources/net/shibboleth/idp/flows/authn/password-authn-flow.xml b/idp-conf-impl/src/main/resources/net/shibboleth/idp/flows/authn/password-authn-flow.xml
index 0d1ae192e..c5b103849 100644
--- a/idp-conf-impl/src/main/resources/net/shibboleth/idp/flows/authn/password-authn-flow.xml
+++ b/idp-conf-impl/src/main/resources/net/shibboleth/idp/flows/authn/password-authn-flow.xml
@@ -33,6 +33,8 @@
             <evaluate expression="authenticationContext.getSubcontext(T(net.shibboleth.idp.authn.context.AuthenticationWarningContext))" result="viewScope.authenticationWarningContext" />
             <evaluate expression="authenticationContext.getSubcontext(T(net.shibboleth.idp.authn.context.LDAPResponseContext))" result="viewScope.ldapResponseContext" />
             <evaluate expression="T(net.shibboleth.shared.codec.HTMLEncoder)" result="viewScope.encoder" />
+            <evaluate expression="flowRequestContext.getActiveFlow().getApplicationContext().getBean('shibboleth.CSPDigester')" result="viewScope.cspDigester" />
+            <evaluate expression="flowRequestContext.getActiveFlow().getApplicationContext().getBean('shibboleth.CSPNonce')" result="viewScope.cspNonce" />
             <evaluate expression="flowRequestContext.getExternalContext().getNativeRequest()" result="viewScope.request" />
             <evaluate expression="flowRequestContext.getExternalContext().getNativeResponse()" result="viewScope.response" />
             <evaluate expression="flowRequestContext.getActiveFlow().getApplicationContext().containsBean('shibboleth.CustomViewContext') ? flowRequestContext.getActiveFlow().getApplicationContext().getBean('shibboleth.CustomViewContext') : null" result="viewScope.custom" />
diff --git a/idp-conf-impl/src/main/resources/net/shibboleth/idp/flows/cas/cas-abstract-flow.xml b/idp-conf-impl/src/main/resources/net/shibboleth/idp/flows/cas/cas-abstract-flow.xml
index fa3957f03..d2b5b7e43 100644
--- a/idp-conf-impl/src/main/resources/net/shibboleth/idp/flows/cas/cas-abstract-flow.xml
+++ b/idp-conf-impl/src/main/resources/net/shibboleth/idp/flows/cas/cas-abstract-flow.xml
@@ -33,6 +33,8 @@
             <evaluate expression="environment" result="requestScope.environment" />
             <evaluate expression="opensamlProfileRequestContext" result="requestScope.profileRequestContext" />
             <evaluate expression="T(net.shibboleth.shared.codec.HTMLEncoder)" result="requestScope.encoder" />
+            <evaluate expression="flowRequestContext.getActiveFlow().getApplicationContext().getBean('shibboleth.CSPDigester')" result="requestScope.cspDigester" />
+            <evaluate expression="flowRequestContext.getActiveFlow().getApplicationContext().getBean('shibboleth.CSPNonce')" result="requestScope.cspNonce" />
             <evaluate expression="flowRequestContext.getExternalContext().getNativeRequest()" result="requestScope.request" />
             <evaluate expression="flowRequestContext.getExternalContext().getNativeResponse()" result="requestScope.response" />
             <evaluate expression="flowRequestContext.getActiveFlow().getApplicationContext().containsBean('shibboleth.CustomViewContext') ? flowRequestContext.getActiveFlow().getApplicationContext().getBean('shibboleth.CustomViewContext') : null" result="requestScope.custom" />
diff --git a/idp-conf-impl/src/main/resources/net/shibboleth/idp/flows/client-storage/client-storage-read-flow.xml b/idp-conf-impl/src/main/resources/net/shibboleth/idp/flows/client-storage/client-storage-read-flow.xml
index f5a19a2cd..22c1aef1a 100644
--- a/idp-conf-impl/src/main/resources/net/shibboleth/idp/flows/client-storage/client-storage-read-flow.xml
+++ b/idp-conf-impl/src/main/resources/net/shibboleth/idp/flows/client-storage/client-storage-read-flow.xml
@@ -16,6 +16,8 @@
             <evaluate expression="opensamlProfileRequestContext" result="viewScope.profileRequestContext" />
             <evaluate expression="opensamlProfileRequestContext.getSubcontext(T(org.opensaml.storage.impl.client.ClientStorageLoadContext))" result="viewScope.loadContext" />
             <evaluate expression="T(net.shibboleth.shared.codec.HTMLEncoder)" result="viewScope.encoder" />
+            <evaluate expression="flowRequestContext.getActiveFlow().getApplicationContext().getBean('shibboleth.CSPDigester')" result="viewScope.cspDigester" />
+            <evaluate expression="flowRequestContext.getActiveFlow().getApplicationContext().getBean('shibboleth.CSPNonce')" result="viewScope.cspNonce" />
             <evaluate expression="flowRequestContext.getExternalContext().getNativeRequest()" result="viewScope.request" />
             <evaluate expression="flowRequestContext.getExternalContext().getNativeResponse()" result="viewScope.response" />
         </on-render>
diff --git a/idp-conf-impl/src/main/resources/net/shibboleth/idp/flows/client-storage/client-storage-write-flow.xml b/idp-conf-impl/src/main/resources/net/shibboleth/idp/flows/client-storage/client-storage-write-flow.xml
index b5af21831..31367fd0e 100644
--- a/idp-conf-impl/src/main/resources/net/shibboleth/idp/flows/client-storage/client-storage-write-flow.xml
+++ b/idp-conf-impl/src/main/resources/net/shibboleth/idp/flows/client-storage/client-storage-write-flow.xml
@@ -16,6 +16,8 @@
             <evaluate expression="opensamlProfileRequestContext" result="viewScope.profileRequestContext" />
             <evaluate expression="opensamlProfileRequestContext.getSubcontext(T(org.opensaml.storage.impl.client.ClientStorageSaveContext))" result="viewScope.saveContext" />
             <evaluate expression="T(net.shibboleth.shared.codec.HTMLEncoder)" result="viewScope.encoder" />
+            <evaluate expression="flowRequestContext.getActiveFlow().getApplicationContext().getBean('shibboleth.CSPDigester')" result="viewScope.cspDigester" />
+            <evaluate expression="flowRequestContext.getActiveFlow().getApplicationContext().getBean('shibboleth.CSPNonce')" result="viewScope.cspNonce" />
             <evaluate expression="flowRequestContext.getExternalContext().getNativeRequest()" result="viewScope.request" />
             <evaluate expression="flowRequestContext.getExternalContext().getNativeResponse()" result="viewScope.response" />
         </on-render>
diff --git a/idp-conf-impl/src/main/resources/net/shibboleth/idp/flows/intercept/attribute-release-flow.xml b/idp-conf-impl/src/main/resources/net/shibboleth/idp/flows/intercept/attribute-release-flow.xml
index 2ee911084..262e8e9a9 100644
--- a/idp-conf-impl/src/main/resources/net/shibboleth/idp/flows/intercept/attribute-release-flow.xml
+++ b/idp-conf-impl/src/main/resources/net/shibboleth/idp/flows/intercept/attribute-release-flow.xml
@@ -122,6 +122,8 @@
         <on-render>
             <evaluate expression="environment" result="viewScope.environment" />
             <evaluate expression="T(net.shibboleth.shared.codec.HTMLEncoder)" result="viewScope.encoder" />
+            <evaluate expression="flowRequestContext.getActiveFlow().getApplicationContext().getBean('shibboleth.CSPDigester')" result="viewScope.cspDigester" />
+            <evaluate expression="flowRequestContext.getActiveFlow().getApplicationContext().getBean('shibboleth.CSPNonce')" result="viewScope.cspNonce" />
             <evaluate expression="flowRequestContext.getExternalContext().getNativeRequest()" result="viewScope.request" />
             <evaluate expression="flowRequestContext.getExternalContext().getNativeResponse()" result="viewScope.response" />
             <evaluate expression="opensamlProfileRequestContext" result="viewScope.profileRequestContext" />
diff --git a/idp-conf-impl/src/main/resources/net/shibboleth/idp/flows/intercept/expiring-password-flow.xml b/idp-conf-impl/src/main/resources/net/shibboleth/idp/flows/intercept/expiring-password-flow.xml
index 73c79e4ea..4fb754f79 100644
--- a/idp-conf-impl/src/main/resources/net/shibboleth/idp/flows/intercept/expiring-password-flow.xml
+++ b/idp-conf-impl/src/main/resources/net/shibboleth/idp/flows/intercept/expiring-password-flow.xml
@@ -33,6 +33,8 @@
             <evaluate expression="ExpiringPasswordCookieManager.addCookie(ExpiringPasswordCookieName, T(java.lang.Long).toString(T(java.lang.System).currentTimeMillis()))" />
             <evaluate expression="environment" result="viewScope.environment" />
             <evaluate expression="T(net.shibboleth.shared.codec.HTMLEncoder)" result="viewScope.encoder" />
+            <evaluate expression="flowRequestContext.getActiveFlow().getApplicationContext().getBean('shibboleth.CSPDigester')" result="viewScope.cspDigester" />
+            <evaluate expression="flowRequestContext.getActiveFlow().getApplicationContext().getBean('shibboleth.CSPNonce')" result="viewScope.cspNonce" />
             <evaluate expression="flowRequestContext.getExternalContext().getNativeRequest()" result="viewScope.request" />
             <evaluate expression="flowRequestContext.getExternalContext().getNativeResponse()" result="viewScope.response" />
             <evaluate expression="opensamlProfileRequestContext" result="viewScope.profileRequestContext" />
diff --git a/idp-conf-impl/src/main/resources/net/shibboleth/idp/flows/intercept/impersonate-flow.xml b/idp-conf-impl/src/main/resources/net/shibboleth/idp/flows/intercept/impersonate-flow.xml
index f97451464..06f522ddd 100644
--- a/idp-conf-impl/src/main/resources/net/shibboleth/idp/flows/intercept/impersonate-flow.xml
+++ b/idp-conf-impl/src/main/resources/net/shibboleth/idp/flows/intercept/impersonate-flow.xml
@@ -22,6 +22,8 @@
         <on-render>
             <evaluate expression="environment" result="viewScope.environment" />
             <evaluate expression="T(net.shibboleth.shared.codec.HTMLEncoder)" result="viewScope.encoder" />
+            <evaluate expression="flowRequestContext.getActiveFlow().getApplicationContext().getBean('shibboleth.CSPDigester')" result="viewScope.cspDigester" />
+            <evaluate expression="flowRequestContext.getActiveFlow().getApplicationContext().getBean('shibboleth.CSPNonce')" result="viewScope.cspNonce" />
             <evaluate expression="flowRequestContext.getExternalContext().getNativeRequest()" result="viewScope.request" />
             <evaluate expression="flowRequestContext.getExternalContext().getNativeResponse()" result="viewScope.response" />
             <evaluate expression="opensamlProfileRequestContext" result="viewScope.profileRequestContext" />
diff --git a/idp-conf-impl/src/main/resources/net/shibboleth/idp/flows/intercept/terms-of-use-flow.xml b/idp-conf-impl/src/main/resources/net/shibboleth/idp/flows/intercept/terms-of-use-flow.xml
index f55302956..48868529d 100644
--- a/idp-conf-impl/src/main/resources/net/shibboleth/idp/flows/intercept/terms-of-use-flow.xml
+++ b/idp-conf-impl/src/main/resources/net/shibboleth/idp/flows/intercept/terms-of-use-flow.xml
@@ -30,9 +30,11 @@
     <view-state id="DisplayTermsOfUsePage" view="#{flowRequestContext.activeFlow.id}">
         <on-render>
             <evaluate expression="environment" result="viewScope.environment" />
+            <evaluate expression="T(net.shibboleth.shared.codec.HTMLEncoder)" result="viewScope.encoder" />
+            <evaluate expression="flowRequestContext.getActiveFlow().getApplicationContext().getBean('shibboleth.CSPDigester')" result="viewScope.cspDigester" />
+            <evaluate expression="flowRequestContext.getActiveFlow().getApplicationContext().getBean('shibboleth.CSPNonce')" result="viewScope.cspNonce" />
             <evaluate expression="flowRequestContext.getExternalContext().getNativeRequest()" result="viewScope.request" />
             <evaluate expression="flowRequestContext.getExternalContext().getNativeResponse()" result="viewScope.response" />
-            <evaluate expression="T(net.shibboleth.shared.codec.HTMLEncoder)" result="viewScope.encoder" />
             <evaluate expression="opensamlProfileRequestContext.ensureSubcontext(T(net.shibboleth.idp.authn.context.AuthenticationContext)).getSubcontext(T(net.shibboleth.idp.ui.context.RelyingPartyUIContext))" result="viewScope.rpUIContext" />
             <evaluate expression="opensamlProfileRequestContext.getSubcontext(T(net.shibboleth.idp.consent.context.ConsentContext)).getCurrentConsents().keySet().iterator().next()" result="viewScope.termsOfUseId" />
             <evaluate expression="flowRequestContext.getActiveFlow().getApplicationContext().containsBean('shibboleth.CustomViewContext') ? flowRequestContext.getActiveFlow().getApplicationContext().getBean('shibboleth.CustomViewContext') : null" result="viewScope.custom" />
diff --git a/idp-conf-impl/src/main/resources/net/shibboleth/idp/flows/intercept/warning-flow.xml b/idp-conf-impl/src/main/resources/net/shibboleth/idp/flows/intercept/warning-flow.xml
index 90a7806ac..8ec542c50 100644
--- a/idp-conf-impl/src/main/resources/net/shibboleth/idp/flows/intercept/warning-flow.xml
+++ b/idp-conf-impl/src/main/resources/net/shibboleth/idp/flows/intercept/warning-flow.xml
@@ -45,6 +45,8 @@
             <evaluate expression="WarningCookieManager.addCookie(WarningCookieName, T(java.lang.Long).toString(T(java.lang.System).currentTimeMillis()))" />
             <evaluate expression="environment" result="viewScope.environment" />
             <evaluate expression="T(net.shibboleth.shared.codec.HTMLEncoder)" result="viewScope.encoder" />
+            <evaluate expression="flowRequestContext.getActiveFlow().getApplicationContext().getBean('shibboleth.CSPDigester')" result="viewScope.cspDigester" />
+            <evaluate expression="flowRequestContext.getActiveFlow().getApplicationContext().getBean('shibboleth.CSPNonce')" result="viewScope.cspNonce" />
             <evaluate expression="flowRequestContext.getExternalContext().getNativeRequest()" result="viewScope.request" />
             <evaluate expression="flowRequestContext.getExternalContext().getNativeResponse()" result="viewScope.response" />
             <evaluate expression="opensamlProfileRequestContext" result="viewScope.profileRequestContext" />
diff --git a/idp-conf-impl/src/main/resources/net/shibboleth/idp/flows/logout/logout-flow.xml b/idp-conf-impl/src/main/resources/net/shibboleth/idp/flows/logout/logout-flow.xml
index d160440b7..0ad62af6d 100644
--- a/idp-conf-impl/src/main/resources/net/shibboleth/idp/flows/logout/logout-flow.xml
+++ b/idp-conf-impl/src/main/resources/net/shibboleth/idp/flows/logout/logout-flow.xml
@@ -97,6 +97,8 @@
             <evaluate expression="opensamlProfileRequestContext.getSubcontext(T(net.shibboleth.idp.session.context.LogoutContext))" result="viewScope.logoutContext" />
             <evaluate expression="opensamlProfileRequestContext.getSubcontext(T(net.shibboleth.idp.profile.context.MultiRelyingPartyContext))" result="viewScope.multiRPContext" />
             <evaluate expression="T(net.shibboleth.shared.codec.HTMLEncoder)" result="viewScope.encoder" />
+            <evaluate expression="flowRequestContext.getActiveFlow().getApplicationContext().getBean('shibboleth.CSPDigester')" result="viewScope.cspDigester" />
+            <evaluate expression="flowRequestContext.getActiveFlow().getApplicationContext().getBean('shibboleth.CSPNonce')" result="viewScope.cspNonce" />
             <evaluate expression="flowRequestContext.getExternalContext().getNativeRequest()" result="viewScope.request" />
             <evaluate expression="flowRequestContext.getExternalContext().getNativeResponse()" result="viewScope.response" />
             <evaluate expression="flowRequestContext.getActiveFlow().getApplicationContext().containsBean('shibboleth.CustomViewContext') ? flowRequestContext.getActiveFlow().getApplicationContext().getBean('shibboleth.CustomViewContext') : null" result="viewScope.custom" />
@@ -129,6 +131,8 @@
             <evaluate expression="T(net.shibboleth.shared.codec.HTMLEncoder)" result="requestScope.htmlEncoder" />
             <evaluate expression="T(java.net.URLEncoder)" result="requestScope.urlEncoder" />
             <evaluate expression="T(org.cryptacular.util.CodecUtil)" result="requestScope.codecUtil" />
+            <evaluate expression="flowRequestContext.getActiveFlow().getApplicationContext().getBean('shibboleth.CSPDigester')" result="requestScope.cspDigester" />
+            <evaluate expression="flowRequestContext.getActiveFlow().getApplicationContext().getBean('shibboleth.CSPNonce')" result="requestScope.cspNonce" />
             <evaluate expression="flowRequestContext.getExternalContext().getNativeRequest()" result="requestScope.request" />
             <evaluate expression="flowRequestContext.getExternalContext().getNativeResponse()" result="requestScope.response" />
             <evaluate expression="flowRequestContext.getActiveFlow().getApplicationContext().getBean('shibboleth.LogoutPropagationFlowSelector')" result="requestScope.flowSelector" />
@@ -144,6 +148,8 @@
             <evaluate expression="opensamlProfileRequestContext.getSubcontext(T(net.shibboleth.idp.session.context.LogoutContext))" result="requestScope.logoutContext" />
             <evaluate expression="opensamlProfileRequestContext.getSubcontext(T(net.shibboleth.idp.profile.context.MultiRelyingPartyContext))" result="requestScope.multiRPContext" />
             <evaluate expression="T(net.shibboleth.shared.codec.HTMLEncoder)" result="requestScope.encoder" />
+            <evaluate expression="flowRequestContext.getActiveFlow().getApplicationContext().getBean('shibboleth.CSPDigester')" result="requestScope.cspDigester" />
+            <evaluate expression="flowRequestContext.getActiveFlow().getApplicationContext().getBean('shibboleth.CSPNonce')" result="requestScope.cspNonce" />
             <evaluate expression="flowRequestContext.getExternalContext().getNativeRequest()" result="requestScope.request" />
             <evaluate expression="flowRequestContext.getExternalContext().getNativeResponse()" result="requestScope.response" />
             <evaluate expression="flowRequestContext.getActiveFlow().getApplicationContext().containsBean('shibboleth.CustomViewContext') ? flowRequestContext.getActiveFlow().getApplicationContext().getBean('shibboleth.CustomViewContext') : null" result="requestScope.custom" />
@@ -178,6 +184,8 @@
             <evaluate expression="environment" result="requestScope.environment" />
             <evaluate expression="opensamlProfileRequestContext" result="requestScope.profileRequestContext" />
             <evaluate expression="T(net.shibboleth.shared.codec.HTMLEncoder)" result="requestScope.encoder" />
+            <evaluate expression="flowRequestContext.getActiveFlow().getApplicationContext().getBean('shibboleth.CSPDigester')" result="requestScope.cspDigester" />
+            <evaluate expression="flowRequestContext.getActiveFlow().getApplicationContext().getBean('shibboleth.CSPNonce')" result="requestScope.cspNonce" />
             <evaluate expression="flowRequestContext.getExternalContext().getNativeRequest()" result="requestScope.request" />
             <evaluate expression="flowRequestContext.getExternalContext().getNativeResponse()" result="requestScope.response" />
             <evaluate expression="flowRequestContext.getActiveFlow().getApplicationContext().containsBean('shibboleth.CustomViewContext') ? flowRequestContext.getActiveFlow().getApplicationContext().getBean('shibboleth.CustomViewContext') : null" result="requestScope.custom" />
@@ -190,6 +198,8 @@
             <evaluate expression="environment" result="requestScope.environment" />
             <evaluate expression="opensamlProfileRequestContext" result="requestScope.profileRequestContext" />
             <evaluate expression="T(net.shibboleth.shared.codec.HTMLEncoder)" result="requestScope.encoder" />
+            <evaluate expression="flowRequestContext.getActiveFlow().getApplicationContext().getBean('shibboleth.CSPDigester')" result="requestScope.cspDigester" />
+            <evaluate expression="flowRequestContext.getActiveFlow().getApplicationContext().getBean('shibboleth.CSPNonce')" result="requestScope.cspNonce" />
             <evaluate expression="flowRequestContext.getExternalContext().getNativeRequest()" result="requestScope.request" />
             <evaluate expression="flowRequestContext.getExternalContext().getNativeResponse()" result="requestScope.response" />
             <evaluate expression="flowRequestContext.getActiveFlow().getApplicationContext().containsBean('shibboleth.CustomViewContext') ? flowRequestContext.getActiveFlow().getApplicationContext().getBean('shibboleth.CustomViewContext') : null" result="requestScope.custom" />
diff --git a/idp-conf-impl/src/main/resources/net/shibboleth/idp/flows/logout/logout-propagation-flow.xml b/idp-conf-impl/src/main/resources/net/shibboleth/idp/flows/logout/logout-propagation-flow.xml
index 1cb71ca3b..bbdb0090e 100644
--- a/idp-conf-impl/src/main/resources/net/shibboleth/idp/flows/logout/logout-propagation-flow.xml
+++ b/idp-conf-impl/src/main/resources/net/shibboleth/idp/flows/logout/logout-propagation-flow.xml
@@ -39,6 +39,8 @@
             <evaluate expression="opensamlProfileRequestContext.getSubcontext(T(net.shibboleth.idp.authn.context.UserAgentContext))" result="requestScope.userAgentContext" />
             <evaluate expression="externalContext.nativeResponse.setContentType('application/json')" />
             <evaluate expression="T(net.shibboleth.shared.codec.HTMLEncoder)" result="requestScope.encoder" />
+            <evaluate expression="flowRequestContext.getActiveFlow().getApplicationContext().getBean('shibboleth.CSPDigester')" result="requestScope.cspDigester" />
+            <evaluate expression="flowRequestContext.getActiveFlow().getApplicationContext().getBean('shibboleth.CSPNonce')" result="requestScope.cspNonce" />
             <evaluate expression="WriteAuditLog" />
         </on-entry>
     </end-state>
diff --git a/idp-conf-impl/src/main/resources/net/shibboleth/idp/flows/saml/saml-abstract-flow.xml b/idp-conf-impl/src/main/resources/net/shibboleth/idp/flows/saml/saml-abstract-flow.xml
index e7c33b785..0d9c4bbc5 100644
--- a/idp-conf-impl/src/main/resources/net/shibboleth/idp/flows/saml/saml-abstract-flow.xml
+++ b/idp-conf-impl/src/main/resources/net/shibboleth/idp/flows/saml/saml-abstract-flow.xml
@@ -163,6 +163,8 @@
             <evaluate expression="environment" result="requestScope.environment" />
             <evaluate expression="opensamlProfileRequestContext" result="requestScope.profileRequestContext" />
             <evaluate expression="T(net.shibboleth.shared.codec.HTMLEncoder)" result="requestScope.encoder" />
+            <evaluate expression="flowRequestContext.getActiveFlow().getApplicationContext().getBean('shibboleth.CSPDigester')" result="requestScope.cspDigester" />
+            <evaluate expression="flowRequestContext.getActiveFlow().getApplicationContext().getBean('shibboleth.CSPNonce')" result="requestScope.cspNonce" />
             <evaluate expression="flowRequestContext.getExternalContext().getNativeRequest()" result="requestScope.request" />
             <evaluate expression="flowRequestContext.getExternalContext().getNativeResponse()" result="requestScope.response" />
             <evaluate expression="flowRequestContext.getActiveFlow().getApplicationContext().containsBean('shibboleth.CustomViewContext') ? flowRequestContext.getActiveFlow().getApplicationContext().getBean('shibboleth.CustomViewContext') : null" result="requestScope.custom" />
@@ -175,6 +177,8 @@
             <evaluate expression="environment" result="requestScope.environment" />
             <evaluate expression="opensamlProfileRequestContext" result="requestScope.profileRequestContext" />
             <evaluate expression="T(net.shibboleth.shared.codec.HTMLEncoder)" result="requestScope.encoder" />
+            <evaluate expression="flowRequestContext.getActiveFlow().getApplicationContext().getBean('shibboleth.CSPDigester')" result="requestScope.cspDigester" />
+            <evaluate expression="flowRequestContext.getActiveFlow().getApplicationContext().getBean('shibboleth.CSPNonce')" result="requestScope.cspNonce" />
             <evaluate expression="flowRequestContext.getExternalContext().getNativeRequest()" result="requestScope.request" />
             <evaluate expression="flowRequestContext.getExternalContext().getNativeResponse()" result="requestScope.response" />
             <evaluate expression="flowRequestContext.getActiveFlow().getApplicationContext().containsBean('shibboleth.CustomViewContext') ? flowRequestContext.getActiveFlow().getApplicationContext().getBean('shibboleth.CustomViewContext') : null" result="requestScope.custom" />
diff --git a/idp-conf-impl/src/main/resources/net/shibboleth/idp/flows/saml/saml2/slo-back-flow.xml b/idp-conf-impl/src/main/resources/net/shibboleth/idp/flows/saml/saml2/slo-back-flow.xml
index 293aac38d..92eb7bc4d 100644
--- a/idp-conf-impl/src/main/resources/net/shibboleth/idp/flows/saml/saml2/slo-back-flow.xml
+++ b/idp-conf-impl/src/main/resources/net/shibboleth/idp/flows/saml/saml2/slo-back-flow.xml
@@ -101,6 +101,8 @@
             <evaluate expression="environment" result="requestScope.environment" />
             <evaluate expression="opensamlProfileRequestContext" result="requestScope.profileRequestContext" />
             <evaluate expression="T(net.shibboleth.shared.codec.HTMLEncoder)" result="requestScope.encoder" />
+            <evaluate expression="flowRequestContext.getActiveFlow().getApplicationContext().getBean('shibboleth.CSPDigester')" result="requestScope.cspDigester" />
+            <evaluate expression="flowRequestContext.getActiveFlow().getApplicationContext().getBean('shibboleth.CSPNonce')" result="requestScope.cspNonce" />
             <evaluate expression="flowRequestContext.getExternalContext().getNativeRequest()" result="requestScope.request" />
             <evaluate expression="flowRequestContext.getExternalContext().getNativeResponse()" result="requestScope.response" />
             <evaluate expression="flowRequestContext.getActiveFlow().getApplicationContext().containsBean('shibboleth.CustomViewContext') ? flowRequestContext.getActiveFlow().getApplicationContext().getBean('shibboleth.CustomViewContext') : null" result="requestScope.custom" />
diff --git a/idp-conf-impl/src/main/resources/net/shibboleth/idp/flows/saml/saml2/slo-front-abstract-flow.xml b/idp-conf-impl/src/main/resources/net/shibboleth/idp/flows/saml/saml2/slo-front-abstract-flow.xml
index b26d7272a..3b7a76e93 100644
--- a/idp-conf-impl/src/main/resources/net/shibboleth/idp/flows/saml/saml2/slo-front-abstract-flow.xml
+++ b/idp-conf-impl/src/main/resources/net/shibboleth/idp/flows/saml/saml2/slo-front-abstract-flow.xml
@@ -141,6 +141,8 @@
             <evaluate expression="opensamlProfileRequestContext.getSubcontext(T(net.shibboleth.idp.session.context.LogoutContext))" result="viewScope.logoutContext" />
             <evaluate expression="opensamlProfileRequestContext.getSubcontext(T(net.shibboleth.idp.profile.context.MultiRelyingPartyContext))" result="viewScope.multiRPContext" />
             <evaluate expression="T(net.shibboleth.shared.codec.HTMLEncoder)" result="viewScope.encoder" />
+            <evaluate expression="flowRequestContext.getActiveFlow().getApplicationContext().getBean('shibboleth.CSPDigester')" result="viewScope.cspDigester" />
+            <evaluate expression="flowRequestContext.getActiveFlow().getApplicationContext().getBean('shibboleth.CSPNonce')" result="viewScope.cspNonce" />
             <evaluate expression="flowRequestContext.getExternalContext().getNativeRequest()" result="viewScope.request" />
             <evaluate expression="flowRequestContext.getExternalContext().getNativeResponse()" result="viewScope.response" />
             <evaluate expression="flowRequestContext.getActiveFlow().getApplicationContext().containsBean('shibboleth.CustomViewContext') ? flowRequestContext.getActiveFlow().getApplicationContext().getBean('shibboleth.CustomViewContext') : null" result="viewScope.custom" />
@@ -172,6 +174,8 @@
             <evaluate expression="T(net.shibboleth.shared.codec.HTMLEncoder)" result="viewScope.htmlEncoder" />
             <evaluate expression="T(java.net.URLEncoder)" result="viewScope.urlEncoder" />
             <evaluate expression="T(org.cryptacular.util.CodecUtil)" result="viewScope.codecUtil" />
+            <evaluate expression="flowRequestContext.getActiveFlow().getApplicationContext().getBean('shibboleth.CSPDigester')" result="viewScope.cspDigester" />
+            <evaluate expression="flowRequestContext.getActiveFlow().getApplicationContext().getBean('shibboleth.CSPNonce')" result="viewScope.cspNonce" />
             <evaluate expression="flowRequestContext.getExternalContext().getNativeRequest()" result="viewScope.request" />
             <evaluate expression="flowRequestContext.getExternalContext().getNativeResponse()" result="viewScope.response" />
             <evaluate expression="flowRequestContext.getActiveFlow().getApplicationContext().getBean('shibboleth.LogoutPropagationFlowSelector')" result="viewScope.flowSelector" />
@@ -189,6 +193,8 @@
             <evaluate expression="opensamlProfileRequestContext.getSubcontext(T(net.shibboleth.idp.session.context.LogoutContext))" result="viewScope.logoutContext" />
             <evaluate expression="opensamlProfileRequestContext.getSubcontext(T(net.shibboleth.idp.profile.context.MultiRelyingPartyContext))" result="viewScope.multiRPContext" />
             <evaluate expression="T(net.shibboleth.shared.codec.HTMLEncoder)" result="viewScope.encoder" />
+            <evaluate expression="flowRequestContext.getActiveFlow().getApplicationContext().getBean('shibboleth.CSPDigester')" result="viewScope.cspDigester" />
+            <evaluate expression="flowRequestContext.getActiveFlow().getApplicationContext().getBean('shibboleth.CSPNonce')" result="viewScope.cspNonce" />
             <evaluate expression="flowRequestContext.getExternalContext().getNativeRequest()" result="viewScope.request" />
             <evaluate expression="flowRequestContext.getExternalContext().getNativeResponse()" result="viewScope.response" />
             <evaluate expression="flowRequestContext.getActiveFlow().getApplicationContext().containsBean('shibboleth.CustomViewContext') ? flowRequestContext.getActiveFlow().getApplicationContext().getBean('shibboleth.CustomViewContext') : null" result="viewScope.custom" />
@@ -248,6 +254,8 @@
             <evaluate expression="environment" result="requestScope.environment" />
             <evaluate expression="opensamlProfileRequestContext" result="requestScope.profileRequestContext" />
             <evaluate expression="T(net.shibboleth.shared.codec.HTMLEncoder)" result="requestScope.encoder" />
+            <evaluate expression="flowRequestContext.getActiveFlow().getApplicationContext().getBean('shibboleth.CSPDigester')" result="requestScope.cspDigester" />
+            <evaluate expression="flowRequestContext.getActiveFlow().getApplicationContext().getBean('shibboleth.CSPNonce')" result="requestScope.cspNonce" />
             <evaluate expression="flowRequestContext.getExternalContext().getNativeRequest()" result="requestScope.request" />
             <evaluate expression="flowRequestContext.getExternalContext().getNativeResponse()" result="requestScope.response" />
             <evaluate expression="flowRequestContext.getActiveFlow().getApplicationContext().containsBean('shibboleth.CustomViewContext') ? flowRequestContext.getActiveFlow().getApplicationContext().getBean('shibboleth.CustomViewContext') : null" result="requestScope.custom" />
@@ -260,6 +268,8 @@
             <evaluate expression="environment" result="requestScope.environment" />
             <evaluate expression="opensamlProfileRequestContext" result="requestScope.profileRequestContext" />
             <evaluate expression="T(net.shibboleth.shared.codec.HTMLEncoder)" result="requestScope.encoder" />
+            <evaluate expression="flowRequestContext.getActiveFlow().getApplicationContext().getBean('shibboleth.CSPDigester')" result="requestScope.cspDigester" />
+            <evaluate expression="flowRequestContext.getActiveFlow().getApplicationContext().getBean('shibboleth.CSPNonce')" result="requestScope.cspNonce" />
             <evaluate expression="flowRequestContext.getExternalContext().getNativeRequest()" result="requestScope.request" />
             <evaluate expression="flowRequestContext.getExternalContext().getNativeResponse()" result="requestScope.response" />
             <evaluate expression="flowRequestContext.getActiveFlow().getApplicationContext().containsBean('shibboleth.CustomViewContext') ? flowRequestContext.getActiveFlow().getApplicationContext().getBean('shibboleth.CustomViewContext') : null" result="requestScope.custom" />
diff --git a/idp-conf-impl/src/main/resources/net/shibboleth/idp/module/flows/user/prefs/prefs-flow.xml b/idp-conf-impl/src/main/resources/net/shibboleth/idp/module/flows/user/prefs/prefs-flow.xml
index 723f360be..3e6efae99 100644
--- a/idp-conf-impl/src/main/resources/net/shibboleth/idp/module/flows/user/prefs/prefs-flow.xml
+++ b/idp-conf-impl/src/main/resources/net/shibboleth/idp/module/flows/user/prefs/prefs-flow.xml
@@ -17,6 +17,8 @@
         <on-entry>
             <evaluate expression="environment" result="requestScope.environment" />
             <evaluate expression="T(net.shibboleth.shared.codec.HTMLEncoder)" result="requestScope.encoder" />
+            <evaluate expression="flowRequestContext.getActiveFlow().getApplicationContext().getBean('shibboleth.CSPDigester')" result="requestScope.cspDigester" />
+            <evaluate expression="flowRequestContext.getActiveFlow().getApplicationContext().getBean('shibboleth.CSPNonce')" result="requestScope.cspNonce" />
             <evaluate expression="flowRequestContext.getExternalContext().getNativeRequest()" result="requestScope.request" />
             <evaluate expression="flowRequestContext.getExternalContext().getNativeResponse()" result="requestScope.response" />
             <evaluate expression="flowRequestContext.getActiveFlow().getApplicationContext().containsBean('shibboleth.CustomViewContext') ? flowRequestContext.getActiveFlow().getApplicationContext().getBean('shibboleth.CustomViewContext') : null" result="requestScope.custom" />
diff --git a/idp-conf-impl/src/main/resources/net/shibboleth/idp/module/views/admin/hello.vm b/idp-conf-impl/src/main/resources/net/shibboleth/idp/module/views/admin/hello.vm
index 6268c6c94..67dc673b5 100644
--- a/idp-conf-impl/src/main/resources/net/shibboleth/idp/module/views/admin/hello.vm
+++ b/idp-conf-impl/src/main/resources/net/shibboleth/idp/module/views/admin/hello.vm
@@ -12,6 +12,7 @@
 ## environment - Spring Environment object for property resolution
 ## custom - arbitrary object injected by deployer
 ##
+$response.setHeader("Content-Security-Policy", "script-src 'none'")
 <!DOCTYPE html>
 <html>
     <head>
diff --git a/idp-conf-impl/src/main/resources/net/shibboleth/idp/module/views/admin/unlock-keys.vm b/idp-conf-impl/src/main/resources/net/shibboleth/idp/module/views/admin/unlock-keys.vm
index 23317bc50..a124a62b4 100644
--- a/idp-conf-impl/src/main/resources/net/shibboleth/idp/module/views/admin/unlock-keys.vm
+++ b/idp-conf-impl/src/main/resources/net/shibboleth/idp/module/views/admin/unlock-keys.vm
@@ -13,6 +13,7 @@
 #set ($titleSuffix = $springMacroRequestContext.getMessage("idp.unlock-keys.title", "Attended Restart Key Unlock"))
 #set ($eventId = $profileRequestContext.getSubcontext("org.opensaml.profile.context.EventContext").getEvent())
 #set ($state = $flowRequestContext.getCurrentState().getId())
+$response.setHeader("Content-Security-Policy", "script-src 'none'")
 <!DOCTYPE html>
 <html>
     <head>
diff --git a/idp-conf-impl/src/main/resources/net/shibboleth/idp/module/views/client-storage/client-storage-read.vm b/idp-conf-impl/src/main/resources/net/shibboleth/idp/module/views/client-storage/client-storage-read.vm
index 1afe818d0..8bfe9a299 100644
--- a/idp-conf-impl/src/main/resources/net/shibboleth/idp/module/views/client-storage/client-storage-read.vm
+++ b/idp-conf-impl/src/main/resources/net/shibboleth/idp/module/views/client-storage/client-storage-read.vm
@@ -8,12 +8,19 @@
 ## profileRequestContext - root of context tree
 ## loadContext - context with details about the storage keys to load
 ## encoder - HTMLEncoder class
+## cspDigester - Calculates base64-encoded SHA-2 hashes (call apply)
+## cspNonce - Calculates secure nonces (call generateIdentifier)
 ## request - HttpServletRequest
 ## response - HttpServletResponse
 ## environment - Spring Environment object for property resolution
 #set ($title = $springMacroRequestContext.getMessage("idp.title", "Web Login Service"))
 #set ($titleSuffix = $springMacroRequestContext.getMessage("idp.client-storage-read.suffix", "Loading Session Information"))
 ##
+#set ($onLoad = "doLoad()")
+$response.setHeader("Content-Security-Policy", "script-src-attr 'unsafe-hashes' 'sha256-$cspDigester.apply($onLoad)'")
+## Nonce for dynanmic scripts.
+#set ($nonce = $cspNonce.generateIdentifier())
+$response.setHeader("Content-Security-Policy", "script-src-elem 'nonce-$nonce'")
 <!DOCTYPE html>
 <html>
     <head>
@@ -22,13 +29,9 @@
         <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
         <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=5.0">
         <link rel="stylesheet" type="text/css" href="$request.getContextPath()#springMessageText("idp.css", "/css/placeholder.css")">
-        <script>
-        <!--
-        #include("client-storage/local-storage-read.js")
-        // -->
-        </script>
+        <script nonce="$nonce"><!-- #include("client-storage/local-storage-read.js") // --></script>
     </head>
-    <body onload="doLoad()">        
+    <body onload="$onLoad">        
         <main class="main">
             <section>
                 <h1>$title - $titleSuffix</h1>
diff --git a/idp-conf-impl/src/main/resources/net/shibboleth/idp/module/views/client-storage/client-storage-write.vm b/idp-conf-impl/src/main/resources/net/shibboleth/idp/module/views/client-storage/client-storage-write.vm
index 066cbdbc1..f03a249ef 100644
--- a/idp-conf-impl/src/main/resources/net/shibboleth/idp/module/views/client-storage/client-storage-write.vm
+++ b/idp-conf-impl/src/main/resources/net/shibboleth/idp/module/views/client-storage/client-storage-write.vm
@@ -8,12 +8,19 @@
 ## profileRequestContext - root of context tree
 ## saveContext - context with details about the storage data to save
 ## encoder - HTMLEncoder class
+## cspDigester - Calculates base64-encoded SHA-2 hashes (call apply)
+## cspNonce - Calculates secure nonces (call generateIdentifier)
 ## request - HttpServletRequest
 ## response - HttpServletResponse
 ## environment - Spring Environment object for property resolution
 #set ($title = $springMacroRequestContext.getMessage("idp.title", "Web Login Service"))
 #set ($titleSuffix = $springMacroRequestContext.getMessage("idp.client-storage-write.suffix", "Saving Session Information..."))
 ##
+#set ($onLoad = "doSave()")
+$response.setHeader("Content-Security-Policy", "script-src-attr 'unsafe-hashes' 'sha256-$cspDigester.apply($onLoad)'")
+## Nonce for dynanmic scripts.
+#set ($nonce = $cspNonce.generateIdentifier())
+$response.setHeader("Content-Security-Policy", "script-src-elem 'nonce-$nonce'")
 <!DOCTYPE html>
 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
     <head>
@@ -22,13 +29,9 @@
         <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
         <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=5.0">
         <link rel="stylesheet" type="text/css" href="$request.getContextPath()#springMessageText("idp.css", "/css/placeholder.css")">
-        <script>
-        <!--
-        #include("client-storage/local-storage-write.js")
-        // -->
-        </script>
+        <script nonce="$nonce"><!-- #include("client-storage/local-storage-write.js") // --></script>
     </head>
-    <body onload="doSave()">    
+    <body onload="$onLoad">    
         <main class="main">
             <section>
                 <h1>$title - $titleSuffix</h1>
diff --git a/idp-conf-impl/src/main/resources/net/shibboleth/idp/module/views/error.vm b/idp-conf-impl/src/main/resources/net/shibboleth/idp/module/views/error.vm
index 0f01e89f7..f3b53c419 100644
--- a/idp-conf-impl/src/main/resources/net/shibboleth/idp/module/views/error.vm
+++ b/idp-conf-impl/src/main/resources/net/shibboleth/idp/module/views/error.vm
@@ -8,6 +8,8 @@
 ## flowRequestContext - the Spring Web Flow RequestContext
 ## profileRequestContext - root of context tree
 ## encoder - HTMLEncoder class
+## cspDigester - Calculates base64-encoded SHA-2 hashes (call apply)
+## cspNonce - Calculates secure nonces (call generateIdentifier)
 ## request - HttpServletRequest
 ## response - HttpServletResponse
 ## environment - Spring Environment object for property resolution
@@ -45,6 +47,7 @@
     $response.setStatus(500)
 #end
 ##
+$response.setHeader("Content-Security-Policy", "script-src 'none'")
 <!DOCTYPE html>
 <html>
     <head>
diff --git a/idp-conf-impl/src/main/resources/net/shibboleth/idp/module/views/intercept/attribute-release.vm b/idp-conf-impl/src/main/resources/net/shibboleth/idp/module/views/intercept/attribute-release.vm
index db103833e..32f9e30f7 100644
--- a/idp-conf-impl/src/main/resources/net/shibboleth/idp/module/views/intercept/attribute-release.vm
+++ b/idp-conf-impl/src/main/resources/net/shibboleth/idp/module/views/intercept/attribute-release.vm
@@ -25,6 +25,7 @@
 #set ($rpOrganizationName = $rpUIContext.organizationDisplayName)
 #set ($replaceDollarWithNewline = true)
 ##
+$response.setHeader("Content-Security-Policy", "script-src 'none'")
 <!DOCTYPE html>
 <html>
     <head>
diff --git a/idp-conf-impl/src/main/resources/net/shibboleth/idp/module/views/intercept/expiring-password.vm b/idp-conf-impl/src/main/resources/net/shibboleth/idp/module/views/intercept/expiring-password.vm
index f0ecc4d94..4523ab4c9 100644
--- a/idp-conf-impl/src/main/resources/net/shibboleth/idp/module/views/intercept/expiring-password.vm
+++ b/idp-conf-impl/src/main/resources/net/shibboleth/idp/module/views/intercept/expiring-password.vm
@@ -16,6 +16,7 @@
 ## environment - Spring Environment object for property resolution
 ## custom - arbitrary object injected by deployer
 ##
+$response.setHeader("Content-Security-Policy", "script-src 'none'")
 <!DOCTYPE html>
 <html>
     <head>
diff --git a/idp-conf-impl/src/main/resources/net/shibboleth/idp/module/views/intercept/impersonate.vm b/idp-conf-impl/src/main/resources/net/shibboleth/idp/module/views/intercept/impersonate.vm
index 296cd197c..8e4b40786 100644
--- a/idp-conf-impl/src/main/resources/net/shibboleth/idp/module/views/intercept/impersonate.vm
+++ b/idp-conf-impl/src/main/resources/net/shibboleth/idp/module/views/intercept/impersonate.vm
@@ -14,6 +14,7 @@
 ## custom - arbitrary object injected by deployer
 ##
 #set ($rpContext = $profileRequestContext.getSubcontext('net.shibboleth.profile.context.RelyingPartyContext'))
+$response.setHeader("Content-Security-Policy", "script-src 'none'")
 <!DOCTYPE html>
 <html>
     <head>
diff --git a/idp-conf-impl/src/main/resources/net/shibboleth/idp/module/views/intercept/terms-of-use.vm b/idp-conf-impl/src/main/resources/net/shibboleth/idp/module/views/intercept/terms-of-use.vm
index 9d43c2a4c..c3a0460d2 100644
--- a/idp-conf-impl/src/main/resources/net/shibboleth/idp/module/views/intercept/terms-of-use.vm
+++ b/idp-conf-impl/src/main/resources/net/shibboleth/idp/module/views/intercept/terms-of-use.vm
@@ -15,6 +15,7 @@
 #set ($serviceName = $rpUIContext.serviceName)
 #set ($rpOrganizationLogo = $rpUIContext.getLogo())
 ##
+$response.setHeader("Content-Security-Policy", "script-src 'none'")
 <!DOCTYPE html>
 <html>
     <head>
diff --git a/idp-conf-impl/src/main/resources/net/shibboleth/idp/module/views/login.vm b/idp-conf-impl/src/main/resources/net/shibboleth/idp/module/views/login.vm
index 20ed38ea0..2ed0cd253 100644
--- a/idp-conf-impl/src/main/resources/net/shibboleth/idp/module/views/login.vm
+++ b/idp-conf-impl/src/main/resources/net/shibboleth/idp/module/views/login.vm
@@ -12,6 +12,8 @@
 ## ldapResponseContext - context with LDAP state (if using native LDAP)
 ## rpUIContext - the context with SP UI information from the metadata
 ## encoder - HTMLEncoder class
+## cspDigester - Calculates base64-encoded SHA-2 hashes (call apply)
+## cspNonce - Calculates secure nonces (call generateIdentifier)
 ## request - HttpServletRequest
 ## response - HttpServletResponse
 ## environment - Spring Environment object for property resolution
@@ -20,6 +22,8 @@
 #set ($rpContext = $profileRequestContext.getSubcontext('net.shibboleth.profile.context.RelyingPartyContext'))
 #set ($username = $authenticationContext.getSubcontext('net.shibboleth.idp.authn.context.UsernamePasswordContext', true).getUsername())
 ##
+#set ($onClick = "this.childNodes[0].nodeValue='#springMessageText('idp.login.pleasewait', 'Logging in, please wait...')'")
+$response.setHeader("Content-Security-Policy", "script-src-attr 'unsafe-hashes' 'sha256-$cspDigester.apply($onClick)'")
 <!DOCTYPE html>
 <html>
     <head>
@@ -84,8 +88,7 @@
     
                     <div class="grid">
                         <div class="grid-item">
-                            <button type="submit" name="_eventId_proceed"
-                                onClick="this.childNodes[0].nodeValue='#springMessageText("idp.login.pleasewait", "Logging in, please wait...")'"
+                            <button type="submit" name="_eventId_proceed" onClick="$onClick"
                                 >#springMessageText("idp.login.login", "Login")</button>
                         </div>
                     </div>
diff --git a/idp-conf-impl/src/main/resources/net/shibboleth/idp/module/views/logout-complete.vm b/idp-conf-impl/src/main/resources/net/shibboleth/idp/module/views/logout-complete.vm
index 2d332eac7..93e9ac9ea 100644
--- a/idp-conf-impl/src/main/resources/net/shibboleth/idp/module/views/logout-complete.vm
+++ b/idp-conf-impl/src/main/resources/net/shibboleth/idp/module/views/logout-complete.vm
@@ -9,6 +9,8 @@
 ## logoutContext - context with SPSession details for logout operation
 ## multiRPContext - context with RelyingPartyContexts and possibly SP UI information from the metadata
 ## encoder - HTMLEncoder class
+## cspDigester - Calculates base64-encoded SHA-2 hashes (call apply)
+## cspNonce - Calculates secure nonces (call generateIdentifier)
 ## request - HttpServletRequest
 ## response - HttpServletResponse
 ## environment - Spring Environment object for property resolution
@@ -16,6 +18,7 @@
 ##
 #set ($activeIdPSessions = $logoutContext and !$logoutContext.getIdPSessions().isEmpty())
 #set ($activeSPSessions = $logoutContext and !$logoutContext.getSessionMap().isEmpty())
+$response.setHeader("Content-Security-Policy", "script-src 'none'")
 <!DOCTYPE html>
 <html>
     <head>
diff --git a/idp-conf-impl/src/main/resources/net/shibboleth/idp/module/views/logout-propagate.vm b/idp-conf-impl/src/main/resources/net/shibboleth/idp/module/views/logout-propagate.vm
index ab733829c..675968882 100644
--- a/idp-conf-impl/src/main/resources/net/shibboleth/idp/module/views/logout-propagate.vm
+++ b/idp-conf-impl/src/main/resources/net/shibboleth/idp/module/views/logout-propagate.vm
@@ -10,6 +10,8 @@
 ## multiRPContext - context with RelyingPartyContexts and possibly SP UI information from the metadata
 ## htmlEncoder - HTMLEncoder class
 ## urlEncoder - urlEncoder class
+## cspDigester - Calculates base64-encoded SHA-2 hashes (call apply)
+## cspNonce - Calculates secure nonces (call generateIdentifier)
 ## codecUtil - CodecUtil class
 ## request - HttpServletRequest
 ## response - HttpServletResponse
@@ -17,6 +19,7 @@
 ## custom - arbitrary object injected by deployer
 ##
 #set ($hidden = $environment.getProperty("idp.logout.propagationHidden", "false"))
+$response.setHeader("Content-Security-Policy", "script-src 'unsafe-inline' 'self'")
 <!DOCTYPE html>
 <html>
     <head>
diff --git a/idp-conf-impl/src/main/resources/net/shibboleth/idp/module/views/logout.vm b/idp-conf-impl/src/main/resources/net/shibboleth/idp/module/views/logout.vm
index ab0160064..dc2397cb0 100644
--- a/idp-conf-impl/src/main/resources/net/shibboleth/idp/module/views/logout.vm
+++ b/idp-conf-impl/src/main/resources/net/shibboleth/idp/module/views/logout.vm
@@ -9,6 +9,8 @@
 ## logoutContext - context with SPSession details for logout operation
 ## multiRPContext - context with RelyingPartyContexts and possibly SP UI information from the metadata
 ## encoder - HTMLEncoder class
+## cspDigester - Calculates base64-encoded SHA-2 hashes (call apply)
+## cspNonce - Calculates secure nonces (call generateIdentifier)
 ## request - HttpServletRequest
 ## response - HttpServletResponse
 ## environment - Spring Environment object for property resolution
@@ -20,6 +22,7 @@
 #end
 #set ($promptForIdP = $logoutContext and !$logoutContext.getIdPSessions().isEmpty())
 #set ($promptForSP = $logoutContext and !$logoutContext.getSessionMap().isEmpty())
+$response.setHeader("Content-Security-Policy", "script-src 'none'")
 <!DOCTYPE html>
 <html>
     <head>
diff --git a/idp-conf-impl/src/main/resources/net/shibboleth/idp/module/views/spnego-unavailable.vm b/idp-conf-impl/src/main/resources/net/shibboleth/idp/module/views/spnego-unavailable.vm
index ee6f17b52..6fed743b6 100644
--- a/idp-conf-impl/src/main/resources/net/shibboleth/idp/module/views/spnego-unavailable.vm
+++ b/idp-conf-impl/src/main/resources/net/shibboleth/idp/module/views/spnego-unavailable.vm
@@ -6,12 +6,16 @@
 ##
 ## Velocity context will contain the following properties
 ## encoder - HTMLEncoder class
+## cspDigester - Calculates base64-encoded SHA-2 hashes (call apply)
+## cspNonce - Calculates secure nonces (call generateIdentifier)
 ## request - HttpServletRequest
 ## response - HttpServletResponse
 ## profileRequestContext - root of context tree
 ## errorUrl - URL to call to indicate error and return back to the login flow
 ##
 #set ($eventKey = $springMacroRequestContext.getMessage("SPNEGOUnavailable", "spnego-unavailable"))
+#set ($onLoad = "window.location = '$errorUrl'")
+$response.setHeader("Content-Security-Policy", "script-src-attr 'unsafe-hashes' 'sha256-$cspDigester.apply($onLoad)'")
 <!DOCTYPE html>
 <html>
     <head>
@@ -21,7 +25,7 @@
         <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=5.0">
         <link rel="stylesheet" type="text/css" href="$request.getContextPath()#springMessageText("idp.css", "/css/placeholder.css")">
     </head>
-    <body onload="window.location = '$errorUrl'">
+    <body onLoad="$onLoad">
         <main class="main">
             <header>
                 <img class="main-logo" src="$request.getContextPath()#springMessageText("idp.logo", "/images/placeholder-logo.png")" alt="#springMessageText("idp.logo.alt-text", "logo")">
diff --git a/idp-conf-impl/src/main/resources/net/shibboleth/idp/module/views/user-prefs.js b/idp-conf-impl/src/main/resources/net/shibboleth/idp/module/views/user-prefs.js
index ab994f9a9..81f143a61 100644
--- a/idp-conf-impl/src/main/resources/net/shibboleth/idp/module/views/user-prefs.js
+++ b/idp-conf-impl/src/main/resources/net/shibboleth/idp/module/views/user-prefs.js
@@ -1,3 +1,4 @@
+<!--
 "use strict";
 
 function createCookie(name, value, seconds) {
@@ -43,3 +44,4 @@ function check(checkbox) {
         eraseCookie(checkbox.name);
     }
 }
+// -->
diff --git a/idp-conf-impl/src/main/resources/net/shibboleth/idp/module/views/user-prefs.vm b/idp-conf-impl/src/main/resources/net/shibboleth/idp/module/views/user-prefs.vm
index 8f70837d2..d790ddb1a 100644
--- a/idp-conf-impl/src/main/resources/net/shibboleth/idp/module/views/user-prefs.vm
+++ b/idp-conf-impl/src/main/resources/net/shibboleth/idp/module/views/user-prefs.vm
@@ -6,7 +6,15 @@
 ## response - HttpServletResponse
 ## environment - Spring Environment object for property resolution
 ## custom - arbitrary object injected by deployer
+## encoder - HTMLEncoder class
+## cspDigester - Calculates base64-encoded SHA-2 hashes (call apply)
+## cspNonce - Calculates secure nonces (call generateIdentifier)
 ##
+#set ($onLoad = "load('spnego')")
+#set ($onClick = "check(this)")
+$response.setHeader("Content-Security-Policy", "script-src-attr 'unsafe-hashes' 'sha256-$cspDigester.apply($onLoad)','sha256-$cspDigester.apply($onClick)'")
+## Hash of user-prefs.js (being injected inline below).
+$response.setHeader("Content-Security-Policy", "script-src-elem 'unsafe-hashes' 'sha256-mXQMhpzvwZ/f5iKzcm/iFe50L/0b7cNjsvcFVu/PMTg='")
 <!DOCTYPE html>
 <html>
     <head>
@@ -15,14 +23,10 @@
         <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
         <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=5.0">
         <link rel="stylesheet" type="text/css" href="$request.getContextPath()#springMessageText("idp.css", "/css/placeholder.css")">
-        <script language="Javascript">
-        <!--
-        #parse( "user-prefs.js" )
-        // -->
-        </script>
+        <script language="Javascript">#parse("user-prefs.js")</script>
     </head>
 
-   <body onLoad="document.getElementById('content').style.display='block'; load('spnego')">
+   <body onLoad="$onLoad">
         <main class="main">
             <header>
                 <img class="main-logo" src="$request.getContextPath()#springMessageText("idp.logo", "/images/placeholder-logo.png")" alt="#springMessageText("idp.logo.alt-text", "logo")">
@@ -41,7 +45,7 @@
         
                 <form>
                     <p>#springMessageText("idp.userprefs.options", "The following options are available:")</p>
-                    <input type="checkbox" id="spnego" name="_idp_spnego_autologin" value="1" onClick="check(this)">
+                    <input type="checkbox" id="spnego" name="_idp_spnego_autologin" value="1" onClick="$onClick">
                     <label for="spnego"> #springMessageText("idp.userprefs.spnego", "Automatically try desktop login when available.")</label>
                 </form>
             </section>
diff --git a/idp-conf-impl/src/main/resources/net/shibboleth/idp/views/client-storage/read.vm b/idp-conf-impl/src/main/resources/net/shibboleth/idp/views/client-storage/read.vm
index fc514d695..6a42fded0 100644
--- a/idp-conf-impl/src/main/resources/net/shibboleth/idp/views/client-storage/read.vm
+++ b/idp-conf-impl/src/main/resources/net/shibboleth/idp/views/client-storage/read.vm
@@ -8,6 +8,8 @@
 ## profileRequestContext - root of context tree
 ## loadContext - context with details about the storage keys to load
 ## encoder - HTMLEncoder class
+## cspDigester - Calculates base64-encoded SHA-2 hashes (call apply)
+## cspNonce - Calculates secure nonces (call generateIdentifier)
 ## request - HttpServletRequest
 ## response - HttpServletResponse
 ## environment - Spring Environment object for property resolution
@@ -29,7 +31,7 @@
     </noscript>
 </form>
 
-<script>
+<script #if ($nonce)nonce="$nonce"#end>
 <!--
 function doLoad() {
     var localStorageSupported = isLocalStorageSupported();
@@ -42,4 +44,4 @@ function doLoad() {
     document.form1.submit();
 }
 // -->
-</script>
\ No newline at end of file
+</script>
diff --git a/idp-conf-impl/src/main/resources/net/shibboleth/idp/views/client-storage/write.vm b/idp-conf-impl/src/main/resources/net/shibboleth/idp/views/client-storage/write.vm
index b059100ca..008ebec11 100644
--- a/idp-conf-impl/src/main/resources/net/shibboleth/idp/views/client-storage/write.vm
+++ b/idp-conf-impl/src/main/resources/net/shibboleth/idp/views/client-storage/write.vm
@@ -8,6 +8,8 @@
 ## profileRequestContext - root of context tree
 ## saveContext - context with details about the storage data to save
 ## encoder - HTMLEncoder class
+## cspDigester - Calculates base64-encoded SHA-2 hashes (call apply)
+## cspNonce - Calculates secure nonces (call generateIdentifier)
 ## request - HttpServletRequest
 ## response - HttpServletResponse
 ## environment - Spring Environment object for property resolution
@@ -28,7 +30,7 @@
     </noscript>
 </form>
 
-<script>
+<script #if ($nonce)nonce="$nonce"#end>
 <!--
 function doSave() {
     #foreach ($op in $saveContext.getStorageOperations())
diff --git a/idp-conf-impl/src/main/resources/net/shibboleth/idp/views/logout/propagate.vm b/idp-conf-impl/src/main/resources/net/shibboleth/idp/views/logout/propagate.vm
index 58a2d4186..34db86bf0 100644
--- a/idp-conf-impl/src/main/resources/net/shibboleth/idp/views/logout/propagate.vm
+++ b/idp-conf-impl/src/main/resources/net/shibboleth/idp/views/logout/propagate.vm
@@ -12,6 +12,8 @@
 ## htmlEncoder - HTMLEncoder class
 ## urlEncoder - urlEncoder class
 ## codecUtil - CodecUtil class
+## cspDigester - Calculates base64-encoded SHA-2 hashes (call apply)
+## cspNonce - Calculates secure nonces (call generateIdentifier)
 ## request - HttpServletRequest
 ## response - HttpServletResponse
 ## environment - Spring Environment object for property resolution
@@ -47,7 +49,7 @@
                 title="$logoutTitle">$htmlEncoder.encodeForHTML($serviceName)</li>
         #end
     </ol>
-    <script src="$request.getContextPath()/js/jquery-3.6.0.min.js"></script>
+    <script src="$request.getContextPath()/js/jquery-3.6.0.min.js" integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4="></script>
     <script>
     <!--
         function check_status() {
diff --git a/idp-conf-impl/src/main/resources/net/shibboleth/idp/views/logout/saml-async.vm b/idp-conf-impl/src/main/resources/net/shibboleth/idp/views/logout/saml-async.vm
index adb519649..836f51251 100644
--- a/idp-conf-impl/src/main/resources/net/shibboleth/idp/views/logout/saml-async.vm
+++ b/idp-conf-impl/src/main/resources/net/shibboleth/idp/views/logout/saml-async.vm
@@ -9,6 +9,7 @@
 ## environment - Spring Environment object for property resolution
 ## custom - arbitrary object injected by deployer
 ##
+$response.setHeader("Content-Security-Policy", "script-src 'none'")
 <!DOCTYPE html>
 <html>
 <head>

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


More information about the commits mailing list