See Release Notes
Long Term Support Release
Differences Between: [Versions 311 and 401] [Versions 401 and 403]
1 <?php 2 // This file is part of Moodle - http://moodle.org/ 3 // 4 // Moodle is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // Moodle is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU General Public License for more details. 13 // 14 // You should have received a copy of the GNU General Public License 15 // along with Moodle. If not, see <http://www.gnu.org/licenses/>. 16 17 namespace core\oauth2\discovery; 18 19 use curl; 20 use stdClass; 21 use moodle_exception; 22 use core\oauth2\issuer; 23 use core\oauth2\endpoint; 24 25 /** 26 * Class for IMS Open Badge Connect API (aka OBv2.1) discovery definition. 27 * 28 * @package core 29 * @since Moodle 3.11 30 * @copyright 2021 Sara Arjona (sara@moodle.com) 31 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 32 */ 33 class imsbadgeconnect extends base_definition { 34 35 /** 36 * Get the URL for the discovery manifest. 37 * 38 * @param issuer $issuer The OAuth issuer the endpoints should be discovered for. 39 * @return string The URL of the discovery file, containing the endpoints. 40 */ 41 public static function get_discovery_endpoint_url(issuer $issuer): string { 42 $url = $issuer->get('baseurl'); 43 if (!empty($url)) { 44 // Add slash at the end of the base url. 45 $url .= (substr($url, -1) == '/' ? '' : '/'); 46 // Append the well-known file for IMS OBv2.1. 47 $url .= '.well-known/badgeconnect.json'; 48 } 49 50 return $url; 51 } 52 53 /** 54 * Process the discovery information and create endpoints defined with the expected format. 55 * 56 * @param issuer $issuer The OAuth issuer the endpoints should be discovered for. 57 * @param stdClass $info The discovery information, with the endpoints to process and create. 58 * @return void 59 */ 60 protected static function process_configuration_json(issuer $issuer, stdClass $info): void { 61 $info = array_pop($info->badgeConnectAPI); 62 foreach ($info as $key => $value) { 63 if (substr_compare($key, 'Url', - strlen('Url')) === 0 && !empty($value)) { 64 $record = new stdClass(); 65 $record->issuerid = $issuer->get('id'); 66 // Convert key names from xxxxUrl to xxxx_endpoint, in order to make it compliant with the Moodle oAuth API. 67 $record->name = strtolower(substr($key, 0, - strlen('Url'))) . '_endpoint'; 68 $record->url = $value; 69 70 $endpoint = new endpoint(0, $record); 71 $endpoint->create(); 72 } else if ($key == 'scopesOffered') { 73 // Get and update supported scopes. 74 $issuer->set('scopessupported', implode(' ', $value)); 75 $issuer->update(); 76 } else if ($key == 'image' && empty($issuer->get('image'))) { 77 // Update the image with the value in the manifest file if it's valid and empty in the issuer. 78 $url = filter_var($value, FILTER_SANITIZE_URL); 79 // Remove multiple slashes in URL. It will fix the Badgr bug with image URL defined in their manifest. 80 $url = preg_replace('/([^:])(\/{2,})/', '$1/', $url); 81 if (filter_var($url, FILTER_VALIDATE_URL) !== false) { 82 $issuer->set('image', $url); 83 $issuer->update(); 84 } 85 } else if ($key == 'apiBase') { 86 (new endpoint(0, (object) [ 87 'issuerid' => $issuer->get('id'), 88 'name' => $key, 89 'url' => $value, 90 ]))->create(); 91 } else if ($key == 'name') { 92 // Get and update issuer name. 93 $issuer->set('name', $value); 94 $issuer->update(); 95 } 96 } 97 } 98 99 /** 100 * Process how to map user field information. 101 * 102 * @param issuer $issuer The OAuth issuer the endpoints should be discovered for. 103 * @return void 104 */ 105 protected static function create_field_mappings(issuer $issuer): void { 106 // In that case, there are no user fields to map. 107 } 108 109 /** 110 * Self-register the issuer if the 'registration' endpoint exists and client id and secret aren't defined. 111 * 112 * @param issuer $issuer The OAuth issuer to register. 113 * @return void 114 */ 115 protected static function register(issuer $issuer): void { 116 global $CFG, $SITE; 117 118 $clientid = $issuer->get('clientid'); 119 $clientsecret = $issuer->get('clientsecret'); 120 121 // Registration request for getting client id and secret will be done only they are empty in the issuer. 122 // For now this can't be run from PHPUNIT (because IMS testing platform needs real URLs). In the future, this 123 // request can be moved to the moodle-exttests repository. 124 if (empty($clientid) && empty($clientsecret) && (!defined('PHPUNIT_TEST') || !PHPUNIT_TEST)) { 125 $url = $issuer->get_endpoint_url('registration'); 126 if ($url) { 127 $scopes = str_replace("\r", " ", $issuer->get('scopessupported')); 128 129 // Add slash at the end of the site URL. 130 $hosturl = $CFG->wwwroot; 131 $hosturl .= (substr($CFG->wwwroot, -1) == '/' ? '' : '/'); 132 133 // Create the registration request following the format defined in the IMS OBv2.1 specification. 134 $request = [ 135 'client_name' => $SITE->fullname, 136 'client_uri' => $hosturl, 137 'logo_uri' => $hosturl . 'pix/f/moodle-256.png', 138 'tos_uri' => $hosturl, 139 'policy_uri' => $hosturl, 140 'software_id' => 'moodle', 141 'software_version' => $CFG->version, 142 'redirect_uris' => [ 143 $hosturl . 'admin/oauth2callback.php' 144 ], 145 'token_endpoint_auth_method' => 'client_secret_basic', 146 'grant_types' => [ 147 'authorization_code', 148 'refresh_token' 149 ], 150 'response_types' => [ 151 'code' 152 ], 153 'scope' => $scopes 154 ]; 155 $jsonrequest = json_encode($request); 156 157 $curl = new curl(); 158 $curl->setHeader(['Content-type: application/json']); 159 $curl->setHeader(['Accept: application/json']); 160 161 // Send the registration request. 162 if (!$jsonresponse = $curl->post($url, $jsonrequest)) { 163 $msg = 'Could not self-register identity issuer: ' . $issuer->get('name') . 164 ". Wrong URL or JSON data [URL: $url]"; 165 throw new moodle_exception($msg); 166 } 167 168 // Process the response and update client id and secret if they are valid. 169 $response = json_decode($jsonresponse); 170 if (property_exists($response, 'client_id')) { 171 $issuer->set('clientid', $response->client_id); 172 $issuer->set('clientsecret', $response->client_secret); 173 $issuer->update(); 174 } else { 175 $msg = 'Could not self-register identity issuer: ' . $issuer->get('name') . 176 '. Invalid response ' . $jsonresponse; 177 throw new moodle_exception($msg); 178 } 179 } 180 } 181 } 182 183 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body