From ea935f65fdc94b94b4509a139477b52f046dc03f Mon Sep 17 00:00:00 2001
From: Sam Bull <aa6bs0@sambull.org>
Date: Mon, 8 Jul 2019 20:54:45 +0100
Subject: [PATCH] Add support for CSP_NONCE server variable

Allow passing a nonce from the web server, allowing the possibility to enforce a strict CSP from the web server.

Signed-off-by: Sam Bull <git@sambull.org>
Signed-off-by: Roeland Jago Douma <roeland@famdouma.nl>
---
 .../CSP/ContentSecurityPolicyNonceManager.php |  6 ++++-
 .../ContentSecurityPolicyNonceManagerTest.php | 23 +++++++++++++++++--
 2 files changed, 26 insertions(+), 3 deletions(-)

diff --git a/lib/private/Security/CSP/ContentSecurityPolicyNonceManager.php b/lib/private/Security/CSP/ContentSecurityPolicyNonceManager.php
index 795d8cc8642..f4743369e6e 100644
--- a/lib/private/Security/CSP/ContentSecurityPolicyNonceManager.php
+++ b/lib/private/Security/CSP/ContentSecurityPolicyNonceManager.php
@@ -58,7 +58,11 @@ class ContentSecurityPolicyNonceManager {
 	 */
 	public function getNonce(): string {
 		if($this->nonce === '') {
-			$this->nonce = base64_encode($this->csrfTokenManager->getToken()->getEncryptedValue());
+			if (empty($this->request->server['CSP_NONCE'])) {
+				$this->nonce = base64_encode($this->csrfTokenManager->getToken()->getEncryptedValue());
+			} else {
+				$this->nonce = $this->request->server['CSP_NONCE'];
+			}
 		}
 
 		return $this->nonce;
diff --git a/tests/lib/Security/CSP/ContentSecurityPolicyNonceManagerTest.php b/tests/lib/Security/CSP/ContentSecurityPolicyNonceManagerTest.php
index 3211a5284f8..705a0b22db8 100644
--- a/tests/lib/Security/CSP/ContentSecurityPolicyNonceManagerTest.php
+++ b/tests/lib/Security/CSP/ContentSecurityPolicyNonceManagerTest.php
@@ -21,23 +21,26 @@
 
 namespace Test\Security\CSP;
 
+use OC\AppFramework\Http\Request;
 use OC\Security\CSP\ContentSecurityPolicyNonceManager;
 use OC\Security\CSRF\CsrfToken;
 use OC\Security\CSRF\CsrfTokenManager;
-use OCP\IRequest;
 use Test\TestCase;
 
 class ContentSecurityPolicyNonceManagerTest extends TestCase  {
 	/** @var CsrfTokenManager */
 	private $csrfTokenManager;
+	/** @var Request */
+	private $request;
 	/** @var ContentSecurityPolicyNonceManager */
 	private $nonceManager;
 
 	public function setUp() {
 		$this->csrfTokenManager = $this->createMock(CsrfTokenManager::class);
+		$this->request = $this->createMock(Request::class);
 		$this->nonceManager = new ContentSecurityPolicyNonceManager(
 			$this->csrfTokenManager,
-			$this->createMock(IRequest::class)
+			$this->request
 		);
 	}
 
@@ -56,4 +59,20 @@ class ContentSecurityPolicyNonceManagerTest extends TestCase  {
 		$this->assertSame('TXlUb2tlbg==', $this->nonceManager->getNonce());
 		$this->assertSame('TXlUb2tlbg==', $this->nonceManager->getNonce());
 	}
+
+	public function testGetNonceServerVar() {
+		$token = 'SERVERNONCE';
+		$this->request
+			->method('__isset')
+			->with('server')
+			->willReturn(true);
+
+		$this->request
+			->method('__get')
+			->with('server')
+			->willReturn(['CSP_NONCE' => $token]);
+
+		$this->assertSame($token, $this->nonceManager->getNonce());
+		$this->assertSame($token, $this->nonceManager->getNonce());
+	}
 }
-- 
GitLab