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/08/10 12:21:10 UTC

[wicket] branch master updated: WICKET-6813: frame-src should clone all values of child-src if unset not just the first

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

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


The following commit(s) were added to refs/heads/master by this push:
     new 27aba85  WICKET-6813: frame-src should clone all values of child-src if unset not just the first
27aba85 is described below

commit 27aba858ea2f1eeb177de2d35961eb939a7bacd6
Author: Emond Papegaaij <em...@topicus.nl>
AuthorDate: Mon Aug 10 14:20:50 2020 +0200

    WICKET-6813: frame-src should clone all values of child-src if unset not just the first
---
 .../apache/wicket/csp/CSPHeaderConfiguration.java  | 14 ++++-
 .../java/org/apache/wicket/csp/ClonedCSPValue.java | 67 ++++++++++++++++++++++
 .../csp/CSPSettingRequestCycleListenerTest.java    | 32 +++++++++++
 3 files changed, 112 insertions(+), 1 deletion(-)

diff --git a/wicket-core/src/main/java/org/apache/wicket/csp/CSPHeaderConfiguration.java b/wicket-core/src/main/java/org/apache/wicket/csp/CSPHeaderConfiguration.java
index ac3a19f..0e3de21 100644
--- a/wicket-core/src/main/java/org/apache/wicket/csp/CSPHeaderConfiguration.java
+++ b/wicket-core/src/main/java/org/apache/wicket/csp/CSPHeaderConfiguration.java
@@ -34,6 +34,7 @@ import static org.apache.wicket.csp.CSPDirectiveSrcValue.UNSAFE_EVAL;
 import static org.apache.wicket.csp.CSPDirectiveSrcValue.UNSAFE_INLINE;
 
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.EnumMap;
 import java.util.List;
 import java.util.Map;
@@ -262,6 +263,16 @@ public class CSPHeaderConfiguration
 	}
 
 	/**
+	 * Returns an unmodifiable map of the directives set for this header.
+	 * 
+	 * @return The directives set for this header.
+	 */
+	public Map<CSPDirective, List<CSPRenderable>> getDirectives()
+	{
+		return Collections.unmodifiableMap(directives);
+	}
+
+	/**
 	 * @return true if this {@code CSPHeaderConfiguration} has any directives configured.
 	 */
 	public boolean isSet()
@@ -307,7 +318,8 @@ public class CSPHeaderConfiguration
 		if (CSPDirective.CHILD_SRC.equals(directive)
 			&& !directives.containsKey(CSPDirective.FRAME_SRC))
 		{
-			doAddDirective(CSPDirective.FRAME_SRC, value);
+			doAddDirective(CSPDirective.FRAME_SRC,
+				new ClonedCSPValue(this, CSPDirective.CHILD_SRC));
 		}
 		List<CSPRenderable> values = directives.computeIfAbsent(directive, x -> new ArrayList<>());
 		directive.checkValueForDirective(value, values);
diff --git a/wicket-core/src/main/java/org/apache/wicket/csp/ClonedCSPValue.java b/wicket-core/src/main/java/org/apache/wicket/csp/ClonedCSPValue.java
new file mode 100644
index 0000000..bd8dcb7
--- /dev/null
+++ b/wicket-core/src/main/java/org/apache/wicket/csp/ClonedCSPValue.java
@@ -0,0 +1,67 @@
+/*
+ * 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.csp;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+import org.apache.wicket.request.cycle.RequestCycle;
+import org.apache.wicket.util.lang.Args;
+
+/**
+ * A CSP value that renders the same value as rendered for the specified directive.
+ * 
+ * @author papegaaij
+ */
+public class ClonedCSPValue implements CSPRenderable
+{
+	private final CSPHeaderConfiguration headerConfiguration;
+
+	private final CSPDirective sourceDirective;
+
+	/**
+	 * Creates a new {@code ClonedCSPValue} for the given directive.
+	 * 
+	 * @param headerConfiguration
+	 *            the header to clone from;
+	 * @param sourceDirective
+	 *            the directive to clone;
+	 */
+	public ClonedCSPValue(CSPHeaderConfiguration headerConfiguration, CSPDirective sourceDirective)
+	{
+		this.headerConfiguration = Args.notNull(headerConfiguration, "headerConfiguration");
+		this.sourceDirective = Args.notNull(sourceDirective, "sourceDirective");
+	}
+
+	@Override
+	public String render(ContentSecurityPolicySettings settings, RequestCycle cycle)
+	{
+		List<CSPRenderable> values = headerConfiguration.getDirectives().get(sourceDirective);
+		if (values == null)
+		{
+			throw new IllegalStateException(
+				"CSP directive " + sourceDirective + " not set, cannot clone its value.");
+		}
+		return values.stream().map(r -> r.render(settings, cycle)).collect(Collectors.joining(" "));
+	}
+
+	@Override
+	public String toString()
+	{
+		return "clone(" + sourceDirective.getValue() + ")";
+	}
+}
diff --git a/wicket-core/src/test/java/org/apache/wicket/csp/CSPSettingRequestCycleListenerTest.java b/wicket-core/src/test/java/org/apache/wicket/csp/CSPSettingRequestCycleListenerTest.java
index 25eb9d9..9679cbc 100644
--- a/wicket-core/src/test/java/org/apache/wicket/csp/CSPSettingRequestCycleListenerTest.java
+++ b/wicket-core/src/test/java/org/apache/wicket/csp/CSPSettingRequestCycleListenerTest.java
@@ -26,6 +26,7 @@ import static org.apache.wicket.csp.CSPDirectiveSandboxValue.EMPTY;
 import static org.apache.wicket.csp.CSPDirectiveSrcValue.NONE;
 import static org.apache.wicket.csp.CSPDirectiveSrcValue.SELF;
 import static org.apache.wicket.csp.CSPDirectiveSrcValue.WILDCARD;
+import static org.junit.jupiter.api.Assertions.assertEquals;
 
 import java.net.URI;
 import java.net.URISyntaxException;
@@ -38,6 +39,8 @@ import java.util.stream.Stream;
 
 import org.apache.wicket.mock.MockHomePage;
 import org.apache.wicket.protocol.http.WebApplication;
+import org.apache.wicket.request.cycle.RequestCycle;
+import org.apache.wicket.util.tester.DummyHomePage;
 import org.apache.wicket.util.tester.WicketTestCase;
 import org.apache.wicket.util.tester.WicketTester;
 import org.junit.jupiter.api.Assertions;
@@ -311,6 +314,35 @@ public class CSPSettingRequestCycleListenerTest extends WicketTestCase
 		}
 	}
 
+	@Test
+	public void testChildIsClonedIntoFrame()
+	{
+		ContentSecurityPolicySettings settings = tester.getApplication().getCspSettings();
+		settings.blocking().add(CHILD_SRC, SELF);
+
+		tester.startPage(DummyHomePage.class);
+		String childSrc = renderDirective(settings.blocking().getDirectives().get(CHILD_SRC),
+			settings, tester.getRequestCycle());
+		String frameSrc = renderDirective(settings.blocking().getDirectives().get(FRAME_SRC),
+			settings, tester.getRequestCycle());
+		assertEquals("'self'", childSrc);
+		assertEquals(childSrc, frameSrc);
+
+		settings.blocking().add(CHILD_SRC, "https://wicket.apache.org");
+		childSrc = renderDirective(settings.blocking().getDirectives().get(CHILD_SRC), settings,
+			tester.getRequestCycle());
+		frameSrc = renderDirective(settings.blocking().getDirectives().get(FRAME_SRC), settings,
+			tester.getRequestCycle());
+		assertEquals("'self' https://wicket.apache.org", childSrc);
+		assertEquals(childSrc, frameSrc);
+	}
+
+	private String renderDirective(List<CSPRenderable> values,
+		ContentSecurityPolicySettings settings, RequestCycle cycle)
+	{
+		return values.stream().map(r -> r.render(settings, cycle)).collect(Collectors.joining(" "));
+	}
+
 	private List<String> checkHeaders()
 	{
 		List<String> headerErrors = new ArrayList<>();