From 0bbd7b82918792ea12f81283f1c7dc3c8f5774e6 Mon Sep 17 00:00:00 2001 From: "yair.spielmann" Date: Thu, 31 Aug 2017 12:21:47 +0100 Subject: [PATCH] MDL-59512 tool_oauth2: add option for basic authentication --- admin/tool/oauth2/classes/form/issuer.php | 4 ++++ admin/tool/oauth2/lang/en/tool_oauth2.php | 2 ++ lib/classes/oauth2/client.php | 11 +++++++++-- lib/classes/oauth2/issuer.php | 4 ++++ lib/db/install.xml | 1 + lib/db/upgrade.php | 15 +++++++++++++++ lib/oauthlib.php | 12 ++++++++++-- version.php | 2 +- 8 files changed, 46 insertions(+), 5 deletions(-) diff --git a/admin/tool/oauth2/classes/form/issuer.php b/admin/tool/oauth2/classes/form/issuer.php index 3a0b64d3cf5..fdf07c0b3c5 100644 --- a/admin/tool/oauth2/classes/form/issuer.php +++ b/admin/tool/oauth2/classes/form/issuer.php @@ -78,6 +78,10 @@ class issuer extends persistent { $mform->addRule('clientsecret', get_string('maximumchars', '', 255), 'maxlength', 255, 'client'); $mform->addHelpButton('clientsecret', 'issuerclientsecret', 'tool_oauth2'); + // Use basic authentication. + $mform->addElement('checkbox', 'basicauth', get_string('usebasicauth', 'tool_oauth2')); + $mform->addHelpButton('basicauth', 'usebasicauth', 'tool_oauth2'); + // Login scopes. $mform->addElement('text', 'loginscopes', get_string('issuerloginscopes', 'tool_oauth2')); $mform->addRule('loginscopes', null, 'required', null, 'client'); diff --git a/admin/tool/oauth2/lang/en/tool_oauth2.php b/admin/tool/oauth2/lang/en/tool_oauth2.php index 5cc423cb8aa..f9a59d71af4 100644 --- a/admin/tool/oauth2/lang/en/tool_oauth2.php +++ b/admin/tool/oauth2/lang/en/tool_oauth2.php @@ -93,6 +93,8 @@ $string['systemaccountconnected_help'] = 'System accounts are used to provide ad $string['systemaccountconnected'] = 'System account connected'; $string['systemaccountnotconnected'] = 'System account not connected'; $string['systemauthstatus'] = 'System account connected'; +$string['usebasicauth'] = 'Authenticate token requests via HTTP headers'; +$string['usebasicauth_help'] = 'Utilize the HTTP Basic authentication scheme when sending client ID and password with a refresh token request. Recommended by the OAuth 2 standard, but may not be available with some issuers.'; $string['userfieldexternalfield'] = 'External field name'; $string['userfieldexternalfield_help'] = 'Name of the field provided by the external OAuth system.'; $string['userfieldinternalfield_help'] = 'Name of the Moodle user field that should be mapped from the external field.'; diff --git a/lib/classes/oauth2/client.php b/lib/classes/oauth2/client.php index 72baad9ae3e..7f3cc96f93d 100644 --- a/lib/classes/oauth2/client.php +++ b/lib/classes/oauth2/client.php @@ -70,6 +70,7 @@ class client extends \oauth2_client { if (empty($returnurl)) { $returnurl = new moodle_url('/'); } + $this->basicauth = $issuer->get('basicauth'); parent::__construct($issuer->get('clientid'), $issuer->get('clientsecret'), $returnurl, $scopes); } @@ -177,11 +178,17 @@ class client extends \oauth2_client { $refreshtoken = $systemaccount->get('refreshtoken'); $params = array('refresh_token' => $refreshtoken, - 'client_id' => $this->issuer->get('clientid'), - 'client_secret' => $this->issuer->get('clientsecret'), 'grant_type' => 'refresh_token' ); + if ($this->basicauth) { + $idsecret = urlencode($this->issuer->get('clientid')) . ':' . urlencode($this->issuer->get('clientsecret')); + $this->setHeader('Authorization: Basic ' . base64_encode($idsecret)); + } else { + $params['client_id'] = $this->issuer->get('clientid'); + $params['client_secret'] = $this->issuer->get('clientsecret'); + } + // Requests can either use http GET or POST. if ($this->use_http_get()) { $response = $this->get($this->token_url(), $params); diff --git a/lib/classes/oauth2/issuer.php b/lib/classes/oauth2/issuer.php index 7960ea654d1..f03e5f85154 100644 --- a/lib/classes/oauth2/issuer.php +++ b/lib/classes/oauth2/issuer.php @@ -72,6 +72,10 @@ class issuer extends persistent { 'type' => PARAM_BOOL, 'default' => false ), + 'basicauth' => array( + 'type' => PARAM_BOOL, + 'default' => false + ), 'scopessupported' => array( 'type' => PARAM_RAW, 'null' => NULL_ALLOWED, diff --git a/lib/db/install.xml b/lib/db/install.xml index 29486634dc8..55162a8f692 100644 --- a/lib/db/install.xml +++ b/lib/db/install.xml @@ -3500,6 +3500,7 @@ + diff --git a/lib/db/upgrade.php b/lib/db/upgrade.php index b28416e5379..90e275ab0c1 100644 --- a/lib/db/upgrade.php +++ b/lib/db/upgrade.php @@ -2961,5 +2961,20 @@ function xmldb_main_upgrade($oldversion) { upgrade_main_savepoint(true, 2017051502.04); } + if ($oldversion < 2017051503.011) { + + // Define field basicauth to be added to oauth2_issuer. + $table = new xmldb_table('oauth2_issuer'); + $field = new xmldb_field('basicauth', XMLDB_TYPE_INTEGER, '2', null, XMLDB_NOTNULL, null, '0', 'showonloginpage'); + + // Conditionally launch add field basicauth. + if (!$dbman->field_exists($table, $field)) { + $dbman->add_field($table, $field); + } + + // Main savepoint reached. + upgrade_main_savepoint(true, 2017051503.011); + } + return true; } diff --git a/lib/oauthlib.php b/lib/oauthlib.php index d269cc10935..c933decedbf 100644 --- a/lib/oauthlib.php +++ b/lib/oauthlib.php @@ -403,6 +403,8 @@ abstract class oauth2_client extends curl { private $mocknextresponse = ''; /** @var array $upgradedcodes list of upgraded codes in this request */ private static $upgradedcodes = []; + /** @var bool basicauth */ + protected $basicauth = false; /** * Returns the auth url for OAuth 2.0 request @@ -542,12 +544,18 @@ abstract class oauth2_client extends curl { public function upgrade_token($code) { $callbackurl = self::callback_url(); $params = array('code' => $code, - 'client_id' => $this->clientid, - 'client_secret' => $this->clientsecret, 'grant_type' => 'authorization_code', 'redirect_uri' => $callbackurl->out(false), ); + if ($this->basicauth) { + $idsecret = urlencode($this->clientid) . ':' . urlencode($this->clientsecret); + $this->setHeader('Authorization: Basic ' . base64_encode($idsecret)); + } else { + $params['client_id'] = $this->clientid; + $params['client_secret'] = $this->clientsecret; + } + // Requests can either use http GET or POST. if ($this->use_http_get()) { $response = $this->get($this->token_url(), $params); diff --git a/version.php b/version.php index 3a95bbd192c..c52b35c8946 100644 --- a/version.php +++ b/version.php @@ -29,7 +29,7 @@ defined('MOODLE_INTERNAL') || die(); -$version = 2017051503.01; // 20170515 = branching date YYYYMMDD - do not modify! +$version = 2017051503.011; // 20170515 = branching date YYYYMMDD - do not modify! // RR = release increments - 00 in DEV branches. // .XX = incremental changes.