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
/**
18
 * Class for loading/storing issuers from the DB.
19
 *
20
 * @package    core
21
 * @copyright  2017 Damyon Wiese
22
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
23
 */
24
namespace core\oauth2;
25
 
26
defined('MOODLE_INTERNAL') || die();
27
 
28
use core\persistent;
29
use lang_string;
30
 
31
/**
32
 * Class for loading/storing issuer from the DB
33
 *
34
 * @copyright  2017 Damyon Wiese
35
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
36
 */
37
class issuer extends persistent {
38
 
39
    /** @var int Issuer is displayed on both login page and in the services lists */
40
    const EVERYWHERE = 1;
41
    /** @var int Issuer is displayed on the login page only */
42
    const LOGINONLY = 2;
43
    /** @var int Issuer is displayed only in the services lists and can not be used for login */
44
    const SERVICEONLY = 0;
45
 
46
    const TABLE = 'oauth2_issuer';
47
 
48
    /**
49
     * Return the definition of the properties of this model.
50
     *
51
     * @return array
52
     */
53
    protected static function define_properties() {
54
        return array(
55
            'name' => array(
56
                'type' => PARAM_TEXT
57
            ),
58
            'image' => array(
59
                'type' => PARAM_URL,
60
                'null' => NULL_ALLOWED,
61
                'default' => null
62
            ),
63
            'clientid' => array(
64
                'type' => PARAM_RAW_TRIMMED,
65
                'default' => ''
66
            ),
67
            'clientsecret' => array(
68
                'type' => PARAM_RAW_TRIMMED,
69
                'default' => ''
70
            ),
71
            'baseurl' => array(
72
                'type' => PARAM_URL,
73
                'default' => ''
74
            ),
75
            'enabled' => array(
76
                'type' => PARAM_BOOL,
77
                'default' => true
78
            ),
79
            'showonloginpage' => array(
80
                'type' => PARAM_INT,
81
                'default' => self::SERVICEONLY,
82
            ),
83
            'basicauth' => array(
84
                'type' => PARAM_BOOL,
85
                'default' => false
86
            ),
87
            'scopessupported' => array(
88
                'type' => PARAM_RAW,
89
                'null' => NULL_ALLOWED,
90
                'default' => null
91
            ),
92
            'loginscopes' => array(
93
                'type' => PARAM_RAW,
94
                'default' => 'openid profile email'
95
            ),
96
            'loginscopesoffline' => array(
97
                'type' => PARAM_RAW,
98
                'default' => 'openid profile email'
99
            ),
100
            'loginparams' => array(
101
                'type' => PARAM_RAW,
102
                'default' => ''
103
            ),
104
            'loginparamsoffline' => array(
105
                'type' => PARAM_RAW,
106
                'default' => ''
107
            ),
108
            'alloweddomains' => array(
109
                'type' => PARAM_RAW,
110
                'default' => ''
111
            ),
112
            'sortorder' => array(
113
                'type' => PARAM_INT,
114
                'default' => 0,
115
            ),
116
            'requireconfirmation' => array(
117
                'type' => PARAM_BOOL,
118
                'default' => true
119
            ),
120
            'servicetype' => array(
121
                'type' => PARAM_ALPHANUM,
122
                'null' => NULL_ALLOWED,
123
                'default' => null,
124
            ),
125
            'loginpagename' => array(
126
                'type' => PARAM_TEXT,
127
                'null' => NULL_ALLOWED,
128
                'default' => null,
129
            ),
130
        );
131
    }
132
 
133
    /**
134
     * Hook to execute before validate.
135
     *
136
     * @return void
137
     */
138
    protected function before_validate() {
139
        if (($this->get('id') && $this->get('sortorder') === null) || !$this->get('id')) {
140
            $this->set('sortorder', $this->count_records());
141
        }
142
    }
143
 
144
    /**
145
     * Helper the get a named service endpoint.
146
     * @param string $type
147
     * @return string|false
148
     */
149
    public function get_endpoint_url($type) {
150
        $endpoint = endpoint::get_record([
151
            'issuerid' => $this->get('id'),
152
            'name' => $type . '_endpoint'
153
        ]);
154
 
155
        if ($endpoint) {
156
            return $endpoint->get('url');
157
        }
158
        return false;
159
    }
160
 
161
    /**
162
     * Perform matching against the list of allowed login domains for this issuer.
163
     *
164
     * @param string $email The email to check.
165
     * @return boolean
166
     */
167
    public function is_valid_login_domain($email) {
168
        if (empty($this->get('alloweddomains'))) {
169
            return true;
170
        }
171
 
172
        $validdomains = explode(',', $this->get('alloweddomains'));
173
 
174
        $parts = explode('@', $email, 2);
175
        $emaildomain = '';
176
        if (count($parts) > 1) {
177
            $emaildomain = $parts[1];
178
        }
179
 
180
        return \core\ip_utils::is_domain_in_allowed_list($emaildomain, $validdomains);
181
    }
182
 
183
    /**
184
     * Does this OAuth service support user authentication?
185
     * @return boolean
186
     */
187
    public function is_authentication_supported() {
188
        debugging('Method is_authentication_supported() is deprecated, please use is_available_for_login()',
189
            DEBUG_DEVELOPER);
190
        return (!empty($this->get_endpoint_url('userinfo')));
191
    }
192
 
193
    /**
194
     * Is this issue fully configured and enabled and can be used for login/signup
195
     *
196
     * @return bool
197
     * @throws \coding_exception
198
     */
199
    public function is_available_for_login(): bool {
200
        return $this->get('id') &&
201
            $this->is_configured() &&
202
            $this->get('showonloginpage') != self::SERVICEONLY &&
203
            $this->get('enabled') &&
204
            !empty($this->get_endpoint_url('userinfo'));
205
    }
206
 
207
    /**
208
     * Return true if this issuer looks like it has been configured.
209
     *
210
     * @return boolean
211
     */
212
    public function is_configured() {
213
        return (!empty($this->get('clientid')) && !empty($this->get('clientsecret')));
214
    }
215
 
216
    /**
217
     * Do we have a refresh token for a system account?
218
     * @return boolean
219
     */
220
    public function is_system_account_connected() {
221
        if (!$this->is_configured()) {
222
            return false;
223
        }
224
        $sys = system_account::get_record(['issuerid' => $this->get('id')]);
225
        if (empty($sys) || empty($sys->get('refreshtoken'))) {
226
            return false;
227
        }
228
 
229
        $scopes = api::get_system_scopes_for_issuer($this);
230
 
231
        $grantedscopes = $sys->get('grantedscopes');
232
 
233
        $scopes = explode(' ', $scopes);
234
 
235
        foreach ($scopes as $scope) {
236
            if (!empty($scope)) {
237
                if (strpos(' ' . $grantedscopes . ' ', ' ' . $scope . ' ') === false) {
238
                    // We have not been granted all the scopes that are required.
239
                    return false;
240
                }
241
            }
242
        }
243
 
244
        return true;
245
    }
246
 
247
    /**
248
     * Custom validator for end point URLs.
249
     * Because we send Bearer tokens we must ensure SSL.
250
     *
251
     * @param string $value The value to check.
252
     * @return lang_string|boolean
253
     */
254
    protected function validate_baseurl($value) {
255
        global $CFG;
256
        include_once($CFG->dirroot . '/lib/validateurlsyntax.php');
257
        if (!empty($value) && !validateUrlSyntax($value, 'S+')) {
258
            return new lang_string('sslonlyaccess', 'error');
259
        }
260
        return true;
261
    }
262
 
263
    /**
264
     * Display name for the issuers used on the login page
265
     *
266
     * @return string
267
     */
268
    public function get_display_name(): string {
269
        return $this->get('loginpagename') ? $this->get('loginpagename') : $this->get('name');
270
    }
271
}