diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index d008378d51..69f230bb79 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -4465,7 +4465,11 @@ phutil_register_library_map(array( 'PhabricatorOAuthClientBaseController' => 'PhabricatorOAuthServerController', 'PhabricatorOAuthClientDeleteController' => 'PhabricatorOAuthClientBaseController', 'PhabricatorOAuthClientEditController' => 'PhabricatorOAuthClientBaseController', - 'PhabricatorOAuthClientListController' => 'PhabricatorOAuthClientBaseController', + 'PhabricatorOAuthClientListController' => + array( + 0 => 'PhabricatorOAuthClientBaseController', + 1 => 'PhabricatorApplicationSearchResultsControllerInterface', + ), 'PhabricatorOAuthClientViewController' => 'PhabricatorOAuthClientBaseController', 'PhabricatorOAuthResponse' => 'AphrontResponse', 'PhabricatorOAuthServerAccessToken' => 'PhabricatorOAuthServerDAO', diff --git a/src/applications/oauthserver/application/PhabricatorApplicationOAuthServer.php b/src/applications/oauthserver/application/PhabricatorApplicationOAuthServer.php index 0eaf49715e..8510f8c5f6 100644 --- a/src/applications/oauthserver/application/PhabricatorApplicationOAuthServer.php +++ b/src/applications/oauthserver/application/PhabricatorApplicationOAuthServer.php @@ -36,7 +36,7 @@ final class PhabricatorApplicationOAuthServer extends PhabricatorApplication { '(?:query/(?P[^/]+)/)?' => 'PhabricatorOAuthClientListController', 'auth/' => 'PhabricatorOAuthServerAuthController', - 'test/' => 'PhabricatorOAuthServerTestController', + 'test/(?P\d+)/' => 'PhabricatorOAuthServerTestController', 'token/' => 'PhabricatorOAuthServerTokenController', 'client/' => array( 'create/' => 'PhabricatorOAuthClientEditController', diff --git a/src/applications/oauthserver/controller/PhabricatorOAuthServerTestController.php b/src/applications/oauthserver/controller/PhabricatorOAuthServerTestController.php index bf2692b18a..d95fdf7d43 100644 --- a/src/applications/oauthserver/controller/PhabricatorOAuthServerTestController.php +++ b/src/applications/oauthserver/controller/PhabricatorOAuthServerTestController.php @@ -1,55 +1,81 @@ id = $data['id']; + } + public function processRequest() { - $request = $this->getRequest(); - $current_user = $request->getUser(); - $server = new PhabricatorOAuthServer(); + $request = $this->getRequest(); + $viewer = $request->getUser(); + $panels = array(); $results = array(); - if (!$request->isFormPost()) { - return new Aphront400Response(); - } - - $action = $request->getStr('action'); - if ($action !== 'testclientauthorization') { + $client = id(new PhabricatorOAuthServerClientQuery()) + ->setViewer($viewer) + ->withIDs(array($this->id)) + ->executeOne(); + if (!$client) { return new Aphront404Response(); } - $user_phid = $current_user->getPHID(); - $client_phid = $request->getStr('client_phid'); - $client = id(new PhabricatorOAuthServerClient) - ->loadOneWhere('phid = %s', $client_phid); - if (!$client) { - throw new Exception('Failed to load client!'); - } - if ($client->getCreatorPHID() != $user_phid || - $current_user->getPHID() != $user_phid) { - throw new Exception( - 'Only allowed to make test data for yourself '. - 'for clients you own!' - ); + $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) { + $dialog = id(new AphrontDialogView()) + ->setUser($viewer) + ->setTitle(pht('Already Authorized')) + ->appendParagraph( + pht( + 'You have already authorized this application to access your '. + 'account.')) + ->addCancelButton($view_uri, pht('Close')); + + return id(new AphrontDialogResponse())->setDialog($dialog); } - // blankclientauthorizations don't get scope - $scope = array(); - $server->setUser($current_user); - $server->setClient($client); - $authorization = $server->authorizeClient($scope); + if ($request->isFormPost()) { + $server = id(new PhabricatorOAuthServer()) + ->setUser($viewer) + ->setClient($client); - $id = $authorization->getID(); - $panel_uri = '/settings/panel/oauthorizations/?id='.$id; + $scope = array(); + $authorization = $server->authorizeClient($scope); - return id(new AphrontRedirectResponse())->setURI($panel_uri); + $id = $authorization->getID(); + $panel_uri = '/settings/panel/oauthorizations/?id='.$id; + + return id(new AphrontRedirectResponse())->setURI($panel_uri); + } + + // TODO: It would be nice to put scope options in this dialog, maybe? + + $dialog = id(new AphrontDialogView()) + ->setUser($viewer) + ->setTitle(pht('Authorize Application?')) + ->appendParagraph( + pht( + 'This will create an authorization, permitting %s to access '. + 'your account.', + phutil_tag('strong', array(), $client->getName()))) + ->addCancelButton($view_uri) + ->addSubmitButton(pht('Authorize Application')); + + return id(new AphrontDialogResponse())->setDialog($dialog); } } diff --git a/src/applications/oauthserver/controller/client/PhabricatorOAuthClientDeleteController.php b/src/applications/oauthserver/controller/client/PhabricatorOAuthClientDeleteController.php index ae3f85a3ac..daf72bf6b7 100644 --- a/src/applications/oauthserver/controller/client/PhabricatorOAuthClientDeleteController.php +++ b/src/applications/oauthserver/controller/client/PhabricatorOAuthClientDeleteController.php @@ -1,47 +1,42 @@ getClientPHID(); - $title = 'Delete OAuth Client'; - $request = $this->getRequest(); - $current_user = $request->getUser(); - $client = id(new PhabricatorOAuthServerClient()) - ->loadOneWhere('phid = %s', - $phid); + $request = $this->getRequest(); + $viewer = $request->getUser(); - if (empty($client)) { + $client = id(new PhabricatorOAuthServerClientQuery()) + ->setViewer($viewer) + ->withPHIDs(array($this->getClientPHID())) + ->requireCapabilities( + array( + PhabricatorPolicyCapability::CAN_VIEW, + PhabricatorPolicyCapability::CAN_EDIT, + )) + ->executeOne(); + if (!$client) { return new Aphront404Response(); } - if ($client->getCreatorPHID() != $current_user->getPHID()) { - $message = 'Access denied to client with phid '.$phid.'. '. - 'Only the user who created the client has permission to '. - 'delete the client.'; - return id(new Aphront403Response()) - ->setForbiddenText($message); - } if ($request->isFormPost()) { $client->delete(); - return id(new AphrontRedirectResponse()) - ->setURI('/oauthserver/client/?deleted=1'); + $app_uri = $this->getApplicationURI(); + return id(new AphrontRedirectResponse())->setURI($app_uri); } - $title .= ' '.$client->getName(); + $dialog = id(new AphrontDialogView()) + ->setUser($viewer) + ->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')); - $dialog = new AphrontDialogView(); - $dialog->setUser($current_user); - $dialog->setTitle($title); - $dialog->appendChild(phutil_tag('p', array(), pht( - 'Are you sure you want to delete this client?'))); - $dialog->addSubmitButton(); - $dialog->addCancelButton($client->getEditURI()); return id(new AphrontDialogResponse())->setDialog($dialog); - } + } diff --git a/src/applications/oauthserver/controller/client/PhabricatorOAuthClientViewController.php b/src/applications/oauthserver/controller/client/PhabricatorOAuthClientViewController.php index b9ffe21336..a48f5f6946 100644 --- a/src/applications/oauthserver/controller/client/PhabricatorOAuthClientViewController.php +++ b/src/applications/oauthserver/controller/client/PhabricatorOAuthClientViewController.php @@ -1,109 +1,121 @@ getClientPHID(); - } - - protected function getExtraClientFilters() { - return array( - array('url' => $this->getFilter(), - 'label' => 'View Client') - ); - } + extends PhabricatorOAuthClientBaseController { public function processRequest() { - $request = $this->getRequest(); - $current_user = $request->getUser(); - $error = null; - $phid = $this->getClientPHID(); + $request = $this->getRequest(); + $viewer = $request->getUser(); - $client = id(new PhabricatorOAuthServerClient()) - ->loadOneWhere('phid = %s', - $phid); - $title = 'View OAuth Client'; - - // validate the client - if (empty($client)) { - $message = 'No client found with id '.$phid.'.'; - return $this->buildStandardPageResponse( - $this->buildErrorView($message), - array('title' => $title)); + $client = id(new PhabricatorOAuthServerClientQuery()) + ->setViewer($viewer) + ->withPHIDs(array($this->getClientPHID())) + ->executeOne(); + if (!$client) { + return new Aphront404Response(); } - $panel = new AphrontPanelView(); - $panel->setHeader($title); + $header = $this->buildHeaderView($client); + $actions = $this->buildActionView($client); + $properties = $this->buildPropertyListView($client); + $properties->setActionList($actions); - $form = id(new AphrontFormView()) - ->setUser($current_user) - ->appendChild( - id(new AphrontFormStaticControl()) - ->setLabel('Name') - ->setValue($client->getName())) - ->appendChild( - id(new AphrontFormStaticControl()) - ->setLabel('ID') - ->setValue($phid)); - if ($current_user->getPHID() == $client->getCreatorPHID()) { - $form - ->appendChild( - id(new AphrontFormStaticControl()) - ->setLabel('Secret') - ->setValue($client->getSecret())); - } - $form - ->appendChild( - id(new AphrontFormStaticControl()) - ->setLabel('Redirect URI') - ->setValue($client->getRedirectURI())); - $created = phabricator_datetime($client->getDateCreated(), - $current_user); - $updated = phabricator_datetime($client->getDateModified(), - $current_user); - $form - ->appendChild( - id(new AphrontFormStaticControl()) - ->setLabel('Created') - ->setValue($created)) - ->appendChild( - id(new AphrontFormStaticControl()) - ->setLabel('Last Updated') - ->setValue($updated)); - $panel->appendChild($form); - $admin_panel = null; - if ($client->getCreatorPHID() == $current_user->getPHID()) { - $edit_button = phutil_tag( - 'a', - array( - 'href' => $client->getEditURI(), - 'class' => 'grey button', - ), - 'Edit OAuth Client'); - $panel->addButton($edit_button); + $crumbs = $this->buildApplicationCrumbs(); + $crumbs->addTextCrumb($client->getName()); - $create_authorization_form = id(new AphrontFormView()) - ->setUser($current_user) - ->addHiddenInput('action', 'testclientauthorization') - ->addHiddenInput('client_phid', $phid) - ->setAction('/oauthserver/test/') - ->appendChild( - id(new AphrontFormSubmitControl()) - ->setValue('Create Scopeless Test Authorization')); - $admin_panel = id(new AphrontPanelView()) - ->setHeader('Admin Tools') - ->appendChild($create_authorization_form); - } + $box = id(new PHUIObjectBoxView()) + ->setHeader($header) + ->addPropertyList($properties); - return $this->buildStandardPageResponse( - array($error, - $panel, - $admin_panel - ), - array('title' => $title)); + return $this->buildApplicationPage( + array( + $crumbs, + $box, + ), + array( + 'title' => pht('OAuth Application: %s', $client->getName()), + 'device' => true, + )); + } + + private function buildHeaderView(PhabricatorOAuthServerClient $client) { + $viewer = $this->getRequest()->getUser(); + + $header = id(new PHUIHeaderView()) + ->setUser($viewer) + ->setHeader(pht('OAuth Application: %s', $client->getName())) + ->setPolicyObject($client); + + return $header; + } + + private function buildActionView(PhabricatorOAuthServerClient $client) { + $viewer = $this->getRequest()->getUser(); + + $can_edit = PhabricatorPolicyFilter::hasCapability( + $viewer, + $client, + PhabricatorPolicyCapability::CAN_EDIT); + + $authorization = id(new PhabricatorOAuthClientAuthorizationQuery()) + ->setViewer($viewer) + ->withUserPHIDs(array($viewer->getPHID())) + ->withClientPHIDs(array($client->getPHID())) + ->executeOne(); + $is_authorized = (bool)$authorization; + + $view = id(new PhabricatorActionListView()) + ->setUser($viewer); + + $view->addAction( + id(new PhabricatorActionView()) + ->setName(pht('Edit Application')) + ->setIcon('edit') + ->setWorkflow(!$can_edit) + ->setDisabled(!$can_edit) + ->setHref($client->getEditURI())); + + $view->addAction( + id(new PhabricatorActionView()) + ->setName(pht('Delete Application')) + ->setIcon('delete') + ->setWorkflow(true) + ->setDisabled(!$can_edit) + ->setHref($client->getDeleteURI())); + + $view->addAction( + id(new PhabricatorActionView()) + ->setName(pht('Create Test Authorization')) + ->setIcon('wrench') + ->setWorkflow(true) + ->setDisabled($is_authorized) + ->setHref($this->getApplicationURI('test/'.$client->getID().'/'))); + + return $view; + } + + private function buildPropertyListView(PhabricatorOAuthServerClient $client) { + $viewer = $this->getRequest()->getUser(); + + $view = id(new PHUIPropertyListView()) + ->setUser($viewer); + + $view->addProperty( + pht('Client ID'), + $client->getPHID()); + + $view->addProperty( + pht('Client Secret'), + $client->getSecret()); + + $view->addProperty( + pht('Redirect URI'), + $client->getRedirectURI()); + + $view->addProperty( + pht('Created'), + phabricator_datetime($client->getDateCreated(), $viewer)); + + return $view; } } diff --git a/src/applications/oauthserver/query/PhabricatorOAuthClientAuthorizationQuery.php b/src/applications/oauthserver/query/PhabricatorOAuthClientAuthorizationQuery.php index c75c349090..0001a03374 100644 --- a/src/applications/oauthserver/query/PhabricatorOAuthClientAuthorizationQuery.php +++ b/src/applications/oauthserver/query/PhabricatorOAuthClientAuthorizationQuery.php @@ -5,6 +5,7 @@ final class PhabricatorOAuthClientAuthorizationQuery private $phids; private $userPHIDs; + private $clientPHIDs; public function witHPHIDs(array $phids) { $this->phids = $phids; @@ -16,6 +17,11 @@ final class PhabricatorOAuthClientAuthorizationQuery return $this; } + public function withClientPHIDs(array $phids) { + $this->clientPHIDs = $phids; + return $this; + } + public function loadPage() { $table = new PhabricatorOAuthClientAuthorization(); $conn_r = $table->establishConnection('r'); @@ -45,6 +51,7 @@ final class PhabricatorOAuthClientAuthorizationQuery $client = idx($clients, $authorization->getClientPHID()); if (!$client) { unset($authorizations[$key]); + continue; } $authorization->attachClient($client); } @@ -69,6 +76,13 @@ final class PhabricatorOAuthClientAuthorizationQuery $this->userPHIDs); } + if ($this->clientPHIDs) { + $where[] = qsprintf( + $conn_r, + 'clientPHID IN (%Ls)', + $this->clientPHIDs); + } + $where[] = $this->buildPagingClause($conn_r); return $this->formatWhereClause($where); diff --git a/src/applications/oauthserver/query/PhabricatorOAuthServerClientQuery.php b/src/applications/oauthserver/query/PhabricatorOAuthServerClientQuery.php index 242e976f8a..64ec0e2bbf 100644 --- a/src/applications/oauthserver/query/PhabricatorOAuthServerClientQuery.php +++ b/src/applications/oauthserver/query/PhabricatorOAuthServerClientQuery.php @@ -3,9 +3,15 @@ final class PhabricatorOAuthServerClientQuery extends PhabricatorCursorPagedPolicyAwareQuery { + private $ids; private $phids; private $creatorPHIDs; + public function withIDs(array $ids) { + $this->ids = $ids; + return $this; + } + public function withPHIDs(array $phids) { $this->phids = $phids; return $this; @@ -35,6 +41,13 @@ final class PhabricatorOAuthServerClientQuery private function buildWhereClause($conn_r) { $where = array(); + if ($this->ids) { + $where[] = qsprintf( + $conn_r, + 'id IN (%Ld)', + $this->ids); + } + if ($this->phids) { $where[] = qsprintf( $conn_r,