コード例 #1
0
 private function serveRequest(AphrontRequest $request)
 {
     $identifier = $this->getRepositoryIdentifierFromRequest($request);
     // If authentication credentials have been provided, try to find a user
     // that actually matches those credentials.
     if (isset($_SERVER['PHP_AUTH_USER']) && isset($_SERVER['PHP_AUTH_PW'])) {
         $username = $_SERVER['PHP_AUTH_USER'];
         $password = new PhutilOpaqueEnvelope($_SERVER['PHP_AUTH_PW']);
         $viewer = $this->authenticateHTTPRepositoryUser($username, $password);
         if (!$viewer) {
             return new PhabricatorVCSResponse(403, pht('Invalid credentials.'));
         }
     } else {
         // User hasn't provided credentials, which means we count them as
         // being "not logged in".
         $viewer = new PhabricatorUser();
     }
     $this->setServiceViewer($viewer);
     $allow_public = PhabricatorEnv::getEnvConfig('policy.allow-public');
     $allow_auth = PhabricatorEnv::getEnvConfig('diffusion.allow-http-auth');
     if (!$allow_public) {
         if (!$viewer->isLoggedIn()) {
             if ($allow_auth) {
                 return new PhabricatorVCSResponse(401, pht('You must log in to access repositories.'));
             } else {
                 return new PhabricatorVCSResponse(403, pht('Public and authenticated HTTP access are both forbidden.'));
             }
         }
     }
     try {
         $repository = id(new PhabricatorRepositoryQuery())->setViewer($viewer)->withIdentifiers(array($identifier))->executeOne();
         if (!$repository) {
             return new PhabricatorVCSResponse(404, pht('No such repository exists.'));
         }
     } catch (PhabricatorPolicyException $ex) {
         if ($viewer->isLoggedIn()) {
             return new PhabricatorVCSResponse(403, pht('You do not have permission to access this repository.'));
         } else {
             if ($allow_auth) {
                 return new PhabricatorVCSResponse(401, pht('You must log in to access this repository.'));
             } else {
                 return new PhabricatorVCSResponse(403, pht('This repository requires authentication, which is forbidden ' . 'over HTTP.'));
             }
         }
     }
     $this->setServiceRepository($repository);
     if (!$repository->isTracked()) {
         return new PhabricatorVCSResponse(403, pht('This repository is inactive.'));
     }
     $is_push = !$this->isReadOnlyRequest($repository);
     switch ($repository->getServeOverHTTP()) {
         case PhabricatorRepository::SERVE_READONLY:
             if ($is_push) {
                 return new PhabricatorVCSResponse(403, pht('This repository is read-only over HTTP.'));
             }
             break;
         case PhabricatorRepository::SERVE_READWRITE:
             if ($is_push) {
                 $can_push = PhabricatorPolicyFilter::hasCapability($viewer, $repository, DiffusionPushCapability::CAPABILITY);
                 if (!$can_push) {
                     if ($viewer->isLoggedIn()) {
                         return new PhabricatorVCSResponse(403, pht('You do not have permission to push to this repository.'));
                     } else {
                         if ($allow_auth) {
                             return new PhabricatorVCSResponse(401, pht('You must log in to push to this repository.'));
                         } else {
                             return new PhabricatorVCSResponse(403, pht('Pushing to this repository requires authentication, ' . 'which is forbidden over HTTP.'));
                         }
                     }
                 }
             }
             break;
         case PhabricatorRepository::SERVE_OFF:
         default:
             return new PhabricatorVCSResponse(403, pht('This repository is not available over HTTP.'));
     }
     $vcs_type = $repository->getVersionControlSystem();
     $req_type = $this->isVCSRequest($request);
     if ($vcs_type != $req_type) {
         switch ($req_type) {
             case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT:
                 $result = new PhabricatorVCSResponse(500, pht('This is not a Git repository.'));
                 break;
             case PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL:
                 $result = new PhabricatorVCSResponse(500, pht('This is not a Mercurial repository.'));
                 break;
             case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN:
                 $result = new PhabricatorVCSResponse(500, pht('This is not a Subversion repository.'));
                 break;
             default:
                 $result = new PhabricatorVCSResponse(500, pht('Unknown request type.'));
                 break;
         }
     } else {
         switch ($vcs_type) {
             case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT:
             case PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL:
                 $result = $this->serveVCSRequest($repository, $viewer);
                 break;
             case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN:
                 $result = new PhabricatorVCSResponse(500, pht('Phabricator does not support HTTP access to Subversion ' . 'repositories.'));
                 break;
             default:
                 $result = new PhabricatorVCSResponse(500, pht('Unknown version control system.'));
                 break;
         }
     }
     $code = $result->getHTTPResponseCode();
     if ($is_push && $code == 200) {
         $unguarded = AphrontWriteGuard::beginScopedUnguardedWrites();
         $repository->writeStatusMessage(PhabricatorRepositoryStatusMessage::TYPE_NEEDS_UPDATE, PhabricatorRepositoryStatusMessage::CODE_OKAY);
         unset($unguarded);
     }
     return $result;
 }
コード例 #2
0
 private function serveRequest(AphrontRequest $request)
 {
     $identifier = $this->getRepositoryIdentifierFromRequest($request);
     // If authentication credentials have been provided, try to find a user
     // that actually matches those credentials.
     // We require both the username and password to be nonempty, because Git
     // won't prompt users who provide a username but no password otherwise.
     // See T10797 for discussion.
     $have_user = strlen(idx($_SERVER, 'PHP_AUTH_USER'));
     $have_pass = strlen(idx($_SERVER, 'PHP_AUTH_PW'));
     if ($have_user && $have_pass) {
         $username = $_SERVER['PHP_AUTH_USER'];
         $password = new PhutilOpaqueEnvelope($_SERVER['PHP_AUTH_PW']);
         // Try Git LFS auth first since we can usually reject it without doing
         // any queries, since the username won't match the one we expect or the
         // request won't be LFS.
         $viewer = $this->authenticateGitLFSUser($username, $password);
         // If that failed, try normal auth. Note that we can use normal auth on
         // LFS requests, so this isn't strictly an alternative to LFS auth.
         if (!$viewer) {
             $viewer = $this->authenticateHTTPRepositoryUser($username, $password);
         }
         if (!$viewer) {
             return new PhabricatorVCSResponse(403, pht('Invalid credentials.'));
         }
     } else {
         // User hasn't provided credentials, which means we count them as
         // being "not logged in".
         $viewer = new PhabricatorUser();
     }
     $this->setServiceViewer($viewer);
     $allow_public = PhabricatorEnv::getEnvConfig('policy.allow-public');
     $allow_auth = PhabricatorEnv::getEnvConfig('diffusion.allow-http-auth');
     if (!$allow_public) {
         if (!$viewer->isLoggedIn()) {
             if ($allow_auth) {
                 return new PhabricatorVCSResponse(401, pht('You must log in to access repositories.'));
             } else {
                 return new PhabricatorVCSResponse(403, pht('Public and authenticated HTTP access are both forbidden.'));
             }
         }
     }
     try {
         $repository = id(new PhabricatorRepositoryQuery())->setViewer($viewer)->withIdentifiers(array($identifier))->needURIs(true)->executeOne();
         if (!$repository) {
             return new PhabricatorVCSResponse(404, pht('No such repository exists.'));
         }
     } catch (PhabricatorPolicyException $ex) {
         if ($viewer->isLoggedIn()) {
             return new PhabricatorVCSResponse(403, pht('You do not have permission to access this repository.'));
         } else {
             if ($allow_auth) {
                 return new PhabricatorVCSResponse(401, pht('You must log in to access this repository.'));
             } else {
                 return new PhabricatorVCSResponse(403, pht('This repository requires authentication, which is forbidden ' . 'over HTTP.'));
             }
         }
     }
     $response = $this->validateGitLFSRequest($repository, $viewer);
     if ($response) {
         return $response;
     }
     $this->setServiceRepository($repository);
     if (!$repository->isTracked()) {
         return new PhabricatorVCSResponse(403, pht('This repository is inactive.'));
     }
     $is_push = !$this->isReadOnlyRequest($repository);
     if ($this->getIsGitLFSRequest() && $this->getGitLFSToken()) {
         // We allow git LFS requests over HTTP even if the repository does not
         // otherwise support HTTP reads or writes, as long as the user is using a
         // token from SSH. If they're using HTTP username + password auth, they
         // have to obey the normal HTTP rules.
     } else {
         // For now, we don't distinguish between HTTP and HTTPS-originated
         // requests that are proxied within the cluster, so the user can connect
         // with HTTPS but we may be on HTTP by the time we reach this part of
         // the code. Allow things to move forward as long as either protocol
         // can be served.
         $proto_https = PhabricatorRepositoryURI::BUILTIN_PROTOCOL_HTTPS;
         $proto_http = PhabricatorRepositoryURI::BUILTIN_PROTOCOL_HTTP;
         $can_read = $repository->canServeProtocol($proto_https, false) || $repository->canServeProtocol($proto_http, false);
         if (!$can_read) {
             return new PhabricatorVCSResponse(403, pht('This repository is not available over HTTP.'));
         }
         if ($is_push) {
             $can_write = $repository->canServeProtocol($proto_https, true) || $repository->canServeProtocol($proto_http, true);
             if (!$can_write) {
                 return new PhabricatorVCSResponse(403, pht('This repository is read-only over HTTP.'));
             }
         }
     }
     if ($is_push) {
         $can_push = PhabricatorPolicyFilter::hasCapability($viewer, $repository, DiffusionPushCapability::CAPABILITY);
         if (!$can_push) {
             if ($viewer->isLoggedIn()) {
                 $error_code = 403;
                 $error_message = pht('You do not have permission to push to this repository ("%s").', $repository->getDisplayName());
                 if ($this->getIsGitLFSRequest()) {
                     return DiffusionGitLFSResponse::newErrorResponse($error_code, $error_message);
                 } else {
                     return new PhabricatorVCSResponse($error_code, $error_message);
                 }
             } else {
                 if ($allow_auth) {
                     return new PhabricatorVCSResponse(401, pht('You must log in to push to this repository.'));
                 } else {
                     return new PhabricatorVCSResponse(403, pht('Pushing to this repository requires authentication, ' . 'which is forbidden over HTTP.'));
                 }
             }
         }
     }
     $vcs_type = $repository->getVersionControlSystem();
     $req_type = $this->isVCSRequest($request);
     if ($vcs_type != $req_type) {
         switch ($req_type) {
             case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT:
                 $result = new PhabricatorVCSResponse(500, pht('This repository ("%s") is not a Git repository.', $repository->getDisplayName()));
                 break;
             case PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL:
                 $result = new PhabricatorVCSResponse(500, pht('This repository ("%s") is not a Mercurial repository.', $repository->getDisplayName()));
                 break;
             case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN:
                 $result = new PhabricatorVCSResponse(500, pht('This repository ("%s") is not a Subversion repository.', $repository->getDisplayName()));
                 break;
             default:
                 $result = new PhabricatorVCSResponse(500, pht('Unknown request type.'));
                 break;
         }
     } else {
         switch ($vcs_type) {
             case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT:
             case PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL:
                 $result = $this->serveVCSRequest($repository, $viewer);
                 break;
             case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN:
                 $result = new PhabricatorVCSResponse(500, pht('Phabricator does not support HTTP access to Subversion ' . 'repositories.'));
                 break;
             default:
                 $result = new PhabricatorVCSResponse(500, pht('Unknown version control system.'));
                 break;
         }
     }
     $code = $result->getHTTPResponseCode();
     if ($is_push && $code == 200) {
         $unguarded = AphrontWriteGuard::beginScopedUnguardedWrites();
         $repository->writeStatusMessage(PhabricatorRepositoryStatusMessage::TYPE_NEEDS_UPDATE, PhabricatorRepositoryStatusMessage::CODE_OKAY);
         unset($unguarded);
     }
     return $result;
 }