2012-02-21 23:28:05 +01:00
|
|
|
<?php
|
|
|
|
|
|
|
|
final class PhabricatorOAuthServerScope {
|
|
|
|
|
|
|
|
const SCOPE_OFFLINE_ACCESS = 'offline_access';
|
|
|
|
const SCOPE_WHOAMI = 'whoami';
|
|
|
|
const SCOPE_NOT_ACCESSIBLE = 'not_accessible';
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Note this does not contain SCOPE_NOT_ACCESSIBLE which is magic
|
|
|
|
* used to simplify code for data that is not currently accessible
|
|
|
|
* via OAuth.
|
|
|
|
*/
|
2015-06-02 14:14:01 +02:00
|
|
|
public static function getScopesDict() {
|
2012-02-21 23:28:05 +01:00
|
|
|
return array(
|
|
|
|
self::SCOPE_OFFLINE_ACCESS => 1,
|
|
|
|
self::SCOPE_WHOAMI => 1,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2015-06-02 14:14:01 +02:00
|
|
|
public static function getDefaultScope() {
|
2015-02-07 00:32:55 +01:00
|
|
|
return self::SCOPE_WHOAMI;
|
|
|
|
}
|
|
|
|
|
2015-06-02 14:14:01 +02:00
|
|
|
public static function getCheckboxControl(
|
2015-02-07 00:32:55 +01:00
|
|
|
array $current_scopes) {
|
|
|
|
|
|
|
|
$have_options = false;
|
2012-02-22 19:21:39 +01:00
|
|
|
$scopes = self::getScopesDict();
|
|
|
|
$scope_keys = array_keys($scopes);
|
|
|
|
sort($scope_keys);
|
2015-02-07 00:32:55 +01:00
|
|
|
$default_scope = self::getDefaultScope();
|
2012-02-22 19:21:39 +01:00
|
|
|
|
|
|
|
$checkboxes = new AphrontFormCheckboxControl();
|
|
|
|
foreach ($scope_keys as $scope) {
|
2015-02-07 00:32:55 +01:00
|
|
|
if ($scope == $default_scope) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (!isset($current_scopes[$scope])) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2012-02-22 19:21:39 +01:00
|
|
|
$checkboxes->addCheckbox(
|
|
|
|
$name = $scope,
|
|
|
|
$value = 1,
|
|
|
|
$label = self::getCheckboxLabel($scope),
|
2013-02-19 22:33:10 +01:00
|
|
|
$checked = isset($current_scopes[$scope]));
|
2015-02-07 00:32:55 +01:00
|
|
|
$have_options = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ($have_options) {
|
|
|
|
$checkboxes->setLabel(pht('Scope'));
|
|
|
|
return $checkboxes;
|
2012-02-22 19:21:39 +01:00
|
|
|
}
|
|
|
|
|
2015-02-07 00:32:55 +01:00
|
|
|
return null;
|
2012-02-22 19:21:39 +01:00
|
|
|
}
|
|
|
|
|
2015-06-02 14:14:01 +02:00
|
|
|
private static function getCheckboxLabel($scope) {
|
2012-02-22 19:21:39 +01:00
|
|
|
$label = null;
|
|
|
|
switch ($scope) {
|
|
|
|
case self::SCOPE_OFFLINE_ACCESS:
|
2015-05-22 09:27:56 +02:00
|
|
|
$label = pht('Make access tokens granted to this client never expire.');
|
2012-02-22 19:21:39 +01:00
|
|
|
break;
|
|
|
|
case self::SCOPE_WHOAMI:
|
2015-05-22 09:27:56 +02:00
|
|
|
$label = pht('Read access to Conduit method %s.', 'user.whoami');
|
2012-02-22 19:21:39 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return $label;
|
|
|
|
}
|
|
|
|
|
2015-06-02 14:14:01 +02:00
|
|
|
public static function getScopesFromRequest(AphrontRequest $request) {
|
2012-02-22 19:21:39 +01:00
|
|
|
$scopes = self::getScopesDict();
|
|
|
|
$requested_scopes = array();
|
|
|
|
foreach ($scopes as $scope => $bit) {
|
|
|
|
if ($request->getBool($scope)) {
|
|
|
|
$requested_scopes[$scope] = 1;
|
|
|
|
}
|
|
|
|
}
|
2015-02-07 00:32:55 +01:00
|
|
|
$requested_scopes[self::getDefaultScope()] = 1;
|
2012-02-22 19:21:39 +01:00
|
|
|
return $requested_scopes;
|
|
|
|
}
|
|
|
|
|
OAuthServer polish and random sauce
Summary:
This diff makes the OAuthServer more compliant with the spec by
- making it return well-formatted error codes with error types from the spec.
- making it respect the "state" variable, which is a transparent variable the
client passes and the server passes back
- making it be super, duper compliant with respect to redirect uris
-- if specified in authorization step, check if its valid relative to the client
registered URI and if so save it
-- if specified in authorization step, check if its been specified in the access
step and error if it doesn't match or doesn't exist
-- note we don't make any use of it in the access step which seems strange but
hey, that's what the spec says!
This diff makes the OAuthServer suck less by
- making the "cancel" button do something in the user authorization flow
- making the client list view and client edit view be a bit more usable around
client secrets
- fixing a few bugs I managed to introduce along the way
Test Plan:
- create a test phabricator client, updated my conf, and then linked and
unlinked phabricator to itself
- wrote some tests for PhabricatorOAuthServer -- they pass!
-- these validate the various validate URI checks
- tried a few important authorization calls
--
http://phabricator.dev/oauthserver/auth/?client_id=X&state=test&redirect_uri=http://www.evil.com
--- verified error'd from mismatching redirect uri's
--- verified state parameter in response
--- verified did not redirect to client redirect uri
-- http://phabricator.dev/oauthserver/auth/?client_id=X w/ existing
authorization
--- got redirected to proper client url with error that response_type not
specified
-- http://phabricator.dev/oauthserver/auth/?client_id=X&response_type=code w/
existing authorization
--- got redirected to proper client url with pertinent code!
- tried a few important access calls
-- verified appropriate errors if missing any required parameters
-- verified good access code with appropriate other variables resulted in an
access token
- verified that if redirect_uri set correctly in authorization required for
access and errors if differs at all / only succeeds if exactly the same
Reviewers: epriestley
Reviewed By: epriestley
CC: aran, epriestley, ajtrichards
Maniphest Tasks: T889, T906, T897
Differential Revision: https://secure.phabricator.com/D1727
2012-03-01 23:46:18 +01:00
|
|
|
/**
|
|
|
|
* A scopes list is considered valid if each scope is a known scope
|
2014-07-10 00:12:48 +02:00
|
|
|
* and each scope is seen only once. Otherwise, the list is invalid.
|
OAuthServer polish and random sauce
Summary:
This diff makes the OAuthServer more compliant with the spec by
- making it return well-formatted error codes with error types from the spec.
- making it respect the "state" variable, which is a transparent variable the
client passes and the server passes back
- making it be super, duper compliant with respect to redirect uris
-- if specified in authorization step, check if its valid relative to the client
registered URI and if so save it
-- if specified in authorization step, check if its been specified in the access
step and error if it doesn't match or doesn't exist
-- note we don't make any use of it in the access step which seems strange but
hey, that's what the spec says!
This diff makes the OAuthServer suck less by
- making the "cancel" button do something in the user authorization flow
- making the client list view and client edit view be a bit more usable around
client secrets
- fixing a few bugs I managed to introduce along the way
Test Plan:
- create a test phabricator client, updated my conf, and then linked and
unlinked phabricator to itself
- wrote some tests for PhabricatorOAuthServer -- they pass!
-- these validate the various validate URI checks
- tried a few important authorization calls
--
http://phabricator.dev/oauthserver/auth/?client_id=X&state=test&redirect_uri=http://www.evil.com
--- verified error'd from mismatching redirect uri's
--- verified state parameter in response
--- verified did not redirect to client redirect uri
-- http://phabricator.dev/oauthserver/auth/?client_id=X w/ existing
authorization
--- got redirected to proper client url with error that response_type not
specified
-- http://phabricator.dev/oauthserver/auth/?client_id=X&response_type=code w/
existing authorization
--- got redirected to proper client url with pertinent code!
- tried a few important access calls
-- verified appropriate errors if missing any required parameters
-- verified good access code with appropriate other variables resulted in an
access token
- verified that if redirect_uri set correctly in authorization required for
access and errors if differs at all / only succeeds if exactly the same
Reviewers: epriestley
Reviewed By: epriestley
CC: aran, epriestley, ajtrichards
Maniphest Tasks: T889, T906, T897
Differential Revision: https://secure.phabricator.com/D1727
2012-03-01 23:46:18 +01:00
|
|
|
*/
|
2015-06-02 14:14:01 +02:00
|
|
|
public static function validateScopesList($scope_list) {
|
OAuthServer polish and random sauce
Summary:
This diff makes the OAuthServer more compliant with the spec by
- making it return well-formatted error codes with error types from the spec.
- making it respect the "state" variable, which is a transparent variable the
client passes and the server passes back
- making it be super, duper compliant with respect to redirect uris
-- if specified in authorization step, check if its valid relative to the client
registered URI and if so save it
-- if specified in authorization step, check if its been specified in the access
step and error if it doesn't match or doesn't exist
-- note we don't make any use of it in the access step which seems strange but
hey, that's what the spec says!
This diff makes the OAuthServer suck less by
- making the "cancel" button do something in the user authorization flow
- making the client list view and client edit view be a bit more usable around
client secrets
- fixing a few bugs I managed to introduce along the way
Test Plan:
- create a test phabricator client, updated my conf, and then linked and
unlinked phabricator to itself
- wrote some tests for PhabricatorOAuthServer -- they pass!
-- these validate the various validate URI checks
- tried a few important authorization calls
--
http://phabricator.dev/oauthserver/auth/?client_id=X&state=test&redirect_uri=http://www.evil.com
--- verified error'd from mismatching redirect uri's
--- verified state parameter in response
--- verified did not redirect to client redirect uri
-- http://phabricator.dev/oauthserver/auth/?client_id=X w/ existing
authorization
--- got redirected to proper client url with error that response_type not
specified
-- http://phabricator.dev/oauthserver/auth/?client_id=X&response_type=code w/
existing authorization
--- got redirected to proper client url with pertinent code!
- tried a few important access calls
-- verified appropriate errors if missing any required parameters
-- verified good access code with appropriate other variables resulted in an
access token
- verified that if redirect_uri set correctly in authorization required for
access and errors if differs at all / only succeeds if exactly the same
Reviewers: epriestley
Reviewed By: epriestley
CC: aran, epriestley, ajtrichards
Maniphest Tasks: T889, T906, T897
Differential Revision: https://secure.phabricator.com/D1727
2012-03-01 23:46:18 +01:00
|
|
|
$scopes = explode(' ', $scope_list);
|
|
|
|
$known_scopes = self::getScopesDict();
|
|
|
|
$seen_scopes = array();
|
|
|
|
foreach ($scopes as $scope) {
|
|
|
|
if (!isset($known_scopes[$scope])) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if (isset($seen_scopes[$scope])) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
$seen_scopes[$scope] = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* A scopes dictionary is considered valid if each key is a known scope.
|
|
|
|
* Otherwise, the dictionary is invalid.
|
|
|
|
*/
|
2015-06-02 14:14:01 +02:00
|
|
|
public static function validateScopesDict($scope_dict) {
|
OAuthServer polish and random sauce
Summary:
This diff makes the OAuthServer more compliant with the spec by
- making it return well-formatted error codes with error types from the spec.
- making it respect the "state" variable, which is a transparent variable the
client passes and the server passes back
- making it be super, duper compliant with respect to redirect uris
-- if specified in authorization step, check if its valid relative to the client
registered URI and if so save it
-- if specified in authorization step, check if its been specified in the access
step and error if it doesn't match or doesn't exist
-- note we don't make any use of it in the access step which seems strange but
hey, that's what the spec says!
This diff makes the OAuthServer suck less by
- making the "cancel" button do something in the user authorization flow
- making the client list view and client edit view be a bit more usable around
client secrets
- fixing a few bugs I managed to introduce along the way
Test Plan:
- create a test phabricator client, updated my conf, and then linked and
unlinked phabricator to itself
- wrote some tests for PhabricatorOAuthServer -- they pass!
-- these validate the various validate URI checks
- tried a few important authorization calls
--
http://phabricator.dev/oauthserver/auth/?client_id=X&state=test&redirect_uri=http://www.evil.com
--- verified error'd from mismatching redirect uri's
--- verified state parameter in response
--- verified did not redirect to client redirect uri
-- http://phabricator.dev/oauthserver/auth/?client_id=X w/ existing
authorization
--- got redirected to proper client url with error that response_type not
specified
-- http://phabricator.dev/oauthserver/auth/?client_id=X&response_type=code w/
existing authorization
--- got redirected to proper client url with pertinent code!
- tried a few important access calls
-- verified appropriate errors if missing any required parameters
-- verified good access code with appropriate other variables resulted in an
access token
- verified that if redirect_uri set correctly in authorization required for
access and errors if differs at all / only succeeds if exactly the same
Reviewers: epriestley
Reviewed By: epriestley
CC: aran, epriestley, ajtrichards
Maniphest Tasks: T889, T906, T897
Differential Revision: https://secure.phabricator.com/D1727
2012-03-01 23:46:18 +01:00
|
|
|
$known_scopes = self::getScopesDict();
|
|
|
|
$unknown_scopes = array_diff_key($scope_dict,
|
|
|
|
$known_scopes);
|
|
|
|
return empty($unknown_scopes);
|
|
|
|
}
|
|
|
|
|
2012-03-05 22:27:20 +01:00
|
|
|
/**
|
|
|
|
* Transforms a space-delimited scopes list into a scopes dict. The list
|
|
|
|
* should be validated by @{method:validateScopesList} before
|
|
|
|
* transformation.
|
|
|
|
*/
|
2015-06-02 14:14:01 +02:00
|
|
|
public static function scopesListToDict($scope_list) {
|
2012-03-05 22:27:20 +01:00
|
|
|
$scopes = explode(' ', $scope_list);
|
|
|
|
return array_fill_keys($scopes, 1);
|
OAuthServer polish and random sauce
Summary:
This diff makes the OAuthServer more compliant with the spec by
- making it return well-formatted error codes with error types from the spec.
- making it respect the "state" variable, which is a transparent variable the
client passes and the server passes back
- making it be super, duper compliant with respect to redirect uris
-- if specified in authorization step, check if its valid relative to the client
registered URI and if so save it
-- if specified in authorization step, check if its been specified in the access
step and error if it doesn't match or doesn't exist
-- note we don't make any use of it in the access step which seems strange but
hey, that's what the spec says!
This diff makes the OAuthServer suck less by
- making the "cancel" button do something in the user authorization flow
- making the client list view and client edit view be a bit more usable around
client secrets
- fixing a few bugs I managed to introduce along the way
Test Plan:
- create a test phabricator client, updated my conf, and then linked and
unlinked phabricator to itself
- wrote some tests for PhabricatorOAuthServer -- they pass!
-- these validate the various validate URI checks
- tried a few important authorization calls
--
http://phabricator.dev/oauthserver/auth/?client_id=X&state=test&redirect_uri=http://www.evil.com
--- verified error'd from mismatching redirect uri's
--- verified state parameter in response
--- verified did not redirect to client redirect uri
-- http://phabricator.dev/oauthserver/auth/?client_id=X w/ existing
authorization
--- got redirected to proper client url with error that response_type not
specified
-- http://phabricator.dev/oauthserver/auth/?client_id=X&response_type=code w/
existing authorization
--- got redirected to proper client url with pertinent code!
- tried a few important access calls
-- verified appropriate errors if missing any required parameters
-- verified good access code with appropriate other variables resulted in an
access token
- verified that if redirect_uri set correctly in authorization required for
access and errors if differs at all / only succeeds if exactly the same
Reviewers: epriestley
Reviewed By: epriestley
CC: aran, epriestley, ajtrichards
Maniphest Tasks: T889, T906, T897
Differential Revision: https://secure.phabricator.com/D1727
2012-03-01 23:46:18 +01:00
|
|
|
}
|
|
|
|
|
2012-02-21 23:28:05 +01:00
|
|
|
}
|