summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lib/private/appframework/dependencyinjection/dicontainer.php10
-rw-r--r--lib/private/appframework/middleware/security/securitymiddleware.php37
-rw-r--r--lib/private/security/csp/contentsecuritypolicy.php199
-rw-r--r--lib/private/security/csp/contentsecuritypolicymanager.php73
-rw-r--r--lib/private/server.php12
-rw-r--r--lib/public/appframework/controller.php2
-rw-r--r--lib/public/appframework/http/contentsecuritypolicy.php335
-rw-r--r--lib/public/appframework/http/emptycontentsecuritypolicy.php387
-rw-r--r--lib/public/iservercontainer.php7
-rw-r--r--lib/public/security/icontentsecuritypolicymanager.php50
-rw-r--r--tests/lib/appframework/http/ContentSecurityPolicyTest.php17
-rw-r--r--tests/lib/appframework/http/EmptyContentSecurityPolicyTest.php430
-rw-r--r--tests/lib/appframework/middleware/security/SecurityMiddlewareTest.php37
-rw-r--r--tests/lib/security/csp/ContentSecurityPolicyManagerTest.php66
-rw-r--r--tests/lib/server.php2
15 files changed, 1316 insertions, 348 deletions
diff --git a/lib/private/appframework/dependencyinjection/dicontainer.php b/lib/private/appframework/dependencyinjection/dicontainer.php
index 61a04482431..ff9da88cd81 100644
--- a/lib/private/appframework/dependencyinjection/dicontainer.php
+++ b/lib/private/appframework/dependencyinjection/dicontainer.php
@@ -32,7 +32,6 @@ namespace OC\AppFramework\DependencyInjection;
use OC;
use OC\AppFramework\Http;
-use OC\AppFramework\Http\Request;
use OC\AppFramework\Http\Dispatcher;
use OC\AppFramework\Http\Output;
use OC\AppFramework\Core\API;
@@ -43,8 +42,6 @@ use OC\AppFramework\Middleware\SessionMiddleware;
use OC\AppFramework\Utility\SimpleContainer;
use OCP\AppFramework\IApi;
use OCP\AppFramework\IAppContainer;
-use OCP\AppFramework\Middleware;
-use OCP\IServerContainer;
class DIContainer extends SimpleContainer implements IAppContainer {
@@ -255,6 +252,10 @@ class DIContainer extends SimpleContainer implements IAppContainer {
return $this->getServer()->getSession();
});
+ $this->registerService('OCP\\Security\\IContentSecurityPolicyManager', function($c) {
+ return $this->getServer()->getContentSecurityPolicyManager();
+ });
+
$this->registerService('ServerContainer', function ($c) {
return $this->getServer();
});
@@ -319,7 +320,8 @@ class DIContainer extends SimpleContainer implements IAppContainer {
$app->getServer()->getLogger(),
$c['AppName'],
$app->isLoggedIn(),
- $app->isAdminUser()
+ $app->isAdminUser(),
+ $app->getServer()->getContentSecurityPolicyManager()
);
});
diff --git a/lib/private/appframework/middleware/security/securitymiddleware.php b/lib/private/appframework/middleware/security/securitymiddleware.php
index 4ef043ad50f..f1ba98254f0 100644
--- a/lib/private/appframework/middleware/security/securitymiddleware.php
+++ b/lib/private/appframework/middleware/security/securitymiddleware.php
@@ -32,6 +32,8 @@ use OC\Appframework\Middleware\Security\Exceptions\CrossSiteRequestForgeryExcept
use OC\Appframework\Middleware\Security\Exceptions\NotAdminException;
use OC\Appframework\Middleware\Security\Exceptions\NotLoggedInException;
use OC\AppFramework\Utility\ControllerMethodReflector;
+use OC\Security\CSP\ContentSecurityPolicyManager;
+use OCP\AppFramework\Http\ContentSecurityPolicy;
use OCP\AppFramework\Http\RedirectResponse;
use OCP\AppFramework\Http\TemplateResponse;
use OCP\AppFramework\Middleware;
@@ -52,15 +54,24 @@ use OC\AppFramework\Middleware\Security\Exceptions\SecurityException;
* check fails
*/
class SecurityMiddleware extends Middleware {
-
+ /** @var INavigationManager */
private $navigationManager;
+ /** @var IRequest */
private $request;
+ /** @var ControllerMethodReflector */
private $reflector;
+ /** @var string */
private $appName;
+ /** @var IURLGenerator */
private $urlGenerator;
+ /** @var ILogger */
private $logger;
+ /** @var bool */
private $isLoggedIn;
+ /** @var bool */
private $isAdminUser;
+ /** @var ContentSecurityPolicyManager */
+ private $contentSecurityPolicyManager;
/**
* @param IRequest $request
@@ -71,6 +82,7 @@ class SecurityMiddleware extends Middleware {
* @param string $appName
* @param bool $isLoggedIn
* @param bool $isAdminUser
+ * @param ContentSecurityPolicyManager $contentSecurityPolicyManager
*/
public function __construct(IRequest $request,
ControllerMethodReflector $reflector,
@@ -79,7 +91,8 @@ class SecurityMiddleware extends Middleware {
ILogger $logger,
$appName,
$isLoggedIn,
- $isAdminUser) {
+ $isAdminUser,
+ ContentSecurityPolicyManager $contentSecurityPolicyManager) {
$this->navigationManager = $navigationManager;
$this->request = $request;
$this->reflector = $reflector;
@@ -88,6 +101,7 @@ class SecurityMiddleware extends Middleware {
$this->logger = $logger;
$this->isLoggedIn = $isLoggedIn;
$this->isAdminUser = $isAdminUser;
+ $this->contentSecurityPolicyManager = $contentSecurityPolicyManager;
}
@@ -139,6 +153,25 @@ class SecurityMiddleware extends Middleware {
}
+ /**
+ * Performs the default CSP modifications that may be injected by other
+ * applications
+ *
+ * @param Controller $controller
+ * @param string $methodName
+ * @param Response $response
+ * @return Response
+ */
+ public function afterController($controller, $methodName, Response $response) {
+ $policy = !is_null($response->getContentSecurityPolicy()) ? $response->getContentSecurityPolicy() : new ContentSecurityPolicy();
+
+ $defaultPolicy = $this->contentSecurityPolicyManager->getDefaultPolicy();
+ $defaultPolicy = $this->contentSecurityPolicyManager->mergePolicies($defaultPolicy, $policy);
+
+ $response->setContentSecurityPolicy($defaultPolicy);
+
+ return $response;
+ }
/**
* If an SecurityException is being caught, ajax requests return a JSON error
diff --git a/lib/private/security/csp/contentsecuritypolicy.php b/lib/private/security/csp/contentsecuritypolicy.php
new file mode 100644
index 00000000000..25eacfab1d6
--- /dev/null
+++ b/lib/private/security/csp/contentsecuritypolicy.php
@@ -0,0 +1,199 @@
+<?php
+/**
+ * @author Lukas Reschke <lukas@owncloud.com>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+namespace OC\Security\CSP;
+
+/**
+ * Class ContentSecurityPolicy extends the public class and adds getter and setters.
+ * This is necessary since we don't want to expose the setters and getters to the
+ * public API.
+ *
+ * @package OC\Security\CSP
+ */
+class ContentSecurityPolicy extends \OCP\AppFramework\Http\ContentSecurityPolicy {
+ /**
+ * @return boolean
+ */
+ public function isInlineScriptAllowed() {
+ return $this->inlineScriptAllowed;
+ }
+
+ /**
+ * @param boolean $inlineScriptAllowed
+ */
+ public function setInlineScriptAllowed($inlineScriptAllowed) {
+ $this->inlineScriptAllowed = $inlineScriptAllowed;
+ }
+
+ /**
+ * @return boolean
+ */
+ public function isEvalScriptAllowed() {
+ return $this->evalScriptAllowed;
+ }
+
+ /**
+ * @param boolean $evalScriptAllowed
+ */
+ public function setEvalScriptAllowed($evalScriptAllowed) {
+ $this->evalScriptAllowed = $evalScriptAllowed;
+ }
+
+ /**
+ * @return array
+ */
+ public function getAllowedScriptDomains() {
+ return $this->allowedScriptDomains;
+ }
+
+ /**
+ * @param array $allowedScriptDomains
+ */
+ public function setAllowedScriptDomains($allowedScriptDomains) {
+ $this->allowedScriptDomains = $allowedScriptDomains;
+ }
+
+ /**
+ * @return boolean
+ */
+ public function isInlineStyleAllowed() {
+ return $this->inlineStyleAllowed;
+ }
+
+ /**
+ * @param boolean $inlineStyleAllowed
+ */
+ public function setInlineStyleAllowed($inlineStyleAllowed) {
+ $this->inlineStyleAllowed = $inlineStyleAllowed;
+ }
+
+ /**
+ * @return array
+ */
+ public function getAllowedStyleDomains() {
+ return $this->allowedStyleDomains;
+ }
+
+ /**
+ * @param array $allowedStyleDomains
+ */
+ public function setAllowedStyleDomains($allowedStyleDomains) {
+ $this->allowedStyleDomains = $allowedStyleDomains;
+ }
+
+ /**
+ * @return array
+ */
+ public function getAllowedImageDomains() {
+ return $this->allowedImageDomains;
+ }
+
+ /**
+ * @param array $allowedImageDomains
+ */
+ public function setAllowedImageDomains($allowedImageDomains) {
+ $this->allowedImageDomains = $allowedImageDomains;
+ }
+
+ /**
+ * @return array
+ */
+ public function getAllowedConnectDomains() {
+ return $this->allowedConnectDomains;
+ }
+
+ /**
+ * @param array $allowedConnectDomains
+ */
+ public function setAllowedConnectDomains($allowedConnectDomains) {
+ $this->allowedConnectDomains = $allowedConnectDomains;
+ }
+
+ /**
+ * @return array
+ */
+ public function getAllowedMediaDomains() {
+ return $this->allowedMediaDomains;
+ }
+
+ /**
+ * @param array $allowedMediaDomains
+ */
+ public function setAllowedMediaDomains($allowedMediaDomains) {
+ $this->allowedMediaDomains = $allowedMediaDomains;
+ }
+
+ /**
+ * @return array
+ */
+ public function getAllowedObjectDomains() {
+ return $this->allowedObjectDomains;
+ }
+
+ /**
+ * @param array $allowedObjectDomains
+ */
+ public function setAllowedObjectDomains($allowedObjectDomains) {
+ $this->allowedObjectDomains = $allowedObjectDomains;
+ }
+
+ /**
+ * @return array
+ */
+ public function getAllowedFrameDomains() {
+ return $this->allowedFrameDomains;
+ }
+
+ /**
+ * @param array $allowedFrameDomains
+ */
+ public function setAllowedFrameDomains($allowedFrameDomains) {
+ $this->allowedFrameDomains = $allowedFrameDomains;
+ }
+
+ /**
+ * @return array
+ */
+ public function getAllowedFontDomains() {
+ return $this->allowedFontDomains;
+ }
+
+ /**
+ * @param array $allowedFontDomains
+ */
+ public function setAllowedFontDomains($allowedFontDomains) {
+ $this->allowedFontDomains = $allowedFontDomains;
+ }
+
+ /**
+ * @return array
+ */
+ public function getAllowedChildSrcDomains() {
+ return $this->allowedChildSrcDomains;
+ }
+
+ /**
+ * @param array $allowedChildSrcDomains
+ */
+ public function setAllowedChildSrcDomains($allowedChildSrcDomains) {
+ $this->allowedChildSrcDomains = $allowedChildSrcDomains;
+ }
+
+}
diff --git a/lib/private/security/csp/contentsecuritypolicymanager.php b/lib/private/security/csp/contentsecuritypolicymanager.php
new file mode 100644
index 00000000000..760cd36e56b
--- /dev/null
+++ b/lib/private/security/csp/contentsecuritypolicymanager.php
@@ -0,0 +1,73 @@
+<?php
+/**
+ * @author Lukas Reschke <lukas@owncloud.com>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OC\Security\CSP;
+
+use OCP\AppFramework\Http\ContentSecurityPolicy;
+use OCP\AppFramework\Http\EmptyContentSecurityPolicy;
+use OCP\Security\IContentSecurityPolicyManager;
+
+class ContentSecurityPolicyManager implements IContentSecurityPolicyManager {
+ /** @var ContentSecurityPolicy[] */
+ private $policies = [];
+
+ /** {@inheritdoc} */
+ public function addDefaultPolicy(EmptyContentSecurityPolicy $policy) {
+ $this->policies[] = $policy;
+ }
+
+ /**
+ * Get the configured default policy. This is not in the public namespace
+ * as it is only supposed to be used by core itself.
+ *
+ * @return ContentSecurityPolicy
+ */
+ public function getDefaultPolicy() {
+ $defaultPolicy = new \OC\Security\CSP\ContentSecurityPolicy();
+ foreach($this->policies as $policy) {
+ $defaultPolicy = $this->mergePolicies($defaultPolicy, $policy);
+ }
+ return $defaultPolicy;
+ }
+
+ /**
+ * Merges the first given policy with the second one
+ *
+ * @param ContentSecurityPolicy $defaultPolicy
+ * @param EmptyContentSecurityPolicy $originalPolicy
+ * @return ContentSecurityPolicy
+ */
+ public function mergePolicies(ContentSecurityPolicy $defaultPolicy,
+ EmptyContentSecurityPolicy $originalPolicy) {
+ foreach((object)(array)$originalPolicy as $name => $value) {
+ $setter = 'set'.ucfirst($name);
+ if(is_array($value)) {
+ $getter = 'get'.ucfirst($name);
+ $currentValues = is_array($defaultPolicy->$getter()) ? $defaultPolicy->$getter() : [];
+ $defaultPolicy->$setter(array_values(array_unique(array_merge($currentValues, $value))));
+ } elseif (is_bool($value)) {
+ $defaultPolicy->$setter($value);
+ }
+ }
+
+ return $defaultPolicy;
+ }
+}
diff --git a/lib/private/server.php b/lib/private/server.php
index d453a42d3a0..d3dbcba86ba 100644
--- a/lib/private/server.php
+++ b/lib/private/server.php
@@ -63,6 +63,7 @@ use OC\Lock\NoopLockingProvider;
use OC\Mail\Mailer;
use OC\Notification\Manager;
use OC\Security\CertificateManager;
+use OC\Security\CSP\ContentSecurityPolicyManager;
use OC\Security\Crypto;
use OC\Security\CSRF\CsrfTokenGenerator;
use OC\Security\CSRF\CsrfTokenManager;
@@ -74,6 +75,7 @@ use OC\Security\TrustedDomainHelper;
use OC\Session\CryptoWrapper;
use OC\Tagging\TagMapper;
use OCP\IServerContainer;
+use OCP\Security\IContentSecurityPolicyManager;
use Symfony\Component\EventDispatcher\EventDispatcher;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
@@ -598,6 +600,9 @@ class Server extends ServerContainer implements IServerContainer {
$sessionStorage
);
});
+ $this->registerService('ContentSecurityPolicyManager', function (Server $c) {
+ return new ContentSecurityPolicyManager();
+ });
$this->registerService('ShareManager', function(Server $c) {
$config = $c->getConfig();
$factoryClass = $config->getSystemValue('sharing.managerFactory', '\OC\Share20\ProviderFactory');
@@ -1221,6 +1226,13 @@ class Server extends ServerContainer implements IServerContainer {
}
/**
+ * @return IContentSecurityPolicyManager
+ */
+ public function getContentSecurityPolicyManager() {
+ return $this->query('ContentSecurityPolicyManager');
+ }
+
+ /**
* Not a public API as of 8.2, wait for 9.0
*
* @return \OCA\Files_External\Service\BackendService
diff --git a/lib/public/appframework/controller.php b/lib/public/appframework/controller.php
index 973c9044684..c3744683300 100644
--- a/lib/public/appframework/controller.php
+++ b/lib/public/appframework/controller.php
@@ -72,7 +72,7 @@ abstract class Controller {
* @since 6.0.0 - parameter $appName was added in 7.0.0 - parameter $app was removed in 7.0.0
*/
public function __construct($appName,
- IRequest $request){
+ IRequest $request) {
$this->appName = $appName;
$this->request = $request;
diff --git a/lib/public/appframework/http/contentsecuritypolicy.php b/lib/public/appframework/http/contentsecuritypolicy.php
index 35da4f05e80..7762ca809a2 100644
--- a/lib/public/appframework/http/contentsecuritypolicy.php
+++ b/lib/public/appframework/http/contentsecuritypolicy.php
@@ -38,17 +38,17 @@ use OCP\AppFramework\Http;
* @package OCP\AppFramework\Http
* @since 8.1.0
*/
-class ContentSecurityPolicy {
+class ContentSecurityPolicy extends EmptyContentSecurityPolicy {
/** @var bool Whether inline JS snippets are allowed */
- private $inlineScriptAllowed = false;
+ protected $inlineScriptAllowed = false;
/**
* @var bool Whether eval in JS scripts is allowed
* TODO: Disallow per default
* @link https://github.com/owncloud/core/issues/11925
*/
- private $evalScriptAllowed = true;
+ protected $evalScriptAllowed = true;
/** @var array Domains from which scripts can get loaded */
- private $allowedScriptDomains = [
+ protected $allowedScriptDomains = [
'\'self\'',
];
/**
@@ -56,342 +56,33 @@ class ContentSecurityPolicy {
* TODO: Disallow per default
* @link https://github.com/owncloud/core/issues/13458
*/
- private $inlineStyleAllowed = true;
+ protected $inlineStyleAllowed = true;
/** @var array Domains from which CSS can get loaded */
- private $allowedStyleDomains = [
+ protected $allowedStyleDomains = [
'\'self\'',
];
/** @var array Domains from which images can get loaded */
- private $allowedImageDomains = [
+ protected $allowedImageDomains = [
'\'self\'',
'data:',
'blob:',
];
/** @var array Domains to which connections can be done */
- private $allowedConnectDomains = [
+ protected $allowedConnectDomains = [
'\'self\'',
];
/** @var array Domains from which media elements can be loaded */
- private $allowedMediaDomains = [
+ protected $allowedMediaDomains = [
'\'self\'',
];
/** @var array Domains from which object elements can be loaded */
- private $allowedObjectDomains = [];
+ protected $allowedObjectDomains = [];
/** @var array Domains from which iframes can be loaded */
- private $allowedFrameDomains = [];
+ protected $allowedFrameDomains = [];
/** @var array Domains from which fonts can be loaded */
- private $allowedFontDomains = [
+ protected $allowedFontDomains = [
'\'self\'',
];
/** @var array Domains from which web-workers and nested browsing content can load elements */
- private $allowedChildSrcDomains = [];
-
- /**
- * Whether inline JavaScript snippets are allowed or forbidden
- * @param bool $state
- * @return $this
- * @since 8.1.0
- */
- public function allowInlineScript($state = false) {
- $this->inlineScriptAllowed = $state;
- return $this;
- }
-
- /**
- * Whether eval in JavaScript is allowed or forbidden
- * @param bool $state
- * @return $this
- * @since 8.1.0
- */
- public function allowEvalScript($state = true) {
- $this->evalScriptAllowed = $state;
- return $this;
- }
-
- /**
- * Allows to execute JavaScript files from a specific domain. Use * to
- * allow JavaScript from all domains.
- * @param string $domain Domain to whitelist. Any passed value needs to be properly sanitized.
- * @return $this
- * @since 8.1.0
- */
- public function addAllowedScriptDomain($domain) {
- $this->allowedScriptDomains[] = $domain;
- return $this;
- }
-
- /**
- * Remove the specified allowed script domain from the allowed domains.
- *
- * @param string $domain
- * @return $this
- * @since 8.1.0
- */
- public function disallowScriptDomain($domain) {
- $this->allowedScriptDomains = array_diff($this->allowedScriptDomains, [$domain]);
- return $this;
- }
-
- /**
- * Whether inline CSS snippets are allowed or forbidden
- * @param bool $state
- * @return $this
- * @since 8.1.0
- */
- public function allowInlineStyle($state = true) {
- $this->inlineStyleAllowed = $state;
- return $this;
- }
-
- /**
- * Allows to execute CSS files from a specific domain. Use * to allow
- * CSS from all domains.
- * @param string $domain Domain to whitelist. Any passed value needs to be properly sanitized.
- * @return $this
- * @since 8.1.0
- */
- public function addAllowedStyleDomain($domain) {
- $this->allowedStyleDomains[] = $domain;
- return $this;
- }
-
- /**
- * Remove the specified allowed style domain from the allowed domains.
- *
- * @param string $domain
- * @return $this
- * @since 8.1.0
- */
- public function disallowStyleDomain($domain) {
- $this->allowedStyleDomains = array_diff($this->allowedStyleDomains, [$domain]);
- return $this;
- }
-
- /**
- * Allows using fonts from a specific domain. Use * to allow
- * fonts from all domains.
- * @param string $domain Domain to whitelist. Any passed value needs to be properly sanitized.
- * @return $this
- * @since 8.1.0
- */
- public function addAllowedFontDomain($domain) {
- $this->allowedFontDomains[] = $domain;
- return $this;
- }
-
- /**
- * Remove the specified allowed font domain from the allowed domains.
- *
- * @param string $domain
- * @return $this
- * @since 8.1.0
- */
- public function disallowFontDomain($domain) {
- $this->allowedFontDomains = array_diff($this->allowedFontDomains, [$domain]);
- return $this;
- }
-
- /**
- * Allows embedding images from a specific domain. Use * to allow
- * images from all domains.
- * @param string $domain Domain to whitelist. Any passed value needs to be properly sanitized.
- * @return $this
- * @since 8.1.0
- */
- public function addAllowedImageDomain($domain) {
- $this->allowedImageDomains[] = $domain;
- return $this;
- }
-
- /**
- * Remove the specified allowed image domain from the allowed domains.
- *
- * @param string $domain
- * @return $this
- * @since 8.1.0
- */
- public function disallowImageDomain($domain) {
- $this->allowedImageDomains = array_diff($this->allowedImageDomains, [$domain]);
- return $this;
- }
-
- /**
- * To which remote domains the JS connect to.
- * @param string $domain Domain to whitelist. Any passed value needs to be properly sanitized.
- * @return $this
- * @since 8.1.0
- */
- public function addAllowedConnectDomain($domain) {
- $this->allowedConnectDomains[] = $domain;
- return $this;
- }
-
- /**
- * Remove the specified allowed connect domain from the allowed domains.
- *
- * @param string $domain
- * @return $this
- * @since 8.1.0
- */
- public function disallowConnectDomain($domain) {
- $this->allowedConnectDomains = array_diff($this->allowedConnectDomains, [$domain]);
- return $this;
- }
-
- /**
- * From which domains media elements can be embedded.
- * @param string $domain Domain to whitelist. Any passed value needs to be properly sanitized.
- * @return $this
- * @since 8.1.0
- */
- public function addAllowedMediaDomain($domain) {
- $this->allowedMediaDomains[] = $domain;
- return $this;
- }
-
- /**
- * Remove the specified allowed media domain from the allowed domains.
- *
- * @param string $domain
- * @return $this
- * @since 8.1.0
- */
- public function disallowMediaDomain($domain) {
- $this->allowedMediaDomains = array_diff($this->allowedMediaDomains, [$domain]);
- return $this;
- }
-
- /**
- * From which domains objects such as <object>, <embed> or <applet> are executed
- * @param string $domain Domain to whitelist. Any passed value needs to be properly sanitized.
- * @return $this
- * @since 8.1.0
- */
- public function addAllowedObjectDomain($domain) {
- $this->allowedObjectDomains[] = $domain;
- return $this;
- }
-
- /**
- * Remove the specified allowed object domain from the allowed domains.
- *
- * @param string $domain
- * @return $this
- * @since 8.1.0
- */
- public function disallowObjectDomain($domain) {
- $this->allowedObjectDomains = array_diff($this->allowedObjectDomains, [$domain]);
- return $this;
- }
-
- /**
- * Which domains can be embedded in an iframe
- * @param string $domain Domain to whitelist. Any passed value needs to be properly sanitized.
- * @return $this
- * @since 8.1.0
- */
- public function addAllowedFrameDomain($domain) {
- $this->allowedFrameDomains[] = $domain;
- return $this;
- }
-
- /**
- * Remove the specified allowed frame domain from the allowed domains.
- *
- * @param string $domain
- * @return $this
- * @since 8.1.0
- */
- public function disallowFrameDomain($domain) {
- $this->allowedFrameDomains = array_diff($this->allowedFrameDomains, [$domain]);
- return $this;
- }
-
- /**
- * Domains from which web-workers and nested browsing content can load elements
- * @param string $domain Domain to whitelist. Any passed value needs to be properly sanitized.
- * @return $this
- * @since 8.1.0
- */
- public function addAllowedChildSrcDomain($domain) {
- $this->allowedChildSrcDomains[] = $domain;
- return $this;
- }
-
- /**
- * Remove the specified allowed child src domain from the allowed domains.
- *
- * @param string $domain
- * @return $this
- * @since 8.1.0
- */
- public function disallowChildSrcDomain($domain) {
- $this->allowedChildSrcDomains = array_diff($this->allowedChildSrcDomains, [$domain]);
- return $this;
- }
-
- /**
- * Get the generated Content-Security-Policy as a string
- * @return string
- * @since 8.1.0
- */
- public function buildPolicy() {
- $policy = "default-src 'none';";
-
- if(!empty($this->allowedScriptDomains)) {
- $policy .= 'script-src ' . implode(' ', $this->allowedScriptDomains);
- if($this->inlineScriptAllowed) {
- $policy .= ' \'unsafe-inline\'';
- }
- if($this->evalScriptAllowed) {
- $policy .= ' \'unsafe-eval\'';
- }
- $policy .= ';';
- }
-
- if(!empty($this->allowedStyleDomains)) {
- $policy .= 'style-src ' . implode(' ', $this->allowedStyleDomains);
- if($this->inlineStyleAllowed) {
- $policy .= ' \'unsafe-inline\'';
- }
- $policy .= ';';
- }
-
- if(!empty($this->allowedImageDomains)) {
- $policy .= 'img-src ' . implode(' ', $this->allowedImageDomains);
- $policy .= ';';
- }
-
- if(!empty($this->allowedFontDomains)) {
- $policy .= 'font-src ' . implode(' ', $this->allowedFontDomains);
- $policy .= ';';
- }
-
- if(!empty($this->allowedConnectDomains)) {
- $policy .= 'connect-src ' . implode(' ', $this->allowedConnectDomains);
- $policy .= ';';
- }
-
- if(!empty($this->allowedMediaDomains)) {
- $policy .= 'media-src ' . implode(' ', $this->allowedMediaDomains);
- $policy .= ';';
- }
-
- if(!empty($this->allowedObjectDomains)) {
- $policy .= 'object-src ' . implode(' ', $this->allowedObjectDomains);
- $policy .= ';';
- }
-
- if(!empty($this->allowedFrameDomains)) {
- $policy .= 'frame-src ' . implode(' ', $this->allowedFrameDomains);
- $policy .= ';';
- }
-
- if(!empty($this->allowedChildSrcDomains)) {
- $policy .= 'child-src ' . implode(' ', $this->allowedChildSrcDomains);
- $policy .= ';';
- }
-
- return rtrim($policy, ';');
- }
+ protected $allowedChildSrcDomains = [];
}
diff --git a/lib/public/appframework/http/emptycontentsecuritypolicy.php b/lib/public/appframework/http/emptycontentsecuritypolicy.php
new file mode 100644
index 00000000000..33860dcdb0f
--- /dev/null
+++ b/lib/public/appframework/http/emptycontentsecuritypolicy.php
@@ -0,0 +1,387 @@
+<?php
+/**
+ * @author Lukas Reschke <lukas@owncloud.com>
+ * @author Morris Jobke <hey@morrisjobke.de>
+ * @author sualko <klaus@jsxc.org>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCP\AppFramework\Http;
+
+use OCP\AppFramework\Http;
+
+/**
+ * Class EmptyContentSecurityPolicy is a simple helper which allows applications
+ * to modify the Content-Security-Policy sent by ownCloud. Per default the policy
+ * is forbidding everything.
+ *
+ * As alternative with sane exemptions look at ContentSecurityPolicy
+ *
+ * @see \OCP\AppFramework\Http\ContentSecurityPolicy
+ * @package OCP\AppFramework\Http
+ * @since 9.0.0
+ */
+class EmptyContentSecurityPolicy {
+ /** @var bool Whether inline JS snippets are allowed */
+ protected $inlineScriptAllowed = null;
+ /**
+ * @var bool Whether eval in JS scripts is allowed
+ * TODO: Disallow per default
+ * @link https://github.com/owncloud/core/issues/11925
+ */
+ protected $evalScriptAllowed = null;
+ /** @var array Domains from which scripts can get loaded */
+ protected $allowedScriptDomains = null;
+ /**
+ * @var bool Whether inline CSS is allowed
+ * TODO: Disallow per default
+ * @link https://github.com/owncloud/core/issues/13458
+ */
+ protected $inlineStyleAllowed = null;
+ /** @var array Domains from which CSS can get loaded */
+ protected $allowedStyleDomains = null;
+ /** @var array Domains from which images can get loaded */
+ protected $allowedImageDomains = null;
+ /** @var array Domains to which connections can be done */
+ protected $allowedConnectDomains = null;
+ /** @var array Domains from which media elements can be loaded */
+ protected $allowedMediaDomains = null;
+ /** @var array Domains from which object elements can be loaded */
+ protected $allowedObjectDomains = null;
+ /** @var array Domains from which iframes can be loaded */
+ protected $allowedFrameDomains = null;
+ /** @var array Domains from which fonts can be loaded */
+ protected $allowedFontDomains = null;
+ /** @var array Domains from which web-workers and nested browsing content can load elements */
+ protected $allowedChildSrcDomains = null;
+
+ /**
+ * Whether inline JavaScript snippets are allowed or forbidden
+ * @param bool $state
+ * @return $this
+ * @since 8.1.0
+ */
+ public function allowInlineScript($state = false) {
+ $this->inlineScriptAllowed = $state;
+ return $this;
+ }
+
+ /**
+ * Whether eval in JavaScript is allowed or forbidden
+ * @param bool $state
+ * @return $this
+ * @since 8.1.0
+ */
+ public function allowEvalScript($state = true) {
+ $this->evalScriptAllowed = $state;
+ return $this;
+ }
+
+ /**
+ * Allows to execute JavaScript files from a specific domain. Use * to
+ * allow JavaScript from all domains.
+ * @param string $domain Domain to whitelist. Any passed value needs to be properly sanitized.
+ * @return $this
+ * @since 8.1.0
+ */
+ public function addAllowedScriptDomain($domain) {
+ $this->allowedScriptDomains[] = $domain;
+ return $this;
+ }
+
+ /**
+ * Remove the specified allowed script domain from the allowed domains.
+ *
+ * @param string $domain
+ * @return $this
+ * @since 8.1.0
+ */
+ public function disallowScriptDomain($domain) {
+ $this->allowedScriptDomains = array_diff($this->allowedScriptDomains, [$domain]);
+ return $this;
+ }
+
+ /**
+ * Whether inline CSS snippets are allowed or forbidden
+ * @param bool $state
+ * @return $this
+ * @since 8.1.0
+ */
+ public function allowInlineStyle($state = true) {
+ $this->inlineStyleAllowed = $state;
+ return $this;
+ }
+
+ /**
+ * Allows to execute CSS files from a specific domain. Use * to allow
+ * CSS from all domains.
+ * @param string $domain Domain to whitelist. Any passed value needs to be properly sanitized.
+ * @return $this
+ * @since 8.1.0
+ */
+ public function addAllowedStyleDomain($domain) {
+ $this->allowedStyleDomains[] = $domain;
+ return $this;
+ }
+
+ /**
+ * Remove the specified allowed style domain from the allowed domains.
+ *
+ * @param string $domain
+ * @return $this
+ * @since 8.1.0
+ */
+ public function disallowStyleDomain($domain) {
+ $this->allowedStyleDomains = array_diff($this->allowedStyleDomains, [$domain]);
+ return $this;
+ }
+
+ /**
+ * Allows using fonts from a specific domain. Use * to allow
+ * fonts from all domains.
+ * @param string $domain Domain to whitelist. Any passed value needs to be properly sanitized.
+ * @return $this
+ * @since 8.1.0
+ */
+ public function addAllowedFontDomain($domain) {
+ $this->allowedFontDomains[] = $domain;
+ return $this;
+ }
+
+ /**
+ * Remove the specified allowed font domain from the allowed domains.
+ *
+ * @param string $domain
+ * @return $this
+ * @since 8.1.0
+ */
+ public function disallowFontDomain($domain) {
+ $this->allowedFontDomains = array_diff($this->allowedFontDomains, [$domain]);
+ return $this;
+ }
+
+ /**
+ * Allows embedding images from a specific domain. Use * to allow
+ * images from all domains.
+ * @param string $domain Domain to whitelist. Any passed value needs to be properly sanitized.
+ * @return $this
+ * @since 8.1.0
+ */
+ public function addAllowedImageDomain($domain) {
+ $this->allowedImageDomains[] = $domain;
+ return $this;
+ }
+
+ /**
+ * Remove the specified allowed image domain from the allowed domains.
+ *
+ * @param string $domain
+ * @return $this
+ * @since 8.1.0
+ */
+ public function disallowImageDomain($domain) {
+ $this->allowedImageDomains = array_diff($this->allowedImageDomains, [$domain]);
+ return $this;
+ }
+
+ /**
+ * To which remote domains the JS connect to.
+ * @param string $domain Domain to whitelist. Any passed value needs to be properly sanitized.
+ * @return $this
+ * @since 8.1.0
+ */
+ public function addAllowedConnectDomain($domain) {
+ $this->allowedConnectDomains[] = $domain;
+ return $this;
+ }
+
+ /**
+ * Remove the specified allowed connect domain from the allowed domains.
+ *
+ * @param string $domain
+ * @return $this
+ * @since 8.1.0
+ */
+ public function disallowConnectDomain($domain) {
+ $this->allowedConnectDomains = array_diff($this->allowedConnectDomains, [$domain]);
+ return $this;
+ }
+
+ /**
+ * From which domains media elements can be embedded.
+ * @param string $domain Domain to whitelist. Any passed value needs to be properly sanitized.
+ * @return $this
+ * @since 8.1.0
+ */
+ public function addAllowedMediaDomain($domain) {
+ $this->allowedMediaDomains[] = $domain;
+ return $this;
+ }
+
+ /**
+ * Remove the specified allowed media domain from the allowed domains.
+ *
+ * @param string $domain
+ * @return $this
+ * @since 8.1.0
+ */
+ public function disallowMediaDomain($domain) {
+ $this->allowedMediaDomains = array_diff($this->allowedMediaDomains, [$domain]);
+ return $this;
+ }
+
+ /**
+ * From which domains objects such as <object>, <embed> or <applet> are executed
+ * @param string $domain Domain to whitelist. Any passed value needs to be properly sanitized.
+ * @return $this
+ * @since 8.1.0
+ */
+ public function addAllowedObjectDomain($domain) {
+ $this->allowedObjectDomains[] = $domain;
+ return $this;
+ }
+
+ /**
+ * Remove the specified allowed object domain from the allowed domains.
+ *
+ * @param string $domain
+ * @return $this
+ * @since 8.1.0
+ */
+ public function disallowObjectDomain($domain) {
+ $this->allowedObjectDomains = array_diff($this->allowedObjectDomains, [$domain]);
+ return $this;
+ }
+
+ /**
+ * Which domains can be embedded in an iframe
+ * @param string $domain Domain to whitelist. Any passed value needs to be properly sanitized.
+ * @return $this
+ * @since 8.1.0
+ */
+ public function addAllowedFrameDomain($domain) {
+ $this->allowedFrameDomains[] = $domain;
+ return $this;
+ }
+
+ /**
+ * Remove the specified allowed frame domain from the allowed domains.
+ *
+ * @param string $domain
+ * @return $this
+ * @since 8.1.0
+ */
+ public function disallowFrameDomain($domain) {
+ $this->allowedFrameDomains = array_diff($this->allowedFrameDomains, [$domain]);
+ return $this;
+ }
+
+ /**
+ * Domains from which web-workers and nested browsing content can load elements
+ * @param string $domain Domain to whitelist. Any passed value needs to be properly sanitized.
+ * @return $this
+ * @since 8.1.0
+ */
+ public function addAllowedChildSrcDomain($domain) {
+ $this->allowedChildSrcDomains[] = $domain;
+ return $this;
+ }
+
+ /**
+ * Remove the specified allowed child src domain from the allowed domains.
+ *
+ * @param string $domain
+ * @return $this
+ * @since 8.1.0
+ */
+ public function disallowChildSrcDomain($domain) {
+ $this->allowedChildSrcDomains = array_diff($this->allowedChildSrcDomains, [$domain]);
+ return $this;
+ }
+
+ /**
+ * Get the generated Content-Security-Policy as a string
+ * @return string
+ * @since 8.1.0
+ */
+ public function buildPolicy() {
+ $policy = "default-src 'none';";
+
+ if(!empty($this->allowedScriptDomains) || $this->inlineScriptAllowed || $this->evalScriptAllowed) {
+ $policy .= 'script-src ';
+ if(is_array($this->allowedScriptDomains)) {
+ $policy .= implode(' ', $this->allowedScriptDomains);
+ }
+ if($this->inlineScriptAllowed) {
+ $policy .= ' \'unsafe-inline\'';
+ }
+ if($this->evalScriptAllowed) {
+ $policy .= ' \'unsafe-eval\'';
+ }
+ $policy .= ';';
+ }
+
+ if(!empty($this->allowedStyleDomains) || $this->inlineStyleAllowed) {
+ $policy .= 'style-src ';
+ if(is_array($this->allowedStyleDomains)) {
+ $policy .= implode(' ', $this->allowedStyleDomains);
+ }
+ if($this->inlineStyleAllowed) {
+ $policy .= ' \'unsafe-inline\'';
+ }
+ $policy .= ';';
+ }
+
+ if(!empty($this->allowedImageDomains)) {
+ $policy .= 'img-src ' . implode(' ', $this->allowedImageDomains);
+ $policy .= ';';
+ }
+
+ if(!empty($this->allowedFontDomains)) {
+ $policy .= 'font-src ' . implode(' ', $this->allowedFontDomains);
+ $policy .= ';';
+ }
+
+ if(!empty($this->allowedConnectDomains)) {
+ $policy .= 'connect-src ' . implode(' ', $this->allowedConnectDomains);
+ $policy .= ';';
+ }
+
+ if(!empty($this->allowedMediaDomains)) {
+ $policy .= 'media-src ' . implode(' ', $this->allowedMediaDomains);
+ $policy .= ';';
+ }
+
+ if(!empty($this->allowedObjectDomains)) {
+ $policy .= 'object-src ' . implode(' ', $this->allowedObjectDomains);
+ $policy .= ';';
+ }
+
+ if(!empty($this->allowedFrameDomains)) {
+ $policy .= 'frame-src ' . implode(' ', $this->allowedFrameDomains);
+ $policy .= ';';
+ }
+
+ if(!empty($this->allowedChildSrcDomains)) {
+ $policy .= 'child-src ' . implode(' ', $this->allowedChildSrcDomains);
+ $policy .= ';';
+ }
+
+ return rtrim($policy, ';');
+ }
+}
diff --git a/lib/public/iservercontainer.php b/lib/public/iservercontainer.php
index ce1364cc4ea..de48daeef88 100644
--- a/lib/public/iservercontainer.php
+++ b/lib/public/iservercontainer.php
@@ -42,6 +42,7 @@
// use OCP namespace for all classes that are considered public.
// This means that they should be used by apps instead of the internal ownCloud classes
namespace OCP;
+use OCP\Security\IContentSecurityPolicyManager;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
@@ -512,4 +513,10 @@ interface IServerContainer {
* @since 9.0.0
*/
public function getShareManager();
+
+ /**
+ * @return IContentSecurityPolicyManager
+ * @since 9.0.0
+ */
+ public function getContentSecurityPolicyManager();
}
diff --git a/lib/public/security/icontentsecuritypolicymanager.php b/lib/public/security/icontentsecuritypolicymanager.php
new file mode 100644
index 00000000000..10f1efe995f
--- /dev/null
+++ b/lib/public/security/icontentsecuritypolicymanager.php
@@ -0,0 +1,50 @@
+<?php
+/**
+ * @author Lukas Reschke <lukas@owncloud.com>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCP\Security;
+use OCP\AppFramework\Http\EmptyContentSecurityPolicy;
+
+/**
+ * Used for Content Security Policy manipulations
+ *
+ * @package OCP\Security
+ * @since 9.0.0
+ */
+interface IContentSecurityPolicyManager {
+ /**
+ * Allows to inject something into the default content policy. This is for
+ * example useful when you're injecting Javascript code into a view belonging
+ * to another controller and cannot modify its Content-Security-Policy itself.
+ * Note that the adjustment is only applied to applications that use AppFramework
+ * controllers.
+ *
+ * To use this from your `app.php` use `\OC::$server->getContentSecurityPolicyManager()->addDefaultPolicy($policy)`,
+ * $policy has to be of type `\OCP\AppFramework\Http\ContentSecurityPolicy`.
+ *
+ * WARNING: Using this API incorrectly may make the instance more insecure.
+ * Do think twice before adding whitelisting resources. Please do also note
+ * that it is not possible to use the `disallowXYZ` functions.
+ *
+ * @param EmptyContentSecurityPolicy $policy
+ * @since 9.0.0
+ */
+ public function addDefaultPolicy(EmptyContentSecurityPolicy $policy);
+}
diff --git a/tests/lib/appframework/http/ContentSecurityPolicyTest.php b/tests/lib/appframework/http/ContentSecurityPolicyTest.php
index 6d9c6d7b8d9..adf03185e9f 100644
--- a/tests/lib/appframework/http/ContentSecurityPolicyTest.php
+++ b/tests/lib/appframework/http/ContentSecurityPolicyTest.php
@@ -426,21 +426,4 @@ class ContentSecurityPolicyTest extends \Test\TestCase {
$this->contentSecurityPolicy->disallowChildSrcDomain('www.owncloud.org')->disallowChildSrcDomain('www.owncloud.com');
$this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy());
}
-
- public function testConfigureStacked() {
- $expectedPolicy = "default-src 'none';script-src 'self' script.owncloud.org;style-src 'self' style.owncloud.org;img-src 'self' data: blob: img.owncloud.org;font-src 'self' font.owncloud.org;connect-src 'self' connect.owncloud.org;media-src 'self' media.owncloud.org;object-src objects.owncloud.org;frame-src frame.owncloud.org;child-src child.owncloud.org";
-
- $this->contentSecurityPolicy->allowInlineStyle(false)
- ->allowEvalScript(false)
- ->addAllowedScriptDomain('script.owncloud.org')
- ->addAllowedStyleDomain('style.owncloud.org')
- ->addAllowedFontDomain('font.owncloud.org')
- ->addAllowedImageDomain('img.owncloud.org')
- ->addAllowedConnectDomain('connect.owncloud.org')
- ->addAllowedMediaDomain('media.owncloud.org')
- ->addAllowedObjectDomain('objects.owncloud.org')
- ->addAllowedChildSrcDomain('child.owncloud.org')
- ->addAllowedFrameDomain('frame.owncloud.org');
- $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy());
- }
}
diff --git a/tests/lib/appframework/http/EmptyContentSecurityPolicyTest.php b/tests/lib/appframework/http/EmptyContentSecurityPolicyTest.php
new file mode 100644
index 00000000000..0d0f92de819
--- /dev/null
+++ b/tests/lib/appframework/http/EmptyContentSecurityPolicyTest.php
@@ -0,0 +1,430 @@
+<?php
+/**
+ * Copyright (c) 2015 Lukas Reschke lukas@owncloud.com
+ * This file is licensed under the Affero General Public License version 3 or
+ * later.
+ * See the COPYING-README file.
+ */
+
+
+namespace OC\AppFramework\Http;
+
+use OCP\AppFramework\Http;
+use OCP\AppFramework\Http\EmptyContentSecurityPolicy;
+
+/**
+ * Class ContentSecurityPolicyTest
+ *
+ * @package OC\AppFramework\Http
+ */
+class EmptyContentSecurityPolicyTest extends \Test\TestCase {
+
+ /** @var EmptyContentSecurityPolicy */
+ private $contentSecurityPolicy;
+
+ public function setUp() {
+ parent::setUp();
+ $this->contentSecurityPolicy = new EmptyContentSecurityPolicy();
+ }
+
+ public function testGetPolicyDefault() {
+ $defaultPolicy = "default-src 'none'";
+ $this->assertSame($defaultPolicy, $this->contentSecurityPolicy->buildPolicy());
+ }
+
+ public function testGetPolicyScriptDomainValid() {
+ $expectedPolicy = "default-src 'none';script-src www.owncloud.com";
+
+ $this->contentSecurityPolicy->addAllowedScriptDomain('www.owncloud.com');
+ $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy());
+ }
+
+ public function testGetPolicyScriptDomainValidMultiple() {
+ $expectedPolicy = "default-src 'none';script-src www.owncloud.com www.owncloud.org";
+
+ $this->contentSecurityPolicy->addAllowedScriptDomain('www.owncloud.com');
+ $this->contentSecurityPolicy->addAllowedScriptDomain('www.owncloud.org');
+ $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy());
+ }
+
+ public function testGetPolicyDisallowScriptDomain() {
+ $expectedPolicy = "default-src 'none'";
+
+ $this->contentSecurityPolicy->addAllowedScriptDomain('www.owncloud.com');
+ $this->contentSecurityPolicy->disallowScriptDomain('www.owncloud.com');
+ $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy());
+ }
+
+ public function testGetPolicyDisallowScriptDomainMultiple() {
+ $expectedPolicy = "default-src 'none';script-src www.owncloud.com";
+
+ $this->contentSecurityPolicy->addAllowedScriptDomain('www.owncloud.com');
+ $this->contentSecurityPolicy->disallowScriptDomain('www.owncloud.org');
+ $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy());
+ }
+
+ public function testGetPolicyDisallowScriptDomainMultipleStacked() {
+ $expectedPolicy = "default-src 'none'";
+
+ $this->contentSecurityPolicy->addAllowedScriptDomain('www.owncloud.com');
+ $this->contentSecurityPolicy->disallowScriptDomain('www.owncloud.org')->disallowScriptDomain('www.owncloud.com');
+ $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy());
+ }
+
+ public function testGetPolicyScriptAllowInline() {
+ $expectedPolicy = "default-src 'none';script-src 'unsafe-inline'";
+
+ $this->contentSecurityPolicy->allowInlineScript(true);
+ $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy());
+ }
+
+ public function testGetPolicyScriptAllowInlineWithDomain() {
+ $expectedPolicy = "default-src 'none';script-src www.owncloud.com 'unsafe-inline'";
+
+ $this->contentSecurityPolicy->addAllowedScriptDomain('www.owncloud.com');
+ $this->contentSecurityPolicy->allowInlineScript(true);
+ $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy());
+ }
+
+ public function testGetPolicyScriptAllowInlineAndEval() {
+ $expectedPolicy = "default-src 'none';script-src 'unsafe-inline' 'unsafe-eval'";
+
+ $this->contentSecurityPolicy->allowInlineScript(true);
+ $this->contentSecurityPolicy->allowEvalScript(true);
+ $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy());
+ }
+
+ public function testGetPolicyStyleDomainValid() {
+ $expectedPolicy = "default-src 'none';style-src www.owncloud.com";
+
+ $this->contentSecurityPolicy->addAllowedStyleDomain('www.owncloud.com');
+ $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy());
+ }
+
+ public function testGetPolicyStyleDomainValidMultiple() {
+ $expectedPolicy = "default-src 'none';style-src www.owncloud.com www.owncloud.org";
+
+ $this->contentSecurityPolicy->addAllowedStyleDomain('www.owncloud.com');
+ $this->contentSecurityPolicy->addAllowedStyleDomain('www.owncloud.org');
+ $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy());
+ }
+
+ public function testGetPolicyDisallowStyleDomain() {
+ $expectedPolicy = "default-src 'none'";
+
+ $this->contentSecurityPolicy->addAllowedStyleDomain('www.owncloud.com');
+ $this->contentSecurityPolicy->disallowStyleDomain('www.owncloud.com');
+ $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy());
+ }
+
+ public function testGetPolicyDisallowStyleDomainMultiple() {
+ $expectedPolicy = "default-src 'none';style-src www.owncloud.com";
+
+ $this->contentSecurityPolicy->addAllowedStyleDomain('www.owncloud.com');
+ $this->contentSecurityPolicy->disallowStyleDomain('www.owncloud.org');
+ $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy());
+ }
+
+ public function testGetPolicyDisallowStyleDomainMultipleStacked() {
+ $expectedPolicy = "default-src 'none'";
+
+ $this->contentSecurityPolicy->addAllowedStyleDomain('www.owncloud.com');
+ $this->contentSecurityPolicy->disallowStyleDomain('www.owncloud.org')->disallowStyleDomain('www.owncloud.com');
+ $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy());
+ }
+
+ public function testGetPolicyStyleAllowInline() {
+ $expectedPolicy = "default-src 'none';style-src 'unsafe-inline'";
+
+ $this->contentSecurityPolicy->allowInlineStyle(true);
+ $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy());
+ }
+
+ public function testGetPolicyStyleAllowInlineWithDomain() {
+ $expectedPolicy = "default-src 'none';style-src www.owncloud.com 'unsafe-inline'";
+
+ $this->contentSecurityPolicy->addAllowedStyleDomain('www.owncloud.com');
+ $this->contentSecurityPolicy->allowInlineStyle(true);
+ $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy());
+ }
+
+ public function testGetPolicyStyleDisallowInline() {
+ $expectedPolicy = "default-src 'none'";
+
+ $this->contentSecurityPolicy->allowInlineStyle(false);
+ $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy());
+ }
+
+ public function testGetPolicyImageDomainValid() {
+ $expectedPolicy = "default-src 'none';img-src www.owncloud.com";
+
+ $this->contentSecurityPolicy->addAllowedImageDomain('www.owncloud.com');
+ $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy());
+ }
+
+ public function testGetPolicyImageDomainValidMultiple() {
+ $expectedPolicy = "default-src 'none';img-src www.owncloud.com www.owncloud.org";
+
+ $this->contentSecurityPolicy->addAllowedImageDomain('www.owncloud.com');
+ $this->contentSecurityPolicy->addAllowedImageDomain('www.owncloud.org');
+ $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy());
+ }
+
+ public function testGetPolicyDisallowImageDomain() {
+ $expectedPolicy = "default-src 'none'";
+
+ $this->contentSecurityPolicy->addAllowedImageDomain('www.owncloud.com');
+ $this->contentSecurityPolicy->disallowImageDomain('www.owncloud.com');
+ $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy());
+ }
+
+ public function testGetPolicyDisallowImageDomainMultiple() {
+ $expectedPolicy = "default-src 'none';img-src www.owncloud.com";
+
+ $this->contentSecurityPolicy->addAllowedImageDomain('www.owncloud.com');
+ $this->contentSecurityPolicy->disallowImageDomain('www.owncloud.org');
+ $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy());
+ }
+
+ public function testGetPolicyDisallowImageDomainMultipleStakes() {
+ $expectedPolicy = "default-src 'none'";
+
+ $this->contentSecurityPolicy->addAllowedImageDomain('www.owncloud.com');
+ $this->contentSecurityPolicy->disallowImageDomain('www.owncloud.org')->disallowImageDomain('www.owncloud.com');
+ $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy());
+ }
+
+ public function testGetPolicyFontDomainValid() {
+ $expectedPolicy = "default-src 'none';font-src www.owncloud.com";
+
+ $this->contentSecurityPolicy->addAllowedFontDomain('www.owncloud.com');
+ $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy());
+ }
+
+ public function testGetPolicyFontDomainValidMultiple() {
+ $expectedPolicy = "default-src 'none';font-src www.owncloud.com www.owncloud.org";
+
+ $this->contentSecurityPolicy->addAllowedFontDomain('www.owncloud.com');
+ $this->contentSecurityPolicy->addAllowedFontDomain('www.owncloud.org');
+ $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy());
+ }
+
+ public function testGetPolicyDisallowFontDomain() {
+ $expectedPolicy = "default-src 'none'";
+
+ $this->contentSecurityPolicy->addAllowedFontDomain('www.owncloud.com');
+ $this->contentSecurityPolicy->disallowFontDomain('www.owncloud.com');
+ $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy());
+ }
+
+ public function testGetPolicyDisallowFontDomainMultiple() {
+ $expectedPolicy = "default-src 'none';font-src www.owncloud.com";
+
+ $this->contentSecurityPolicy->addAllowedFontDomain('www.owncloud.com');
+ $this->contentSecurityPolicy->disallowFontDomain('www.owncloud.org');
+ $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy());
+ }
+
+ public function testGetPolicyDisallowFontDomainMultipleStakes() {
+ $expectedPolicy = "default-src 'none'";
+
+ $this->contentSecurityPolicy->addAllowedFontDomain('www.owncloud.com');
+ $this->contentSecurityPolicy->disallowFontDomain('www.owncloud.org')->disallowFontDomain('www.owncloud.com');
+ $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy());
+ }
+
+ public function testGetPolicyConnectDomainValid() {
+ $expectedPolicy = "default-src 'none';connect-src www.owncloud.com";
+
+ $this->contentSecurityPolicy->addAllowedConnectDomain('www.owncloud.com');
+ $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy());
+ }
+
+ public function testGetPolicyConnectDomainValidMultiple() {
+ $expectedPolicy = "default-src 'none';connect-src www.owncloud.com www.owncloud.org";
+
+ $this->contentSecurityPolicy->addAllowedConnectDomain('www.owncloud.com');
+ $this->contentSecurityPolicy->addAllowedConnectDomain('www.owncloud.org');
+ $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy());
+ }
+
+ public function testGetPolicyDisallowConnectDomain() {
+ $expectedPolicy = "default-src 'none'";
+
+ $this->contentSecurityPolicy->addAllowedConnectDomain('www.owncloud.com');
+ $this->contentSecurityPolicy->disallowConnectDomain('www.owncloud.com');
+ $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy());
+ }
+
+ public function testGetPolicyDisallowConnectDomainMultiple() {
+ $expectedPolicy = "default-src 'none';connect-src www.owncloud.com";
+
+ $this->contentSecurityPolicy->addAllowedConnectDomain('www.owncloud.com');
+ $this->contentSecurityPolicy->disallowConnectDomain('www.owncloud.org');
+ $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy());
+ }
+
+ public function testGetPolicyDisallowConnectDomainMultipleStakes() {
+ $expectedPolicy = "default-src 'none'";
+
+ $this->contentSecurityPolicy->addAllowedConnectDomain('www.owncloud.com');
+ $this->contentSecurityPolicy->disallowConnectDomain('www.owncloud.org')->disallowConnectDomain('www.owncloud.com');
+ $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy());
+ }
+
+ public function testGetPolicyMediaDomainValid() {
+ $expectedPolicy = "default-src 'none';media-src www.owncloud.com";
+
+ $this->contentSecurityPolicy->addAllowedMediaDomain('www.owncloud.com');
+ $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy());
+ }
+
+ public function testGetPolicyMediaDomainValidMultiple() {
+ $expectedPolicy = "default-src 'none';media-src www.owncloud.com www.owncloud.org";
+
+ $this->contentSecurityPolicy->addAllowedMediaDomain('www.owncloud.com');
+ $this->contentSecurityPolicy->addAllowedMediaDomain('www.owncloud.org');
+ $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy());
+ }
+
+ public function testGetPolicyDisallowMediaDomain() {
+ $expectedPolicy = "default-src 'none'";
+
+ $this->contentSecurityPolicy->addAllowedMediaDomain('www.owncloud.com');
+ $this->contentSecurityPolicy->disallowMediaDomain('www.owncloud.com');
+ $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy());
+ }
+
+ public function testGetPolicyDisallowMediaDomainMultiple() {
+ $expectedPolicy = "default-src 'none';media-src www.owncloud.com";
+
+ $this->contentSecurityPolicy->addAllowedMediaDomain('www.owncloud.com');
+ $this->contentSecurityPolicy->disallowMediaDomain('www.owncloud.org');
+ $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy());
+ }
+
+ public function testGetPolicyDisallowMediaDomainMultipleStakes() {
+ $expectedPolicy = "default-src 'none'";
+
+ $this->contentSecurityPolicy->addAllowedMediaDomain('www.owncloud.com');
+ $this->contentSecurityPolicy->disallowMediaDomain('www.owncloud.org')->disallowMediaDomain('www.owncloud.com');
+ $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy());
+ }
+
+ public function testGetPolicyObjectDomainValid() {
+ $expectedPolicy = "default-src 'none';object-src www.owncloud.com";
+
+ $this->contentSecurityPolicy->addAllowedObjectDomain('www.owncloud.com');
+ $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy());
+ }
+
+ public function testGetPolicyObjectDomainValidMultiple() {
+ $expectedPolicy = "default-src 'none';object-src www.owncloud.com www.owncloud.org";
+
+ $this->contentSecurityPolicy->addAllowedObjectDomain('www.owncloud.com');
+ $this->contentSecurityPolicy->addAllowedObjectDomain('www.owncloud.org');
+ $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy());
+ }
+
+ public function testGetPolicyDisallowObjectDomain() {
+ $expectedPolicy = "default-src 'none'";
+
+ $this->contentSecurityPolicy->addAllowedObjectDomain('www.owncloud.com');
+ $this->contentSecurityPolicy->disallowObjectDomain('www.owncloud.com');
+ $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy());
+ }
+
+ public function testGetPolicyDisallowObjectDomainMultiple() {
+ $expectedPolicy = "default-src 'none';object-src www.owncloud.com";
+
+ $this->contentSecurityPolicy->addAllowedObjectDomain('www.owncloud.com');
+ $this->contentSecurityPolicy->disallowObjectDomain('www.owncloud.org');
+ $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy());
+ }
+
+ public function testGetPolicyDisallowObjectDomainMultipleStakes() {
+ $expectedPolicy = "default-src 'none'";
+
+ $this->contentSecurityPolicy->addAllowedObjectDomain('www.owncloud.com');
+ $this->contentSecurityPolicy->disallowObjectDomain('www.owncloud.org')->disallowObjectDomain('www.owncloud.com');
+ $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy());
+ }
+
+ public function testGetAllowedFrameDomain() {
+ $expectedPolicy = "default-src 'none';frame-src www.owncloud.com";
+
+ $this->contentSecurityPolicy->addAllowedFrameDomain('www.owncloud.com');
+ $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy());
+ }
+
+ public function testGetPolicyFrameDomainValidMultiple() {
+ $expectedPolicy = "default-src 'none';frame-src www.owncloud.com www.owncloud.org";
+
+ $this->contentSecurityPolicy->addAllowedFrameDomain('www.owncloud.com');
+ $this->contentSecurityPolicy->addAllowedFrameDomain('www.owncloud.org');
+ $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy());
+ }
+
+ public function testGetPolicyDisallowFrameDomain() {
+ $expectedPolicy = "default-src 'none'";
+
+ $this->contentSecurityPolicy->addAllowedFrameDomain('www.owncloud.com');
+ $this->contentSecurityPolicy->disallowFrameDomain('www.owncloud.com');
+ $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy());
+ }
+
+ public function testGetPolicyDisallowFrameDomainMultiple() {
+ $expectedPolicy = "default-src 'none';frame-src www.owncloud.com";
+
+ $this->contentSecurityPolicy->addAllowedFrameDomain('www.owncloud.com');
+ $this->contentSecurityPolicy->disallowFrameDomain('www.owncloud.org');
+ $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy());
+ }
+
+ public function testGetPolicyDisallowFrameDomainMultipleStakes() {
+ $expectedPolicy = "default-src 'none'";
+
+ $this->contentSecurityPolicy->addAllowedFrameDomain('www.owncloud.com');
+ $this->contentSecurityPolicy->disallowFrameDomain('www.owncloud.org')->disallowFrameDomain('www.owncloud.com');
+ $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy());
+ }
+
+ public function testGetAllowedChildSrcDomain() {
+ $expectedPolicy = "default-src 'none';child-src child.owncloud.com";
+
+ $this->contentSecurityPolicy->addAllowedChildSrcDomain('child.owncloud.com');
+ $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy());
+ }
+
+ public function testGetPolicyChildSrcValidMultiple() {
+ $expectedPolicy = "default-src 'none';child-src child.owncloud.com child.owncloud.org";
+
+ $this->contentSecurityPolicy->addAllowedChildSrcDomain('child.owncloud.com');
+ $this->contentSecurityPolicy->addAllowedChildSrcDomain('child.owncloud.org');
+ $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy());
+ }
+
+ public function testGetPolicyDisallowChildSrcDomain() {
+ $expectedPolicy = "default-src 'none'";
+
+ $this->contentSecurityPolicy->addAllowedChildSrcDomain('www.owncloud.com');
+ $this->contentSecurityPolicy->disallowChildSrcDomain('www.owncloud.com');
+ $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy());
+ }
+
+ public function testGetPolicyDisallowChildSrcDomainMultiple() {
+ $expectedPolicy = "default-src 'none';child-src www.owncloud.com";
+
+ $this->contentSecurityPolicy->addAllowedChildSrcDomain('www.owncloud.com');
+ $this->contentSecurityPolicy->disallowChildSrcDomain('www.owncloud.org');
+ $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy());
+ }
+
+ public function testGetPolicyDisallowChildSrcDomainMultipleStakes() {
+ $expectedPolicy = "default-src 'none'";
+
+ $this->contentSecurityPolicy->addAllowedChildSrcDomain('www.owncloud.com');
+ $this->contentSecurityPolicy->disallowChildSrcDomain('www.owncloud.org')->disallowChildSrcDomain('www.owncloud.com');
+ $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy());
+ }
+}
diff --git a/tests/lib/appframework/middleware/security/SecurityMiddlewareTest.php b/tests/lib/appframework/middleware/security/SecurityMiddlewareTest.php
index 62223bbc2d9..9e71a3d0961 100644
--- a/tests/lib/appframework/middleware/security/SecurityMiddlewareTest.php
+++ b/tests/lib/appframework/middleware/security/SecurityMiddlewareTest.php
@@ -32,6 +32,7 @@ use OC\Appframework\Middleware\Security\Exceptions\NotAdminException;
use OC\Appframework\Middleware\Security\Exceptions\NotLoggedInException;
use OC\AppFramework\Middleware\Security\Exceptions\SecurityException;
use OC\AppFramework\Utility\ControllerMethodReflector;
+use OC\Security\CSP\ContentSecurityPolicy;
use OCP\AppFramework\Http\RedirectResponse;
use OCP\AppFramework\Http\JSONResponse;
use OCP\AppFramework\Http\TemplateResponse;
@@ -48,6 +49,7 @@ class SecurityMiddlewareTest extends \Test\TestCase {
private $logger;
private $navigationManager;
private $urlGenerator;
+ private $contentSecurityPolicyManager;
protected function setUp() {
parent::setUp();
@@ -72,6 +74,10 @@ class SecurityMiddlewareTest extends \Test\TestCase {
'OCP\IRequest')
->disableOriginalConstructor()
->getMock();
+ $this->contentSecurityPolicyManager = $this->getMockBuilder(
+ 'OC\Security\CSP\ContentSecurityPolicyManager')
+ ->disableOriginalConstructor()
+ ->getMock();
$this->middleware = $this->getMiddleware(true, true);
$this->secException = new SecurityException('hey', false);
$this->secAjaxException = new SecurityException('hey', true);
@@ -91,7 +97,8 @@ class SecurityMiddlewareTest extends \Test\TestCase {
$this->logger,
'files',
$isLoggedIn,
- $isAdminUser
+ $isAdminUser,
+ $this->contentSecurityPolicyManager
);
}
@@ -410,5 +417,31 @@ class SecurityMiddlewareTest extends \Test\TestCase {
$this->assertTrue($response instanceof JSONResponse);
}
-
+ public function testAfterController() {
+ $response = $this->getMockBuilder('\OCP\AppFramework\Http\Response')->disableOriginalConstructor()->getMock();
+ $defaultPolicy = new ContentSecurityPolicy();
+ $defaultPolicy->addAllowedImageDomain('defaultpolicy');
+ $currentPolicy = new ContentSecurityPolicy();
+ $currentPolicy->addAllowedConnectDomain('currentPolicy');
+ $mergedPolicy = new ContentSecurityPolicy();
+ $mergedPolicy->addAllowedMediaDomain('mergedPolicy');
+ $response
+ ->expects($this->exactly(2))
+ ->method('getContentSecurityPolicy')
+ ->willReturn($currentPolicy);
+ $this->contentSecurityPolicyManager
+ ->expects($this->once())
+ ->method('getDefaultPolicy')
+ ->willReturn($defaultPolicy);
+ $this->contentSecurityPolicyManager
+ ->expects($this->once())
+ ->method('mergePolicies')
+ ->with($defaultPolicy, $currentPolicy)
+ ->willReturn($mergedPolicy);
+ $response->expects($this->once())
+ ->method('setContentSecurityPolicy')
+ ->with($mergedPolicy);
+
+ $this->middleware->afterController($this->controller, 'test', $response);
+ }
}
diff --git a/tests/lib/security/csp/ContentSecurityPolicyManagerTest.php b/tests/lib/security/csp/ContentSecurityPolicyManagerTest.php
new file mode 100644
index 00000000000..975c35d3780
--- /dev/null
+++ b/tests/lib/security/csp/ContentSecurityPolicyManagerTest.php
@@ -0,0 +1,66 @@
+<?php
+/**
+ * @author Lukas Reschke <lukas@owncloud.com>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+use OC\Security\CSP\ContentSecurityPolicyManager;
+
+class ContentSecurityPolicyManagerTest extends \Test\TestCase {
+ /** @var ContentSecurityPolicyManager */
+ private $contentSecurityPolicyManager;
+
+ public function setUp() {
+ parent::setUp();
+ $this->contentSecurityPolicyManager = new ContentSecurityPolicyManager();
+ }
+
+ public function testAddDefaultPolicy() {
+ $this->contentSecurityPolicyManager->addDefaultPolicy(new \OCP\AppFramework\Http\ContentSecurityPolicy());
+ }
+
+ public function testGetDefaultPolicyWithPolicies() {
+ $policy = new \OCP\AppFramework\Http\ContentSecurityPolicy();
+ $policy->addAllowedFontDomain('mydomain.com');
+ $policy->addAllowedImageDomain('anotherdomain.de');
+ $this->contentSecurityPolicyManager->addDefaultPolicy($policy);
+ $policy = new \OCP\AppFramework\Http\ContentSecurityPolicy();
+ $policy->addAllowedFontDomain('example.com');
+ $policy->addAllowedImageDomain('example.org');
+ $policy->allowInlineScript(true);
+ $this->contentSecurityPolicyManager->addDefaultPolicy($policy);
+ $policy = new \OCP\AppFramework\Http\EmptyContentSecurityPolicy();
+ $policy->addAllowedChildSrcDomain('childdomain');
+ $policy->addAllowedFontDomain('anotherFontDomain');
+ $this->contentSecurityPolicyManager->addDefaultPolicy($policy);
+
+ $expected = new \OC\Security\CSP\ContentSecurityPolicy();
+ $expected->allowInlineScript(true);
+ $expected->addAllowedFontDomain('mydomain.com');
+ $expected->addAllowedFontDomain('example.com');
+ $expected->addAllowedFontDomain('anotherFontDomain');
+ $expected->addAllowedImageDomain('anotherdomain.de');
+ $expected->addAllowedImageDomain('example.org');
+ $expected->addAllowedChildSrcDomain('childdomain');
+ $expectedStringPolicy = 'default-src \'none\';script-src \'self\' \'unsafe-inline\' \'unsafe-eval\';style-src \'self\' \'unsafe-inline\';img-src \'self\' data: blob: anotherdomain.de example.org;font-src \'self\' mydomain.com example.com anotherFontDomain;connect-src \'self\';media-src \'self\';child-src childdomain';
+
+ $this->assertEquals($expected, $this->contentSecurityPolicyManager->getDefaultPolicy());
+ $this->assertSame($expectedStringPolicy, $this->contentSecurityPolicyManager->getDefaultPolicy()->buildPolicy());
+ }
+
+}
diff --git a/tests/lib/server.php b/tests/lib/server.php
index 8b2fec1f5a1..d13f9be0c9e 100644
--- a/tests/lib/server.php
+++ b/tests/lib/server.php
@@ -62,10 +62,12 @@ class Server extends \Test\TestCase {
['CapabilitiesManager', '\OC\CapabilitiesManager'],
['ContactsManager', '\OC\ContactsManager'],
['ContactsManager', '\OCP\Contacts\IManager'],
+ ['ContentSecurityPolicyManager', '\OC\Security\CSP\ContentSecurityPolicyManager'],
['CommentsManager', '\OCP\Comments\ICommentsManager'],
['Crypto', '\OC\Security\Crypto'],
['Crypto', '\OCP\Security\ICrypto'],
['CryptoWrapper', '\OC\Session\CryptoWrapper'],
+ ['CsrfTokenManager', '\OC\Security\CSRF\CsrfTokenManager'],
['DatabaseConnection', '\OC\DB\Connection'],
['DatabaseConnection', '\OCP\IDBConnection'],