2011-01-24 18:00:29 +01:00
|
|
|
<?php
|
|
|
|
|
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) {
|
2014-07-25 03:24:31 +02:00
|
|
|
if (!($ex instanceof ConduitMethodNotFoundException)) {
|
|
|
|
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) {
|
|
|
|
|
Security - disable conduit act as user by default
Summary: Introduce a new configuration setting that by default disables the conduit as as user method. Wordily explain that turning it on is not recommended. Fixes T3818.
Test Plan:
```
15:25:19 ~/Dropbox/code/phalanx/src/applications/conduit (T3818)
~> echo '{}' | arc call-conduit --conduit-uri http://phalanx.dev/ user.whoami
Waiting for JSON parameters on stdin...
{"error":null,"errorMessage":null,"response":{"phid":"PHID-USER-tghb3b2gbdyezdcuw2or","userName":"btrahan","realName":"Bob Trahan","image":"http:\/\/phalanx.dev\/file\/data\/yncjbh7phk7ktrdhuorn\/PHID-FILE-qyf4ui3x2ll3e52hpg5e\/profile-profile-gravatar","uri":"http:\/\/phalanx.dev\/p\/btrahan\/","roles":["admin","verified","approved","activated"]}}
15:25:34 ~/Dropbox/code/phalanx/src/applications/conduit (T3818)
<go edit libconfig/conduitclient to spoof another user...>
~> echo '{}' | arc call-conduit --conduit-uri http://phalanx.dev/ user.whoami
Waiting for JSON parameters on stdin...
{"error":"ERR-CONDUIT-CORE","errorMessage":"ERR-CONDUIT-CORE: security.allow-conduit-act-as-user is disabled","response":null}
15:26:40 ~/Dropbox/code/phalanx/src/applications/conduit (T3818)
<enable option via bin/config....>
~> echo '{}' | arc call-conduit --conduit-uri http://phalanx.dev/ user.whoami
Waiting for JSON parameters on stdin...
{"error":null,"errorMessage":null,"response":{"phid":"PHID-USER-6lcglnzbkiamdofishgi","userName":"xerxes","realName":"Xerxes Trahan","image":"http:\/\/phalanx.dev\/file\/data\/n2kyeevowetcuynbcxrg\/PHID-FILE-voquikectzpde256zzvm\/profile-1275455993.jpg","uri":"http:\/\/phalanx.dev\/p\/xerxes\/","roles":["verified","approved","activated"]}}
```
Reviewers: epriestley
Reviewed By: epriestley
Subscribers: jevripio, sowedance, epriestley, Korvin
Maniphest Tasks: T3818
Differential Revision: https://secure.phabricator.com/D9881
2014-07-11 00:43:53 +02:00
|
|
|
$config_key = 'security.allow-conduit-act-as-user';
|
|
|
|
if (!PhabricatorEnv::getEnvConfig($config_key)) {
|
|
|
|
throw new Exception('security.allow-conduit-act-as-user is disabled');
|
|
|
|
}
|
|
|
|
|
2011-11-08 00:11:25 +01:00
|
|
|
if (!$api_request->getUser()->getIsAdmin()) {
|
2014-06-09 20:36:49 +02:00
|
|
|
throw new Exception('Only administrators can use actAsUser');
|
2011-11-08 00:11:25 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
$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
|
|
|
}
|
|
|
|
|
2014-11-17 22:11:52 +01:00
|
|
|
$auth_type = idx($metadata, 'auth.type');
|
|
|
|
if ($auth_type === ConduitClient::AUTH_ASYMMETRIC) {
|
|
|
|
$host = idx($metadata, 'auth.host');
|
|
|
|
if (!$host) {
|
|
|
|
return array(
|
|
|
|
'ERR-INVALID-AUTH',
|
|
|
|
pht(
|
|
|
|
'Request is missing required "auth.host" parameter.'),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO: Validate that we are the host!
|
|
|
|
|
|
|
|
$raw_key = idx($metadata, 'auth.key');
|
|
|
|
$public_key = PhabricatorAuthSSHPublicKey::newFromRawKey($raw_key);
|
|
|
|
$ssl_public_key = $public_key->toPCKS8();
|
|
|
|
|
|
|
|
// First, verify the signature.
|
|
|
|
try {
|
|
|
|
$protocol_data = $metadata;
|
|
|
|
|
|
|
|
// TODO: We should stop writing this into the protocol data when
|
|
|
|
// processing a request.
|
|
|
|
unset($protocol_data['scope']);
|
|
|
|
|
|
|
|
ConduitClient::verifySignature(
|
|
|
|
$this->method,
|
|
|
|
$api_request->getAllParameters(),
|
|
|
|
$protocol_data,
|
|
|
|
$ssl_public_key);
|
|
|
|
} catch (Exception $ex) {
|
|
|
|
return array(
|
|
|
|
'ERR-INVALID-AUTH',
|
|
|
|
pht(
|
|
|
|
'Signature verification failure. %s',
|
|
|
|
$ex->getMessage()),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
// If the signature is valid, find the user or device which is
|
|
|
|
// associated with this public key.
|
|
|
|
|
|
|
|
$stored_key = id(new PhabricatorAuthSSHKeyQuery())
|
|
|
|
->setViewer(PhabricatorUser::getOmnipotentUser())
|
|
|
|
->withKeys(array($public_key))
|
|
|
|
->executeOne();
|
|
|
|
if (!$stored_key) {
|
|
|
|
return array(
|
|
|
|
'ERR-INVALID-AUTH',
|
|
|
|
pht(
|
|
|
|
'No user or device is associated with that public key.'),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
$object = $stored_key->getObject();
|
|
|
|
|
|
|
|
if ($object instanceof PhabricatorUser) {
|
|
|
|
$user = $object;
|
|
|
|
} else {
|
|
|
|
throw new Exception(
|
|
|
|
pht('Not Implemented: Would authenticate Almanac device.'));
|
|
|
|
}
|
|
|
|
|
|
|
|
return $this->validateAuthenticatedUser(
|
|
|
|
$api_request,
|
|
|
|
$user);
|
|
|
|
} else if ($auth_type === null) {
|
|
|
|
// No specified authentication type, continue with other authentication
|
|
|
|
// methods below.
|
|
|
|
} else {
|
|
|
|
return array(
|
|
|
|
'ERR-INVALID-AUTH',
|
|
|
|
pht(
|
|
|
|
'Provided "auth.type" ("%s") is not recognized.',
|
|
|
|
$auth_type),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
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',
|
2014-10-07 15:01:04 +02:00
|
|
|
'Session key is not present.',
|
2011-04-08 03:27:39 +02:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2014-01-14 22:22:27 +01:00
|
|
|
$user = id(new PhabricatorAuthSessionEngine())
|
2014-01-14 22:22:34 +01:00
|
|
|
->loadUserForSession(PhabricatorAuthSession::TYPE_CONDUIT, $session_key);
|
2011-04-08 03:27:39 +02:00
|
|
|
|
|
|
|
if (!$user) {
|
|
|
|
return array(
|
|
|
|
'ERR-INVALID-SESSION',
|
2014-01-14 22:22:27 +01:00
|
|
|
'Session key is invalid.',
|
2011-04-08 03:27:39 +02:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
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) {
|
|
|
|
|
Improve handling of email verification and "activated" accounts
Summary:
Small step forward which improves existing stuff or lays groudwork for future stuff:
- Currently, to check for email verification, we have to single-query the email address on every page. Instead, denoramlize it into the user object.
- Migrate all the existing users.
- When the user verifies an email, mark them as `isEmailVerified` if the email is their primary email.
- Just make the checks look at the `isEmailVerified` field.
- Add a new check, `isUserActivated()`, to cover email-verified plus disabled. Currently, a non-verified-but-not-disabled user could theoretically use Conduit over SSH, if anyone deployed it. Tighten that up.
- Add an `isApproved` flag, which is always true for now. In a future diff, I want to add a default-on admin approval queue for new accounts, to prevent configuration mistakes. The way it will work is:
- When the queue is enabled, registering users are created with `isApproved = false`.
- Admins are sent an email, "[Phabricator] New User Approval (alincoln)", telling them that a new user is waiting for approval.
- They go to the web UI and approve the user.
- Manually-created accounts are auto-approved.
- The email will have instructions for disabling the queue.
I think this queue will be helpful for new installs and give them peace of mind, and when you go to disable it we have a better opportunity to warn you about exactly what that means.
Generally, I want to improve the default safety of registration, since if you just blindly coast through the path of least resistance right now your install ends up pretty open, and realistically few installs are on VPNs.
Test Plan:
- Ran migration, verified `isEmailVerified` populated correctly.
- Created a new user, checked DB for verified (not verified).
- Verified, checked DB (now verified).
- Used Conduit, People, Diffusion.
Reviewers: btrahan
Reviewed By: btrahan
CC: chad, aran
Differential Revision: https://secure.phabricator.com/D7572
2013-11-12 23:37:04 +01:00
|
|
|
if (!$user->isUserActivated()) {
|
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 array(
|
|
|
|
'ERR-USER-DISABLED',
|
Improve handling of email verification and "activated" accounts
Summary:
Small step forward which improves existing stuff or lays groudwork for future stuff:
- Currently, to check for email verification, we have to single-query the email address on every page. Instead, denoramlize it into the user object.
- Migrate all the existing users.
- When the user verifies an email, mark them as `isEmailVerified` if the email is their primary email.
- Just make the checks look at the `isEmailVerified` field.
- Add a new check, `isUserActivated()`, to cover email-verified plus disabled. Currently, a non-verified-but-not-disabled user could theoretically use Conduit over SSH, if anyone deployed it. Tighten that up.
- Add an `isApproved` flag, which is always true for now. In a future diff, I want to add a default-on admin approval queue for new accounts, to prevent configuration mistakes. The way it will work is:
- When the queue is enabled, registering users are created with `isApproved = false`.
- Admins are sent an email, "[Phabricator] New User Approval (alincoln)", telling them that a new user is waiting for approval.
- They go to the web UI and approve the user.
- Manually-created accounts are auto-approved.
- The email will have instructions for disabling the queue.
I think this queue will be helpful for new installs and give them peace of mind, and when you go to disable it we have a better opportunity to warn you about exactly what that means.
Generally, I want to improve the default safety of registration, since if you just blindly coast through the path of least resistance right now your install ends up pretty open, and realistically few installs are on VPNs.
Test Plan:
- Ran migration, verified `isEmailVerified` populated correctly.
- Created a new user, checked DB for verified (not verified).
- Verified, checked DB (now verified).
- Used Conduit, People, Diffusion.
Reviewers: btrahan
Reviewed By: btrahan
CC: chad, aran
Differential Revision: https://secure.phabricator.com/D7572
2013-11-12 23:37:04 +01:00
|
|
|
pht('User account is not activated.'),
|
|
|
|
);
|
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
|
|
|
}
|
|
|
|
|
|
|
|
$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-09-17 18:12:37 +02:00
|
|
|
$param_head = id(new PHUIHeaderView())
|
2013-07-01 21:36:34 +02:00
|
|
|
->setHeader(pht('Method Parameters'));
|
|
|
|
|
2013-09-17 18:12:37 +02:00
|
|
|
$result_head = id(new PHUIHeaderView())
|
2013-07-01 21:36:34 +02:00
|
|
|
->setHeader(pht('Method Result'));
|
|
|
|
|
|
|
|
$method_uri = $this->getApplicationURI('method/'.$method.'/');
|
|
|
|
|
2013-12-19 02:47:34 +01:00
|
|
|
$crumbs = $this->buildApplicationCrumbs()
|
|
|
|
->addTextCrumb($method, $method_uri)
|
|
|
|
->addTextCrumb(pht('Call'));
|
2013-07-01 21:36:34 +02:00
|
|
|
|
|
|
|
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',
|
|
|
|
));
|
|
|
|
}
|
|
|
|
|
2011-07-29 06:32:11 +02:00
|
|
|
private function renderAPIValue($value) {
|
|
|
|
$json = new PhutilJSON();
|
|
|
|
if (is_array($value)) {
|
|
|
|
$value = $json->encodeFormatted($value);
|
|
|
|
}
|
|
|
|
|
2013-11-11 18:23:23 +01:00
|
|
|
$value = phutil_tag(
|
|
|
|
'pre',
|
|
|
|
array('style' => 'white-space: pre-wrap;'),
|
|
|
|
$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;
|
|
|
|
}
|
2014-07-10 00:12:48 +02:00
|
|
|
|
2011-01-24 18:00:29 +01:00
|
|
|
}
|