Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 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\service;
18
 
19
use core\http_client;
20
use core\oauth2\discovery\auth_server_config_reader;
21
use core\oauth2\endpoint;
22
use core\oauth2\issuer;
23
use GuzzleHttp\Psr7\Request;
24
 
25
/**
26
 * MoodleNet OAuth 2 configuration.
27
 *
28
 * @package    core
29
 * @copyright  2023 Jake Dallimore <jrhdallimore@gmail.com>
30
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
31
 */
32
class moodlenet implements issuer_interface {
33
 
34
    /**
35
     * Get the issuer template to display in the form.
36
     *
37
     * @return issuer the issuer.
38
     */
39
    public static function init(): ?issuer {
40
        $record = (object) [
41
            'name' => 'MoodleNet',
42
            'image' => 'https://moodle.net/favicon.ico',
43
            'baseurl' => 'https://moodle.net',
44
            'loginscopes' => '',
45
            'loginscopesoffline' => '',
46
            'loginparamsoffline' => '',
47
            'showonloginpage' => issuer::SERVICEONLY,
48
            'servicetype' => 'moodlenet',
49
        ];
50
        $issuer = new issuer(0, $record);
51
 
52
        return $issuer;
53
    }
54
 
55
    /**
56
     * Create the endpoints for the issuer.
57
     *
58
     * @param issuer $issuer the issuer instance.
59
     * @return issuer the issuer instance.
60
     */
61
    public static function create_endpoints(issuer $issuer): issuer {
62
        self::discover_endpoints($issuer);
63
        return $issuer;
64
    }
65
 
66
    /**
67
     * Read the OAuth 2 Auth Server Metadata.
68
     *
69
     * @param issuer $issuer the issuer instance.
70
     * @return int the number of endpoints created.
71
     */
72
    public static function discover_endpoints($issuer): int {
73
        $baseurl = $issuer->get('baseurl');
74
        if (empty($baseurl)) {
75
            return 0;
76
        }
77
 
78
        $endpointscreated = 0;
79
        $config = [];
80
        if (defined('BEHAT_SITE_RUNNING')) {
81
            $config['verify'] = false;
82
        }
83
        $configreader = new auth_server_config_reader(new http_client($config));
84
        try {
85
            $config = $configreader->read_configuration(new \moodle_url($baseurl));
86
 
87
            foreach ($config as $key => $value) {
88
                if (substr_compare($key, '_endpoint', -strlen('_endpoint')) === 0) {
89
                    $record = new \stdClass();
90
                    $record->issuerid = $issuer->get('id');
91
                    $record->name = $key;
92
                    $record->url = $value;
93
 
94
                    $endpoint = new endpoint(0, $record);
95
                    $endpoint->create();
96
                    $endpointscreated++;
97
                }
98
 
99
                if ($key == 'scopes_supported') {
100
                    $issuer->set('scopessupported', implode(' ', $value));
101
                    $issuer->update();
102
                }
103
            }
104
        } catch (\Exception $e) {
105
            throw new \moodle_exception('Could not read service configuration for issuer: ' . $issuer->get('name'));
106
        }
107
 
108
        try {
109
            self::client_registration($issuer);
110
        } catch (\Exception $e) {
111
            throw new \moodle_exception('Could not register client for issuer: ' . $issuer->get('name'));
112
        }
113
 
114
        return $endpointscreated;
115
    }
116
 
117
    /**
118
     * Perform (open) OAuth 2 Dynamic Client Registration with the MoodleNet application.
119
     *
120
     * @param issuer $issuer the issuer instance containing the service baseurl.
121
     * @return void
122
     */
123
    protected static function client_registration(issuer $issuer): void {
124
        global $CFG, $SITE;
125
 
126
        $clientid = $issuer->get('clientid');
127
        $clientsecret = $issuer->get('clientsecret');
128
 
129
        if (empty($clientid) && empty($clientsecret)) {
130
            $url = $issuer->get_endpoint_url('registration');
131
            if ($url) {
132
                $scopes = str_replace("\r", " ", $issuer->get('scopessupported'));
133
                $hosturl = $CFG->wwwroot;
134
 
135
                $request = [
136
                    'client_name' => $SITE->fullname,
137
                    'client_uri' => $hosturl,
138
                    'logo_uri' => $hosturl . '/pix/moodlelogo.png',
139
                    'tos_uri' => $hosturl,
140
                    'policy_uri' => $hosturl,
141
                    'software_id' => 'moodle',
142
                    'software_version' => $CFG->version,
143
                    'redirect_uris' => [
144
                        $hosturl . '/admin/oauth2callback.php'
145
                    ],
146
                    'token_endpoint_auth_method' => 'client_secret_basic',
147
                    'grant_types' => [
148
                        'authorization_code',
149
                        'refresh_token'
150
                    ],
151
                    'response_types' => [
152
                        'code'
153
                    ],
154
                    'scope' => $scopes
155
                ];
156
 
157
                $config = [];
158
                if (defined('BEHAT_SITE_RUNNING')) {
159
                    $config['verify'] = false;
160
                }
161
                $client = new http_client($config);
162
                $request = new Request(
163
                    'POST',
164
                    $url,
165
                    [
166
                        'Content-type' => 'application/json',
167
                        'Accept' => 'application/json',
168
                    ],
169
                    json_encode($request)
170
                );
171
 
172
                try {
173
                    $response = $client->send($request);
174
                    $responsebody = $response->getBody()->getContents();
175
                    $decodedbody = json_decode($responsebody, true);
176
                    if (is_null($decodedbody)) {
177
                        throw new \moodle_exception('Error: ' . __METHOD__ . ': Failed to decode response body. Invalid JSON.');
178
                    }
179
                    $issuer->set('clientid', $decodedbody['client_id']);
180
                    $issuer->set('clientsecret', $decodedbody['client_secret']);
181
                    $issuer->update();
182
                } catch (\Exception $e) {
183
                    $msg = "Could not self-register {$issuer->get('name')}. Wrong URL or JSON data [URL: $url]";
184
                    throw new \moodle_exception($msg);
185
                }
186
            }
187
        }
188
    }
189
}