diff options
Diffstat (limited to 'lib/private/AppFramework/Middleware/Security/SecurityMiddleware.php')
-rw-r--r-- | lib/private/AppFramework/Middleware/Security/SecurityMiddleware.php | 70 |
1 files changed, 61 insertions, 9 deletions
diff --git a/lib/private/AppFramework/Middleware/Security/SecurityMiddleware.php b/lib/private/AppFramework/Middleware/Security/SecurityMiddleware.php index eb8c1b8dc43..8e0794f9645 100644 --- a/lib/private/AppFramework/Middleware/Security/SecurityMiddleware.php +++ b/lib/private/AppFramework/Middleware/Security/SecurityMiddleware.php @@ -48,6 +48,12 @@ use OC\Settings\AuthorizedGroupMapper; use OCP\App\AppPathNotFoundException; use OCP\App\IAppManager; use OCP\AppFramework\Controller; +use OCP\AppFramework\Http\Attribute\AuthorizedAdminSetting; +use OCP\AppFramework\Http\Attribute\NoAdminRequired; +use OCP\AppFramework\Http\Attribute\NoCSRFRequired; +use OCP\AppFramework\Http\Attribute\PublicPage; +use OCP\AppFramework\Http\Attribute\StrictCookiesRequired; +use OCP\AppFramework\Http\Attribute\SubAdminRequired; use OCP\AppFramework\Http\JSONResponse; use OCP\AppFramework\Http\RedirectResponse; use OCP\AppFramework\Http\Response; @@ -61,6 +67,7 @@ use OCP\IURLGenerator; use OCP\IUserSession; use OCP\Util; use Psr\Log\LoggerInterface; +use ReflectionMethod; /** * Used to do all the authentication and checking stuff for a controller method @@ -145,22 +152,24 @@ class SecurityMiddleware extends Middleware { $this->navigationManager->setActiveEntry('spreed'); } + $reflectionMethod = new ReflectionMethod($controller, $methodName); + // security checks - $isPublicPage = $this->reflector->hasAnnotation('PublicPage'); + $isPublicPage = $this->hasAnnotationOrAttribute($reflectionMethod, 'PublicPage', PublicPage::class); if (!$isPublicPage) { if (!$this->isLoggedIn) { throw new NotLoggedInException(); } $authorized = false; - if ($this->reflector->hasAnnotation('AuthorizedAdminSetting')) { + if ($this->hasAnnotationOrAttribute($reflectionMethod, 'AuthorizedAdminSetting', AuthorizedAdminSetting::class)) { $authorized = $this->isAdminUser; - if (!$authorized && $this->reflector->hasAnnotation('SubAdminRequired')) { + if (!$authorized && $this->hasAnnotationOrAttribute($reflectionMethod, 'SubAdminRequired', SubAdminRequired::class)) { $authorized = $this->isSubAdmin; } if (!$authorized) { - $settingClasses = explode(';', $this->reflector->getAnnotationParameter('AuthorizedAdminSetting', 'settings')); + $settingClasses = $this->getAuthorizedAdminSettingClasses($reflectionMethod); $authorizedClasses = $this->groupAuthorizationMapper->findAllClassesForUser($this->userSession->getUser()); foreach ($settingClasses as $settingClass) { $authorized = in_array($settingClass, $authorizedClasses, true); @@ -174,14 +183,14 @@ class SecurityMiddleware extends Middleware { throw new NotAdminException($this->l10n->t('Logged in user must be an admin, a sub admin or gotten special right to access this setting')); } } - if ($this->reflector->hasAnnotation('SubAdminRequired') + if ($this->hasAnnotationOrAttribute($reflectionMethod, 'SubAdminRequired', SubAdminRequired::class) && !$this->isSubAdmin && !$this->isAdminUser && !$authorized) { throw new NotAdminException($this->l10n->t('Logged in user must be an admin or sub admin')); } - if (!$this->reflector->hasAnnotation('SubAdminRequired') - && !$this->reflector->hasAnnotation('NoAdminRequired') + if (!$this->hasAnnotationOrAttribute($reflectionMethod, 'SubAdminRequired', SubAdminRequired::class) + && !$this->hasAnnotationOrAttribute($reflectionMethod, 'NoAdminRequired', NoAdminRequired::class) && !$this->isAdminUser && !$authorized) { throw new NotAdminException($this->l10n->t('Logged in user must be an admin')); @@ -189,14 +198,15 @@ class SecurityMiddleware extends Middleware { } // Check for strict cookie requirement - if ($this->reflector->hasAnnotation('StrictCookieRequired') || !$this->reflector->hasAnnotation('NoCSRFRequired')) { + if ($this->hasAnnotationOrAttribute($reflectionMethod, 'StrictCookieRequired', StrictCookiesRequired::class) || + !$this->hasAnnotationOrAttribute($reflectionMethod, 'NoCSRFRequired', NoCSRFRequired::class)) { if (!$this->request->passesStrictCookieCheck()) { throw new StrictCookieMissingException(); } } // CSRF check - also registers the CSRF token since the session may be closed later Util::callRegister(); - if (!$this->reflector->hasAnnotation('NoCSRFRequired')) { + if (!$this->hasAnnotationOrAttribute($reflectionMethod, 'NoCSRFRequired', NoCSRFRequired::class)) { /* * Only allow the CSRF check to fail on OCS Requests. This kind of * hacks around that we have no full token auth in place yet and we @@ -233,6 +243,48 @@ class SecurityMiddleware extends Middleware { } /** + * @template T + * + * @param ReflectionMethod $reflectionMethod + * @param string $annotationName + * @param class-string<T> $attributeClass + * @return boolean + */ + protected function hasAnnotationOrAttribute(ReflectionMethod $reflectionMethod, string $annotationName, string $attributeClass): bool { + if (!empty($reflectionMethod->getAttributes($attributeClass))) { + return true; + } + + if ($this->reflector->hasAnnotation($annotationName)) { + return true; + } + + return false; + } + + /** + * @param ReflectionMethod $reflectionMethod + * @return string[] + */ + protected function getAuthorizedAdminSettingClasses(ReflectionMethod $reflectionMethod): array { + $classes = []; + if ($this->reflector->hasAnnotation('AuthorizedAdminSetting')) { + $classes = explode(';', $this->reflector->getAnnotationParameter('AuthorizedAdminSetting', 'settings')); + } + + $attributes = $reflectionMethod->getAttributes(AuthorizedAdminSetting::class); + if (!empty($attributes)) { + foreach ($attributes as $attribute) { + /** @var AuthorizedAdminSetting $setting */ + $setting = $attribute->newInstance(); + $classes[] = $setting->getSettings(); + } + } + + return $classes; + } + + /** * If an SecurityException is being caught, ajax requests return a JSON error * response and non ajax requests redirect to the index * |