mirror of
https://we.phorge.it/source/phorge.git
synced 2024-12-21 04:50:55 +01:00
Provide $request->getUser() for Conduit API Requests
Summary: Allow Conduit methods to retrieve the authoritative, logged-in user identity. Test Plan: Ran user.whoami (an authenticated method) and got my info back. Ran conduit.connect (an unauthenticated method) and the world did not explode. Reviewed By: tuomaspelkonen Reviewers: tuomaspelkonen CC: tuomaspelkonen, epriestley Differential Revision: 113
This commit is contained in:
parent
a6b873692f
commit
5e9d053f8e
5 changed files with 155 additions and 34 deletions
|
@ -87,6 +87,7 @@ phutil_register_library_map(array(
|
|||
'ConduitAPI_differential_updaterevision_Method' => 'applications/conduit/method/differential/updaterevision',
|
||||
'ConduitAPI_file_upload_Method' => 'applications/conduit/method/file/upload',
|
||||
'ConduitAPI_user_find_Method' => 'applications/conduit/method/user/find',
|
||||
'ConduitAPI_user_whoami_Method' => 'applications/conduit/method/user/whoami',
|
||||
'ConduitException' => 'applications/conduit/protocol/exception',
|
||||
'DarkConsole' => 'aphront/console/api',
|
||||
'DarkConsoleConfigPlugin' => 'aphront/console/plugin/config',
|
||||
|
@ -526,6 +527,7 @@ phutil_register_library_map(array(
|
|||
'ConduitAPI_differential_updaterevision_Method' => 'ConduitAPIMethod',
|
||||
'ConduitAPI_file_upload_Method' => 'ConduitAPIMethod',
|
||||
'ConduitAPI_user_find_Method' => 'ConduitAPIMethod',
|
||||
'ConduitAPI_user_whoami_Method' => 'ConduitAPIMethod',
|
||||
'DarkConsoleConfigPlugin' => 'DarkConsolePlugin',
|
||||
'DarkConsoleController' => 'PhabricatorController',
|
||||
'DarkConsoleErrorLogPlugin' => 'DarkConsolePlugin',
|
||||
|
|
|
@ -79,44 +79,16 @@ class PhabricatorConduitAPIController
|
|||
$metadata = idx($params, '__conduit__', array());
|
||||
unset($params['__conduit__']);
|
||||
|
||||
$result = null;
|
||||
|
||||
$api_request = new ConduitAPIRequest($params);
|
||||
|
||||
if ($request->getUser()->getPHID()) {
|
||||
$auth_okay = true;
|
||||
} else if (!$method_handler->shouldRequireAuthentication()) {
|
||||
$auth_okay = true;
|
||||
} else {
|
||||
$session_key = idx($metadata, 'sessionKey');
|
||||
if (!$session_key) {
|
||||
$auth_okay = false;
|
||||
$error_code = 'ERR-NO-CERTIFICATE';
|
||||
$error_info = "This server requires authentication but your client ".
|
||||
"is not configured with an authentication ".
|
||||
"certificate. Please refer to ".
|
||||
"page http://www.phabricator.com/docs/".
|
||||
"phabricator/article/".
|
||||
"Installing_Arcanist_Certificates.html for more info.";
|
||||
} else {
|
||||
$user = new PhabricatorUser();
|
||||
$session = queryfx_one(
|
||||
$user->establishConnection('r'),
|
||||
'SELECT * FROM %T WHERE sessionKey = %s',
|
||||
PhabricatorUser::SESSION_TABLE,
|
||||
$session_key);
|
||||
if (!$session) {
|
||||
$auth_okay = false;
|
||||
$result = null;
|
||||
$error_code = 'ERR-INVALID-SESSION';
|
||||
$error_info = 'Session key is invalid.';
|
||||
} else {
|
||||
// TODO: Make sessions timeout.
|
||||
$auth_okay = true;
|
||||
}
|
||||
}
|
||||
// TODO: When we session, read connectionID from the session table.
|
||||
$auth_error = null;
|
||||
if ($method_handler->shouldRequireAuthentication()) {
|
||||
$auth_error = $this->authenticateUser($api_request, $metadata);
|
||||
}
|
||||
|
||||
if ($auth_okay) {
|
||||
if ($auth_error === null) {
|
||||
try {
|
||||
$result = $method_handler->executeMethod($api_request);
|
||||
$error_code = null;
|
||||
|
@ -126,6 +98,8 @@ class PhabricatorConduitAPIController
|
|||
$error_code = $ex->getMessage();
|
||||
$error_info = $method_handler->getErrorDescription($error_code);
|
||||
}
|
||||
} else {
|
||||
list($error_code, $error_info) = $auth_error;
|
||||
}
|
||||
} catch (Exception $ex) {
|
||||
$result = null;
|
||||
|
@ -167,6 +141,65 @@ class PhabricatorConduitAPIController
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Authenticate the client making the request to a Phabricator user account.
|
||||
*
|
||||
* @param ConduitAPIRequest Request being executed.
|
||||
* @param dict Request metadata.
|
||||
* @return null|pair Null to indicate successful authentication, or
|
||||
* an error code and error message pair.
|
||||
*/
|
||||
private function authenticateUser(
|
||||
ConduitAPIRequest $api_request,
|
||||
array $metadata) {
|
||||
|
||||
$request = $this->getRequest();
|
||||
|
||||
if ($request->getUser()->getPHID()) {
|
||||
$api_request->setUser($request->getUser());
|
||||
return null;
|
||||
}
|
||||
|
||||
$session_key = idx($metadata, 'sessionKey');
|
||||
if (!$session_key) {
|
||||
return array(
|
||||
'ERR-NO-CERTIFICATE',
|
||||
'This server requires authentication but your client is not '.
|
||||
'configured with an authentication certificate. Please refer to '.
|
||||
'<http://www.phabricator.com/docs/phabricator/article/'.
|
||||
'Installing_Arcanist_Certificates.html> for more info.',
|
||||
);
|
||||
}
|
||||
|
||||
$session = queryfx_one(
|
||||
id(new PhabricatorUser())->establishConnection('r'),
|
||||
'SELECT * FROM %T WHERE sessionKey = %s',
|
||||
PhabricatorUser::SESSION_TABLE,
|
||||
$session_key);
|
||||
if (!$session) {
|
||||
return array(
|
||||
'ERR-INVALID-SESSION',
|
||||
'Session key is invalid.',
|
||||
);
|
||||
}
|
||||
|
||||
// TODO: Make sessions timeout.
|
||||
// TODO: When we pull a session, read connectionID from the session table.
|
||||
|
||||
$user = id(new PhabricatorUser())->loadOneWhere(
|
||||
'phid = %s',
|
||||
$session['userPHID']);
|
||||
if (!$user) {
|
||||
return array(
|
||||
'ERR-INVALID-SESSION',
|
||||
'Session is for nonexistent user.',
|
||||
);
|
||||
}
|
||||
|
||||
$api_request->setUser($user);
|
||||
return null;
|
||||
}
|
||||
|
||||
private function buildHumanReadableResponse(
|
||||
$method,
|
||||
ConduitAPIRequest $request = null,
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright 2011 Facebook, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
class ConduitAPI_user_whoami_Method extends ConduitAPIMethod {
|
||||
|
||||
public function getMethodDescription() {
|
||||
return "Retrieve information about the logged-in user.";
|
||||
}
|
||||
|
||||
public function defineParamTypes() {
|
||||
return array(
|
||||
);
|
||||
}
|
||||
|
||||
public function defineReturnType() {
|
||||
return 'nonempty dict<string, wild>';
|
||||
}
|
||||
|
||||
public function defineErrorTypes() {
|
||||
return array(
|
||||
);
|
||||
}
|
||||
|
||||
protected function execute(ConduitAPIRequest $request) {
|
||||
$user = $request->getUser();
|
||||
return array(
|
||||
'phid' => $user->getPHID(),
|
||||
'userName' => $user->getUserName(),
|
||||
'realName' => $user->getRealName(),
|
||||
);
|
||||
}
|
||||
|
||||
}
|
12
src/applications/conduit/method/user/whoami/__init__.php
Normal file
12
src/applications/conduit/method/user/whoami/__init__.php
Normal file
|
@ -0,0 +1,12 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is automatically generated. Lint this module to rebuild it.
|
||||
* @generated
|
||||
*/
|
||||
|
||||
|
||||
|
||||
phutil_require_module('phabricator', 'applications/conduit/method/base');
|
||||
|
||||
|
||||
phutil_require_source('ConduitAPI_user_whoami_Method.php');
|
|
@ -19,6 +19,7 @@
|
|||
class ConduitAPIRequest {
|
||||
|
||||
protected $params;
|
||||
private $user;
|
||||
|
||||
public function __construct(array $params) {
|
||||
$this->params = $params;
|
||||
|
@ -32,4 +33,29 @@ class ConduitAPIRequest {
|
|||
return $this->params;
|
||||
}
|
||||
|
||||
public function setUser($user) {
|
||||
$this->user = $user;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the authentic identity of the user making the request. If a
|
||||
* method requires authentication (the default) the user object will always
|
||||
* be available. If a method does not require authentication (i.e., overrides
|
||||
* shouldRequireAuthentication() to return false) the user object will NEVER
|
||||
* be available.
|
||||
*
|
||||
* @return PhabricatorUser Authentic user, available ONLY if the method
|
||||
* requires authentication.
|
||||
*/
|
||||
public function getUser() {
|
||||
if (!$this->user) {
|
||||
throw new Exception(
|
||||
"You can not access the user inside the implementation of a Conduit ".
|
||||
"method which does not require authentication (as per ".
|
||||
"shouldRequireAuthentication()).");
|
||||
}
|
||||
return $this->user;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue