mirror of
https://we.phorge.it/source/phorge.git
synced 2024-11-10 08:52:39 +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_differential_updaterevision_Method' => 'applications/conduit/method/differential/updaterevision',
|
||||||
'ConduitAPI_file_upload_Method' => 'applications/conduit/method/file/upload',
|
'ConduitAPI_file_upload_Method' => 'applications/conduit/method/file/upload',
|
||||||
'ConduitAPI_user_find_Method' => 'applications/conduit/method/user/find',
|
'ConduitAPI_user_find_Method' => 'applications/conduit/method/user/find',
|
||||||
|
'ConduitAPI_user_whoami_Method' => 'applications/conduit/method/user/whoami',
|
||||||
'ConduitException' => 'applications/conduit/protocol/exception',
|
'ConduitException' => 'applications/conduit/protocol/exception',
|
||||||
'DarkConsole' => 'aphront/console/api',
|
'DarkConsole' => 'aphront/console/api',
|
||||||
'DarkConsoleConfigPlugin' => 'aphront/console/plugin/config',
|
'DarkConsoleConfigPlugin' => 'aphront/console/plugin/config',
|
||||||
|
@ -526,6 +527,7 @@ phutil_register_library_map(array(
|
||||||
'ConduitAPI_differential_updaterevision_Method' => 'ConduitAPIMethod',
|
'ConduitAPI_differential_updaterevision_Method' => 'ConduitAPIMethod',
|
||||||
'ConduitAPI_file_upload_Method' => 'ConduitAPIMethod',
|
'ConduitAPI_file_upload_Method' => 'ConduitAPIMethod',
|
||||||
'ConduitAPI_user_find_Method' => 'ConduitAPIMethod',
|
'ConduitAPI_user_find_Method' => 'ConduitAPIMethod',
|
||||||
|
'ConduitAPI_user_whoami_Method' => 'ConduitAPIMethod',
|
||||||
'DarkConsoleConfigPlugin' => 'DarkConsolePlugin',
|
'DarkConsoleConfigPlugin' => 'DarkConsolePlugin',
|
||||||
'DarkConsoleController' => 'PhabricatorController',
|
'DarkConsoleController' => 'PhabricatorController',
|
||||||
'DarkConsoleErrorLogPlugin' => 'DarkConsolePlugin',
|
'DarkConsoleErrorLogPlugin' => 'DarkConsolePlugin',
|
||||||
|
|
|
@ -79,44 +79,16 @@ class PhabricatorConduitAPIController
|
||||||
$metadata = idx($params, '__conduit__', array());
|
$metadata = idx($params, '__conduit__', array());
|
||||||
unset($params['__conduit__']);
|
unset($params['__conduit__']);
|
||||||
|
|
||||||
|
$result = null;
|
||||||
|
|
||||||
$api_request = new ConduitAPIRequest($params);
|
$api_request = new ConduitAPIRequest($params);
|
||||||
|
|
||||||
if ($request->getUser()->getPHID()) {
|
$auth_error = null;
|
||||||
$auth_okay = true;
|
if ($method_handler->shouldRequireAuthentication()) {
|
||||||
} else if (!$method_handler->shouldRequireAuthentication()) {
|
$auth_error = $this->authenticateUser($api_request, $metadata);
|
||||||
$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.
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($auth_okay) {
|
if ($auth_error === null) {
|
||||||
try {
|
try {
|
||||||
$result = $method_handler->executeMethod($api_request);
|
$result = $method_handler->executeMethod($api_request);
|
||||||
$error_code = null;
|
$error_code = null;
|
||||||
|
@ -126,6 +98,8 @@ class PhabricatorConduitAPIController
|
||||||
$error_code = $ex->getMessage();
|
$error_code = $ex->getMessage();
|
||||||
$error_info = $method_handler->getErrorDescription($error_code);
|
$error_info = $method_handler->getErrorDescription($error_code);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
list($error_code, $error_info) = $auth_error;
|
||||||
}
|
}
|
||||||
} catch (Exception $ex) {
|
} catch (Exception $ex) {
|
||||||
$result = null;
|
$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(
|
private function buildHumanReadableResponse(
|
||||||
$method,
|
$method,
|
||||||
ConduitAPIRequest $request = null,
|
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 {
|
class ConduitAPIRequest {
|
||||||
|
|
||||||
protected $params;
|
protected $params;
|
||||||
|
private $user;
|
||||||
|
|
||||||
public function __construct(array $params) {
|
public function __construct(array $params) {
|
||||||
$this->params = $params;
|
$this->params = $params;
|
||||||
|
@ -32,4 +33,29 @@ class ConduitAPIRequest {
|
||||||
return $this->params;
|
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