MDL-70725 oauth2: move expectException to separate method
[moodle.git] / lib / tests / oauth2_test.php
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/>.
17 /**
18  * Tests for oauth2 apis (\core\oauth2\*).
19  *
20  * @package    core
21  * @copyright  2017 Damyon Wiese
22  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later.
23  */
25 defined('MOODLE_INTERNAL') || die();
27 /**
28  * Tests for oauth2 apis (\core\oauth2\*).
29  *
30  * @package    core
31  * @copyright  2017 Damyon Wiese
32  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later.
33  */
34 class core_oauth2_testcase extends advanced_testcase {
36     /**
37      * Tests the crud operations on oauth2 issuers.
38      */
39     public function test_create_and_delete_standard_issuers() {
40         $this->resetAfterTest();
41         $this->setAdminUser();
42         \core\oauth2\api::create_standard_issuer('google');
43         \core\oauth2\api::create_standard_issuer('facebook');
44         \core\oauth2\api::create_standard_issuer('microsoft');
45         \core\oauth2\api::create_standard_issuer('nextcloud', 'https://dummy.local/nextcloud/');
47         $issuers = \core\oauth2\api::get_all_issuers();
49         $this->assertEquals($issuers[0]->get('name'), 'Google');
50         $this->assertEquals($issuers[1]->get('name'), 'Facebook');
51         $this->assertEquals($issuers[2]->get('name'), 'Microsoft');
52         $this->assertEquals($issuers[3]->get('name'), 'Nextcloud');
54         \core\oauth2\api::move_down_issuer($issuers[0]->get('id'));
56         $issuers = \core\oauth2\api::get_all_issuers();
58         $this->assertEquals($issuers[0]->get('name'), 'Facebook');
59         $this->assertEquals($issuers[1]->get('name'), 'Google');
60         $this->assertEquals($issuers[2]->get('name'), 'Microsoft');
61         $this->assertEquals($issuers[3]->get('name'), 'Nextcloud');
63         \core\oauth2\api::delete_issuer($issuers[1]->get('id'));
65         $issuers = \core\oauth2\api::get_all_issuers();
67         $this->assertEquals($issuers[0]->get('name'), 'Facebook');
68         $this->assertEquals($issuers[1]->get('name'), 'Microsoft');
69         $this->assertEquals($issuers[2]->get('name'), 'Nextcloud');
70     }
72     /**
73      * Tests the crud operations on oauth2 issuers.
74      */
75     public function test_create_nextcloud_without_url() {
76         $this->resetAfterTest();
77         $this->setAdminUser();
79         $this->expectException(\moodle_exception::class);
80         \core\oauth2\api::create_standard_issuer('nextcloud');
81     }
83     /**
84      * Tests we can list and delete each of the persistents related to an issuer.
85      */
86     public function test_getters() {
87         $this->resetAfterTest();
88         $this->setAdminUser();
89         $issuer = \core\oauth2\api::create_standard_issuer('microsoft');
91         $same = \core\oauth2\api::get_issuer($issuer->get('id'));
93         foreach ($same->properties_definition() as $name => $def) {
94             $this->assertTrue($issuer->get($name) == $same->get($name));
95         }
97         $endpoints = \core\oauth2\api::get_endpoints($issuer);
98         $same = \core\oauth2\api::get_endpoint($endpoints[0]->get('id'));
99         $this->assertEquals($endpoints[0]->get('id'), $same->get('id'));
100         $this->assertEquals($endpoints[0]->get('name'), $same->get('name'));
102         $todelete = $endpoints[0];
103         \core\oauth2\api::delete_endpoint($todelete->get('id'));
104         $endpoints = \core\oauth2\api::get_endpoints($issuer);
105         $this->assertNotEquals($endpoints[0]->get('id'), $todelete->get('id'));
107         $userfields = \core\oauth2\api::get_user_field_mappings($issuer);
108         $same = \core\oauth2\api::get_user_field_mapping($userfields[0]->get('id'));
109         $this->assertEquals($userfields[0]->get('id'), $same->get('id'));
111         $todelete = $userfields[0];
112         \core\oauth2\api::delete_user_field_mapping($todelete->get('id'));
113         $userfields = \core\oauth2\api::get_user_field_mappings($issuer);
114         $this->assertNotEquals($userfields[0]->get('id'), $todelete->get('id'));
115     }
117     /**
118      * Data provider for \core_oauth2_testcase::test_get_system_oauth_client().
119      *
120      * @return array
121      */
122     public function system_oauth_client_provider() {
123         return [
124             [
125                 (object) [
126                     'access_token' => 'fdas...',
127                     'token_type' => 'Bearer',
128                     'expires_in' => '3600',
129                     'id_token' => 'llfsd..',
130                 ], HOURSECS - 10
131             ],
132             [
133                 (object) [
134                     'access_token' => 'fdas...',
135                     'token_type' => 'Bearer',
136                     'id_token' => 'llfsd..',
137                 ], WEEKSECS
138             ],
139         ];
140     }
142     /**
143      * Tests we can get a logged in oauth client for a system account.
144      *
145      * @dataProvider system_oauth_client_provider
146      * @param stdClass $responsedata The response data to be mocked.
147      * @param int $expiresin The expected expiration time.
148      */
149     public function test_get_system_oauth_client($responsedata, $expiresin) {
150         $this->resetAfterTest();
151         $this->setAdminUser();
153         $issuer = \core\oauth2\api::create_standard_issuer('microsoft');
155         $requiredscopes = \core\oauth2\api::get_system_scopes_for_issuer($issuer);
156         // Fake a system account.
157         $data = (object) [
158             'issuerid' => $issuer->get('id'),
159             'refreshtoken' => 'abc',
160             'grantedscopes' => $requiredscopes,
161             'email' => 'sys@example.com',
162             'username' => 'sys'
163         ];
164         $sys = new \core\oauth2\system_account(0, $data);
165         $sys->create();
167         // Fake a response with an access token.
168         $response = json_encode($responsedata);
169         curl::mock_response($response);
170         $client = \core\oauth2\api::get_system_oauth_client($issuer);
171         $this->assertTrue($client->is_logged_in());
173         // Check token expiry.
174         $accesstoken = \core\oauth2\access_token::get_record(['issuerid' => $issuer->get('id')]);
176         // Get the difference between the actual and expected expiry times.
177         // They might differ by a couple of seconds depending on the timing when the token gets actually processed.
178         $expiresdifference = time() + $expiresin - $accesstoken->get('expires');
180         // Assert that the actual token expiration is more or less the same as the expected.
181         $this->assertGreaterThanOrEqual(0, $expiresdifference);
182         $this->assertLessThanOrEqual(3, $expiresdifference);
183     }
185     /**
186      * Tests we can enable and disable an issuer.
187      */
188     public function test_enable_disable_issuer() {
189         $this->resetAfterTest();
190         $this->setAdminUser();
192         $issuer = \core\oauth2\api::create_standard_issuer('microsoft');
194         $issuerid = $issuer->get('id');
196         \core\oauth2\api::enable_issuer($issuerid);
197         $check = \core\oauth2\api::get_issuer($issuer->get('id'));
198         $this->assertTrue((boolean)$check->get('enabled'));
200         \core\oauth2\api::enable_issuer($issuerid);
201         $check = \core\oauth2\api::get_issuer($issuer->get('id'));
202         $this->assertTrue((boolean)$check->get('enabled'));
204         \core\oauth2\api::disable_issuer($issuerid);
205         $check = \core\oauth2\api::get_issuer($issuer->get('id'));
206         $this->assertFalse((boolean)$check->get('enabled'));
208         \core\oauth2\api::enable_issuer($issuerid);
209         $check = \core\oauth2\api::get_issuer($issuer->get('id'));
210         $this->assertTrue((boolean)$check->get('enabled'));
211     }
213     /**
214      * Test the alloweddomains for an issuer.
215      */
216     public function test_issuer_alloweddomains() {
217         $this->resetAfterTest();
218         $this->setAdminUser();
220         $issuer = \core\oauth2\api::create_standard_issuer('microsoft');
222         $issuer->set('alloweddomains', '');
224         // Anything is allowed when domain is empty.
225         $this->assertTrue($issuer->is_valid_login_domain(''));
226         $this->assertTrue($issuer->is_valid_login_domain('a@b'));
227         $this->assertTrue($issuer->is_valid_login_domain('longer.example@example.com'));
229         $issuer->set('alloweddomains', 'example.com');
231         // One domain - must match exactly - no substrings etc.
232         $this->assertFalse($issuer->is_valid_login_domain(''));
233         $this->assertFalse($issuer->is_valid_login_domain('a@b'));
234         $this->assertFalse($issuer->is_valid_login_domain('longer.example@example'));
235         $this->assertTrue($issuer->is_valid_login_domain('longer.example@example.com'));
237         $issuer->set('alloweddomains', 'example.com,example.net');
238         // Multiple domains - must match any exactly - no substrings etc.
239         $this->assertFalse($issuer->is_valid_login_domain(''));
240         $this->assertFalse($issuer->is_valid_login_domain('a@b'));
241         $this->assertFalse($issuer->is_valid_login_domain('longer.example@example'));
242         $this->assertFalse($issuer->is_valid_login_domain('invalid@email@example.net'));
243         $this->assertTrue($issuer->is_valid_login_domain('longer.example@example.net'));
244         $this->assertTrue($issuer->is_valid_login_domain('longer.example@example.com'));
246         $issuer->set('alloweddomains', '*.example.com');
247         // Wildcard.
248         $this->assertFalse($issuer->is_valid_login_domain(''));
249         $this->assertFalse($issuer->is_valid_login_domain('a@b'));
250         $this->assertFalse($issuer->is_valid_login_domain('longer.example@example'));
251         $this->assertFalse($issuer->is_valid_login_domain('longer.example@example.com'));
252         $this->assertTrue($issuer->is_valid_login_domain('longer.example@sub.example.com'));
253     }