public function processRequest()
 {
     $request = $this->getRequest();
     $grant_type = $request->getStr('grant_type');
     $code = $request->getStr('code');
     $redirect_uri = $request->getStr('redirect_uri');
     $client_phid = $request->getStr('client_id');
     $client_secret = $request->getStr('client_secret');
     $response = new PhabricatorOAuthResponse();
     $server = new PhabricatorOAuthServer();
     if ($grant_type != 'authorization_code') {
         $response->setError('unsupported_grant_type');
         $response->setErrorDescription(pht('Only %s %s is supported.', 'grant_type', 'authorization_code'));
         return $response;
     }
     if (!$code) {
         $response->setError('invalid_request');
         $response->setErrorDescription(pht('Required parameter code missing.'));
         return $response;
     }
     if (!$client_phid) {
         $response->setError('invalid_request');
         $response->setErrorDescription(pht('Required parameter %s missing.', 'client_id'));
         return $response;
     }
     if (!$client_secret) {
         $response->setError('invalid_request');
         $response->setErrorDescription(pht('Required parameter %s missing.', 'client_secret'));
         return $response;
     }
     // one giant try / catch around all the exciting database stuff so we
     // can return a 'server_error' response if something goes wrong!
     try {
         $auth_code = id(new PhabricatorOAuthServerAuthorizationCode())->loadOneWhere('code = %s', $code);
         if (!$auth_code) {
             $response->setError('invalid_grant');
             $response->setErrorDescription(pht('Authorization code %d not found.', $code));
             return $response;
         }
         // if we have an auth code redirect URI, there must be a redirect_uri
         // in the request and it must match the auth code redirect uri *exactly*
         $auth_code_redirect_uri = $auth_code->getRedirectURI();
         if ($auth_code_redirect_uri) {
             $auth_code_redirect_uri = new PhutilURI($auth_code_redirect_uri);
             $redirect_uri = new PhutilURI($redirect_uri);
             if (!$redirect_uri->getDomain() || $redirect_uri != $auth_code_redirect_uri) {
                 $response->setError('invalid_grant');
                 $response->setErrorDescription(pht('Redirect URI in request must exactly match redirect URI ' . 'from authorization code.'));
                 return $response;
             }
         } else {
             if ($redirect_uri) {
                 $response->setError('invalid_grant');
                 $response->setErrorDescription(pht('Redirect URI in request and no redirect URI in authorization ' . 'code. The two must exactly match.'));
                 return $response;
             }
         }
         $client = id(new PhabricatorOAuthServerClient())->loadOneWhere('phid = %s', $client_phid);
         if (!$client) {
             $response->setError('invalid_client');
             $response->setErrorDescription(pht('Client with %s %d not found.', 'client_id', $client_phid));
             return $response;
         }
         $server->setClient($client);
         $user_phid = $auth_code->getUserPHID();
         $user = id(new PhabricatorUser())->loadOneWhere('phid = %s', $user_phid);
         if (!$user) {
             $response->setError('invalid_grant');
             $response->setErrorDescription(pht('User with PHID %d not found.', $user_phid));
             return $response;
         }
         $server->setUser($user);
         $test_code = new PhabricatorOAuthServerAuthorizationCode();
         $test_code->setClientSecret($client_secret);
         $test_code->setClientPHID($client_phid);
         $is_good_code = $server->validateAuthorizationCode($auth_code, $test_code);
         if (!$is_good_code) {
             $response->setError('invalid_grant');
             $response->setErrorDescription(pht('Invalid authorization code %d.', $code));
             return $response;
         }
         $unguarded = AphrontWriteGuard::beginScopedUnguardedWrites();
         $access_token = $server->generateAccessToken();
         $auth_code->delete();
         unset($unguarded);
         $result = array('access_token' => $access_token->getToken(), 'token_type' => 'Bearer', 'expires_in' => PhabricatorOAuthServer::ACCESS_TOKEN_TIMEOUT);
         return $response->setContent($result);
     } catch (Exception $e) {
         $response->setError('server_error');
         $response->setErrorDescription(pht('The authorization server encountered an unexpected condition ' . 'which prevented it from fulfilling the request.'));
         return $response;
     }
 }
 /**
  * @task token
  */
 public function validateAuthorizationCode(PhabricatorOAuthServerAuthorizationCode $test_code, PhabricatorOAuthServerAuthorizationCode $valid_code)
 {
     // check that all the meta data matches
     if ($test_code->getClientPHID() != $valid_code->getClientPHID()) {
         return false;
     }
     if ($test_code->getClientSecret() != $valid_code->getClientSecret()) {
         return false;
     }
     // check that the authorization code hasn't timed out
     $created_time = $test_code->getDateCreated();
     $must_be_used_by = $created_time + self::AUTHORIZATION_CODE_TIMEOUT;
     return time() < $must_be_used_by;
 }
 public function handleRequest(AphrontRequest $request)
 {
     $grant_type = $request->getStr('grant_type');
     $code = $request->getStr('code');
     $redirect_uri = $request->getStr('redirect_uri');
     $response = new PhabricatorOAuthResponse();
     $server = new PhabricatorOAuthServer();
     $client_id_parameter = $request->getStr('client_id');
     $client_id_header = idx($_SERVER, 'PHP_AUTH_USER');
     if (strlen($client_id_parameter) && strlen($client_id_header)) {
         if ($client_id_parameter !== $client_id_header) {
             throw new Exception(pht('Request included a client_id parameter and an "Authorization" ' . 'header with a username, but the values "%s" and "%s") disagree. ' . 'The values must match.', $client_id_parameter, $client_id_header));
         }
     }
     $client_secret_parameter = $request->getStr('client_secret');
     $client_secret_header = idx($_SERVER, 'PHP_AUTH_PW');
     if (strlen($client_secret_parameter)) {
         // If the `client_secret` parameter is present, prefer parameters.
         $client_phid = $client_id_parameter;
         $client_secret = $client_secret_parameter;
     } else {
         // Otherwise, read values from the "Authorization" header.
         $client_phid = $client_id_header;
         $client_secret = $client_secret_header;
     }
     if ($grant_type != 'authorization_code') {
         $response->setError('unsupported_grant_type');
         $response->setErrorDescription(pht('Only %s %s is supported.', 'grant_type', 'authorization_code'));
         return $response;
     }
     if (!$code) {
         $response->setError('invalid_request');
         $response->setErrorDescription(pht('Required parameter code missing.'));
         return $response;
     }
     if (!$client_phid) {
         $response->setError('invalid_request');
         $response->setErrorDescription(pht('Required parameter %s missing.', 'client_id'));
         return $response;
     }
     if (!$client_secret) {
         $response->setError('invalid_request');
         $response->setErrorDescription(pht('Required parameter %s missing.', 'client_secret'));
         return $response;
     }
     // one giant try / catch around all the exciting database stuff so we
     // can return a 'server_error' response if something goes wrong!
     try {
         $auth_code = id(new PhabricatorOAuthServerAuthorizationCode())->loadOneWhere('code = %s', $code);
         if (!$auth_code) {
             $response->setError('invalid_grant');
             $response->setErrorDescription(pht('Authorization code %s not found.', $code));
             return $response;
         }
         // if we have an auth code redirect URI, there must be a redirect_uri
         // in the request and it must match the auth code redirect uri *exactly*
         $auth_code_redirect_uri = $auth_code->getRedirectURI();
         if ($auth_code_redirect_uri) {
             $auth_code_redirect_uri = new PhutilURI($auth_code_redirect_uri);
             $redirect_uri = new PhutilURI($redirect_uri);
             if (!$redirect_uri->getDomain() || $redirect_uri != $auth_code_redirect_uri) {
                 $response->setError('invalid_grant');
                 $response->setErrorDescription(pht('Redirect URI in request must exactly match redirect URI ' . 'from authorization code.'));
                 return $response;
             }
         } else {
             if ($redirect_uri) {
                 $response->setError('invalid_grant');
                 $response->setErrorDescription(pht('Redirect URI in request and no redirect URI in authorization ' . 'code. The two must exactly match.'));
                 return $response;
             }
         }
         $client = id(new PhabricatorOAuthServerClient())->loadOneWhere('phid = %s', $client_phid);
         if (!$client) {
             $response->setError('invalid_client');
             $response->setErrorDescription(pht('Client with %s %s not found.', 'client_id', $client_phid));
             return $response;
         }
         if ($client->getIsDisabled()) {
             $response->setError('invalid_client');
             $response->setErrorDescription(pht('OAuth application "%s" has been disabled.', $client->getName()));
             return $response;
         }
         $server->setClient($client);
         $user_phid = $auth_code->getUserPHID();
         $user = id(new PhabricatorUser())->loadOneWhere('phid = %s', $user_phid);
         if (!$user) {
             $response->setError('invalid_grant');
             $response->setErrorDescription(pht('User with PHID %s not found.', $user_phid));
             return $response;
         }
         $server->setUser($user);
         $test_code = new PhabricatorOAuthServerAuthorizationCode();
         $test_code->setClientSecret($client_secret);
         $test_code->setClientPHID($client_phid);
         $is_good_code = $server->validateAuthorizationCode($auth_code, $test_code);
         if (!$is_good_code) {
             $response->setError('invalid_grant');
             $response->setErrorDescription(pht('Invalid authorization code %s.', $code));
             return $response;
         }
         $unguarded = AphrontWriteGuard::beginScopedUnguardedWrites();
         $access_token = $server->generateAccessToken();
         $auth_code->delete();
         unset($unguarded);
         $result = array('access_token' => $access_token->getToken(), 'token_type' => 'Bearer');
         return $response->setContent($result);
     } catch (Exception $e) {
         $response->setError('server_error');
         $response->setErrorDescription(pht('The authorization server encountered an unexpected condition ' . 'which prevented it from fulfilling the request.'));
         return $response;
     }
 }