Allow OAuth applications to be disabled instead of destroyed
Summary: Ref T7303. This interaction is very oldschool; modernize it to enable/disable instead of "nuke from orbit". Test Plan: - Enabled applications. - Disabled applications. - Viewed applications in list view. - Generated new tokens. - Tried to use a token from a disabled application (got rebuffed). - Tried to use a token from an enabled application (worked fine). Reviewers: chad Reviewed By: chad Maniphest Tasks: T7303 Differential Revision: https://secure.phabricator.com/D15620
This commit is contained in:
@@ -62,6 +62,15 @@ final class PhabricatorOAuthServerAuthController
|
||||
phutil_tag('strong', array(), 'client_id')));
|
||||
}
|
||||
|
||||
if ($client->getIsDisabled()) {
|
||||
return $this->buildErrorResponse(
|
||||
'invalid_request',
|
||||
pht('Application Disabled'),
|
||||
pht(
|
||||
'The %s OAuth application has been disabled.',
|
||||
phutil_tag('strong', array(), 'client_id')));
|
||||
}
|
||||
|
||||
$name = $client->getName();
|
||||
$server->setClient($client);
|
||||
if ($redirect_uri) {
|
||||
|
||||
@@ -67,7 +67,7 @@ final class PhabricatorOAuthServerTokenController
|
||||
$response->setError('invalid_grant');
|
||||
$response->setErrorDescription(
|
||||
pht(
|
||||
'Authorization code %d not found.',
|
||||
'Authorization code %s not found.',
|
||||
$code));
|
||||
return $response;
|
||||
}
|
||||
@@ -102,11 +102,22 @@ final class PhabricatorOAuthServerTokenController
|
||||
$response->setError('invalid_client');
|
||||
$response->setErrorDescription(
|
||||
pht(
|
||||
'Client with %s %d not found.',
|
||||
'Client with %s %s not found.',
|
||||
'client_id',
|
||||
$client_phid));
|
||||
return $response;
|
||||
}
|
||||
|
||||
if ($client->getIsDisabled()) {
|
||||
$response->setError('invalid_client');
|
||||
$response->setErrorDescription(
|
||||
pht(
|
||||
'OAuth application "%s" has been disabled.',
|
||||
$client->getName()));
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
$server->setClient($client);
|
||||
|
||||
$user_phid = $auth_code->getUserPHID();
|
||||
@@ -116,7 +127,7 @@ final class PhabricatorOAuthServerTokenController
|
||||
$response->setError('invalid_grant');
|
||||
$response->setErrorDescription(
|
||||
pht(
|
||||
'User with PHID %d not found.',
|
||||
'User with PHID %s not found.',
|
||||
$user_phid));
|
||||
return $response;
|
||||
}
|
||||
@@ -132,7 +143,7 @@ final class PhabricatorOAuthServerTokenController
|
||||
$response->setError('invalid_grant');
|
||||
$response->setErrorDescription(
|
||||
pht(
|
||||
'Invalid authorization code %d.',
|
||||
'Invalid authorization code %s.',
|
||||
$code));
|
||||
return $response;
|
||||
}
|
||||
|
||||
@@ -1,40 +0,0 @@
|
||||
<?php
|
||||
|
||||
final class PhabricatorOAuthClientDeleteController
|
||||
extends PhabricatorOAuthClientController {
|
||||
|
||||
public function handleRequest(AphrontRequest $request) {
|
||||
$viewer = $this->getViewer();
|
||||
|
||||
$client = id(new PhabricatorOAuthServerClientQuery())
|
||||
->setViewer($viewer)
|
||||
->withIDs(array($request->getURIData('id')))
|
||||
->requireCapabilities(
|
||||
array(
|
||||
PhabricatorPolicyCapability::CAN_VIEW,
|
||||
PhabricatorPolicyCapability::CAN_EDIT,
|
||||
))
|
||||
->executeOne();
|
||||
if (!$client) {
|
||||
return new Aphront404Response();
|
||||
}
|
||||
|
||||
// TODO: This should be "disable", not "delete"!
|
||||
|
||||
if ($request->isFormPost()) {
|
||||
$client->delete();
|
||||
$app_uri = $this->getApplicationURI();
|
||||
return id(new AphrontRedirectResponse())->setURI($app_uri);
|
||||
}
|
||||
|
||||
return $this->newDialog()
|
||||
->setTitle(pht('Delete OAuth Application?'))
|
||||
->appendParagraph(
|
||||
pht(
|
||||
'Really delete the OAuth application %s?',
|
||||
phutil_tag('strong', array(), $client->getName())))
|
||||
->addCancelButton($client->getViewURI())
|
||||
->addSubmitButton(pht('Delete Application'));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
<?php
|
||||
|
||||
final class PhabricatorOAuthClientDisableController
|
||||
extends PhabricatorOAuthClientController {
|
||||
|
||||
public function handleRequest(AphrontRequest $request) {
|
||||
$viewer = $this->getViewer();
|
||||
|
||||
$client = id(new PhabricatorOAuthServerClientQuery())
|
||||
->setViewer($viewer)
|
||||
->withIDs(array($request->getURIData('id')))
|
||||
->requireCapabilities(
|
||||
array(
|
||||
PhabricatorPolicyCapability::CAN_VIEW,
|
||||
PhabricatorPolicyCapability::CAN_EDIT,
|
||||
))
|
||||
->executeOne();
|
||||
if (!$client) {
|
||||
return new Aphront404Response();
|
||||
}
|
||||
|
||||
$done_uri = $client->getViewURI();
|
||||
$is_disable = !$client->getIsDisabled();
|
||||
|
||||
if ($request->isFormPost()) {
|
||||
$xactions = array();
|
||||
|
||||
$xactions[] = id(new PhabricatorOAuthServerTransaction())
|
||||
->setTransactionType(PhabricatorOAuthServerTransaction::TYPE_DISABLED)
|
||||
->setNewValue((int)$is_disable);
|
||||
|
||||
$editor = id(new PhabricatorOAuthServerEditor())
|
||||
->setActor($viewer)
|
||||
->setContentSourceFromRequest($request)
|
||||
->setContinueOnNoEffect(true)
|
||||
->setContinueOnMissingFields(true)
|
||||
->applyTransactions($client, $xactions);
|
||||
|
||||
return id(new AphrontRedirectResponse())->setURI($done_uri);
|
||||
}
|
||||
|
||||
if ($is_disable) {
|
||||
$title = pht('Disable OAuth Application');
|
||||
$body = pht(
|
||||
'Really disable the %s OAuth application? Users will no longer be '.
|
||||
'able to authenticate against it, nor access Phabricator using '.
|
||||
'tokens generated by this application.',
|
||||
phutil_tag('strong', array(), $client->getName()));
|
||||
$button = pht('Disable Application');
|
||||
} else {
|
||||
$title = pht('Enable OAuth Application');
|
||||
$body = pht(
|
||||
'Really enable the %s OAuth application? Users will be able to '.
|
||||
'authenticate against it, and existing tokens will become usable '.
|
||||
'again.',
|
||||
phutil_tag('strong', array(), $client->getName()));
|
||||
$button = pht('Enable Application');
|
||||
}
|
||||
|
||||
return $this->newDialog()
|
||||
->setTitle($title)
|
||||
->appendParagraph($body)
|
||||
->addCancelButton($done_uri)
|
||||
->addSubmitButton($button);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -15,36 +15,41 @@ final class PhabricatorOAuthClientTestController
|
||||
return new Aphront404Response();
|
||||
}
|
||||
|
||||
$view_uri = $client->getViewURI();
|
||||
|
||||
// Look for an existing authorization.
|
||||
$authorization = id(new PhabricatorOAuthClientAuthorizationQuery())
|
||||
->setViewer($viewer)
|
||||
->withUserPHIDs(array($viewer->getPHID()))
|
||||
->withClientPHIDs(array($client->getPHID()))
|
||||
->executeOne();
|
||||
if ($authorization) {
|
||||
return $this->newDialog()
|
||||
->setTitle(pht('Already Authorized'))
|
||||
->appendParagraph(
|
||||
pht(
|
||||
'You have already authorized this application to access your '.
|
||||
'account.'))
|
||||
->addCancelButton($view_uri, pht('Close'));
|
||||
}
|
||||
$done_uri = $client->getViewURI();
|
||||
|
||||
if ($request->isFormPost()) {
|
||||
$server = id(new PhabricatorOAuthServer())
|
||||
->setUser($viewer)
|
||||
->setClient($client);
|
||||
|
||||
$scope = array();
|
||||
$authorization = $server->authorizeClient($scope);
|
||||
// Create an authorization if we don't already have one.
|
||||
$authorization = id(new PhabricatorOAuthClientAuthorizationQuery())
|
||||
->setViewer($viewer)
|
||||
->withUserPHIDs(array($viewer->getPHID()))
|
||||
->withClientPHIDs(array($client->getPHID()))
|
||||
->executeOne();
|
||||
if (!$authorization) {
|
||||
$scope = array();
|
||||
$authorization = $server->authorizeClient($scope);
|
||||
}
|
||||
|
||||
$id = $authorization->getID();
|
||||
$panel_uri = '/settings/panel/oauthorizations/?id='.$id;
|
||||
$access_token = $server->generateAccessToken();
|
||||
|
||||
return id(new AphrontRedirectResponse())->setURI($panel_uri);
|
||||
$form = id(new AphrontFormView())
|
||||
->setViewer($viewer)
|
||||
->appendInstructions(
|
||||
pht(
|
||||
'Keep this token private, it allows any bearer to access '.
|
||||
'your account on behalf of this application.'))
|
||||
->appendChild(
|
||||
id(new AphrontFormTextControl())
|
||||
->setLabel(pht('Token'))
|
||||
->setValue($access_token->getToken()));
|
||||
|
||||
return $this->newDialog()
|
||||
->setTitle(pht('OAuth Access Token'))
|
||||
->appendForm($form)
|
||||
->addCancelButton($done_uri, pht('Close'));
|
||||
}
|
||||
|
||||
// TODO: It would be nice to put scope options in this dialog, maybe?
|
||||
@@ -53,10 +58,10 @@ final class PhabricatorOAuthClientTestController
|
||||
->setTitle(pht('Authorize Application?'))
|
||||
->appendParagraph(
|
||||
pht(
|
||||
'This will create an authorization, permitting %s to access '.
|
||||
'your account.',
|
||||
'This will create an authorization and OAuth token, permitting %s '.
|
||||
'to access your account.',
|
||||
phutil_tag('strong', array(), $client->getName())))
|
||||
->addCancelButton($view_uri)
|
||||
->addCancelButton($done_uri)
|
||||
->addSubmitButton(pht('Authorize Application'));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,6 +51,12 @@ final class PhabricatorOAuthClientViewController
|
||||
->setHeader(pht('OAuth Application: %s', $client->getName()))
|
||||
->setPolicyObject($client);
|
||||
|
||||
if ($client->getIsDisabled()) {
|
||||
$header->setStatus('fa-ban', 'indigo', pht('Disabled'));
|
||||
} else {
|
||||
$header->setStatus('fa-check', 'green', pht('Enabled'));
|
||||
}
|
||||
|
||||
return $header;
|
||||
}
|
||||
|
||||
@@ -62,12 +68,6 @@ final class PhabricatorOAuthClientViewController
|
||||
$client,
|
||||
PhabricatorPolicyCapability::CAN_EDIT);
|
||||
|
||||
$authorization = id(new PhabricatorOAuthClientAuthorizationQuery())
|
||||
->setViewer($viewer)
|
||||
->withUserPHIDs(array($viewer->getPHID()))
|
||||
->withClientPHIDs(array($client->getPHID()))
|
||||
->executeOne();
|
||||
$is_authorized = (bool)$authorization;
|
||||
$id = $client->getID();
|
||||
|
||||
$view = id(new PhabricatorActionListView())
|
||||
@@ -89,20 +89,30 @@ final class PhabricatorOAuthClientViewController
|
||||
->setDisabled(!$can_edit)
|
||||
->setWorkflow(true));
|
||||
|
||||
$view->addAction(
|
||||
id(new PhabricatorActionView())
|
||||
->setName(pht('Delete Application'))
|
||||
->setIcon('fa-times')
|
||||
->setWorkflow(true)
|
||||
->setDisabled(!$can_edit)
|
||||
->setHref($client->getDeleteURI()));
|
||||
$is_disabled = $client->getIsDisabled();
|
||||
if ($is_disabled) {
|
||||
$disable_text = pht('Enable Application');
|
||||
$disable_icon = 'fa-check';
|
||||
} else {
|
||||
$disable_text = pht('Disable Application');
|
||||
$disable_icon = 'fa-ban';
|
||||
}
|
||||
|
||||
$disable_uri = $this->getApplicationURI("client/disable/{$id}/");
|
||||
|
||||
$view->addAction(
|
||||
id(new PhabricatorActionView())
|
||||
->setName(pht('Create Test Authorization'))
|
||||
->setIcon('fa-wrench')
|
||||
->setName($disable_text)
|
||||
->setIcon($disable_icon)
|
||||
->setWorkflow(true)
|
||||
->setDisabled(!$can_edit)
|
||||
->setHref($disable_uri));
|
||||
|
||||
$view->addAction(
|
||||
id(new PhabricatorActionView())
|
||||
->setName(pht('Generate Test Token'))
|
||||
->setIcon('fa-plus')
|
||||
->setWorkflow(true)
|
||||
->setDisabled($is_authorized)
|
||||
->setHref($this->getApplicationURI("client/test/{$id}/")));
|
||||
|
||||
return $view;
|
||||
|
||||
Reference in New Issue
Block a user