diff --git a/lib/private/AppFramework/DependencyInjection/DIContainer.php b/lib/private/AppFramework/DependencyInjection/DIContainer.php
index 9a9740b7bccc4..a6772fd8bfc2c 100644
--- a/lib/private/AppFramework/DependencyInjection/DIContainer.php
+++ b/lib/private/AppFramework/DependencyInjection/DIContainer.php
@@ -268,7 +268,7 @@ public function __construct(string $appName, array $urlParams = [], ServerContai
)
);
$dispatcher->registerMiddleware(
- $server->query(OC\AppFramework\Middleware\Security\FeaturePolicyMiddleware::class)
+ $server->query(OC\AppFramework\Middleware\Security\PermissionPolicyMiddleware::class)
);
$dispatcher->registerMiddleware(
new OC\AppFramework\Middleware\Security\PasswordConfirmationMiddleware(
diff --git a/lib/private/AppFramework/Middleware/Security/FeaturePolicyMiddleware.php b/lib/private/AppFramework/Middleware/Security/PermissionPolicyMiddleware.php
similarity index 52%
rename from lib/private/AppFramework/Middleware/Security/FeaturePolicyMiddleware.php
rename to lib/private/AppFramework/Middleware/Security/PermissionPolicyMiddleware.php
index 418d4185184e5..6f5c897f5aeec 100644
--- a/lib/private/AppFramework/Middleware/Security/FeaturePolicyMiddleware.php
+++ b/lib/private/AppFramework/Middleware/Security/PermissionPolicyMiddleware.php
@@ -23,21 +23,30 @@
* along with this program. If not, see .
*
*/
+
namespace OC\AppFramework\Middleware\Security;
use OC\Security\FeaturePolicy\FeaturePolicy;
use OC\Security\FeaturePolicy\FeaturePolicyManager;
+use OC\Security\PermissionPolicy\PermissionPolicy;
+use OC\Security\PermissionPolicy\PermissionPolicyManager;
use OCP\AppFramework\Controller;
use OCP\AppFramework\Http\EmptyFeaturePolicy;
+use OCP\AppFramework\Http\EmptyPermissionPolicy;
use OCP\AppFramework\Http\Response;
use OCP\AppFramework\Middleware;
-class FeaturePolicyMiddleware extends Middleware {
+class PermissionPolicyMiddleware extends Middleware {
+
/** @var FeaturePolicyManager */
- private $policyManager;
+ private $featurePolicyManager;
+
+ /** @var PermissionPolicyManager */
+ private $permissionPolicyManager;
- public function __construct(FeaturePolicyManager $policyManager) {
- $this->policyManager = $policyManager;
+ public function __construct(FeaturePolicyManager $featurePolicyManager, PermissionPolicyManager $permissionPolicyManager) {
+ $this->featurePolicyManager = $featurePolicyManager;
+ $this->permissionPolicyManager = $permissionPolicyManager;
}
/**
@@ -50,15 +59,20 @@ public function __construct(FeaturePolicyManager $policyManager) {
* @return Response
*/
public function afterController($controller, $methodName, Response $response): Response {
- $policy = !is_null($response->getFeaturePolicy()) ? $response->getFeaturePolicy() : new FeaturePolicy();
-
- if (get_class($policy) === EmptyFeaturePolicy::class) {
- return $response;
+ $featurePolicy = $response->getFeaturePolicy() ?? new FeaturePolicy();
+ if ($featurePolicy::class !== EmptyFeaturePolicy::class) {
+ $defaultPolicy = $this->featurePolicyManager->getDefaultPolicy();
+ $defaultPolicy = $this->featurePolicyManager->mergePolicies($defaultPolicy, $featurePolicy);
+ $response->setFeaturePolicy($defaultPolicy);
}
- $defaultPolicy = $this->policyManager->getDefaultPolicy();
- $defaultPolicy = $this->policyManager->mergePolicies($defaultPolicy, $policy);
- $response->setFeaturePolicy($defaultPolicy);
+ $permissionPolicy = $response->getPermissionPolicy() ?? new PermissionPolicy();
+ if ($permissionPolicy::class !== EmptyPermissionPolicy::class) {
+ $defaultPolicy = $this->permissionPolicyManager->getDefaultPolicy();
+ $defaultPolicy = $this->permissionPolicyManager->mergePolicies($defaultPolicy, $permissionPolicy);
+ $defaultPolicy = $this->permissionPolicyManager->mergeFeaturePolicy($defaultPolicy, $response->getFeaturePolicy());
+ $response->setPermissionPolicy($defaultPolicy);
+ }
return $response;
}
diff --git a/lib/private/Security/PermissionPolicy/PermissionPolicy.php b/lib/private/Security/PermissionPolicy/PermissionPolicy.php
new file mode 100644
index 0000000000000..87f4240f9ad63
--- /dev/null
+++ b/lib/private/Security/PermissionPolicy/PermissionPolicy.php
@@ -0,0 +1,76 @@
+
+ *
+ * @author Roeland Jago Douma
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * 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
+ * along with this program. If not, see .
+ *
+ */
+
+namespace OC\Security\PermissionPolicy;
+
+class PermissionPolicy extends \OCP\AppFramework\Http\PermissionPolicy {
+ public function getAutoplayDomains(): array {
+ return $this->autoplayDomains;
+ }
+
+ public function setAutoplayDomains(array $autoplayDomains): void {
+ $this->autoplayDomains = $autoplayDomains;
+ }
+
+ public function getCameraDomains(): array {
+ return $this->cameraDomains;
+ }
+
+ public function setCameraDomains(array $cameraDomains): void {
+ $this->cameraDomains = $cameraDomains;
+ }
+
+ public function getFullscreenDomains(): array {
+ return $this->fullscreenDomains;
+ }
+
+ public function setFullscreenDomains(array $fullscreenDomains): void {
+ $this->fullscreenDomains = $fullscreenDomains;
+ }
+
+ public function getGeolocationDomains(): array {
+ return $this->geolocationDomains;
+ }
+
+ public function setGeolocationDomains(array $geolocationDomains): void {
+ $this->geolocationDomains = $geolocationDomains;
+ }
+
+ public function getMicrophoneDomains(): array {
+ return $this->microphoneDomains;
+ }
+
+ public function setMicrophoneDomains(array $microphoneDomains): void {
+ $this->microphoneDomains = $microphoneDomains;
+ }
+
+ public function getPaymentDomains(): array {
+ return $this->paymentDomains;
+ }
+
+ public function setPaymentDomains(array $paymentDomains): void {
+ $this->paymentDomains = $paymentDomains;
+ }
+}
diff --git a/lib/private/Security/PermissionPolicy/PermissionPolicyManager.php b/lib/private/Security/PermissionPolicy/PermissionPolicyManager.php
new file mode 100644
index 0000000000000..1aedeb6b3e255
--- /dev/null
+++ b/lib/private/Security/PermissionPolicy/PermissionPolicyManager.php
@@ -0,0 +1,94 @@
+
+ *
+ * @author Roeland Jago Douma
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * 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
+ * along with this program. If not, see .
+ *
+ */
+
+
+namespace OC\Security\PermissionPolicy;
+
+use OCP\AppFramework\Http\EmptyFeaturePolicy;
+use OCP\AppFramework\Http\EmptyPermissionPolicy;
+use OCP\EventDispatcher\IEventDispatcher;
+use OCP\Security\PermissionPolicy\AddPermissionsPolicyEvent;
+
+class PermissionPolicyManager {
+ /** @var EmptyPermissionPolicy[] */
+ private $policies = [];
+
+ /** @var IEventDispatcher */
+ private $dispatcher;
+
+ public function __construct(IEventDispatcher $dispatcher) {
+ $this->dispatcher = $dispatcher;
+ }
+
+ public function addDefaultPolicy(EmptyPermissionPolicy $policy): void {
+ $this->policies[] = $policy;
+ }
+
+ public function getDefaultPolicy(): PermissionPolicy {
+ $event = new AddPermissionsPolicyEvent($this);
+ $this->dispatcher->dispatchTyped($event);
+
+ $defaultPolicy = new PermissionPolicy();
+ foreach ($this->policies as $policy) {
+ $defaultPolicy = $this->mergePolicies($defaultPolicy, $policy);
+ }
+ return $defaultPolicy;
+ }
+
+ /**
+ * Merges the first given policy with the second one
+ *
+ */
+ public function mergePolicies(PermissionPolicy $defaultPolicy,
+ EmptyPermissionPolicy $originalPolicy): PermissionPolicy {
+ 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;
+ }
+
+ public function mergeFeaturePolicy(PermissionPolicy $defaultPolicy, EmptyFeaturePolicy $featurePolicy): PermissionPolicy {
+ foreach ((object)(array)$featurePolicy 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/public/AppFramework/Http/EmptyFeaturePolicy.php b/lib/public/AppFramework/Http/EmptyFeaturePolicy.php
index b73eaf667e73f..d254954e4f8b8 100644
--- a/lib/public/AppFramework/Http/EmptyFeaturePolicy.php
+++ b/lib/public/AppFramework/Http/EmptyFeaturePolicy.php
@@ -34,6 +34,7 @@
*
* @see \OCP\AppFramework\Http\FeaturePolicy
* @since 17.0.0
+ * @deprecated 28.0.0 Use \OCP\AppFramework\Http\EmptyPermissionPolicy
*/
class EmptyFeaturePolicy {
/** @var string[] of allowed domains to autoplay media */
@@ -60,6 +61,7 @@ class EmptyFeaturePolicy {
* @param string $domain Domain to whitelist. Any passed value needs to be properly sanitized.
* @return $this
* @since 17.0.0
+ * @deprecated 28.0.0 Use \OCP\AppFramework\Http\EmptyPermissionPolicy
*/
public function addAllowedAutoplayDomain(string $domain): self {
$this->autoplayDomains[] = $domain;
@@ -72,6 +74,7 @@ public function addAllowedAutoplayDomain(string $domain): self {
* @param string $domain Domain to whitelist. Any passed value needs to be properly sanitized.
* @return $this
* @since 17.0.0
+ * @deprecated 28.0.0 Use \OCP\AppFramework\Http\EmptyPermissionPolicy
*/
public function addAllowedCameraDomain(string $domain): self {
$this->cameraDomains[] = $domain;
@@ -84,6 +87,7 @@ public function addAllowedCameraDomain(string $domain): self {
* @param string $domain Domain to whitelist. Any passed value needs to be properly sanitized.
* @return $this
* @since 17.0.0
+ * @deprecated 28.0.0 Use \OCP\AppFramework\Http\EmptyPermissionPolicy
*/
public function addAllowedFullScreenDomain(string $domain): self {
$this->fullscreenDomains[] = $domain;
@@ -96,6 +100,7 @@ public function addAllowedFullScreenDomain(string $domain): self {
* @param string $domain Domain to whitelist. Any passed value needs to be properly sanitized.
* @return $this
* @since 17.0.0
+ * @deprecated 28.0.0 Use \OCP\AppFramework\Http\EmptyPermissionPolicy
*/
public function addAllowedGeoLocationDomain(string $domain): self {
$this->geolocationDomains[] = $domain;
@@ -108,6 +113,7 @@ public function addAllowedGeoLocationDomain(string $domain): self {
* @param string $domain Domain to whitelist. Any passed value needs to be properly sanitized.
* @return $this
* @since 17.0.0
+ * @deprecated 28.0.0 Use \OCP\AppFramework\Http\EmptyPermissionPolicy
*/
public function addAllowedMicrophoneDomain(string $domain): self {
$this->microphoneDomains[] = $domain;
@@ -120,6 +126,7 @@ public function addAllowedMicrophoneDomain(string $domain): self {
* @param string $domain Domain to whitelist. Any passed value needs to be properly sanitized.
* @return $this
* @since 17.0.0
+ * @deprecated 28.0.0 Use \OCP\AppFramework\Http\EmptyPermissionPolicy
*/
public function addAllowedPaymentDomain(string $domain): self {
$this->paymentDomains[] = $domain;
@@ -131,6 +138,7 @@ public function addAllowedPaymentDomain(string $domain): self {
*
* @return string
* @since 17.0.0
+ * @deprecated 28.0.0 Use \OCP\AppFramework\Http\EmptyPermissionPolicy
*/
public function buildPolicy(): string {
$policy = '';
diff --git a/lib/public/AppFramework/Http/EmptyPermissionPolicy.php b/lib/public/AppFramework/Http/EmptyPermissionPolicy.php
new file mode 100644
index 0000000000000..1d94467e5a4f7
--- /dev/null
+++ b/lib/public/AppFramework/Http/EmptyPermissionPolicy.php
@@ -0,0 +1,173 @@
+
+ *
+ * @author Roeland Jago Douma
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * 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
+ * along with this program. If not, see .
+ *
+ */
+
+namespace OCP\AppFramework\Http;
+
+/**
+ * Class EmptyPermissionsPolicy is a simple helper which allows applications
+ * to modify the PermissionPolicy sent by Nextcloud. Per default the policy
+ * is forbidding everything.
+ *
+ * As alternative with sane exemptions look at PermissionPolicy
+ *
+ * @see \OCP\AppFramework\Http\FeaturePolicy
+ * @since 21.0.0
+ */
+class EmptyPermissionPolicy {
+
+ /** @var string[] of allowed domains to autoplay media */
+ protected $autoplayDomains = null;
+
+ /** @var string[] of allowed domains that can access the camera */
+ protected $cameraDomains = null;
+
+ /** @var string[] of allowed domains that can use fullscreen */
+ protected $fullscreenDomains = null;
+
+ /** @var string[] of allowed domains that can use the geolocation of the device */
+ protected $geolocationDomains = null;
+
+ /** @var string[] of allowed domains that can use the microphone */
+ protected $microphoneDomains = null;
+
+ /** @var string[] of allowed domains that can use the payment API */
+ protected $paymentDomains = null;
+
+ /**
+ * Allows to use autoplay from a specific domain. Use * to allow from all domains.
+ *
+ * @param string $domain Domain to whitelist. Any passed value needs to be properly sanitized.
+ * @return $this
+ * @since 21.0.0
+ */
+ public function addAllowedAutoplayDomain(string $domain): self {
+ $this->autoplayDomains[] = $domain;
+ return $this;
+ }
+
+ /**
+ * Allows to use the camera on a specific domain. Use * to allow from all domains
+ *
+ * @param string $domain Domain to whitelist. Any passed value needs to be properly sanitized.
+ * @return $this
+ * @since 21.0.0
+ */
+ public function addAllowedCameraDomain(string $domain): self {
+ $this->cameraDomains[] = $domain;
+ return $this;
+ }
+
+ /**
+ * Allows the full screen functionality to be used on a specific domain. Use * to allow from all domains
+ *
+ * @param string $domain Domain to whitelist. Any passed value needs to be properly sanitized.
+ * @return $this
+ * @since 21.0.0
+ */
+ public function addAllowedFullScreenDomain(string $domain): self {
+ $this->fullscreenDomains[] = $domain;
+ return $this;
+ }
+
+ /**
+ * Allows to use the geolocation on a specific domain. Use * to allow from all domains
+ *
+ * @param string $domain Domain to whitelist. Any passed value needs to be properly sanitized.
+ * @return $this
+ * @since 21.0.0
+ */
+ public function addAllowedGeoLocationDomain(string $domain): self {
+ $this->geolocationDomains[] = $domain;
+ return $this;
+ }
+
+ /**
+ * Allows to use the microphone on a specific domain. Use * to allow from all domains
+ *
+ * @param string $domain Domain to whitelist. Any passed value needs to be properly sanitized.
+ * @return $this
+ * @since 21.0.0
+ */
+ public function addAllowedMicrophoneDomain(string $domain): self {
+ $this->microphoneDomains[] = $domain;
+ return $this;
+ }
+
+ /**
+ * Allows to use the payment API on a specific domain. Use * to allow from all domains
+ *
+ * @param string $domain Domain to whitelist. Any passed value needs to be properly sanitized.
+ * @return $this
+ * @since 21.0.0
+ */
+ public function addAllowedPaymentDomain(string $domain): self {
+ $this->paymentDomains[] = $domain;
+ return $this;
+ }
+
+ /**
+ * Get the generated Feature-Policy as a string
+ *
+ * @return string
+ * @since 21.0.0
+ */
+ public function buildPolicy(): string {
+ $policy = '';
+
+ $policy .= 'autoplay=(' . implode(' ', $this->formatDomainList($this->autoplayDomains)) . ') ';
+ $policy .= 'camera=(' . implode(' ', $this->formatDomainList($this->cameraDomains)) . ') ';
+ $policy .= 'fullscreen=(' . implode(' ', $this->formatDomainList($this->fullscreenDomains)) . ') ';
+ $policy .= 'geolocation=(' . implode(' ', $this->formatDomainList($this->geolocationDomains)) . ') ';
+ $policy .= 'microphone=(' . implode(' ', $this->formatDomainList($this->microphoneDomains)) . ') ';
+ $policy .= 'payment=(' . implode(' ', $this->formatDomainList($this->paymentDomains)) . ') ';
+
+ return rtrim($policy, ' ');
+ }
+
+ private function formatDomainList(?array $domains): array {
+ if ($domains === null) {
+ return [];
+ }
+
+ $result = [];
+
+ foreach ($domains as $domain) {
+ if (!is_string($domain)) {
+ // Ignore wrong entries
+ continue;
+ }
+
+ if ($domain === '\'self\'') {
+ $domain = 'self';
+ }
+
+ $result[] = $domain;
+ }
+
+ $result = array_unique($result);
+
+ return $result;
+ }
+}
diff --git a/lib/public/AppFramework/Http/FeaturePolicy.php b/lib/public/AppFramework/Http/FeaturePolicy.php
index d193dda546be0..39e4847ef1c43 100644
--- a/lib/public/AppFramework/Http/FeaturePolicy.php
+++ b/lib/public/AppFramework/Http/FeaturePolicy.php
@@ -35,6 +35,7 @@
* should require no modification at all for most use-cases.
*
* @since 17.0.0
+ * @depreacted 21.0.0 use \OCP\AppFramework\Http\PermissionPolicy
*/
class FeaturePolicy extends EmptyFeaturePolicy {
protected $autoplayDomains = [
diff --git a/lib/public/AppFramework/Http/PermissionPolicy.php b/lib/public/AppFramework/Http/PermissionPolicy.php
new file mode 100644
index 0000000000000..958080aef0df9
--- /dev/null
+++ b/lib/public/AppFramework/Http/PermissionPolicy.php
@@ -0,0 +1,59 @@
+
+ *
+ * @author Roeland Jago Douma
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * 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
+ * along with this program. If not, see .
+ *
+ */
+
+namespace OCP\AppFramework\Http;
+
+/**
+ * Class PermissionPolicy is a simple helper which allows applications to
+ * modify the Permission-Policy sent by Nextcloud. Per default only autoplay is allowed
+ * from the same domain and full screen as well from the same domain.
+ *
+ * Even if a value gets modified above defaults will still get appended. Please
+ * notice that Nextcloud ships already with sensible defaults and those policies
+ * should require no modification at all for most use-cases.
+ *
+ * @since 21.0.0
+ */
+class PermissionPolicy extends EmptyPermissionPolicy {
+ protected $autoplayDomains = [
+ 'self',
+ ];
+
+ /** @var string[] of allowed domains that can access the camera */
+ protected $cameraDomains = [];
+
+ protected $fullscreenDomains = [
+ 'self',
+ ];
+
+ /** @var string[] of allowed domains that can use the geolocation of the device */
+ protected $geolocationDomains = [];
+
+ /** @var string[] of allowed domains that can use the microphone */
+ protected $microphoneDomains = [];
+
+ /** @var string[] of allowed domains that can use the payment API */
+ protected $paymentDomains = [];
+}
diff --git a/lib/public/AppFramework/Http/Response.php b/lib/public/AppFramework/Http/Response.php
index 152f8c4a3c5ea..593916883559e 100644
--- a/lib/public/AppFramework/Http/Response.php
+++ b/lib/public/AppFramework/Http/Response.php
@@ -85,6 +85,9 @@ class Response {
/** @var FeaturePolicy */
private $featurePolicy;
+ /** @var PermissionPolicy */
+ private $permissionPolicy;
+
/** @var bool */
private $throttled = false;
/** @var array */
@@ -257,6 +260,7 @@ public function getHeaders() {
$this->headers['Content-Security-Policy'] = $this->getContentSecurityPolicy()->buildPolicy();
$this->headers['Feature-Policy'] = $this->getFeaturePolicy()->buildPolicy();
+ $this->headers['Permissions-Policy'] = $this->getPermissionPolicy()->buildPolicy();
$this->headers['X-Robots-Tag'] = 'noindex, nofollow';
if ($this->ETag) {
@@ -316,6 +320,7 @@ public function getContentSecurityPolicy() {
/**
* @since 17.0.0
+ * @depreacted 28.0.0 Use getPermissionPolicy
*/
public function getFeaturePolicy(): EmptyFeaturePolicy {
if ($this->featurePolicy === null) {
@@ -326,6 +331,7 @@ public function getFeaturePolicy(): EmptyFeaturePolicy {
/**
* @since 17.0.0
+ * @depreacted 28.0.0 Use setPermissionPolicy
*/
public function setFeaturePolicy(EmptyFeaturePolicy $featurePolicy): self {
$this->featurePolicy = $featurePolicy;
@@ -333,6 +339,26 @@ public function setFeaturePolicy(EmptyFeaturePolicy $featurePolicy): self {
return $this;
}
+ /**
+ * @since 28.0.0
+ */
+ public function getPermissionPolicy(): EmptyPermissionPolicy {
+ if ($this->permissionPolicy === null) {
+ $this->setPermissionPolicy(new EmptyPermissionPolicy());
+ }
+ return $this->permissionPolicy;
+ }
+
+ /**
+ * @since 17.0.0
+ * @depreacted 28.0.0 Use setPermissionPolicy
+ */
+ public function setPermissionPolicy(EmptyPermissionPolicy $permissionPolicy): self {
+ $this->permissionPolicy = $permissionPolicy;
+
+ return $this;
+ }
+
/**
diff --git a/lib/public/AppFramework/Http/TemplateResponse.php b/lib/public/AppFramework/Http/TemplateResponse.php
index 23843cd21d1cd..f4a14175ec001 100644
--- a/lib/public/AppFramework/Http/TemplateResponse.php
+++ b/lib/public/AppFramework/Http/TemplateResponse.php
@@ -111,6 +111,7 @@ public function __construct($appName, $templateName, array $params = [],
$this->setContentSecurityPolicy(new ContentSecurityPolicy());
$this->setFeaturePolicy(new FeaturePolicy());
+ $this->setPermissionPolicy(new PermissionPolicy());
}
diff --git a/lib/public/Security/FeaturePolicy/AddFeaturePolicyEvent.php b/lib/public/Security/FeaturePolicy/AddFeaturePolicyEvent.php
index 8d39b58a141c8..784322f65c35a 100644
--- a/lib/public/Security/FeaturePolicy/AddFeaturePolicyEvent.php
+++ b/lib/public/Security/FeaturePolicy/AddFeaturePolicyEvent.php
@@ -35,6 +35,7 @@
* Event that allows to register a feature policy header to a request.
*
* @since 17.0.0
+ * @deprecated 28.0.0 use AddPermissionPolicyEvent
*/
class AddFeaturePolicyEvent extends Event {
/** @var FeaturePolicyManager */
@@ -42,6 +43,7 @@ class AddFeaturePolicyEvent extends Event {
/**
* @since 17.0.0
+ * @deprecated 28.0.0 use AddPermissionPolicyEvent
*/
public function __construct(FeaturePolicyManager $policyManager) {
parent::__construct();
@@ -50,6 +52,7 @@ public function __construct(FeaturePolicyManager $policyManager) {
/**
* @since 17.0.0
+ * @depreacted 21.0.0 use AddPermissionPolicyEvent
*/
public function addPolicy(EmptyFeaturePolicy $policy) {
$this->policyManager->addDefaultPolicy($policy);
diff --git a/lib/public/Security/PermissionsPolicy/AddPermissionsPolicyEvent.php b/lib/public/Security/PermissionsPolicy/AddPermissionsPolicyEvent.php
new file mode 100644
index 0000000000000..0e810fd7aab95
--- /dev/null
+++ b/lib/public/Security/PermissionsPolicy/AddPermissionsPolicyEvent.php
@@ -0,0 +1,56 @@
+
+ *
+ * @author Roeland Jago Douma
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * 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
+ * along with this program. If not, see .
+ *
+ */
+
+namespace OCP\Security\PermissionPolicy;
+
+use OC\Security\PermissionPolicy\PermissionPolicyManager;
+use OCP\AppFramework\Http\EmptyPermissionPolicy;
+use OCP\EventDispatcher\Event;
+
+/**
+ * Event that allows to register a feature policy header to a request.
+ *
+ * @since 28.0.0
+ */
+class AddPermissionsPolicyEvent extends Event {
+
+ /** @var PermissionPolicyManager */
+ private $policyManager;
+
+ /**
+ * @since 28.0.0
+ */
+ public function __construct(PermissionPolicyManager $policyManager) {
+ parent::__construct();
+ $this->policyManager = $policyManager;
+ }
+
+ /**
+ * @since 28.0.0
+ */
+ public function addPolicy(EmptyPermissionPolicy $policy) {
+ $this->policyManager->addDefaultPolicy($policy);
+ }
+}
diff --git a/tests/lib/AppFramework/Middleware/Security/FeaturePolicyMiddlewareTest.php b/tests/lib/AppFramework/Middleware/Security/PermissionPolicyMiddlewareTest.php
similarity index 57%
rename from tests/lib/AppFramework/Middleware/Security/FeaturePolicyMiddlewareTest.php
rename to tests/lib/AppFramework/Middleware/Security/PermissionPolicyMiddlewareTest.php
index 154b43f69a5ba..65cc0c31eb5bd 100644
--- a/tests/lib/AppFramework/Middleware/Security/FeaturePolicyMiddlewareTest.php
+++ b/tests/lib/AppFramework/Middleware/Security/PermissionPolicyMiddlewareTest.php
@@ -25,16 +25,20 @@
namespace Test\AppFramework\Middleware\Security;
-use OC\AppFramework\Middleware\Security\FeaturePolicyMiddleware;
+use OC\AppFramework\Middleware\Security\PermissionPolicyMiddleware;
use OC\Security\FeaturePolicy\FeaturePolicy;
use OC\Security\FeaturePolicy\FeaturePolicyManager;
+use OC\Security\PermissionPolicy\PermissionPolicy;
+use OC\Security\PermissionPolicy\PermissionPolicyManager;
use OCP\AppFramework\Controller;
use OCP\AppFramework\Http\EmptyFeaturePolicy;
+use OCP\AppFramework\Http\EmptyPermissionPolicy;
use OCP\AppFramework\Http\Response;
use PHPUnit\Framework\MockObject\MockObject;
-class FeaturePolicyMiddlewareTest extends \Test\TestCase {
- /** @var FeaturePolicyMiddleware|MockObject */
+class PermissionPolicyMiddlewareTest extends \Test\TestCase {
+
+ /** @var PermissionPolicyMiddleware|MockObject */
private $middleware;
/** @var Controller|MockObject */
private $controller;
@@ -45,9 +49,11 @@ protected function setUp(): void {
parent::setUp();
$this->controller = $this->createMock(Controller::class);
- $this->manager = $this->createMock(FeaturePolicyManager::class);
- $this->middleware = new FeaturePolicyMiddleware(
- $this->manager
+ $this->featurePolicyManager = $this->createMock(FeaturePolicyManager::class);
+ $this->permissionPolicyManager = $this->createMock(PermissionPolicyManager::class);
+ $this->middleware = new PermissionPolicyMiddleware(
+ $this->featurePolicyManager,
+ $this->permissionPolicyManager
);
}
@@ -61,25 +67,49 @@ public function testAfterController() {
$mergedPolicy->addAllowedGeoLocationDomain('mergedPolicy');
$response->method('getFeaturePolicy')
->willReturn($currentPolicy);
- $this->manager->method('getDefaultPolicy')
+ $this->featurePolicyManager->method('getDefaultPolicy')
->willReturn($defaultPolicy);
- $this->manager->method('mergePolicies')
+ $this->featurePolicyManager->method('mergePolicies')
->with($defaultPolicy, $currentPolicy)
->willReturn($mergedPolicy);
$response->expects($this->once())
->method('setFeaturePolicy')
->with($mergedPolicy);
+ $defaultPermissionPolicy = new PermissionPolicy();
+ $this->permissionPolicyManager->method('getDefaultPolicy')
+ ->willReturn($defaultPermissionPolicy);
+ $currentPermissionPolicy = new PermissionPolicy();
+ $response->method('getPermissionPolicy')
+ ->willReturn($currentPermissionPolicy);
+ $mergedPermissionPolicy = new PermissionPolicy();
+ $this->permissionPolicyManager->method('mergePolicies')
+ ->with($defaultPermissionPolicy, $currentPermissionPolicy)
+ ->willReturn($mergedPermissionPolicy);
+ $mergedPermissionPolicyWithFeaturePolicy = new PermissionPolicy();
+ $this->permissionPolicyManager->method('mergeFeaturePolicy')
+ ->with($mergedPermissionPolicy, $currentPolicy)
+ ->willReturn($mergedPermissionPolicyWithFeaturePolicy);
+
+ $response->expects($this->once())
+ ->method('setPermissionPolicy')
+ ->with($mergedPermissionPolicy);
+
$this->middleware->afterController($this->controller, 'test', $response);
}
- public function testAfterControllerEmptyCSP() {
+ public function testAfterControllerEmpty() {
$response = $this->createMock(Response::class);
$emptyPolicy = new EmptyFeaturePolicy();
+ $emptyPermissionPolicy = new EmptyPermissionPolicy();
$response->method('getFeaturePolicy')
->willReturn($emptyPolicy);
+ $response->method('getPermissionPolicy')
+ ->willReturn($emptyPermissionPolicy);
$response->expects($this->never())
->method('setFeaturePolicy');
+ $response->expects($this->never())
+ ->method('setPermissionPolicy');
$this->middleware->afterController($this->controller, 'test', $response);
}