You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@wicket.apache.org by pa...@apache.org on 2020/01/17 21:27:02 UTC

[wicket] 07/08: WICKET-6727: Remove old CspNonceHeaderResponse and update example

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

papegaaij pushed a commit to branch csp-configurable
in repository https://gitbox.apache.org/repos/asf/wicket.git

commit cfc46152d08d89d259e6666d3f0895e7b63266a0
Author: Emond Papegaaij <em...@topicus.nl>
AuthorDate: Fri Jan 17 22:14:48 2020 +0100

    WICKET-6727: Remove old CspNonceHeaderResponse and update example
---
 .../markup/head/filter/CspNonceHeaderResponse.java | 93 ----------------------
 .../markup/head/filter/CspNoncePageExpected.html   |  3 +-
 .../head/filter/FilteringHeaderResponseTest.java   | 28 ++++++-
 .../apache/wicket/examples/csp/CspApplication.java | 35 +-------
 4 files changed, 27 insertions(+), 132 deletions(-)

diff --git a/wicket-core/src/main/java/org/apache/wicket/markup/head/filter/CspNonceHeaderResponse.java b/wicket-core/src/main/java/org/apache/wicket/markup/head/filter/CspNonceHeaderResponse.java
deleted file mode 100644
index f2a9ce1..0000000
--- a/wicket-core/src/main/java/org/apache/wicket/markup/head/filter/CspNonceHeaderResponse.java
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.wicket.markup.head.filter;
-
-import org.apache.wicket.Application;
-import org.apache.wicket.markup.head.AbstractCspHeaderItem;
-import org.apache.wicket.markup.head.HeaderItem;
-import org.apache.wicket.markup.head.IHeaderResponse;
-import org.apache.wicket.markup.head.IWrappedHeaderItem;
-import org.apache.wicket.markup.head.MetaDataHeaderItem;
-import org.apache.wicket.markup.head.ResourceAggregator;
-import org.apache.wicket.markup.html.DecoratingHeaderResponse;
-
-/**
- * Add a <em>Content Security Policy<em> (CSP) nonce to all {@link AbstractCspHeaderItem}s.
- * <p>
- * Note: please don't forget to wrap with {@link ResourceAggregator} when setting it up with
- * {@link Application#setHeaderResponseDecorator}, otherwise dependencies will not be rendered.
- * 
- * @see AbstractCspHeaderItem
- */
-public class CspNonceHeaderResponse extends DecoratingHeaderResponse
-{
-	private static final String CONTENT_SECURITY_POLICY = "Content-Security-Policy";
-
-	/**
-	 * Has the <em>Content-Security-Policy</em> header been rendered once.
-	 */
-	private boolean policyRendered = false;
-
-	private String nonce;
-
-	public CspNonceHeaderResponse(IHeaderResponse real, String nonce)
-	{
-		super(real);
-
-		this.nonce = nonce;
-	}
-
-	@Override
-	public void render(HeaderItem item)
-	{
-		while (item instanceof IWrappedHeaderItem)
-		{
-			item = ((IWrappedHeaderItem)item).getWrapped();
-		}
-
-		if (item instanceof AbstractCspHeaderItem)
-		{
-			if (policyRendered == false)
-			{
-				policyRendered = true;
-
-				String policy = getContentSecurityPolicy(nonce);
-
-				super.render(MetaDataHeaderItem.forHttpEquiv(CONTENT_SECURITY_POLICY, policy));
-			}
-
-			((AbstractCspHeaderItem)item).setNonce(nonce);
-		}
-		
-		super.render(item);
-	}
-
-	/**
-	 * Get the <em>Content-Security-Policy</em> (CSP).
-	 * <p>
-	 * There is a variety of CSP configurations, this default implementation uses the nonce for scripts and styles
-	 * and allows <code>strict-dynamic</code>s (needed for Wicket Ajax).
-	 * 
-	 * @param nonce
-	 *            the nonce
-	 * @return content security policy
-	 */
-	protected String getContentSecurityPolicy(String nonce)
-	{
-		return String.format("script-src 'strict-dynamic' 'nonce-%1$s'; style-src 'nonce-%1$s';", nonce);
-	}
-}
diff --git a/wicket-core/src/test/java/org/apache/wicket/markup/head/filter/CspNoncePageExpected.html b/wicket-core/src/test/java/org/apache/wicket/markup/head/filter/CspNoncePageExpected.html
index 2c44fc9..6cf3902 100644
--- a/wicket-core/src/test/java/org/apache/wicket/markup/head/filter/CspNoncePageExpected.html
+++ b/wicket-core/src/test/java/org/apache/wicket/markup/head/filter/CspNoncePageExpected.html
@@ -1,6 +1,5 @@
 <html xmlns:wicket="http://wicket.apache.org/dtds.data/wicket-xhtml1.4-strict.dtd" >
-    <head><meta http-equiv="Content-Security-Policy" content="script-src 'strict-dynamic' 'nonce-NONCE'; style-src 'nonce-NONCE';" />
-<script type="text/javascript" src="../resource/org.apache.wicket.resource.JQueryResourceReference/jquery/jquery-3.4.1.js" nonce="NONCE"></script>
+    <head><script type="text/javascript" src="../resource/org.apache.wicket.resource.JQueryResourceReference/jquery/jquery-3.4.1.js" nonce="NONCE"></script>
 <script type="text/javascript" src="../resource/org.apache.wicket.ajax.AbstractDefaultAjaxBehavior/res/js/wicket-ajax-jquery.js" nonce="NONCE"></script>
 <script type="text/javascript" id="wicket-ajax-debug-enable" nonce="NONCE">
 /*<![CDATA[*/
diff --git a/wicket-core/src/test/java/org/apache/wicket/markup/head/filter/FilteringHeaderResponseTest.java b/wicket-core/src/test/java/org/apache/wicket/markup/head/filter/FilteringHeaderResponseTest.java
index 63bbadf..2d5c467 100644
--- a/wicket-core/src/test/java/org/apache/wicket/markup/head/filter/FilteringHeaderResponseTest.java
+++ b/wicket-core/src/test/java/org/apache/wicket/markup/head/filter/FilteringHeaderResponseTest.java
@@ -20,12 +20,17 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
 
 import java.util.Collections;
 
+import org.apache.wicket.csp.CSPDirective;
+import org.apache.wicket.csp.ContentSecurityPolicyEnforcer;
 import org.apache.wicket.markup.head.IHeaderResponse;
 import org.apache.wicket.markup.head.ResourceAggregator;
 import org.apache.wicket.markup.head.StringHeaderItem;
 import org.apache.wicket.markup.head.internal.HeaderResponse;
 import org.apache.wicket.markup.html.IHeaderResponseDecorator;
+import org.apache.wicket.mock.MockApplication;
+import org.apache.wicket.protocol.http.WebApplication;
 import org.apache.wicket.request.Response;
+import org.apache.wicket.request.cycle.RequestCycle;
 import org.apache.wicket.response.StringResponse;
 import org.apache.wicket.util.tester.WicketTestCase;
 import org.junit.jupiter.api.Test;
@@ -37,6 +42,25 @@ import org.junit.jupiter.api.Test;
  */
 class FilteringHeaderResponseTest extends WicketTestCase
 {
+	@Override
+	protected WebApplication newApplication()
+	{
+		return new MockApplication()
+		{
+			@Override
+			protected ContentSecurityPolicyEnforcer newCspEnforcer()
+			{
+				return new ContentSecurityPolicyEnforcer(this)
+				{
+					@Override
+					public String getNonce(RequestCycle cycle)
+					{
+						return "NONCE";
+					}
+				};
+			}
+		};
+	}
 
 	@Test
 	void footerDependsOnHeadItem() throws Exception
@@ -96,9 +120,7 @@ class FilteringHeaderResponseTest extends WicketTestCase
 	@Test
 	void nonce() throws Exception
 	{
-		tester.getApplication()
-			.getHeaderResponseDecorators()
-			.add(response -> new CspNonceHeaderResponse(response, "NONCE"));
+		tester.getApplication().getCsp().blocking().strict();
 		executeTest(CspNoncePage.class, "CspNoncePageExpected.html");
 	}
 }
diff --git a/wicket-examples/src/main/java/org/apache/wicket/examples/csp/CspApplication.java b/wicket-examples/src/main/java/org/apache/wicket/examples/csp/CspApplication.java
index e8eff7e..ae9187d 100644
--- a/wicket-examples/src/main/java/org/apache/wicket/examples/csp/CspApplication.java
+++ b/wicket-examples/src/main/java/org/apache/wicket/examples/csp/CspApplication.java
@@ -16,24 +16,11 @@
  */
 package org.apache.wicket.examples.csp;
 
-import java.util.Base64;
-import java.util.concurrent.ThreadLocalRandom;
-
-import org.apache.wicket.MetaDataKey;
 import org.apache.wicket.Page;
-import org.apache.wicket.Session;
 import org.apache.wicket.examples.WicketExampleApplication;
-import org.apache.wicket.markup.head.ResourceAggregator;
-import org.apache.wicket.markup.head.filter.CspNonceHeaderResponse;
 
 public class CspApplication extends WicketExampleApplication
 {
-	private static final int NONCE_LENGTH = 24;
-	
-	public static MetaDataKey<String> NONCE_KEY = new MetaDataKey<String>()
-	{
-	};
-
 	@Override
 	public Class<? extends Page> getHomePage()
 	{
@@ -45,28 +32,8 @@ public class CspApplication extends WicketExampleApplication
 	{
 		super.init();
 
-		getHeaderResponseDecorators().add(response -> new CspNonceHeaderResponse(response, getNonce()));
+		getCsp().blocking().strict();
 		
 		mountPage("noncedemo", NonceDemoPage.class);
 	}
-
-	protected static String generateNonce()
-	{
-		byte[] randomBytes = new byte[NONCE_LENGTH];
-		ThreadLocalRandom.current().nextBytes(randomBytes);
-		return Base64.getUrlEncoder().encodeToString(randomBytes);
-	}
-
-	public static String getNonce()
-	{
-		Session session = Session.get();
-		session.bind();
-		String nonce = session.getMetaData(NONCE_KEY);
-		if (nonce == null)
-		{
-			nonce = generateNonce();
-			session.setMetaData(NONCE_KEY, nonce);
-		}
-		return nonce;
-	}
 }