コード例 #1
0
 public function processRequest()
 {
     $request = $this->getRequest();
     $current_user = $request->getUser();
     $server = new PhabricatorOAuthServer($current_user);
     $panels = array();
     $results = array();
     if ($request->isFormPost()) {
         $action = $request->getStr('action');
         switch ($action) {
             case 'testclientauthorization':
                 $user_phid = $current_user->getPHID();
                 $client_phid = $request->getStr('client_phid');
                 $client = id(new PhabricatorOAuthServerClient())->loadOneWhere('phid = %s', $client_phid);
                 if (!$client) {
                     throw new Exception('Failed to load client!');
                 }
                 if ($client->getCreatorPHID() != $user_phid || $current_user->getPHID() != $user_phid) {
                     throw new Exception('Only allowed to make test data for yourself ' . 'for clients you own!');
                 }
                 // blankclientauthorizations don't get scope
                 $scope = array();
                 $server->setUser($current_user);
                 $server->setClient($client);
                 $authorization = $server->authorizeClient($scope);
                 return id(new AphrontRedirectResponse())->setURI('/oauthserver/clientauthorization/?edited=' . $authorization->getPHID());
                 break;
             default:
                 break;
         }
     }
 }
 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;
     }
 }
 public function processRequest()
 {
     $request = $this->getRequest();
     $viewer = $request->getUser();
     $server = new PhabricatorOAuthServer();
     $client_phid = $request->getStr('client_id');
     $scope = $request->getStr('scope');
     $redirect_uri = $request->getStr('redirect_uri');
     $response_type = $request->getStr('response_type');
     // state is an opaque value the client sent us for their own purposes
     // we just need to send it right back to them in the response!
     $state = $request->getStr('state');
     if (!$client_phid) {
         return $this->buildErrorResponse('invalid_request', pht('Malformed Request'), pht('Required parameter %s was not present in the request.', phutil_tag('strong', array(), 'client_id')));
     }
     $server->setUser($viewer);
     $is_authorized = false;
     $authorization = null;
     $uri = null;
     $name = null;
     // one giant try / catch around all the exciting database stuff so we
     // can return a 'server_error' response if something goes wrong!
     try {
         try {
             $client = id(new PhabricatorOAuthServerClientQuery())->setViewer($viewer)->withPHIDs(array($client_phid))->executeOne();
         } catch (PhabricatorPolicyException $ex) {
             // We require that users must be able to see an OAuth application
             // in order to authorize it. This allows an application's visibility
             // policy to be used to restrict authorized users.
             // None of the OAuth error responses are a perfect fit for this, but
             // 'invalid_client' seems closest.
             return $this->buildErrorResponse('invalid_client', pht('Not Authorized'), pht('You are not authorized to authenticate.'));
         }
         if (!$client) {
             return $this->buildErrorResponse('invalid_request', pht('Invalid Client Application'), pht('Request parameter %s does not specify a valid client application.', phutil_tag('strong', array(), 'client_id')));
         }
         $name = $client->getName();
         $server->setClient($client);
         if ($redirect_uri) {
             $client_uri = new PhutilURI($client->getRedirectURI());
             $redirect_uri = new PhutilURI($redirect_uri);
             if (!$server->validateSecondaryRedirectURI($redirect_uri, $client_uri)) {
                 return $this->buildErrorResponse('invalid_request', pht('Invalid Redirect URI'), pht('Request parameter %s specifies an invalid redirect URI. ' . 'The redirect URI must be a fully-qualified domain with no ' . 'fragments, and must have the same domain and at least ' . 'the same query parameters as the redirect URI the client ' . 'registered.', phutil_tag('strong', array(), 'redirect_uri')));
             }
             $uri = $redirect_uri;
         } else {
             $uri = new PhutilURI($client->getRedirectURI());
         }
         if (empty($response_type)) {
             return $this->buildErrorResponse('invalid_request', pht('Invalid Response Type'), pht('Required request parameter %s is missing.', phutil_tag('strong', array(), 'response_type')));
         }
         if ($response_type != 'code') {
             return $this->buildErrorResponse('unsupported_response_type', pht('Unsupported Response Type'), pht('Request parameter %s specifies an unsupported response type. ' . 'Valid response types are: %s.', phutil_tag('strong', array(), 'response_type'), implode(', ', array('code'))));
         }
         if ($scope) {
             if (!PhabricatorOAuthServerScope::validateScopesList($scope)) {
                 return $this->buildErrorResponse('invalid_scope', pht('Invalid Scope'), pht('Request parameter %s specifies an unsupported scope.', phutil_tag('strong', array(), 'scope')));
             }
             $scope = PhabricatorOAuthServerScope::scopesListToDict($scope);
         } else {
             return $this->buildErrorResponse('invalid_request', pht('Malformed Request'), pht('Required parameter %s was not present in the request.', phutil_tag('strong', array(), 'scope')));
         }
         // NOTE: We're always requiring a confirmation dialog to redirect.
         // Partly this is a general defense against redirect attacks, and
         // partly this shakes off anchors in the URI (which are not shaken
         // by 302'ing).
         $auth_info = $server->userHasAuthorizedClient($scope);
         list($is_authorized, $authorization) = $auth_info;
         if ($request->isFormPost()) {
             $scope = PhabricatorOAuthServerScope::getScopesFromRequest($request);
             if ($authorization) {
                 $authorization->setScope($scope)->save();
             } else {
                 $authorization = $server->authorizeClient($scope);
             }
             $is_authorized = true;
         }
     } catch (Exception $e) {
         return $this->buildErrorResponse('server_error', pht('Server Error'), pht('The authorization server encountered an unexpected condition ' . 'which prevented it from fulfilling the request.'));
     }
     // When we reach this part of the controller, we can be in two states:
     //
     //   1. The user has not authorized the application yet. We want to
     //      give them an "Authorize this application?" dialog.
     //   2. The user has authorized the application. We want to give them
     //      a "Confirm Login" dialog.
     if ($is_authorized) {
         // The second case is simpler, so handle it first. The user either
         // authorized the application previously, or has just authorized the
         // application. Show them a confirm dialog with a normal link back to
         // the application. This shakes anchors from the URI.
         $unguarded = AphrontWriteGuard::beginScopedUnguardedWrites();
         $auth_code = $server->generateAuthorizationCode($uri);
         unset($unguarded);
         $full_uri = $this->addQueryParams($uri, array('code' => $auth_code->getCode(), 'scope' => $authorization->getScopeString(), 'state' => $state));
         if ($client->getIsTrusted()) {
             return id(new AphrontRedirectResponse())->setIsExternal(true)->setURI((string) $full_uri);
         }
         // TODO: It would be nice to give the user more options here, like
         // reviewing permissions, canceling the authorization, or aborting
         // the workflow.
         $dialog = id(new AphrontDialogView())->setUser($viewer)->setTitle(pht('Authenticate: %s', $name))->appendParagraph(pht('This application ("%s") is authorized to use your Phabricator ' . 'credentials. Continue to complete the authentication workflow.', phutil_tag('strong', array(), $name)))->addCancelButton((string) $full_uri, pht('Continue to Application'));
         return id(new AphrontDialogResponse())->setDialog($dialog);
     }
     // Here, we're confirming authorization for the application.
     if ($authorization) {
         $desired_scopes = array_merge($scope, $authorization->getScope());
     } else {
         $desired_scopes = $scope;
     }
     if (!PhabricatorOAuthServerScope::validateScopesDict($desired_scopes)) {
         return $this->buildErrorResponse('invalid_scope', pht('Invalid Scope'), pht('The requested scope is invalid, unknown, or malformed.'));
     }
     $form = id(new AphrontFormView())->addHiddenInput('client_id', $client_phid)->addHiddenInput('redirect_uri', $redirect_uri)->addHiddenInput('response_type', $response_type)->addHiddenInput('state', $state)->addHiddenInput('scope', $request->getStr('scope'))->setUser($viewer)->appendChild(PhabricatorOAuthServerScope::getCheckboxControl($desired_scopes));
     $cancel_msg = pht('The user declined to authorize this application.');
     $cancel_uri = $this->addQueryParams($uri, array('error' => 'access_denied', 'error_description' => $cancel_msg));
     $dialog = id(new AphrontDialogView())->setUser($viewer)->setTitle(pht('Authorize "%s"?', $name))->setSubmitURI($request->getRequestURI()->getPath())->setWidth(AphrontDialogView::WIDTH_FORM)->appendParagraph(pht('Do you want to authorize the external application "%s" to ' . 'access your Phabricator account data, including your primary ' . 'email address?', phutil_tag('strong', array(), $name)))->appendChild($form->buildLayoutView())->addSubmitButton(pht('Authorize Access'))->addCancelButton((string) $cancel_uri, pht('Do Not Authorize'));
     return id(new AphrontDialogResponse())->setDialog($dialog);
 }
 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;
     }
 }
コード例 #5
0
 public function processRequest()
 {
     $request = $this->getRequest();
     $current_user = $request->getUser();
     $server = new PhabricatorOAuthServer();
     $client_phid = $request->getStr('client_id');
     $scope = $request->getStr('scope');
     $redirect_uri = $request->getStr('redirect_uri');
     $state = $request->getStr('state');
     $response_type = $request->getStr('response_type');
     $response = new PhabricatorOAuthResponse();
     // state is an opaque value the client sent us for their own purposes
     // we just need to send it right back to them in the response!
     if ($state) {
         $response->setState($state);
     }
     if (!$client_phid) {
         $response->setError('invalid_request');
         $response->setErrorDescription('Required parameter client_id not specified.');
         return $response;
     }
     $server->setUser($current_user);
     // one giant try / catch around all the exciting database stuff so we
     // can return a 'server_error' response if something goes wrong!
     try {
         $client = id(new PhabricatorOAuthServerClient())->loadOneWhere('phid = %s', $client_phid);
         if (!$client) {
             $response->setError('invalid_request');
             $response->setErrorDescription('Client with id ' . $client_phid . ' not found.');
             return $response;
         }
         $server->setClient($client);
         if ($redirect_uri) {
             $client_uri = new PhutilURI($client->getRedirectURI());
             $redirect_uri = new PhutilURI($redirect_uri);
             if (!$server->validateSecondaryRedirectURI($redirect_uri, $client_uri)) {
                 $response->setError('invalid_request');
                 $response->setErrorDescription('The specified redirect URI is invalid. The redirect URI ' . 'must be a fully-qualified domain with no fragments and ' . 'must have the same domain and at least the same query ' . 'parameters as the redirect URI the client registered.');
                 return $response;
             }
             $uri = $redirect_uri;
             $access_token_uri = $uri;
         } else {
             $uri = new PhutilURI($client->getRedirectURI());
             $access_token_uri = null;
         }
         // we've now validated this request enough overall such that we
         // can safely redirect to the client with the response
         $response->setClientURI($uri);
         if (empty($response_type)) {
             $response->setError('invalid_request');
             $response->setErrorDescription('Required parameter response_type not specified.');
             return $response;
         }
         if ($response_type != 'code') {
             $response->setError('unsupported_response_type');
             $response->setErrorDescription('The authorization server does not support obtaining an ' . 'authorization code using the specified response_type. ' . 'You must specify the response_type as "code".');
             return $response;
         }
         if ($scope) {
             if (!PhabricatorOAuthServerScope::validateScopesList($scope)) {
                 $response->setError('invalid_scope');
                 $response->setErrorDescription('The requested scope is invalid, unknown, or malformed.');
                 return $response;
             }
             $scope = PhabricatorOAuthServerScope::scopesListToDict($scope);
         }
         list($is_authorized, $authorization) = $server->userHasAuthorizedClient($scope);
         if ($is_authorized) {
             $return_auth_code = true;
             $unguarded_write = AphrontWriteGuard::beginScopedUnguardedWrites();
         } else {
             if ($request->isFormPost()) {
                 $scope = PhabricatorOAuthServerScope::getScopesFromRequest($request);
                 if ($authorization) {
                     $authorization->setScope($scope)->save();
                 } else {
                     $authorization = $server->authorizeClient($scope);
                 }
                 $return_auth_code = true;
                 $unguarded_write = null;
             } else {
                 $return_auth_code = false;
                 $unguarded_write = null;
             }
         }
         if ($return_auth_code) {
             // step 1 -- generate authorization code
             $auth_code = $server->generateAuthorizationCode($access_token_uri);
             // step 2 return it
             $content = array('code' => $auth_code->getCode(), 'scope' => $authorization->getScopeString());
             $response->setContent($content);
             return $response;
         }
         unset($unguarded_write);
     } catch (Exception $e) {
         // Note we could try harder to determine between a server_error
         // vs temporarily_unavailable.  Good enough though.
         $response->setError('server_error');
         $response->setErrorDescription('The authorization server encountered an unexpected condition ' . 'which prevented it from fulfilling the request. ');
         return $response;
     }
     // display time -- make a nice form for the user to grant the client
     // access to the granularity specified by $scope
     $name = phutil_escape_html($client->getName());
     $title = 'Authorize ' . $name . '?';
     $panel = new AphrontPanelView();
     $panel->setWidth(AphrontPanelView::WIDTH_FORM);
     $panel->setHeader($title);
     $description = "Do want to authorize {$name} to access your " . "Phabricator account data?";
     if ($scope) {
         if ($authorization) {
             $desired_scopes = array_merge($scope, $authorization->getScope());
         } else {
             $desired_scopes = $scope;
         }
         if (!PhabricatorOAuthServerScope::validateScopesDict($desired_scopes)) {
             $response->setError('invalid_scope');
             $response->setErrorDescription('The requested scope is invalid, unknown, or malformed.');
             return $response;
         }
     } else {
         $desired_scopes = array(PhabricatorOAuthServerScope::SCOPE_WHOAMI => 1, PhabricatorOAuthServerScope::SCOPE_OFFLINE_ACCESS => 1);
     }
     $cancel_uri = clone $uri;
     $cancel_params = array('error' => 'access_denied', 'error_description' => 'The resource owner (aka the user) denied the request.');
     $cancel_uri->setQueryParams($cancel_params);
     $form = id(new AphrontFormView())->setUser($current_user)->appendChild(id(new AphrontFormStaticControl())->setValue($description))->appendChild(PhabricatorOAuthServerScope::getCheckboxControl($desired_scopes))->appendChild(id(new AphrontFormSubmitControl())->setValue('Authorize')->addCancelButton($cancel_uri));
     $panel->appendChild($form);
     return $this->buildStandardPageResponse($panel, array('title' => $title));
 }