From afcb4cd69a345234d2f0de278c5fe9d31ae6dbb7 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 a57b4c21a69..23874bb2042 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 8c20c6a4f3f..b8fe75bab7e 100644 --- a/admin/tool/oauth2/lang/en/tool_oauth2.php +++ b/admin/tool/oauth2/lang/en/tool_oauth2.php @@ -95,6 +95,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 c6cb7567c9a..8baa221daef 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 03e5684d4ad..c1a4efb9607 100644 --- a/lib/db/install.xml +++ b/lib/db/install.xml @@ -3514,6 +3514,7 @@ + diff --git a/lib/db/upgrade.php b/lib/db/upgrade.php index 4024e5a4936..f61a19cface 100644 --- a/lib/db/upgrade.php +++ b/lib/db/upgrade.php @@ -2811,5 +2811,20 @@ function xmldb_main_upgrade($oldversion) { // Automatically generated Moodle v3.4.0 release upgrade line. // Put any upgrade step following this. + if ($oldversion < 2017111300.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, 2017111300.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 d168eebf4aa..f8eefa9f540 100644 --- a/version.php +++ b/version.php @@ -29,7 +29,7 @@ defined('MOODLE_INTERNAL') || die(); -$version = 2017111300.01; // 20171113 = branching date YYYYMMDD - do not modify! +$version = 2017111300.011; // 20171113 = branching date YYYYMMDD - do not modify! // RR = release increments - 00 in DEV branches. // .XX = incremental changes.