/** * This runs all the security checks before a method call. The * security checks are determined by inspecting the controller method * annotations * @param string/Controller $controller the controllername or string * @param string $methodName the name of the method * @throws SecurityException when a security check fails */ public function beforeController($controller, $methodName) { // get annotations from comments $annotationReader = new MethodAnnotationReader($controller, $methodName); // this will set the current navigation entry of the app, use this only // for normal HTML requests and not for AJAX requests $this->app->getServer()->getNavigationManager()->setActiveEntry($this->app->getAppName()); // security checks $isPublicPage = $annotationReader->hasAnnotation('PublicPage'); if (!$isPublicPage) { if (!$this->app->isLoggedIn()) { throw new SecurityException('Current user is not logged in', Http::STATUS_UNAUTHORIZED); } if (!$annotationReader->hasAnnotation('NoAdminRequired')) { if (!$this->app->isAdminUser()) { throw new SecurityException('Logged in user must be an admin', Http::STATUS_FORBIDDEN); } } } if (!$annotationReader->hasAnnotation('NoCSRFRequired')) { if (!$this->request->passesCSRFCheck()) { throw new SecurityException('CSRF check failed', Http::STATUS_PRECONDITION_FAILED); } } }
/** * This runs all the security checks before a method call. The * security checks are determined by inspecting the controller method * annotations * @param string $controller the controllername or string * @param string $methodName the name of the method * @throws SecurityException when a security check fails */ public function beforeController($controller, $methodName) { // this will set the current navigation entry of the app, use this only // for normal HTML requests and not for AJAX requests $this->navigationManager->setActiveEntry($this->appName); // security checks $isPublicPage = $this->reflector->hasAnnotation('PublicPage'); if (!$isPublicPage) { if (!$this->isLoggedIn) { throw new NotLoggedInException(); } if (!$this->reflector->hasAnnotation('NoAdminRequired')) { if (!$this->isAdminUser) { throw new NotAdminException(); } } } // CSRF check - also registers the CSRF token since the session may be closed later Util::callRegister(); if (!$this->reflector->hasAnnotation('NoCSRFRequired')) { if (!$this->request->passesCSRFCheck()) { throw new CrossSiteRequestForgeryException(); } } /** * FIXME: Use DI once available * Checks if app is enabled (also includes a check whether user is allowed to access the resource) * The getAppPath() check is here since components such as settings also use the AppFramework and * therefore won't pass this check. */ if (\OC_App::getAppPath($this->appName) !== false && !\OC_App::isEnabled($this->appName)) { throw new AppNotEnabledException(); } }
private function protectAgainstCSRF() { $user = $this->auth->getCurrentUser(); if ($this->auth->isDavAuthenticated($user)) { return true; } if ($this->request->passesCSRFCheck()) { return true; } throw new BadRequest(); }
/** * @param RequestInterface $request * @param ResponseInterface $response * @return array * @throws NotAuthenticated */ private function auth(RequestInterface $request, ResponseInterface $response) { $forcedLogout = false; if (!$this->request->passesCSRFCheck() && $this->requiresCSRFCheck()) { // In case of a fail with POST we need to recheck the credentials if ($this->request->getMethod() === 'POST') { $forcedLogout = true; } else { $response->setStatus(401); throw new \Sabre\DAV\Exception\NotAuthenticated('CSRF check not passed.'); } } if ($forcedLogout) { $this->userSession->logout(); } else { if ($this->twoFactorManager->needsSecondFactor()) { throw new \Sabre\DAV\Exception\NotAuthenticated('2FA challenge not passed.'); } if (\OC_User::handleApacheAuth() || $this->userSession->isLoggedIn() && is_null($this->session->get(self::DAV_AUTHENTICATED)) || $this->userSession->isLoggedIn() && $this->session->get(self::DAV_AUTHENTICATED) === $this->userSession->getUser()->getUID() && $request->getHeader('Authorization') === null) { $user = $this->userSession->getUser()->getUID(); \OC_Util::setupFS($user); $this->currentUser = $user; $this->session->close(); return [true, $this->principalPrefix . $user]; } } if (!$this->userSession->isLoggedIn() && in_array('XMLHttpRequest', explode(',', $request->getHeader('X-Requested-With')))) { // do not re-authenticate over ajax, use dummy auth name to prevent browser popup $response->addHeader('WWW-Authenticate', 'DummyBasic realm="' . $this->realm . '"'); $response->setStatus(401); throw new \Sabre\DAV\Exception\NotAuthenticated('Cannot authenticate over ajax calls'); } $data = parent::check($request, $response); if ($data[0] === true) { $startPos = strrpos($data[1], '/') + 1; $user = $this->userSession->getUser()->getUID(); $data[1] = substr_replace($data[1], $user, $startPos); } return $data; }
/** * @param RequestInterface $request * @param ResponseInterface $response * @return array * @throws NotAuthenticated */ private function auth(RequestInterface $request, ResponseInterface $response) { // If request is not GET and not authenticated via WebDAV a requesttoken is required if ($this->userSession->isLoggedIn() && $this->request->getMethod() !== 'GET' && !$this->isDavAuthenticated($this->userSession->getUser()->getUID())) { if (!$this->request->passesCSRFCheck()) { $response->setStatus(401); throw new \Sabre\DAV\Exception\NotAuthenticated('CSRF check not passed.'); } } if (\OC_User::handleApacheAuth() || $this->userSession->isLoggedIn() && is_null($this->session->get(self::DAV_AUTHENTICATED)) || $this->userSession->isLoggedIn() && $this->session->get(self::DAV_AUTHENTICATED) === $this->userSession->getUser()->getUID() && $request->getHeader('Authorization') === null) { $user = $this->userSession->getUser()->getUID(); \OC_Util::setupFS($user); $this->currentUser = $user; $this->session->close(); return [true, $this->principalPrefix . $user]; } if (!$this->userSession->isLoggedIn() && in_array('XMLHttpRequest', explode(',', $request->getHeader('X-Requested-With')))) { // do not re-authenticate over ajax, use dummy auth name to prevent browser popup $response->addHeader('WWW-Authenticate', 'DummyBasic realm="' . $this->realm . '"'); $response->setStatus(401); throw new \Sabre\DAV\Exception\NotAuthenticated('Cannot authenticate over ajax calls'); } return parent::check($request, $response); }