diff --git a/admin/tool/oauth2/tests/behat/basic_settings.feature b/admin/tool/oauth2/tests/behat/basic_settings.feature new file mode 100644 index 00000000000..2eb33451ac6 --- /dev/null +++ b/admin/tool/oauth2/tests/behat/basic_settings.feature @@ -0,0 +1,303 @@ +@tool @tool_oauth2 @external +Feature: Basic OAuth2 functionality + In order to use them later for authentication or repository plugins + As an administrator + I need to add a manage customised OAuth2 services. + + Background: + Given I log in as "admin" + And I navigate to "Server > OAuth 2 services" in site administration + + Scenario: Create, edit and delete standard service for Google + Given I press "Google" + And I should see "Create new service: Google" + And I set the following fields to these values: + | Name | Testing service | + | Client ID | thisistheclientid | + | Client secret | supersecret | + When I press "Save changes" + Then I should see "Changes saved" + And I should see "Testing service" + And "Configured" "icon" should exist in the "Testing service" "table_row" + And "Allow login" "icon" should exist in the "Testing service" "table_row" + And "Service discovery successful" "icon" should exist in the "Testing service" "table_row" + And I click on "Configure endpoints" "link" in the "Testing service" "table_row" + And I should see "https://accounts.google.com/.well-known/openid-configuration" in the "discovery_endpoint" "table_row" + And I should see "authorization_endpoint" + And I follow "OAuth 2 services" + And I click on "Configure user field mappings" "link" in the "Testing service" "table_row" + And I should see "firstname" in the "given_name" "table_row" + And I should see "middlename" in the "middle_name" "table_row" + And I follow "OAuth 2 services" + And I click on "Edit" "link" in the "Testing service" "table_row" + And I set the following fields to these values: + | Name | Testing service modified | + And I press "Save changes" + And I should see "Changes saved" + And I should see "Testing service modified" + And I click on "Delete" "link" in the "Testing service modified" "table_row" + And I should see "Are you sure you want to delete the identity issuer \"Testing service modified\"?" + And I press "Continue" + And I should see "Identity issuer deleted" + And I should not see "Testing service modified" + + Scenario: Create, edit and delete standard service for Microsoft + Given I press "Microsoft" + And I should see "Create new service: Microsoft" + And I set the following fields to these values: + | Name | Testing service | + | Client ID | thisistheclientid | + | Client secret | supersecret | + When I press "Save changes" + Then I should see "Changes saved" + And I should see "Testing service" + And "Configured" "icon" should exist in the "Testing service" "table_row" + And "Allow login" "icon" should exist in the "Testing service" "table_row" + And I should see "-" in the "Testing service" "table_row" + And I click on "Configure endpoints" "link" in the "Testing service" "table_row" + And I should see "authorization_endpoint" + And I should not see "discovery_endpoint" + And I follow "OAuth 2 services" + And I click on "Configure user field mappings" "link" in the "Testing service" "table_row" + And I should see "firstname" in the "givenName" "table_row" + And I follow "OAuth 2 services" + And I click on "Edit" "link" in the "Testing service" "table_row" + And I set the following fields to these values: + | Name | Testing service modified | + And I press "Save changes" + And I should see "Changes saved" + And I should see "Testing service modified" + And I click on "Delete" "link" in the "Testing service modified" "table_row" + And I should see "Are you sure you want to delete the identity issuer \"Testing service modified\"?" + And I press "Continue" + And I should see "Identity issuer deleted" + And I should not see "Testing service modified" + + Scenario: Create, edit and delete standard service for Facebook + Given I press "Facebook" + And I should see "Create new service: Facebook" + And I set the following fields to these values: + | Name | Testing service | + | Client ID | thisistheclientid | + | Client secret | supersecret | + When I press "Save changes" + Then I should see "Changes saved" + And I should see "Testing service" + And "Configured" "icon" should exist in the "Testing service" "table_row" + And "Allow login" "icon" should exist in the "Testing service" "table_row" + And I should see "-" in the "Testing service" "table_row" + And I click on "Configure endpoints" "link" in the "Testing service" "table_row" + And I should see "authorization_endpoint" + And I should not see "discovery_endpoint" + And I follow "OAuth 2 services" + And I click on "Configure user field mappings" "link" in the "Testing service" "table_row" + And I should see "firstname" in the "first_name" "table_row" + And I follow "OAuth 2 services" + And I click on "Edit" "link" in the "Testing service" "table_row" + And I set the following fields to these values: + | Name | Testing service modified | + And I press "Save changes" + And I should see "Changes saved" + And I should see "Testing service modified" + And I click on "Delete" "link" in the "Testing service modified" "table_row" + And I should see "Are you sure you want to delete the identity issuer \"Testing service modified\"?" + And I press "Continue" + And I should see "Identity issuer deleted" + And I should not see "Testing service modified" + + @javascript + Scenario: Create, edit and delete standard service for Nextcloud + Given I press "Nextcloud" + And I should see "Create new service: Nextcloud" + And I set the following fields to these values: + | Name | Testing service | + | Client ID | thisistheclientid | + | Client secret | supersecret | + And I press "Save changes" + And I should see "You must supply a value here." + And I set the following fields to these values: + | Service base URL | https://dummy.local/nextcloud/ | + When I press "Save changes" + Then I should see "Changes saved" + And I should see "Testing service" + And "Configured" "icon" should exist in the "Testing service" "table_row" + And "Do not allow login" "icon" should exist in the "Testing service" "table_row" + And I should see "-" in the "Testing service" "table_row" + And I click on "Configure endpoints" "link" in the "Testing service" "table_row" + And I should see "authorization_endpoint" + And I should not see "discovery_endpoint" + And I follow "OAuth 2 services" + And I click on "Configure user field mappings" "link" in the "Testing service" "table_row" + And I should see "username" in the "ocs-data-id" "table_row" + And I follow "OAuth 2 services" + And I click on "Edit" "link" in the "Testing service" "table_row" + And I set the following fields to these values: + | Name | Testing service modified | + And I press "Save changes" + And I should see "Could not discover service endpoints" + And I should see "Testing service modified" + And I click on "Delete" "link" in the "Testing service modified" "table_row" + And I should see "Are you sure you want to delete the identity issuer \"Testing service modified\"?" + And I press "Continue" + And I should see "Identity issuer deleted" + And I should not see "Testing service modified" + + Scenario: Create, edit and delete standard service for IMS OBv2.1 + Given I press "IMS OBv2.1" + And I should see "Create new service: IMS OBv2.1" + And I set the following fields to these values: + | Client ID | thisistheclientid | + | Client secret | supersecret | + | Service base URL | https://dc.imsglobal.org/ | + When I press "Save changes" + Then I should see "Changes saved" + And I should see "IMS OBv2.1" + And "Configured" "icon" should exist in the "IMS OBv2.1" "table_row" + And "Do not allow login" "icon" should exist in the "IMS OBv2.1" "table_row" + And "Service discovery successful" "icon" should exist in the "IMS OBv2.1" "table_row" + And the "src" attribute of "table.admintable th img" "css_element" should contain "IMS-Global-Logo.png" + And I click on "Configure endpoints" "link" in the "IMS OBv2.1" "table_row" + And I should see "https://dc.imsglobal.org/.well-known/badgeconnect.json" in the "discovery_endpoint" "table_row" + And I should see "authorization_endpoint" + And I follow "OAuth 2 services" + And I click on "Configure user field mappings" "link" in the "IMS OBv2.1" "table_row" + And I should not see "given_name" + And I should not see "middle_name" + And I follow "OAuth 2 services" + And I click on "Edit" "link" in the "IMS OBv2.1" "table_row" + And I set the following fields to these values: + | Name | IMS Global | + And I press "Save changes" + And I should see "Changes saved" + And I should see "IMS Global" + And I click on "Delete" "link" in the "IMS Global" "table_row" + And I should see "Are you sure you want to delete the identity issuer \"IMS Global\"?" + And I press "Continue" + And I should see "Identity issuer deleted" + And I should not see "IMS Global" + + Scenario: Create, edit and delete valid custom OIDC service + Given I press "Custom" + And I should see "Create new service: Custom" + And I set the following fields to these values: + | Name | Google custom | + | Client ID | thisistheclientid | + | Client secret | supersecret | + | Service base URL | https://accounts.google.com/ | + When I press "Save changes" + Then I should see "Changes saved" + And I should see "Google custom" + And "Configured" "icon" should exist in the "Google custom" "table_row" + And "Do not allow login" "icon" should exist in the "Google custom" "table_row" + And "Service discovery successful" "icon" should exist in the "Google custom" "table_row" + And the "src" attribute of "table.admintable th img" "css_element" should contain "favicon.ico" + And I click on "Configure endpoints" "link" in the "Google custom" "table_row" + And I should see "https://accounts.google.com/.well-known/openid-configuration" in the "discovery_endpoint" "table_row" + And I should see "authorization_endpoint" + And I follow "OAuth 2 services" + And I click on "Configure user field mappings" "link" in the "Google custom" "table_row" + And I should see "firstname" in the "given_name" "table_row" + And I should see "middlename" in the "middle_name" "table_row" + And I follow "OAuth 2 services" + And I click on "Edit" "link" in the "Google custom" "table_row" + And I set the following fields to these values: + | Name | Google custom modified | + And I press "Save changes" + And I should see "Changes saved" + And I should see "Google custom modified" + And I click on "Delete" "link" in the "Google custom modified" "table_row" + And I should see "Are you sure you want to delete the identity issuer \"Google custom modified\"?" + And I press "Continue" + And I should see "Identity issuer deleted" + And I should not see "Google custom modified" + + Scenario: Create, edit and delete invalid custom OIDC service + Given I press "Custom" + And I should see "Create new service: Custom" + And I set the following fields to these values: + | Name | Invalid custom service | + | Client ID | thisistheclientid | + | Client secret | supersecret | + | Service base URL | https://dc.imsglobal.org/ | + When I press "Save changes" + Then I should see "Could not discover end points for identity issuer: Invalid custom service" + And I should see "URL: https://dc.imsglobal.org/.well-known/openid-configuration" + And "Configured" "icon" should exist in the "Invalid custom service" "table_row" + And "Do not allow login" "icon" should exist in the "Invalid custom service" "table_row" + And I should see "-" in the "Invalid custom service" "table_row" + And I click on "Configure endpoints" "link" in the "Invalid custom service" "table_row" + And I should not see "discovery_endpoint" + And I follow "OAuth 2 services" + And I click on "Configure user field mappings" "link" in the "Invalid custom service" "table_row" + And I should not see "given_name" + And I should not see "middle_name" + And I follow "OAuth 2 services" + And I click on "Edit" "link" in the "Invalid custom service" "table_row" + And I set the following fields to these values: + | Name | Valid custom service | + | Service base URL | https://accounts.google.com/ | + And I press "Save changes" + And "Configured" "icon" should exist in the "Valid custom" "table_row" + And "Do not allow login" "icon" should exist in the "Valid custom" "table_row" + And "Service discovery successful" "icon" should exist in the "Valid custom" "table_row" + And I click on "Edit" "link" in the "Valid custom service" "table_row" + And I set the following fields to these values: + | Name | Invalid custom service | + | Service base URL | https://dc.imsglobal.org/ | + And I press "Save changes" + Then I should see "Could not discover end points for identity issuer: Invalid custom service" + And I should see "-" in the "Invalid custom service" "table_row" + And I click on "Delete" "link" in the "Invalid custom service" "table_row" + And I should see "Are you sure you want to delete the identity issuer \"Invalid custom service\"?" + And I press "Continue" + And I should see "Identity issuer deleted" + And I should not see "Invalid custom service" + + Scenario: Create, edit and delete empty custom OIDC service + Given I press "Custom" + And I should see "Create new service: Custom" + And I set the following fields to these values: + | Name | Empty custom service | + | Client ID | thisistheclientid | + | Client secret | supersecret | + When I press "Save changes" + And I should see "Changes saved" + And I should see "Empty custom service" + And "Configured" "icon" should exist in the "Empty custom service" "table_row" + And "Do not allow login" "icon" should exist in the "Empty custom service" "table_row" + And I should see "-" in the "Empty custom service" "table_row" + And I click on "Configure endpoints" "link" in the "Empty custom service" "table_row" + And I should not see "discovery_endpoint" + And I follow "OAuth 2 services" + And I click on "Configure user field mappings" "link" in the "Empty custom service" "table_row" + And I should not see "given_name" + And I should not see "middle_name" + And I follow "OAuth 2 services" + And I click on "Edit" "link" in the "Empty custom service" "table_row" + # Check it works as expected too without slash at the end of the service base URL. + And I set the following fields to these values: + | Name | Valid custom service | + | Service base URL | https://accounts.google.com | + And I press "Save changes" + And "Configured" "icon" should exist in the "Valid custom" "table_row" + And "Do not allow login" "icon" should exist in the "Valid custom" "table_row" + And "Service discovery successful" "icon" should exist in the "Valid custom" "table_row" + And I click on "Edit" "link" in the "Valid custom service" "table_row" + And I set the following fields to these values: + | Name | Invalid custom service | + | Service base URL | https://dc.imsglobal.org/ | + And I press "Save changes" + Then I should see "Could not discover end points for identity issuer: Invalid custom service" + And I should see "-" in the "Invalid custom service" "table_row" + And I click on "Edit" "link" in the "Invalid custom service" "table_row" + And I set the following fields to these values: + | Name | Empty custom service | + | Service base URL | | + And I press "Save changes" + And I should see "Changes saved" + And I should see "Empty custom service" + And I click on "Delete" "link" in the "Empty custom service" "table_row" + And I should see "Are you sure you want to delete the identity issuer \"Empty custom service\"?" + And I press "Continue" + And I should see "Identity issuer deleted" + And I should not see "Empty custom service" diff --git a/lib/tests/oauth2_test.php b/lib/tests/oauth2_test.php index 26fd9e21512..09595adf9d5 100644 --- a/lib/tests/oauth2_test.php +++ b/lib/tests/oauth2_test.php @@ -252,4 +252,118 @@ class core_oauth2_testcase extends advanced_testcase { $this->assertTrue($issuer->is_valid_login_domain('longer.example@sub.example.com')); } + /** + * Test endpoints creation for issuers. + * @dataProvider create_endpoints_for_standard_issuer_provider + * + * @covers ::create_endpoints_for_standard_issuer + * + * @param string $type Issuer type to create. + * @param string|null $discoveryurl Expected discovery URL or null if this endpoint doesn't exist. + * @param bool $hasmappingfields True if it's expected the issuer to create has mapping fields. + * @param string|null $baseurl The service URL (mandatory parameter for some issuers, such as NextCloud or IMS OBv2.1). + * @param string|null $expectedexception Name of the expected expection or null if no exception will be thrown. + */ + public function test_create_endpoints_for_standard_issuer(string $type, ?string $discoveryurl = null, + bool $hasmappingfields = true, ?string $baseurl = null, ?string $expectedexception = null): void { + + $this->resetAfterTest(); + + // Mark test as long because it connects with external services. + if (!PHPUNIT_LONGTEST) { + $this->markTestSkipped('PHPUNIT_LONGTEST is not defined'); + } + + $this->setAdminUser(); + + // Method create_endpoints_for_standard_issuer is called internally from create_standard_issuer. + if ($expectedexception) { + $this->expectException($expectedexception); + } + $issuer = \core\oauth2\api::create_standard_issuer($type, $baseurl); + + // Check endpoints have been created. + $endpoints = \core\oauth2\api::get_endpoints($issuer); + $this->assertNotEmpty($endpoints); + $this->assertNotEmpty($issuer->get('image')); + // Check discovery URL. + if ($discoveryurl) { + $this->assertStringContainsString($discoveryurl, $issuer->get_endpoint_url('discovery')); + } else { + $this->assertFalse($issuer->get_endpoint_url('discovery')); + } + // Check userfield mappings. + $userfieldmappings = core\oauth2\api::get_user_field_mappings($issuer); + if ($hasmappingfields) { + $this->assertNotEmpty($userfieldmappings); + } else { + $this->assertEmpty($userfieldmappings); + } + } + + /** + * Data provider for test_create_endpoints_for_standard_issuer. + * + * @return array + */ + public function create_endpoints_for_standard_issuer_provider(): array { + return [ + 'Google' => [ + 'type' => 'google', + 'discoveryurl' => '.well-known/openid-configuration', + ], + 'Google will work too with a valid baseurl parameter' => [ + 'type' => 'google', + 'discoveryurl' => '.well-known/openid-configuration', + 'hasmappingfields' => true, + 'baseurl' => 'https://accounts.google.com/', + ], + 'IMS OBv2.1' => [ + 'type' => 'imsobv2p1', + 'discoveryurl' => '.well-known/badgeconnect.json', + 'hasmappingfields' => false, + 'baseurl' => 'https://dc.imsglobal.org/', + ], + 'IMS OBv2.1 without slash in baseurl should work too' => [ + 'type' => 'imsobv2p1', + 'discoveryurl' => '.well-known/badgeconnect.json', + 'hasmappingfields' => false, + 'baseurl' => 'https://dc.imsglobal.org', + ], + 'IMS OBv2.1 with empty baseurl should return an exception' => [ + 'type' => 'imsobv2p1', + 'discoveryurl' => null, + 'hasmappingfields' => false, + 'baseurl' => null, + 'expectedexception' => \moodle_exception::class, + ], + 'Microsoft' => [ + 'type' => 'microsoft', + ], + 'Facebook' => [ + 'type' => 'facebook', + ], + 'NextCloud' => [ + 'type' => 'nextcloud', + 'discoveryurl' => null, + 'hasmappingfields' => true, + 'baseurl' => 'https://dummy.local/nextcloud/', + ], + 'NextCloud with empty baseurl should return an exception' => [ + 'type' => 'nextcloud', + 'discoveryurl' => null, + 'hasmappingfields' => true, + 'baseurl' => null, + 'expectedexception' => \moodle_exception::class, + ], + 'Invalid type should return an exception' => [ + 'type' => 'fictitious', + 'discoveryurl' => null, + 'hasmappingfields' => true, + 'baseurl' => null, + 'expectedexception' => \moodle_exception::class, + ], + ]; + } + }