2011-01-24 18:00:29 +01:00
|
|
|
<?php
|
|
|
|
|
2011-07-04 21:03:36 +02:00
|
|
|
/**
|
|
|
|
* @group conduit
|
|
|
|
*/
|
2012-03-10 00:46:25 +01:00
|
|
|
final class PhabricatorConduitAPIController
|
2011-01-24 18:00:29 +01:00
|
|
|
extends PhabricatorConduitController {
|
|
|
|
|
2011-01-26 02:17:19 +01:00
|
|
|
public function shouldRequireLogin() {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2011-01-24 18:00:29 +01:00
|
|
|
private $method;
|
|
|
|
|
|
|
|
public function willProcessRequest(array $data) {
|
|
|
|
$this->method = $data['method'];
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function processRequest() {
|
|
|
|
$time_start = microtime(true);
|
|
|
|
$request = $this->getRequest();
|
|
|
|
|
|
|
|
$method = $this->method;
|
|
|
|
|
|
|
|
$api_request = null;
|
|
|
|
|
|
|
|
$log = new PhabricatorConduitMethodCallLog();
|
|
|
|
$log->setMethod($method);
|
2012-06-28 18:54:48 +02:00
|
|
|
$metadata = array();
|
2011-01-24 18:00:29 +01:00
|
|
|
|
|
|
|
try {
|
|
|
|
|
2012-10-04 18:30:32 +02:00
|
|
|
$params = $this->decodeConduitParams($request, $method);
|
2011-01-24 18:00:29 +01:00
|
|
|
$metadata = idx($params, '__conduit__', array());
|
|
|
|
unset($params['__conduit__']);
|
|
|
|
|
2013-05-19 13:16:09 +02:00
|
|
|
$call = new ConduitCall(
|
|
|
|
$method, $params, idx($metadata, 'isProxied', false));
|
Allow applications to call Conduit directly
Summary:
Sorry this took so long, had a bunch of stuff going on today.
Separate the actual core part of making conduit calls from the controller, so the application can make conduit calls without needing to invoke HTTP or redo auth. Generally, this lets us build more parts of the application on top of Conduit, as appropriate.
This diff can be simplified, but I wanted to unblock you guys first. I'll followup with a cleanup patch once I have a chance.
Test Plan: Ran unit tests, ran calls from the conduit API console, and ran calls over arc.
Reviewers: nodren, 20after4, btrahan, vrana
Reviewed By: 20after4
CC: aran, svemir
Maniphest Tasks: T945
Differential Revision: https://secure.phabricator.com/D2718
2012-06-17 17:47:09 +02:00
|
|
|
|
2011-04-08 03:27:39 +02:00
|
|
|
$result = null;
|
|
|
|
|
Allow applications to call Conduit directly
Summary:
Sorry this took so long, had a bunch of stuff going on today.
Separate the actual core part of making conduit calls from the controller, so the application can make conduit calls without needing to invoke HTTP or redo auth. Generally, this lets us build more parts of the application on top of Conduit, as appropriate.
This diff can be simplified, but I wanted to unblock you guys first. I'll followup with a cleanup patch once I have a chance.
Test Plan: Ran unit tests, ran calls from the conduit API console, and ran calls over arc.
Reviewers: nodren, 20after4, btrahan, vrana
Reviewed By: 20after4
CC: aran, svemir
Maniphest Tasks: T945
Differential Revision: https://secure.phabricator.com/D2718
2012-06-17 17:47:09 +02:00
|
|
|
// TODO: Straighten out the auth pathway here. We shouldn't be creating
|
|
|
|
// a ConduitAPIRequest at this level, but some of the auth code expects
|
|
|
|
// it. Landing a halfway version of this to unblock T945.
|
|
|
|
|
2011-01-24 18:00:29 +01:00
|
|
|
$api_request = new ConduitAPIRequest($params);
|
|
|
|
|
Create AphrontWriteGuard, a backup mechanism for CSRF validation
Summary:
Provide a catchall mechanism to find unprotected writes.
- Depends on D758.
- Similar to WriteOnHTTPGet stuff from Facebook's stack.
- Since we have a small number of storage mechanisms and highly structured
read/write pathways, we can explicitly answer the question "is this page
performing a write?".
- Never allow writes without CSRF checks.
- This will probably break some things. That's fine: they're CSRF
vulnerabilities or weird edge cases that we can fix. But don't push to Facebook
for a few days unless you're prepared to deal with this.
- **>>> MEGADERP: All Conduit write APIs are currently vulnerable to CSRF!
<<<**
Test Plan:
- Ran some scripts that perform writes (scripts/search indexers), no issues.
- Performed normal CSRF submits.
- Added writes to an un-CSRF'd page, got an exception.
- Executed conduit methods.
- Did login/logout (this works because the logged-out user validates the
logged-out csrf "token").
- Did OAuth login.
- Did OAuth registration.
Reviewers: pedram, andrewjcg, erling, jungejason, tuomaspelkonen, aran,
codeblock
Commenters: pedram
CC: aran, epriestley, pedram
Differential Revision: 777
2011-08-03 20:49:27 +02:00
|
|
|
$allow_unguarded_writes = false;
|
2011-04-08 03:27:39 +02:00
|
|
|
$auth_error = null;
|
2012-04-28 22:08:10 +02:00
|
|
|
$conduit_username = '-';
|
Allow applications to call Conduit directly
Summary:
Sorry this took so long, had a bunch of stuff going on today.
Separate the actual core part of making conduit calls from the controller, so the application can make conduit calls without needing to invoke HTTP or redo auth. Generally, this lets us build more parts of the application on top of Conduit, as appropriate.
This diff can be simplified, but I wanted to unblock you guys first. I'll followup with a cleanup patch once I have a chance.
Test Plan: Ran unit tests, ran calls from the conduit API console, and ran calls over arc.
Reviewers: nodren, 20after4, btrahan, vrana
Reviewed By: 20after4
CC: aran, svemir
Maniphest Tasks: T945
Differential Revision: https://secure.phabricator.com/D2718
2012-06-17 17:47:09 +02:00
|
|
|
if ($call->shouldRequireAuthentication()) {
|
|
|
|
$metadata['scope'] = $call->getRequiredScope();
|
2011-04-08 03:27:39 +02:00
|
|
|
$auth_error = $this->authenticateUser($api_request, $metadata);
|
Create AphrontWriteGuard, a backup mechanism for CSRF validation
Summary:
Provide a catchall mechanism to find unprotected writes.
- Depends on D758.
- Similar to WriteOnHTTPGet stuff from Facebook's stack.
- Since we have a small number of storage mechanisms and highly structured
read/write pathways, we can explicitly answer the question "is this page
performing a write?".
- Never allow writes without CSRF checks.
- This will probably break some things. That's fine: they're CSRF
vulnerabilities or weird edge cases that we can fix. But don't push to Facebook
for a few days unless you're prepared to deal with this.
- **>>> MEGADERP: All Conduit write APIs are currently vulnerable to CSRF!
<<<**
Test Plan:
- Ran some scripts that perform writes (scripts/search indexers), no issues.
- Performed normal CSRF submits.
- Added writes to an un-CSRF'd page, got an exception.
- Executed conduit methods.
- Did login/logout (this works because the logged-out user validates the
logged-out csrf "token").
- Did OAuth login.
- Did OAuth registration.
Reviewers: pedram, andrewjcg, erling, jungejason, tuomaspelkonen, aran,
codeblock
Commenters: pedram
CC: aran, epriestley, pedram
Differential Revision: 777
2011-08-03 20:49:27 +02:00
|
|
|
// If we've explicitly authenticated the user here and either done
|
|
|
|
// CSRF validation or are using a non-web authentication mechanism.
|
|
|
|
$allow_unguarded_writes = true;
|
2011-11-08 00:11:25 +01:00
|
|
|
|
|
|
|
if (isset($metadata['actAsUser'])) {
|
|
|
|
$this->actAsUser($api_request, $metadata['actAsUser']);
|
|
|
|
}
|
Create AphrontWriteGuard, a backup mechanism for CSRF validation
Summary:
Provide a catchall mechanism to find unprotected writes.
- Depends on D758.
- Similar to WriteOnHTTPGet stuff from Facebook's stack.
- Since we have a small number of storage mechanisms and highly structured
read/write pathways, we can explicitly answer the question "is this page
performing a write?".
- Never allow writes without CSRF checks.
- This will probably break some things. That's fine: they're CSRF
vulnerabilities or weird edge cases that we can fix. But don't push to Facebook
for a few days unless you're prepared to deal with this.
- **>>> MEGADERP: All Conduit write APIs are currently vulnerable to CSRF!
<<<**
Test Plan:
- Ran some scripts that perform writes (scripts/search indexers), no issues.
- Performed normal CSRF submits.
- Added writes to an un-CSRF'd page, got an exception.
- Executed conduit methods.
- Did login/logout (this works because the logged-out user validates the
logged-out csrf "token").
- Did OAuth login.
- Did OAuth registration.
Reviewers: pedram, andrewjcg, erling, jungejason, tuomaspelkonen, aran,
codeblock
Commenters: pedram
CC: aran, epriestley, pedram
Differential Revision: 777
2011-08-03 20:49:27 +02:00
|
|
|
|
2012-04-30 20:18:04 +02:00
|
|
|
if ($auth_error === null) {
|
|
|
|
$conduit_user = $api_request->getUser();
|
|
|
|
if ($conduit_user && $conduit_user->getPHID()) {
|
|
|
|
$conduit_username = $conduit_user->getUsername();
|
|
|
|
}
|
Allow applications to call Conduit directly
Summary:
Sorry this took so long, had a bunch of stuff going on today.
Separate the actual core part of making conduit calls from the controller, so the application can make conduit calls without needing to invoke HTTP or redo auth. Generally, this lets us build more parts of the application on top of Conduit, as appropriate.
This diff can be simplified, but I wanted to unblock you guys first. I'll followup with a cleanup patch once I have a chance.
Test Plan: Ran unit tests, ran calls from the conduit API console, and ran calls over arc.
Reviewers: nodren, 20after4, btrahan, vrana
Reviewed By: 20after4
CC: aran, svemir
Maniphest Tasks: T945
Differential Revision: https://secure.phabricator.com/D2718
2012-06-17 17:47:09 +02:00
|
|
|
$call->setUser($api_request->getUser());
|
Allow Phabricator to write an access log using PhutilDeferredLog
Summary: Provide a configurable access log.
Test Plan:
Got a sensible-looking log including logged-in, logged-out, conduit, 404, etc:
[Mon, 23 Apr 2012 20:08:12 -0700] 32599 orbital - epriestley DifferentialCommentPreviewController - /differential/comment/preview/42/ http://local.aphront.com:8080/D42 200 65406
[Mon, 23 Apr 2012 20:08:12 -0700] 32881 orbital - epriestley DifferentialChangesetViewController - /differential/changeset/ http://local.aphront.com:8080/D42 200 72669
[Mon, 23 Apr 2012 20:08:39 -0700] 32882 orbital 127.0.0.1 epriestley DifferentialRevisionListController - /differential/ http://local.aphront.com:8080/D42 200 106444
[Mon, 23 Apr 2012 20:08:54 -0700] 32867 orbital 127.0.0.1 epriestley DifferentialRevisionListController - /differential/ http://local.aphront.com:8080/differential/ 200 112229
[Mon, 23 Apr 2012 20:09:05 -0700] 32530 orbital 127.0.0.1 epriestley PhabricatorDirectoryMainController - / http://local.aphront.com:8080/differential/ 200 141350
[Mon, 23 Apr 2012 20:09:10 -0700] 32598 orbital 127.0.0.1 epriestley PhabricatorDirectoryCategoryViewController - /directory/6/ http://local.aphront.com:8080/ 200 43474
[Mon, 23 Apr 2012 20:09:12 -0700] 32880 orbital 127.0.0.1 epriestley PhabricatorConduitConsoleController - /conduit/ http://local.aphront.com:8080/directory/6/ 200 139340
[Mon, 23 Apr 2012 20:09:15 -0700] 32868 orbital 127.0.0.1 epriestley PhabricatorConduitAPIController arcanist.projectinfo /api/arcanist.projectinfo http://local.aphront.com:8080/conduit/ 200 128774
[Mon, 23 Apr 2012 20:10:04 -0700] 32599 orbital 127.0.0.1 epriestley Phabricator404Controller - /asdbmabdmbsm - 404 38782
[Mon, 23 Apr 2012 20:10:04 -0700] 32881 orbital 127.0.0.1 - CelerityResourceController - /res/c9a43002/rsrc/css/aphront/request-failure-view.css http://local.aphront.com:8080/asdbmabdmbsm 200 25160
[Mon, 23 Apr 2012 20:10:57 -0700] 32882 orbital 127.0.0.1 epriestley PhabricatorLogoutController - /logout/ http://local.aphront.com:8080/asdbmabdmbsm 200 40810
[Mon, 23 Apr 2012 20:10:57 -0700] 32867 orbital 127.0.0.1 - PhabricatorLoginController - /login/ http://local.aphront.com:8080/asdbmabdmbsm 200 42526
[Mon, 23 Apr 2012 20:10:59 -0700] 32919 orbital 127.0.0.1 - PhabricatorLoginController - /login/ http://local.aphront.com:8080/asdbmabdmbsm 200 49052
[Mon, 23 Apr 2012 20:10:59 -0700] 32880 orbital 127.0.0.1 - CelerityResourceController - /res/c80156c4/rsrc/js/application/core/behavior-dark-console.js http://local.aphront.com:8080/login/ 200 33166
[Mon, 23 Apr 2012 20:10:59 -0700] 32868 orbital 127.0.0.1 - CelerityResourceController - /res/4965d970/rsrc/css/aphront/dark-console.css http://local.aphront.com:8080/login/ 200 38078
[Mon, 23 Apr 2012 20:10:59 -0700] 32599 orbital 127.0.0.1 - CelerityResourceController - /res/pkg/8a5de8a3/javelin.pkg.js http://local.aphront.com:8080/login/ 200 40534
[Mon, 23 Apr 2012 20:10:59 -0700] 32882 orbital 127.0.0.1 - CelerityResourceController - /res/pkg/9c4e265b/core.pkg.css http://local.aphront.com:8080/login/ 200 41262
[Mon, 23 Apr 2012 20:10:59 -0700] 32881 orbital 127.0.0.1 - CelerityResourceController - /res/pkg/0c96375e/core.pkg.js http://local.aphront.com:8080/login/ 200 43720
[Mon, 23 Apr 2012 20:10:59 -0700] 32921 orbital 127.0.0.1 - CelerityResourceController - /res/caa86a45/rsrc/js/javelin/core/init.js http://local.aphront.com:8080/login/ 200 47566
[Mon, 23 Apr 2012 20:10:59 -0700] 32867 orbital 127.0.0.1 - CelerityResourceController - /res/f46289e9/rsrc/js/application/core/behavior-error-log.js http://local.aphront.com:8080/login/ 200 29328
[Mon, 23 Apr 2012 20:10:59 -0700] 32919 orbital 127.0.0.1 - CelerityResourceController - /res/7e62ff40/rsrc/image/phabricator_logo.png http://local.aphront.com:8080/login/ 200 25583
[Mon, 23 Apr 2012 20:10:59 -0700] 32880 orbital 127.0.0.1 - CelerityResourceController - /res/8c6200d3/rsrc/image/sprite.png http://local.aphront.com:8080/login/ 200 29829
[Mon, 23 Apr 2012 20:11:01 -0700] 32868 orbital 127.0.0.1 - PhabricatorOAuthLoginController - /oauth/facebook/login/ http://local.aphront.com:8080/login/ 200 855931
[Mon, 23 Apr 2012 20:11:02 -0700] 32882 orbital 127.0.0.1 epriestley789 PhabricatorLoginValidateController - /login/validate/ http://local.aphront.com:8080/login/ 200 29793
[Mon, 23 Apr 2012 20:11:02 -0700] 32881 orbital 127.0.0.1 epriestley789 PhabricatorDirectoryMainController - / http://local.aphront.com:8080/login/ 200 91638
Reviewers: jungejason, btrahan, vrana
Reviewed By: btrahan
CC: aran
Differential Revision: https://secure.phabricator.com/D2310
2012-04-25 16:24:08 +02:00
|
|
|
}
|
2012-04-28 22:08:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
$access_log = PhabricatorAccessLog::getLog();
|
|
|
|
if ($access_log) {
|
Allow Phabricator to write an access log using PhutilDeferredLog
Summary: Provide a configurable access log.
Test Plan:
Got a sensible-looking log including logged-in, logged-out, conduit, 404, etc:
[Mon, 23 Apr 2012 20:08:12 -0700] 32599 orbital - epriestley DifferentialCommentPreviewController - /differential/comment/preview/42/ http://local.aphront.com:8080/D42 200 65406
[Mon, 23 Apr 2012 20:08:12 -0700] 32881 orbital - epriestley DifferentialChangesetViewController - /differential/changeset/ http://local.aphront.com:8080/D42 200 72669
[Mon, 23 Apr 2012 20:08:39 -0700] 32882 orbital 127.0.0.1 epriestley DifferentialRevisionListController - /differential/ http://local.aphront.com:8080/D42 200 106444
[Mon, 23 Apr 2012 20:08:54 -0700] 32867 orbital 127.0.0.1 epriestley DifferentialRevisionListController - /differential/ http://local.aphront.com:8080/differential/ 200 112229
[Mon, 23 Apr 2012 20:09:05 -0700] 32530 orbital 127.0.0.1 epriestley PhabricatorDirectoryMainController - / http://local.aphront.com:8080/differential/ 200 141350
[Mon, 23 Apr 2012 20:09:10 -0700] 32598 orbital 127.0.0.1 epriestley PhabricatorDirectoryCategoryViewController - /directory/6/ http://local.aphront.com:8080/ 200 43474
[Mon, 23 Apr 2012 20:09:12 -0700] 32880 orbital 127.0.0.1 epriestley PhabricatorConduitConsoleController - /conduit/ http://local.aphront.com:8080/directory/6/ 200 139340
[Mon, 23 Apr 2012 20:09:15 -0700] 32868 orbital 127.0.0.1 epriestley PhabricatorConduitAPIController arcanist.projectinfo /api/arcanist.projectinfo http://local.aphront.com:8080/conduit/ 200 128774
[Mon, 23 Apr 2012 20:10:04 -0700] 32599 orbital 127.0.0.1 epriestley Phabricator404Controller - /asdbmabdmbsm - 404 38782
[Mon, 23 Apr 2012 20:10:04 -0700] 32881 orbital 127.0.0.1 - CelerityResourceController - /res/c9a43002/rsrc/css/aphront/request-failure-view.css http://local.aphront.com:8080/asdbmabdmbsm 200 25160
[Mon, 23 Apr 2012 20:10:57 -0700] 32882 orbital 127.0.0.1 epriestley PhabricatorLogoutController - /logout/ http://local.aphront.com:8080/asdbmabdmbsm 200 40810
[Mon, 23 Apr 2012 20:10:57 -0700] 32867 orbital 127.0.0.1 - PhabricatorLoginController - /login/ http://local.aphront.com:8080/asdbmabdmbsm 200 42526
[Mon, 23 Apr 2012 20:10:59 -0700] 32919 orbital 127.0.0.1 - PhabricatorLoginController - /login/ http://local.aphront.com:8080/asdbmabdmbsm 200 49052
[Mon, 23 Apr 2012 20:10:59 -0700] 32880 orbital 127.0.0.1 - CelerityResourceController - /res/c80156c4/rsrc/js/application/core/behavior-dark-console.js http://local.aphront.com:8080/login/ 200 33166
[Mon, 23 Apr 2012 20:10:59 -0700] 32868 orbital 127.0.0.1 - CelerityResourceController - /res/4965d970/rsrc/css/aphront/dark-console.css http://local.aphront.com:8080/login/ 200 38078
[Mon, 23 Apr 2012 20:10:59 -0700] 32599 orbital 127.0.0.1 - CelerityResourceController - /res/pkg/8a5de8a3/javelin.pkg.js http://local.aphront.com:8080/login/ 200 40534
[Mon, 23 Apr 2012 20:10:59 -0700] 32882 orbital 127.0.0.1 - CelerityResourceController - /res/pkg/9c4e265b/core.pkg.css http://local.aphront.com:8080/login/ 200 41262
[Mon, 23 Apr 2012 20:10:59 -0700] 32881 orbital 127.0.0.1 - CelerityResourceController - /res/pkg/0c96375e/core.pkg.js http://local.aphront.com:8080/login/ 200 43720
[Mon, 23 Apr 2012 20:10:59 -0700] 32921 orbital 127.0.0.1 - CelerityResourceController - /res/caa86a45/rsrc/js/javelin/core/init.js http://local.aphront.com:8080/login/ 200 47566
[Mon, 23 Apr 2012 20:10:59 -0700] 32867 orbital 127.0.0.1 - CelerityResourceController - /res/f46289e9/rsrc/js/application/core/behavior-error-log.js http://local.aphront.com:8080/login/ 200 29328
[Mon, 23 Apr 2012 20:10:59 -0700] 32919 orbital 127.0.0.1 - CelerityResourceController - /res/7e62ff40/rsrc/image/phabricator_logo.png http://local.aphront.com:8080/login/ 200 25583
[Mon, 23 Apr 2012 20:10:59 -0700] 32880 orbital 127.0.0.1 - CelerityResourceController - /res/8c6200d3/rsrc/image/sprite.png http://local.aphront.com:8080/login/ 200 29829
[Mon, 23 Apr 2012 20:11:01 -0700] 32868 orbital 127.0.0.1 - PhabricatorOAuthLoginController - /oauth/facebook/login/ http://local.aphront.com:8080/login/ 200 855931
[Mon, 23 Apr 2012 20:11:02 -0700] 32882 orbital 127.0.0.1 epriestley789 PhabricatorLoginValidateController - /login/validate/ http://local.aphront.com:8080/login/ 200 29793
[Mon, 23 Apr 2012 20:11:02 -0700] 32881 orbital 127.0.0.1 epriestley789 PhabricatorDirectoryMainController - / http://local.aphront.com:8080/login/ 200 91638
Reviewers: jungejason, btrahan, vrana
Reviewed By: btrahan
CC: aran
Differential Revision: https://secure.phabricator.com/D2310
2012-04-25 16:24:08 +02:00
|
|
|
$access_log->setData(
|
|
|
|
array(
|
|
|
|
'u' => $conduit_username,
|
|
|
|
'm' => $method,
|
|
|
|
));
|
|
|
|
}
|
|
|
|
|
Allow applications to call Conduit directly
Summary:
Sorry this took so long, had a bunch of stuff going on today.
Separate the actual core part of making conduit calls from the controller, so the application can make conduit calls without needing to invoke HTTP or redo auth. Generally, this lets us build more parts of the application on top of Conduit, as appropriate.
This diff can be simplified, but I wanted to unblock you guys first. I'll followup with a cleanup patch once I have a chance.
Test Plan: Ran unit tests, ran calls from the conduit API console, and ran calls over arc.
Reviewers: nodren, 20after4, btrahan, vrana
Reviewed By: 20after4
CC: aran, svemir
Maniphest Tasks: T945
Differential Revision: https://secure.phabricator.com/D2718
2012-06-17 17:47:09 +02:00
|
|
|
if ($call->shouldAllowUnguardedWrites()) {
|
Create AphrontWriteGuard, a backup mechanism for CSRF validation
Summary:
Provide a catchall mechanism to find unprotected writes.
- Depends on D758.
- Similar to WriteOnHTTPGet stuff from Facebook's stack.
- Since we have a small number of storage mechanisms and highly structured
read/write pathways, we can explicitly answer the question "is this page
performing a write?".
- Never allow writes without CSRF checks.
- This will probably break some things. That's fine: they're CSRF
vulnerabilities or weird edge cases that we can fix. But don't push to Facebook
for a few days unless you're prepared to deal with this.
- **>>> MEGADERP: All Conduit write APIs are currently vulnerable to CSRF!
<<<**
Test Plan:
- Ran some scripts that perform writes (scripts/search indexers), no issues.
- Performed normal CSRF submits.
- Added writes to an un-CSRF'd page, got an exception.
- Executed conduit methods.
- Did login/logout (this works because the logged-out user validates the
logged-out csrf "token").
- Did OAuth login.
- Did OAuth registration.
Reviewers: pedram, andrewjcg, erling, jungejason, tuomaspelkonen, aran,
codeblock
Commenters: pedram
CC: aran, epriestley, pedram
Differential Revision: 777
2011-08-03 20:49:27 +02:00
|
|
|
$allow_unguarded_writes = true;
|
2011-02-06 07:36:21 +01:00
|
|
|
}
|
|
|
|
|
2011-04-08 03:27:39 +02:00
|
|
|
if ($auth_error === null) {
|
Create AphrontWriteGuard, a backup mechanism for CSRF validation
Summary:
Provide a catchall mechanism to find unprotected writes.
- Depends on D758.
- Similar to WriteOnHTTPGet stuff from Facebook's stack.
- Since we have a small number of storage mechanisms and highly structured
read/write pathways, we can explicitly answer the question "is this page
performing a write?".
- Never allow writes without CSRF checks.
- This will probably break some things. That's fine: they're CSRF
vulnerabilities or weird edge cases that we can fix. But don't push to Facebook
for a few days unless you're prepared to deal with this.
- **>>> MEGADERP: All Conduit write APIs are currently vulnerable to CSRF!
<<<**
Test Plan:
- Ran some scripts that perform writes (scripts/search indexers), no issues.
- Performed normal CSRF submits.
- Added writes to an un-CSRF'd page, got an exception.
- Executed conduit methods.
- Did login/logout (this works because the logged-out user validates the
logged-out csrf "token").
- Did OAuth login.
- Did OAuth registration.
Reviewers: pedram, andrewjcg, erling, jungejason, tuomaspelkonen, aran,
codeblock
Commenters: pedram
CC: aran, epriestley, pedram
Differential Revision: 777
2011-08-03 20:49:27 +02:00
|
|
|
if ($allow_unguarded_writes) {
|
|
|
|
$unguarded = AphrontWriteGuard::beginScopedUnguardedWrites();
|
|
|
|
}
|
2011-11-08 00:11:25 +01:00
|
|
|
|
2011-02-06 07:36:21 +01:00
|
|
|
try {
|
Allow applications to call Conduit directly
Summary:
Sorry this took so long, had a bunch of stuff going on today.
Separate the actual core part of making conduit calls from the controller, so the application can make conduit calls without needing to invoke HTTP or redo auth. Generally, this lets us build more parts of the application on top of Conduit, as appropriate.
This diff can be simplified, but I wanted to unblock you guys first. I'll followup with a cleanup patch once I have a chance.
Test Plan: Ran unit tests, ran calls from the conduit API console, and ran calls over arc.
Reviewers: nodren, 20after4, btrahan, vrana
Reviewed By: 20after4
CC: aran, svemir
Maniphest Tasks: T945
Differential Revision: https://secure.phabricator.com/D2718
2012-06-17 17:47:09 +02:00
|
|
|
$result = $call->execute();
|
2011-02-06 07:36:21 +01:00
|
|
|
$error_code = null;
|
|
|
|
$error_info = null;
|
|
|
|
} catch (ConduitException $ex) {
|
|
|
|
$result = null;
|
|
|
|
$error_code = $ex->getMessage();
|
2011-12-21 16:51:50 +01:00
|
|
|
if ($ex->getErrorDescription()) {
|
|
|
|
$error_info = $ex->getErrorDescription();
|
|
|
|
} else {
|
Allow applications to call Conduit directly
Summary:
Sorry this took so long, had a bunch of stuff going on today.
Separate the actual core part of making conduit calls from the controller, so the application can make conduit calls without needing to invoke HTTP or redo auth. Generally, this lets us build more parts of the application on top of Conduit, as appropriate.
This diff can be simplified, but I wanted to unblock you guys first. I'll followup with a cleanup patch once I have a chance.
Test Plan: Ran unit tests, ran calls from the conduit API console, and ran calls over arc.
Reviewers: nodren, 20after4, btrahan, vrana
Reviewed By: 20after4
CC: aran, svemir
Maniphest Tasks: T945
Differential Revision: https://secure.phabricator.com/D2718
2012-06-17 17:47:09 +02:00
|
|
|
$error_info = $call->getErrorDescription($error_code);
|
2011-12-21 16:51:50 +01:00
|
|
|
}
|
2011-02-06 07:36:21 +01:00
|
|
|
}
|
Create AphrontWriteGuard, a backup mechanism for CSRF validation
Summary:
Provide a catchall mechanism to find unprotected writes.
- Depends on D758.
- Similar to WriteOnHTTPGet stuff from Facebook's stack.
- Since we have a small number of storage mechanisms and highly structured
read/write pathways, we can explicitly answer the question "is this page
performing a write?".
- Never allow writes without CSRF checks.
- This will probably break some things. That's fine: they're CSRF
vulnerabilities or weird edge cases that we can fix. But don't push to Facebook
for a few days unless you're prepared to deal with this.
- **>>> MEGADERP: All Conduit write APIs are currently vulnerable to CSRF!
<<<**
Test Plan:
- Ran some scripts that perform writes (scripts/search indexers), no issues.
- Performed normal CSRF submits.
- Added writes to an un-CSRF'd page, got an exception.
- Executed conduit methods.
- Did login/logout (this works because the logged-out user validates the
logged-out csrf "token").
- Did OAuth login.
- Did OAuth registration.
Reviewers: pedram, andrewjcg, erling, jungejason, tuomaspelkonen, aran,
codeblock
Commenters: pedram
CC: aran, epriestley, pedram
Differential Revision: 777
2011-08-03 20:49:27 +02:00
|
|
|
if ($allow_unguarded_writes) {
|
|
|
|
unset($unguarded);
|
|
|
|
}
|
2011-04-08 03:27:39 +02:00
|
|
|
} else {
|
|
|
|
list($error_code, $error_info) = $auth_error;
|
2011-01-24 18:00:29 +01:00
|
|
|
}
|
|
|
|
} catch (Exception $ex) {
|
2011-08-16 22:05:12 +02:00
|
|
|
phlog($ex);
|
2011-01-24 18:00:29 +01:00
|
|
|
$result = null;
|
2012-12-15 02:19:52 +01:00
|
|
|
$error_code = ($ex instanceof ConduitException
|
|
|
|
? 'ERR-CONDUIT-CALL'
|
|
|
|
: 'ERR-CONDUIT-CORE');
|
2011-01-24 18:00:29 +01:00
|
|
|
$error_info = $ex->getMessage();
|
|
|
|
}
|
|
|
|
|
|
|
|
$time_end = microtime(true);
|
|
|
|
|
|
|
|
$connection_id = null;
|
|
|
|
if (idx($metadata, 'connectionID')) {
|
|
|
|
$connection_id = $metadata['connectionID'];
|
|
|
|
} else if (($method == 'conduit.connect') && $result) {
|
|
|
|
$connection_id = idx($result, 'connectionID');
|
|
|
|
}
|
|
|
|
|
2013-07-01 21:37:34 +02:00
|
|
|
$log
|
|
|
|
->setCallerPHID(
|
|
|
|
isset($conduit_user)
|
|
|
|
? $conduit_user->getPHID()
|
|
|
|
: null)
|
|
|
|
->setConnectionID($connection_id)
|
|
|
|
->setError((string)$error_code)
|
|
|
|
->setDuration(1000000 * ($time_end - $time_start));
|
|
|
|
|
|
|
|
$unguarded = AphrontWriteGuard::beginScopedUnguardedWrites();
|
|
|
|
$log->save();
|
|
|
|
unset($unguarded);
|
2011-01-24 18:00:29 +01:00
|
|
|
|
2012-01-11 01:48:59 +01:00
|
|
|
$response = id(new ConduitAPIResponse())
|
|
|
|
->setResult($result)
|
|
|
|
->setErrorCode($error_code)
|
|
|
|
->setErrorInfo($error_info);
|
2011-01-24 18:00:29 +01:00
|
|
|
|
|
|
|
switch ($request->getStr('output')) {
|
|
|
|
case 'human':
|
|
|
|
return $this->buildHumanReadableResponse(
|
|
|
|
$method,
|
|
|
|
$api_request,
|
2012-01-11 01:48:59 +01:00
|
|
|
$response->toDictionary());
|
2011-01-24 18:00:29 +01:00
|
|
|
case 'json':
|
|
|
|
default:
|
2012-02-14 23:51:51 +01:00
|
|
|
return id(new AphrontJSONResponse())
|
2012-08-13 23:49:32 +02:00
|
|
|
->setAddJSONShield(false)
|
2012-02-14 23:51:51 +01:00
|
|
|
->setContent($response->toDictionary());
|
2011-01-24 18:00:29 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-11-08 00:11:25 +01:00
|
|
|
/**
|
|
|
|
* Change the api request user to the user that we want to act as.
|
|
|
|
* Only admins can use actAsUser
|
|
|
|
*
|
|
|
|
* @param ConduitAPIRequest Request being executed.
|
|
|
|
* @param string The username of the user we want to act as
|
|
|
|
*/
|
|
|
|
private function actAsUser(
|
|
|
|
ConduitAPIRequest $api_request,
|
|
|
|
$user_name) {
|
|
|
|
|
|
|
|
if (!$api_request->getUser()->getIsAdmin()) {
|
|
|
|
throw new Exception("Only administrators can use actAsUser");
|
|
|
|
}
|
|
|
|
|
|
|
|
$user = id(new PhabricatorUser())->loadOneWhere(
|
|
|
|
'userName = %s',
|
|
|
|
$user_name);
|
|
|
|
|
|
|
|
if (!$user) {
|
|
|
|
throw new Exception(
|
|
|
|
"The actAsUser username '{$user_name}' is not a valid user."
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
$api_request->setUser($user);
|
|
|
|
}
|
|
|
|
|
2011-04-08 03:27:39 +02:00
|
|
|
/**
|
|
|
|
* 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()) {
|
Create AphrontWriteGuard, a backup mechanism for CSRF validation
Summary:
Provide a catchall mechanism to find unprotected writes.
- Depends on D758.
- Similar to WriteOnHTTPGet stuff from Facebook's stack.
- Since we have a small number of storage mechanisms and highly structured
read/write pathways, we can explicitly answer the question "is this page
performing a write?".
- Never allow writes without CSRF checks.
- This will probably break some things. That's fine: they're CSRF
vulnerabilities or weird edge cases that we can fix. But don't push to Facebook
for a few days unless you're prepared to deal with this.
- **>>> MEGADERP: All Conduit write APIs are currently vulnerable to CSRF!
<<<**
Test Plan:
- Ran some scripts that perform writes (scripts/search indexers), no issues.
- Performed normal CSRF submits.
- Added writes to an un-CSRF'd page, got an exception.
- Executed conduit methods.
- Did login/logout (this works because the logged-out user validates the
logged-out csrf "token").
- Did OAuth login.
- Did OAuth registration.
Reviewers: pedram, andrewjcg, erling, jungejason, tuomaspelkonen, aran,
codeblock
Commenters: pedram
CC: aran, epriestley, pedram
Differential Revision: 777
2011-08-03 20:49:27 +02:00
|
|
|
$request->validateCSRF();
|
Allow installs to require email verification
Summary:
Allow installs to require users to verify email addresses before they can use Phabricator. If a user logs in without a verified email address, they're given instructions to verify their address.
This isn't too useful on its own since we don't actually have arbitrary email registration, but the next step is to allow installs to restrict email to only some domains (e.g., @mycompany.com).
Test Plan:
- Verification
- Set verification requirement to `true`.
- Tried to use Phabricator with an unverified account, was told to verify.
- Tried to use Conduit, was given a verification error.
- Verified account, used Phabricator.
- Unverified account, reset password, verified implicit verification, used Phabricator.
- People Admin Interface
- Viewed as admin. Clicked "Administrate User".
- Viewed as non-admin
- Sanity Checks
- Used Conduit normally from web/CLI with a verified account.
- Logged in/out.
- Sent password reset email.
- Created a new user.
- Logged in with an unverified user but with the configuration set to off.
Reviewers: btrahan, vrana, jungejason
Reviewed By: btrahan
CC: aran, csilvers
Maniphest Tasks: T1184
Differential Revision: https://secure.phabricator.com/D2520
2012-05-21 21:47:38 +02:00
|
|
|
return $this->validateAuthenticatedUser(
|
|
|
|
$api_request,
|
|
|
|
$request->getUser());
|
2011-04-08 03:27:39 +02:00
|
|
|
}
|
|
|
|
|
2012-02-19 23:23:30 +01:00
|
|
|
// handle oauth
|
|
|
|
$access_token = $request->getStr('access_token');
|
2012-02-21 23:28:05 +01:00
|
|
|
$method_scope = $metadata['scope'];
|
|
|
|
if ($access_token &&
|
|
|
|
$method_scope != PhabricatorOAuthServerScope::SCOPE_NOT_ACCESSIBLE) {
|
2012-02-19 23:23:30 +01:00
|
|
|
$token = id(new PhabricatorOAuthServerAccessToken())
|
|
|
|
->loadOneWhere('token = %s',
|
|
|
|
$access_token);
|
2012-02-21 23:28:05 +01:00
|
|
|
if (!$token) {
|
|
|
|
return array(
|
|
|
|
'ERR-INVALID-AUTH',
|
|
|
|
'Access token does not exist.',
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
$oauth_server = new PhabricatorOAuthServer();
|
|
|
|
$valid = $oauth_server->validateAccessToken($token,
|
|
|
|
$method_scope);
|
|
|
|
if (!$valid) {
|
|
|
|
return array(
|
|
|
|
'ERR-INVALID-AUTH',
|
|
|
|
'Access token is invalid.',
|
|
|
|
);
|
2012-02-19 23:23:30 +01:00
|
|
|
}
|
2012-02-21 23:28:05 +01:00
|
|
|
|
|
|
|
// valid token, so let's log in the user!
|
|
|
|
$user_phid = $token->getUserPHID();
|
|
|
|
$user = id(new PhabricatorUser())
|
|
|
|
->loadOneWhere('phid = %s',
|
|
|
|
$user_phid);
|
|
|
|
if (!$user) {
|
|
|
|
return array(
|
|
|
|
'ERR-INVALID-AUTH',
|
|
|
|
'Access token is for invalid user.',
|
|
|
|
);
|
|
|
|
}
|
Allow installs to require email verification
Summary:
Allow installs to require users to verify email addresses before they can use Phabricator. If a user logs in without a verified email address, they're given instructions to verify their address.
This isn't too useful on its own since we don't actually have arbitrary email registration, but the next step is to allow installs to restrict email to only some domains (e.g., @mycompany.com).
Test Plan:
- Verification
- Set verification requirement to `true`.
- Tried to use Phabricator with an unverified account, was told to verify.
- Tried to use Conduit, was given a verification error.
- Verified account, used Phabricator.
- Unverified account, reset password, verified implicit verification, used Phabricator.
- People Admin Interface
- Viewed as admin. Clicked "Administrate User".
- Viewed as non-admin
- Sanity Checks
- Used Conduit normally from web/CLI with a verified account.
- Logged in/out.
- Sent password reset email.
- Created a new user.
- Logged in with an unverified user but with the configuration set to off.
Reviewers: btrahan, vrana, jungejason
Reviewed By: btrahan
CC: aran, csilvers
Maniphest Tasks: T1184
Differential Revision: https://secure.phabricator.com/D2520
2012-05-21 21:47:38 +02:00
|
|
|
return $this->validateAuthenticatedUser(
|
|
|
|
$api_request,
|
|
|
|
$user);
|
2012-02-19 23:23:30 +01:00
|
|
|
}
|
|
|
|
|
2011-04-13 03:06:25 +02:00
|
|
|
// Handle sessionless auth. TOOD: This is super messy.
|
|
|
|
if (isset($metadata['authUser'])) {
|
|
|
|
$user = id(new PhabricatorUser())->loadOneWhere(
|
|
|
|
'userName = %s',
|
|
|
|
$metadata['authUser']);
|
|
|
|
if (!$user) {
|
|
|
|
return array(
|
|
|
|
'ERR-INVALID-AUTH',
|
|
|
|
'Authentication is invalid.',
|
|
|
|
);
|
|
|
|
}
|
|
|
|
$token = idx($metadata, 'authToken');
|
|
|
|
$signature = idx($metadata, 'authSignature');
|
|
|
|
$certificate = $user->getConduitCertificate();
|
|
|
|
if (sha1($token.$certificate) !== $signature) {
|
|
|
|
return array(
|
|
|
|
'ERR-INVALID-AUTH',
|
|
|
|
'Authentication is invalid.',
|
|
|
|
);
|
|
|
|
}
|
Allow installs to require email verification
Summary:
Allow installs to require users to verify email addresses before they can use Phabricator. If a user logs in without a verified email address, they're given instructions to verify their address.
This isn't too useful on its own since we don't actually have arbitrary email registration, but the next step is to allow installs to restrict email to only some domains (e.g., @mycompany.com).
Test Plan:
- Verification
- Set verification requirement to `true`.
- Tried to use Phabricator with an unverified account, was told to verify.
- Tried to use Conduit, was given a verification error.
- Verified account, used Phabricator.
- Unverified account, reset password, verified implicit verification, used Phabricator.
- People Admin Interface
- Viewed as admin. Clicked "Administrate User".
- Viewed as non-admin
- Sanity Checks
- Used Conduit normally from web/CLI with a verified account.
- Logged in/out.
- Sent password reset email.
- Created a new user.
- Logged in with an unverified user but with the configuration set to off.
Reviewers: btrahan, vrana, jungejason
Reviewed By: btrahan
CC: aran, csilvers
Maniphest Tasks: T1184
Differential Revision: https://secure.phabricator.com/D2520
2012-05-21 21:47:38 +02:00
|
|
|
return $this->validateAuthenticatedUser(
|
|
|
|
$api_request,
|
|
|
|
$user);
|
2011-04-13 03:06:25 +02:00
|
|
|
}
|
|
|
|
|
2011-04-08 03:27:39 +02:00
|
|
|
$session_key = idx($metadata, 'sessionKey');
|
|
|
|
if (!$session_key) {
|
|
|
|
return array(
|
2011-04-10 22:08:47 +02:00
|
|
|
'ERR-INVALID-SESSION',
|
|
|
|
'Session key is not present.'
|
2011-04-08 03:27:39 +02:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
$session = queryfx_one(
|
|
|
|
id(new PhabricatorUser())->establishConnection('r'),
|
|
|
|
'SELECT * FROM %T WHERE sessionKey = %s',
|
|
|
|
PhabricatorUser::SESSION_TABLE,
|
2013-05-31 02:30:06 +02:00
|
|
|
PhabricatorHash::digest($session_key));
|
2011-04-08 03:27:39 +02:00
|
|
|
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.',
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
Allow installs to require email verification
Summary:
Allow installs to require users to verify email addresses before they can use Phabricator. If a user logs in without a verified email address, they're given instructions to verify their address.
This isn't too useful on its own since we don't actually have arbitrary email registration, but the next step is to allow installs to restrict email to only some domains (e.g., @mycompany.com).
Test Plan:
- Verification
- Set verification requirement to `true`.
- Tried to use Phabricator with an unverified account, was told to verify.
- Tried to use Conduit, was given a verification error.
- Verified account, used Phabricator.
- Unverified account, reset password, verified implicit verification, used Phabricator.
- People Admin Interface
- Viewed as admin. Clicked "Administrate User".
- Viewed as non-admin
- Sanity Checks
- Used Conduit normally from web/CLI with a verified account.
- Logged in/out.
- Sent password reset email.
- Created a new user.
- Logged in with an unverified user but with the configuration set to off.
Reviewers: btrahan, vrana, jungejason
Reviewed By: btrahan
CC: aran, csilvers
Maniphest Tasks: T1184
Differential Revision: https://secure.phabricator.com/D2520
2012-05-21 21:47:38 +02:00
|
|
|
return $this->validateAuthenticatedUser(
|
|
|
|
$api_request,
|
|
|
|
$user);
|
|
|
|
}
|
|
|
|
|
|
|
|
private function validateAuthenticatedUser(
|
|
|
|
ConduitAPIRequest $request,
|
|
|
|
PhabricatorUser $user) {
|
|
|
|
|
|
|
|
if ($user->getIsDisabled()) {
|
|
|
|
return array(
|
|
|
|
'ERR-USER-DISABLED',
|
|
|
|
'User is disabled.');
|
|
|
|
}
|
|
|
|
|
Allow restriction of permitted email domains
Summary:
Allow allowed email addresses to be restricted to certain domains. This implies email must be verified.
This probably isn't QUITE ready for prime-time without a few other tweaks (better administrative tools, notably) but we're nearly there.
Test Plan:
- With no restrictions:
- Registered with OAuth
- Created an account with accountadmin
- Added an email
- With restrictions:
- Tried to OAuth register with a restricted address, was prompted to provide a valid one.
- Tried to OAuth register with a valid address, worked fine.
- Tried to accountadmin a restricted address, got blocked.
- Tried to accountadmin a valid address, worked fine.
- Tried to add a restricted address, blocked.
- Tried to add a valid address, worked fine.
- Created a user with People with an invalid address, got blocked.
- Created a user with People with a valid address, worked fine.
Reviewers: btrahan, csilvers
Reviewed By: csilvers
CC: aran, joe, csilvers
Maniphest Tasks: T1184
Differential Revision: https://secure.phabricator.com/D2581
2012-05-26 15:04:35 +02:00
|
|
|
if (PhabricatorUserEmail::isEmailVerificationRequired()) {
|
Allow installs to require email verification
Summary:
Allow installs to require users to verify email addresses before they can use Phabricator. If a user logs in without a verified email address, they're given instructions to verify their address.
This isn't too useful on its own since we don't actually have arbitrary email registration, but the next step is to allow installs to restrict email to only some domains (e.g., @mycompany.com).
Test Plan:
- Verification
- Set verification requirement to `true`.
- Tried to use Phabricator with an unverified account, was told to verify.
- Tried to use Conduit, was given a verification error.
- Verified account, used Phabricator.
- Unverified account, reset password, verified implicit verification, used Phabricator.
- People Admin Interface
- Viewed as admin. Clicked "Administrate User".
- Viewed as non-admin
- Sanity Checks
- Used Conduit normally from web/CLI with a verified account.
- Logged in/out.
- Sent password reset email.
- Created a new user.
- Logged in with an unverified user but with the configuration set to off.
Reviewers: btrahan, vrana, jungejason
Reviewed By: btrahan
CC: aran, csilvers
Maniphest Tasks: T1184
Differential Revision: https://secure.phabricator.com/D2520
2012-05-21 21:47:38 +02:00
|
|
|
$email = $user->loadPrimaryEmail();
|
|
|
|
if (!$email) {
|
|
|
|
return array(
|
|
|
|
'ERR-USER-NOEMAIL',
|
|
|
|
'User has no primary email address.');
|
|
|
|
}
|
|
|
|
if (!$email->getIsVerified()) {
|
|
|
|
return array(
|
|
|
|
'ERR-USER-UNVERIFIED',
|
|
|
|
'User has unverified email address.');
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
$request->setUser($user);
|
2011-04-08 03:27:39 +02:00
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
2011-01-24 18:00:29 +01:00
|
|
|
private function buildHumanReadableResponse(
|
|
|
|
$method,
|
|
|
|
ConduitAPIRequest $request = null,
|
|
|
|
$result = null) {
|
|
|
|
|
|
|
|
$param_rows = array();
|
2011-07-29 06:32:11 +02:00
|
|
|
$param_rows[] = array('Method', $this->renderAPIValue($method));
|
2011-01-24 18:00:29 +01:00
|
|
|
if ($request) {
|
|
|
|
foreach ($request->getAllParameters() as $key => $value) {
|
|
|
|
$param_rows[] = array(
|
2013-02-13 23:50:15 +01:00
|
|
|
$key,
|
2011-07-29 06:32:11 +02:00
|
|
|
$this->renderAPIValue($value),
|
2011-01-24 18:00:29 +01:00
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
$param_table = new AphrontTableView($param_rows);
|
2013-07-01 21:36:34 +02:00
|
|
|
$param_table->setDeviceReadyTable(true);
|
2011-01-24 18:00:29 +01:00
|
|
|
$param_table->setColumnClasses(
|
|
|
|
array(
|
|
|
|
'header',
|
|
|
|
'wide',
|
|
|
|
));
|
|
|
|
|
|
|
|
$result_rows = array();
|
|
|
|
foreach ($result as $key => $value) {
|
|
|
|
$result_rows[] = array(
|
2013-02-13 23:50:15 +01:00
|
|
|
$key,
|
2011-07-29 06:32:11 +02:00
|
|
|
$this->renderAPIValue($value),
|
2011-01-24 18:00:29 +01:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
$result_table = new AphrontTableView($result_rows);
|
2013-07-01 21:36:34 +02:00
|
|
|
$result_table->setDeviceReadyTable(true);
|
2011-01-24 18:00:29 +01:00
|
|
|
$result_table->setColumnClasses(
|
|
|
|
array(
|
|
|
|
'header',
|
|
|
|
'wide',
|
|
|
|
));
|
|
|
|
|
|
|
|
$param_panel = new AphrontPanelView();
|
|
|
|
$param_panel->setHeader('Method Parameters');
|
|
|
|
$param_panel->appendChild($param_table);
|
|
|
|
|
|
|
|
$result_panel = new AphrontPanelView();
|
|
|
|
$result_panel->setHeader('Method Result');
|
|
|
|
$result_panel->appendChild($result_table);
|
|
|
|
|
2013-07-01 21:36:34 +02:00
|
|
|
$param_head = id(new PhabricatorHeaderView())
|
|
|
|
->setHeader(pht('Method Parameters'));
|
|
|
|
|
|
|
|
$result_head = id(new PhabricatorHeaderView())
|
|
|
|
->setHeader(pht('Method Result'));
|
|
|
|
|
|
|
|
$method_uri = $this->getApplicationURI('method/'.$method.'/');
|
|
|
|
|
|
|
|
$crumbs = $this->buildApplicationCrumbs();
|
|
|
|
$crumbs
|
|
|
|
->addCrumb(
|
|
|
|
id(new PhabricatorCrumbView())
|
|
|
|
->setName($method)
|
|
|
|
->setHref($method_uri))
|
|
|
|
->addCrumb(
|
|
|
|
id(new PhabricatorCrumbView())
|
|
|
|
->setName(pht('Call')));
|
|
|
|
|
|
|
|
return $this->buildApplicationPage(
|
2011-01-24 18:00:29 +01:00
|
|
|
array(
|
2013-07-01 21:36:34 +02:00
|
|
|
$crumbs,
|
|
|
|
$param_head,
|
|
|
|
$param_table,
|
|
|
|
$result_head,
|
|
|
|
$result_table,
|
2011-01-24 18:00:29 +01:00
|
|
|
),
|
|
|
|
array(
|
|
|
|
'title' => 'Method Call Result',
|
2013-07-01 21:36:34 +02:00
|
|
|
'device' => true,
|
2011-01-24 18:00:29 +01:00
|
|
|
));
|
|
|
|
}
|
|
|
|
|
2011-07-29 06:32:11 +02:00
|
|
|
private function renderAPIValue($value) {
|
|
|
|
$json = new PhutilJSON();
|
|
|
|
if (is_array($value)) {
|
|
|
|
$value = $json->encodeFormatted($value);
|
|
|
|
}
|
|
|
|
|
2013-02-05 21:49:46 +01:00
|
|
|
$value = hsprintf('<pre style="white-space: pre-wrap;">%s</pre>', $value);
|
2011-07-29 06:32:11 +02:00
|
|
|
|
|
|
|
return $value;
|
|
|
|
}
|
|
|
|
|
2012-10-04 18:30:32 +02:00
|
|
|
private function decodeConduitParams(
|
|
|
|
AphrontRequest $request,
|
|
|
|
$method) {
|
Allow applications to call Conduit directly
Summary:
Sorry this took so long, had a bunch of stuff going on today.
Separate the actual core part of making conduit calls from the controller, so the application can make conduit calls without needing to invoke HTTP or redo auth. Generally, this lets us build more parts of the application on top of Conduit, as appropriate.
This diff can be simplified, but I wanted to unblock you guys first. I'll followup with a cleanup patch once I have a chance.
Test Plan: Ran unit tests, ran calls from the conduit API console, and ran calls over arc.
Reviewers: nodren, 20after4, btrahan, vrana
Reviewed By: 20after4
CC: aran, svemir
Maniphest Tasks: T945
Differential Revision: https://secure.phabricator.com/D2718
2012-06-17 17:47:09 +02:00
|
|
|
|
|
|
|
// Look for parameters from the Conduit API Console, which are encoded
|
|
|
|
// as HTTP POST parameters in an array, e.g.:
|
|
|
|
//
|
|
|
|
// params[name]=value¶ms[name2]=value2
|
|
|
|
//
|
|
|
|
// The fields are individually JSON encoded, since we require users to
|
|
|
|
// enter JSON so that we avoid type ambiguity.
|
|
|
|
|
|
|
|
$params = $request->getArr('params', null);
|
|
|
|
if ($params !== null) {
|
|
|
|
foreach ($params as $key => $value) {
|
|
|
|
if ($value == '') {
|
|
|
|
// Interpret empty string null (e.g., the user didn't type anything
|
|
|
|
// into the box).
|
|
|
|
$value = 'null';
|
|
|
|
}
|
|
|
|
$decoded_value = json_decode($value, true);
|
|
|
|
if ($decoded_value === null && strtolower($value) != 'null') {
|
|
|
|
// When json_decode() fails, it returns null. This almost certainly
|
|
|
|
// indicates that a user was using the web UI and didn't put quotes
|
|
|
|
// around a string value. We can either do what we think they meant
|
|
|
|
// (treat it as a string) or fail. For now, err on the side of
|
|
|
|
// caution and fail. In the future, if we make the Conduit API
|
|
|
|
// actually do type checking, it might be reasonable to treat it as
|
|
|
|
// a string if the parameter type is string.
|
|
|
|
throw new Exception(
|
|
|
|
"The value for parameter '{$key}' is not valid JSON. All ".
|
|
|
|
"parameters must be encoded as JSON values, including strings ".
|
|
|
|
"(which means you need to surround them in double quotes). ".
|
|
|
|
"Check your syntax. Value was: {$value}");
|
|
|
|
}
|
|
|
|
$params[$key] = $decoded_value;
|
|
|
|
}
|
|
|
|
|
|
|
|
return $params;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Otherwise, look for a single parameter called 'params' which has the
|
|
|
|
// entire param dictionary JSON encoded. This is the usual case for remote
|
|
|
|
// requests.
|
|
|
|
|
|
|
|
$params_json = $request->getStr('params');
|
|
|
|
if (!strlen($params_json)) {
|
Detect missing 'params' in Conduit calls
Summary:
Suhosin has about 50 options for filtering input variables, doucmented here:
http://www.hardened-php.net/suhosin/configuration.html
The default behavior of Suhosin is to drop the variable entirely if it violates any of the rules, then continue with the request. It doesn't affect 'php://input' and doesn't drop other variables, so it evades existing detection, and we can't figure out that it's happened at runtime. We could add blanket checks (Suhosin enabled + suhosin.filter.action set to nothing means this may happen, and will be undetectable if it does happen) but can't tailor a check or recovery to this specific problem.
Instead, raise a better error in the specific case where we encounter this, which is Conduit calls of "arc diff" of files over 1MB (the default POST limit). In these cases, Suhosin drops the variable entirely. If there is no 'params', scream. We never encounter this case normall (`arc`, including `arc call-conduit`, always sends this parameter) although other clients might omit it. The only exception is the web console with `conduit.ping`, which submits nothing; make it submit something so it keeps working.
See also https://github.com/facebook/phabricator/issues/233#issuecomment-11186074
Test Plan: Brought up a Debian + Suhosin box, verified the behavior of Suhosin, made requests with and without 'params'.
Reviewers: btrahan, vrana
Reviewed By: btrahan
CC: aran
Differential Revision: https://secure.phabricator.com/D4144
2012-12-11 23:01:18 +01:00
|
|
|
if ($request->getBool('allowEmptyParams')) {
|
|
|
|
// TODO: This is a bit messy, but otherwise you can't call
|
|
|
|
// "conduit.ping" from the web console.
|
|
|
|
$params = array();
|
|
|
|
} else {
|
|
|
|
throw new Exception(
|
|
|
|
"Request has no 'params' key. This may mean that an extension like ".
|
|
|
|
"Suhosin has dropped data from the request. Check the PHP ".
|
|
|
|
"configuration on your server. If you are developing a Conduit ".
|
|
|
|
"client, you MUST provide a 'params' parameter when making a ".
|
|
|
|
"Conduit request, even if the value is empty (e.g., provide '{}').");
|
|
|
|
}
|
Allow applications to call Conduit directly
Summary:
Sorry this took so long, had a bunch of stuff going on today.
Separate the actual core part of making conduit calls from the controller, so the application can make conduit calls without needing to invoke HTTP or redo auth. Generally, this lets us build more parts of the application on top of Conduit, as appropriate.
This diff can be simplified, but I wanted to unblock you guys first. I'll followup with a cleanup patch once I have a chance.
Test Plan: Ran unit tests, ran calls from the conduit API console, and ran calls over arc.
Reviewers: nodren, 20after4, btrahan, vrana
Reviewed By: 20after4
CC: aran, svemir
Maniphest Tasks: T945
Differential Revision: https://secure.phabricator.com/D2718
2012-06-17 17:47:09 +02:00
|
|
|
} else {
|
|
|
|
$params = json_decode($params_json, true);
|
|
|
|
if (!is_array($params)) {
|
|
|
|
throw new Exception(
|
|
|
|
"Invalid parameter information was passed to method ".
|
2012-10-04 18:30:32 +02:00
|
|
|
"'{$method}', could not decode JSON serialization. Data: ".
|
|
|
|
$params_json);
|
Allow applications to call Conduit directly
Summary:
Sorry this took so long, had a bunch of stuff going on today.
Separate the actual core part of making conduit calls from the controller, so the application can make conduit calls without needing to invoke HTTP or redo auth. Generally, this lets us build more parts of the application on top of Conduit, as appropriate.
This diff can be simplified, but I wanted to unblock you guys first. I'll followup with a cleanup patch once I have a chance.
Test Plan: Ran unit tests, ran calls from the conduit API console, and ran calls over arc.
Reviewers: nodren, 20after4, btrahan, vrana
Reviewed By: 20after4
CC: aran, svemir
Maniphest Tasks: T945
Differential Revision: https://secure.phabricator.com/D2718
2012-06-17 17:47:09 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return $params;
|
|
|
|
}
|
2011-01-24 18:00:29 +01:00
|
|
|
}
|