mirror of
https://github.com/moodle/moodle.git
synced 2025-04-13 04:22:07 +02:00
MDL-63696 oauth2: Store system account access tokens in DB
This commit is contained in:
parent
dccda6546b
commit
f11a7d6a05
71
lib/classes/oauth2/access_token.php
Normal file
71
lib/classes/oauth2/access_token.php
Normal file
@ -0,0 +1,71 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Loads/stores oauth2 access tokens in DB for system accounts in order to use a single token across multiple sessions.
|
||||
*
|
||||
* @package core
|
||||
* @copyright 2018 Jan Dageförde <jan.dagefoerde@ercis.uni-muenster.de>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
namespace core\oauth2;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
use core\persistent;
|
||||
|
||||
/**
|
||||
* Loads/stores oauth2 access tokens in DB for system accounts in order to use a single token across multiple sessions.
|
||||
*
|
||||
* When a system user is authenticated via OAuth, we need to use a single access token across user sessions,
|
||||
* because we want to avoid using multiple tokens at the same time for a single remote user. Reasons are that,
|
||||
* first, redeeming the refresh token for an access token requires an additional request, and second, there is
|
||||
* no guarantee that redeeming the refresh token doesn't invalidate *all* corresponding previous access tokes.
|
||||
* As a result, we would need to either continuously request lots and lots of new access tokens, or persist the
|
||||
* access token in the DB where it can be used from all sessions. Let's do the latter!
|
||||
*
|
||||
* @copyright 2018 Jan Dageförde <jan.dagefoerde@ercis.uni-muenster.de>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class access_token extends persistent {
|
||||
|
||||
/** The table name. */
|
||||
const TABLE = 'oauth2_access_token';
|
||||
|
||||
/**
|
||||
* Return the definition of the properties of this model.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected static function define_properties() {
|
||||
return array(
|
||||
// Issuer id instead of the system account id because, at the time of storing/loading a token we may not
|
||||
// know the system account id.
|
||||
'issuerid' => array(
|
||||
'type' => PARAM_INT
|
||||
),
|
||||
'token' => array(
|
||||
'type' => PARAM_RAW,
|
||||
),
|
||||
'expires' => array(
|
||||
'type' => PARAM_INT,
|
||||
),
|
||||
'scope' => array(
|
||||
'type' => PARAM_RAW,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
@ -33,7 +33,7 @@ use moodle_exception;
|
||||
use stdClass;
|
||||
|
||||
/**
|
||||
* Configurable oauth2 client class where the urls come from DB.
|
||||
* Configurable oauth2 client class. URLs come from DB and access tokens from either DB (system accounts) or session (users').
|
||||
*
|
||||
* @copyright 2017 Damyon Wiese
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
@ -152,6 +152,56 @@ class client extends \oauth2_client {
|
||||
return $name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a token between requests. Uses session named by get_tokenname for user account tokens
|
||||
* and a database record for system account tokens.
|
||||
*
|
||||
* @param stdClass|null $token token object to store or null to clear
|
||||
*/
|
||||
protected function store_token($token) {
|
||||
if (!$this->system) {
|
||||
parent::store_token($token);
|
||||
return;
|
||||
}
|
||||
|
||||
$this->accesstoken = $token;
|
||||
|
||||
// Create or update a DB record with the new token.
|
||||
$persistedtoken = access_token::get_record(['issuerid' => $this->issuer->get('id')]);
|
||||
if ($token !== null) {
|
||||
if (!$persistedtoken) {
|
||||
$persistedtoken = new access_token();
|
||||
$persistedtoken->set('issuerid', $this->issuer->get('id'));
|
||||
}
|
||||
// Update values from $token. Don't use from_record because that would skip validation.
|
||||
$persistedtoken->set('token', $token->token);
|
||||
$persistedtoken->set('expires', $token->expires);
|
||||
$persistedtoken->set('scope', $token->scope);
|
||||
$persistedtoken->save();
|
||||
} else {
|
||||
if ($persistedtoken) {
|
||||
$persistedtoken->delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a stored token from session (user accounts) or database (system accounts).
|
||||
*
|
||||
* @return stdClass|null token object
|
||||
*/
|
||||
protected function get_stored_token() {
|
||||
if ($this->system) {
|
||||
$token = access_token::get_record(['issuerid' => $this->issuer->get('id')]);
|
||||
if ($token !== false) {
|
||||
return $token->to_record();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
return parent::get_stored_token();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of the mapping user fields in an associative array.
|
||||
*
|
||||
|
@ -3926,6 +3926,22 @@
|
||||
<INDEX NAME="predictionidanduseridandactionname" UNIQUE="false" FIELDS="predictionid, userid, actionname"/>
|
||||
</INDEXES>
|
||||
</TABLE>
|
||||
<TABLE NAME="oauth2_access_token" COMMENT="Stores access tokens for system accounts in order to be able to use a single token across multiple sessions">
|
||||
<FIELDS>
|
||||
<FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="true"/>
|
||||
<FIELD NAME="timecreated" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false" COMMENT="Time this record was created."/>
|
||||
<FIELD NAME="timemodified" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false" COMMENT="Time this record was modified."/>
|
||||
<FIELD NAME="usermodified" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false" COMMENT="The user who modified this record."/>
|
||||
<FIELD NAME="issuerid" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false" COMMENT="Corresponding oauth2 issuer"/>
|
||||
<FIELD NAME="token" TYPE="text" NOTNULL="true" SEQUENCE="false" COMMENT="access token"/>
|
||||
<FIELD NAME="expires" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false" COMMENT="Expiry timestamp (according to the issuer)"/>
|
||||
<FIELD NAME="scope" TYPE="text" NOTNULL="true" SEQUENCE="false"/>
|
||||
</FIELDS>
|
||||
<KEYS>
|
||||
<KEY NAME="primary" TYPE="primary" FIELDS="id"/>
|
||||
<KEY NAME="issueridkey" TYPE="foreign-unique" FIELDS="issuerid" REFTABLE="oauth2_issuer" REFFIELDS="id"/>
|
||||
</KEYS>
|
||||
</TABLE>
|
||||
<TABLE NAME="analytics_used_analysables" COMMENT="List of analysables used by each model">
|
||||
<FIELDS>
|
||||
<FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="true"/>
|
||||
|
@ -2771,5 +2771,32 @@ function xmldb_main_upgrade($oldversion) {
|
||||
upgrade_main_savepoint(true, 2018110700.01);
|
||||
}
|
||||
|
||||
if ($oldversion < 2018111300.01) {
|
||||
// Define table oauth2_access_token to be created.
|
||||
$table = new xmldb_table('oauth2_access_token');
|
||||
|
||||
// Adding fields to table oauth2_access_token.
|
||||
$table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
|
||||
$table->add_field('timecreated', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
|
||||
$table->add_field('timemodified', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
|
||||
$table->add_field('usermodified', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
|
||||
$table->add_field('issuerid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
|
||||
$table->add_field('token', XMLDB_TYPE_TEXT, null, null, XMLDB_NOTNULL, null, null);
|
||||
$table->add_field('expires', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
|
||||
$table->add_field('scope', XMLDB_TYPE_TEXT, null, null, XMLDB_NOTNULL, null, null);
|
||||
|
||||
// Adding keys to table oauth2_access_token.
|
||||
$table->add_key('primary', XMLDB_KEY_PRIMARY, ['id']);
|
||||
$table->add_key('issueridkey', XMLDB_KEY_FOREIGN_UNIQUE, ['issuerid'], 'oauth2_issuer', ['id']);
|
||||
|
||||
// Conditionally launch create table for oauth2_access_token.
|
||||
if (!$dbman->table_exists($table)) {
|
||||
$dbman->create_table($table);
|
||||
}
|
||||
|
||||
// Main savepoint reached.
|
||||
upgrade_main_savepoint(true, 2018111300.01);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -396,7 +396,7 @@ abstract class oauth2_client extends curl {
|
||||
/** @var string $scope of the authentication request */
|
||||
protected $scope = '';
|
||||
/** @var stdClass $accesstoken access token object */
|
||||
private $accesstoken = null;
|
||||
protected $accesstoken = null;
|
||||
/** @var string $refreshtoken refresh token string */
|
||||
protected $refreshtoken = '';
|
||||
/** @var string $mocknextresponse string */
|
||||
|
@ -29,7 +29,7 @@
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$version = 2018111300.00; // YYYYMMDD = weekly release date of this DEV branch.
|
||||
$version = 2018111300.01; // YYYYMMDD = weekly release date of this DEV branch.
|
||||
// RR = release increments - 00 in DEV branches.
|
||||
// .XX = incremental changes.
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user