diff --git a/changelog/unreleased/36613 b/changelog/unreleased/36613 new file mode 100644 index 000000000000..9137af6930eb --- /dev/null +++ b/changelog/unreleased/36613 @@ -0,0 +1,5 @@ +Enhancement: Allow plus sign in username + +The plus sign is now allowed in a username, e.g. John+Smith + +https://github.com/owncloud/core/pull/36613 diff --git a/core/Command/User/Add.php b/core/Command/User/Add.php index cfbdd894a3f2..90200cee05b7 100644 --- a/core/Command/User/Add.php +++ b/core/Command/User/Add.php @@ -64,7 +64,7 @@ protected function configure() { ->addArgument( 'uid', InputArgument::REQUIRED, - 'User ID used to login (must only contain a-z, A-Z, 0-9, -, _ and @).' + 'User ID used to login (must only contain a-z, A-Z, 0-9, "+_.@-\'").' ) ->addOption( 'password-from-env', diff --git a/lib/private/User/Manager.php b/lib/private/User/Manager.php index 3e24b65d1d5f..bc732d66d34b 100644 --- a/lib/private/User/Manager.php +++ b/lib/private/User/Manager.php @@ -332,10 +332,10 @@ public function createUser($uid, $password) { $l = \OC::$server->getL10N('lib'); // Check the name for bad characters - // Allowed are: "a-z", "A-Z", "0-9" and "_.@-'" - if (\preg_match('/[^a-zA-Z0-9 _\.@\-\']/', $uid)) { + // Allowed are: "a-z", "A-Z", "0-9" and "+_.@-'" + if (\preg_match('/[^a-zA-Z0-9 \+_\.@\-\']/', $uid)) { throw new \Exception($l->t('Only the following characters are allowed in a username:' - . ' "a-z", "A-Z", "0-9", and "_.@-\'"')); + . ' "a-z", "A-Z", "0-9", and "+_.@-\'"')); } // No empty username if (\trim($uid) == '') { diff --git a/tests/acceptance/features/apiProvisioning-v1/addUser.feature b/tests/acceptance/features/apiProvisioning-v1/addUser.feature index 74eaedb3139a..9a380174526e 100644 --- a/tests/acceptance/features/apiProvisioning-v1/addUser.feature +++ b/tests/acceptance/features/apiProvisioning-v1/addUser.feature @@ -16,6 +16,18 @@ Feature: add user And user "brand-new-user" should exist And user "brand-new-user" should be able to access a skeleton file + Scenario Outline: admin creates a user with special characters in the username + Given user "" has been deleted + When the administrator sends a user creation request for user "" password "%alt1%" using the provisioning API + Then the OCS status code should be "100" + And the HTTP status code should be "200" + And user "" should exist + And user "" should be able to access a skeleton file + Examples: + | username | + | a@-+_.b | + | a space | + Scenario: admin tries to create an existing user Given user "brand-new-user" has been created with default attributes and skeleton files When the administrator sends a user creation request for user "brand-new-user" password "%alt1%" using the provisioning API diff --git a/tests/acceptance/features/apiProvisioning-v1/deleteUser.feature b/tests/acceptance/features/apiProvisioning-v1/deleteUser.feature index 68707f416061..9b6b12b279aa 100644 --- a/tests/acceptance/features/apiProvisioning-v1/deleteUser.feature +++ b/tests/acceptance/features/apiProvisioning-v1/deleteUser.feature @@ -15,6 +15,19 @@ Feature: delete users And the HTTP status code should be "200" And user "brand-new-user" should not exist + Scenario Outline: Delete a user with special characters in the username + Given these users have been created with skeleton files: + | username | email | + | | | + When the administrator deletes user "" using the provisioning API + Then the OCS status code should be "100" + And the HTTP status code should be "200" + And user "" should not exist + Examples: + | username | email | + | a@-+_.b | a.b@example.com | + | a space | a.space@example.com | + Scenario: Delete a user, and specify the user name in different case Given user "brand-new-user" has been created with default attributes and skeleton files When the administrator deletes user "Brand-New-User" using the provisioning API diff --git a/tests/acceptance/features/apiProvisioning-v1/disableUser.feature b/tests/acceptance/features/apiProvisioning-v1/disableUser.feature index 691a6a9100e5..a045810de44f 100644 --- a/tests/acceptance/features/apiProvisioning-v1/disableUser.feature +++ b/tests/acceptance/features/apiProvisioning-v1/disableUser.feature @@ -15,6 +15,19 @@ Feature: disable user And the HTTP status code should be "200" And user "user1" should be disabled + Scenario Outline: admin disables an user with special characters in the username + Given these users have been created with skeleton files: + | username | email | + | | | + When the administrator disables user "" using the provisioning API + Then the OCS status code should be "100" + And the HTTP status code should be "200" + And user "" should be disabled + Examples: + | username | email | + | a@-+_.b | a.b@example.com | + | a space | a.space@example.com | + @smokeTest Scenario: Subadmin should be able to disable an user in their group Given these users have been created with default attributes and skeleton files: diff --git a/tests/acceptance/features/apiProvisioning-v1/editUser.feature b/tests/acceptance/features/apiProvisioning-v1/editUser.feature index e67b85edeb92..a3ceb756335e 100644 --- a/tests/acceptance/features/apiProvisioning-v1/editUser.feature +++ b/tests/acceptance/features/apiProvisioning-v1/editUser.feature @@ -15,6 +15,19 @@ Feature: edit users And the OCS status code should be "100" And the email address of user "brand-new-user" should be "brand-new-user@example.com" + Scenario Outline: the administrator can edit a user email of an user with special characters in the username + Given these users have been created with skeleton files: + | username | email | + | | | + When the administrator changes the email of user "" to "a-different-email@example.com" using the provisioning API + Then the HTTP status code should be "200" + And the OCS status code should be "100" + And the email address of user "" should be "a-different-email@example.com" + Examples: + | username | email | + | a@-+_.b | a.b@example.com | + | a space | a.space@example.com | + @smokeTest Scenario: the administrator can edit a user display (the API allows editing the "display name" by using the key word "display") Given user "brand-new-user" has been created with default attributes and skeleton files diff --git a/tests/acceptance/features/apiProvisioning-v1/enableUser.feature b/tests/acceptance/features/apiProvisioning-v1/enableUser.feature index f2798a5112b0..b9142ecd22ba 100644 --- a/tests/acceptance/features/apiProvisioning-v1/enableUser.feature +++ b/tests/acceptance/features/apiProvisioning-v1/enableUser.feature @@ -16,6 +16,20 @@ Feature: enable user And the HTTP status code should be "200" And user "user1" should be enabled + Scenario Outline: admin enables an user with special characters in the username + Given these users have been created with skeleton files: + | username | email | + | | | + And user "" has been disabled + When the administrator enables user "" using the provisioning API + Then the OCS status code should be "100" + And the HTTP status code should be "200" + And user "" should be enabled + Examples: + | username | email | + | a@-+_.b | a.b@example.com | + | a space | a.space@example.com | + Scenario: admin enables another admin user Given user "another-admin" has been created with default attributes and skeleton files And user "another-admin" has been added to group "admin" diff --git a/tests/acceptance/features/apiProvisioning-v1/getUser.feature b/tests/acceptance/features/apiProvisioning-v1/getUser.feature index 9bce792b64d5..096b90628b6e 100644 --- a/tests/acceptance/features/apiProvisioning-v1/getUser.feature +++ b/tests/acceptance/features/apiProvisioning-v1/getUser.feature @@ -18,6 +18,21 @@ Feature: get user And the display name returned by the API should be "Brand New User" And the quota definition returned by the API should be "default" + Scenario Outline: admin gets an existing user with special characters in the username + Given these users have been created with skeleton files: + | username | displayname | email | + | | | | + When the administrator retrieves the information of user "" using the provisioning API + Then the OCS status code should be "100" + And the HTTP status code should be "200" + And the display name returned by the API should be "" + And the email address returned by the API should be "" + And the quota definition returned by the API should be "default" + Examples: + | username | displayname | email | + | a@-+_.b | A weird b | a.b@example.com | + | a space | A Space Name | a.space@example.com | + Scenario: admin tries to get a not existing user When the administrator retrieves the information of user "not-a-user" using the provisioning API Then the OCS status code should be "998" diff --git a/tests/acceptance/features/apiProvisioning-v2/addUser.feature b/tests/acceptance/features/apiProvisioning-v2/addUser.feature index 9cef2a178df8..a72abd826038 100644 --- a/tests/acceptance/features/apiProvisioning-v2/addUser.feature +++ b/tests/acceptance/features/apiProvisioning-v2/addUser.feature @@ -16,6 +16,18 @@ Feature: add user And user "brand-new-user" should exist And user "brand-new-user" should be able to access a skeleton file + Scenario Outline: admin creates a user with special characters in the username + Given user "" has been deleted + When the administrator sends a user creation request for user "" password "%alt1%" using the provisioning API + Then the OCS status code should be "200" + And the HTTP status code should be "200" + And user "" should exist + And user "" should be able to access a skeleton file + Examples: + | username | + | a@-+_.b | + | a space | + Scenario: admin tries to create an existing user Given user "brand-new-user" has been created with default attributes and skeleton files When the administrator sends a user creation request for user "brand-new-user" password "%alt1%" using the provisioning API diff --git a/tests/acceptance/features/apiProvisioning-v2/deleteUser.feature b/tests/acceptance/features/apiProvisioning-v2/deleteUser.feature index e3fa5c5fc117..c618f99bf58b 100644 --- a/tests/acceptance/features/apiProvisioning-v2/deleteUser.feature +++ b/tests/acceptance/features/apiProvisioning-v2/deleteUser.feature @@ -15,6 +15,19 @@ Feature: delete users And the HTTP status code should be "200" And user "brand-new-user" should not exist + Scenario Outline: Delete a user with special characters in the username + Given these users have been created with skeleton files: + | username | email | + | | | + When the administrator deletes user "" using the provisioning API + Then the OCS status code should be "200" + And the HTTP status code should be "200" + And user "" should not exist + Examples: + | username | email | + | a@-+_.b | a.b@example.com | + | a space | a.space@example.com | + Scenario: Delete a user, and specify the user name in different case Given user "brand-new-user" has been created with default attributes and skeleton files When the administrator deletes user "Brand-New-User" using the provisioning API diff --git a/tests/acceptance/features/apiProvisioning-v2/disableUser.feature b/tests/acceptance/features/apiProvisioning-v2/disableUser.feature index 234d82bba22b..b809d258fe9c 100644 --- a/tests/acceptance/features/apiProvisioning-v2/disableUser.feature +++ b/tests/acceptance/features/apiProvisioning-v2/disableUser.feature @@ -15,6 +15,19 @@ Feature: disable user And the HTTP status code should be "200" And user "user1" should be disabled + Scenario Outline: admin disables an user with special characters in the username + Given these users have been created with skeleton files: + | username | email | + | | | + When the administrator disables user "" using the provisioning API + Then the OCS status code should be "200" + And the HTTP status code should be "200" + And user "" should be disabled + Examples: + | username | email | + | a@-+_.b | a.b@example.com | + | a space | a.space@example.com | + @smokeTest Scenario: Subadmin should be able to disable an user in their group Given these users have been created with default attributes and skeleton files: diff --git a/tests/acceptance/features/apiProvisioning-v2/editUser.feature b/tests/acceptance/features/apiProvisioning-v2/editUser.feature index c169763b1fb9..e31501bbdf71 100644 --- a/tests/acceptance/features/apiProvisioning-v2/editUser.feature +++ b/tests/acceptance/features/apiProvisioning-v2/editUser.feature @@ -15,6 +15,19 @@ Feature: edit users And the OCS status code should be "200" And the email address of user "brand-new-user" should be "brand-new-user@example.com" + Scenario Outline: the administrator can edit a user email of an user with special characters in the username + Given these users have been created with skeleton files: + | username | email | + | | | + When the administrator changes the email of user "" to "a-different-email@example.com" using the provisioning API + Then the HTTP status code should be "200" + And the OCS status code should be "200" + And the email address of user "" should be "a-different-email@example.com" + Examples: + | username | email | + | a@-+_.b | a.b@example.com | + | a space | a.space@example.com | + @smokeTest Scenario: the administrator can edit a user display (the API allows editing the "display name" by using the key word "display") Given user "brand-new-user" has been created with default attributes and skeleton files diff --git a/tests/acceptance/features/apiProvisioning-v2/enableUser.feature b/tests/acceptance/features/apiProvisioning-v2/enableUser.feature index 763ef2233cc3..fa6f07a1a01d 100644 --- a/tests/acceptance/features/apiProvisioning-v2/enableUser.feature +++ b/tests/acceptance/features/apiProvisioning-v2/enableUser.feature @@ -16,6 +16,20 @@ Feature: enable user And the HTTP status code should be "200" And user "user1" should be enabled + Scenario Outline: admin enables an user with special characters in the username + Given these users have been created with skeleton files: + | username | email | + | | | + And user "" has been disabled + When the administrator enables user "" using the provisioning API + Then the OCS status code should be "200" + And the HTTP status code should be "200" + And user "" should be enabled + Examples: + | username | email | + | a@-+_.b | a.b@example.com | + | a space | a.space@example.com | + Scenario: admin enables another admin user Given user "another-admin" has been created with default attributes and skeleton files And user "another-admin" has been added to group "admin" diff --git a/tests/acceptance/features/apiProvisioning-v2/getUser.feature b/tests/acceptance/features/apiProvisioning-v2/getUser.feature index b661dd1c9efb..7ef50c39e951 100644 --- a/tests/acceptance/features/apiProvisioning-v2/getUser.feature +++ b/tests/acceptance/features/apiProvisioning-v2/getUser.feature @@ -18,6 +18,21 @@ Feature: get user And the display name returned by the API should be "Brand New User" And the quota definition returned by the API should be "default" + Scenario Outline: admin gets an existing user with special characters in the username + Given these users have been created with skeleton files: + | username | displayname | email | + | | | | + When the administrator retrieves the information of user "" using the provisioning API + Then the OCS status code should be "200" + And the HTTP status code should be "200" + And the display name returned by the API should be "" + And the email address returned by the API should be "" + And the quota definition returned by the API should be "default" + Examples: + | username | displayname | email | + | a@-+_.b | A weird b | a.b@example.com | + | a space | A Space Name | a.space@example.com | + Scenario: admin tries to get a not existing user When the administrator retrieves the information of user "not-a-user" using the provisioning API Then the OCS status code should be "404" diff --git a/tests/acceptance/features/cliProvisioning/addUser.feature b/tests/acceptance/features/cliProvisioning/addUser.feature index 5035e16ad056..8ff83c3c44c5 100644 --- a/tests/acceptance/features/cliProvisioning/addUser.feature +++ b/tests/acceptance/features/cliProvisioning/addUser.feature @@ -6,14 +6,18 @@ Feature: add a user using the using the occ command So that I can give people controlled individual access to resources on the ownCloud server and So that I can write scripts to add users - Scenario: admin creates an ordinary user using the occ command + Scenario Outline: admin creates an ordinary user using the occ command When the administrator creates this user using the occ command: + | username | + | | + Then the command should have been successful + And the command output should contain the text 'The user "" was created successfully' + And user "" should exist + And user "" should be able to access a skeleton file + Examples: | username | | justauser | - Then the command should have been successful - And the command output should contain the text 'The user "justauser" was created successfully' - And user "justauser" should exist - And user "justauser" should be able to access a skeleton file + | a@-+_.b | Scenario: admin creates an ordinary user specifying attributes using the occ command When the administrator creates this user using the occ command: diff --git a/tests/acceptance/features/webUIAddUsers/addUsers.feature b/tests/acceptance/features/webUIAddUsers/addUsers.feature index abb61999e91e..d26022d8edaf 100644 --- a/tests/acceptance/features/webUIAddUsers/addUsers.feature +++ b/tests/acceptance/features/webUIAddUsers/addUsers.feature @@ -15,19 +15,19 @@ Feature: add users Then the user should be redirected to a webUI page with the title "Files - %productname%" Scenario: use the webUI to create a user with special valid characters - When the administrator creates a user with the name "@-_.'" and the password "%regular%" using the webUI + When the administrator creates a user with the name "@-+_.'" and the password "%regular%" using the webUI And the administrator logs out of the webUI - And user "@-_.'" logs in using the webUI + And user "@-+_.'" logs in using the webUI Then the user should be redirected to a webUI page with the title "Files - %productname%" Scenario: use the webUI to create a user with special invalid characters When the administrator attempts to create these users then the notifications should be as listed - | user | password | notification | - | a#% | "%regular%" | Error creating user: Only the following characters are allowed in a username: "a-z", "A-Z", "0-9", and "_.@-'" | - | a+^ | "%alt1%" | Error creating user: Only the following characters are allowed in a username: "a-z", "A-Z", "0-9", and "_.@-'" | - | a)~ | "%alt2%" | Error creating user: Only the following characters are allowed in a username: "a-z", "A-Z", "0-9", and "_.@-'" | - | a(= | "%alt3%" | Error creating user: Only the following characters are allowed in a username: "a-z", "A-Z", "0-9", and "_.@-'" | - | a`*^ | "%alt4%" | Error creating user: Only the following characters are allowed in a username: "a-z", "A-Z", "0-9", and "_.@-'" | + | user | password | notification | + | a#% | "%regular%" | Error creating user: Only the following characters are allowed in a username: "a-z", "A-Z", "0-9", and "+_.@-'" | + | a+^ | "%alt1%" | Error creating user: Only the following characters are allowed in a username: "a-z", "A-Z", "0-9", and "+_.@-'" | + | a)~ | "%alt2%" | Error creating user: Only the following characters are allowed in a username: "a-z", "A-Z", "0-9", and "+_.@-'" | + | a(= | "%alt3%" | Error creating user: Only the following characters are allowed in a username: "a-z", "A-Z", "0-9", and "+_.@-'" | + | a`*^ | "%alt4%" | Error creating user: Only the following characters are allowed in a username: "a-z", "A-Z", "0-9", and "+_.@-'" | Scenario: use the webUI to create a user with empty password When the administrator attempts to create a user with the name "bijay" and the password "" using the webUI @@ -71,7 +71,7 @@ Feature: add users Examples: | username | comment | | guiusr1 | simple user-name | - | a@-_.'b | complicated user-name | + | a@-+_.'b | complicated user-name | Scenario Outline: user sets his own password but retypes it wrongly after being created with an Email address only When the administrator creates a user with the name "" and the email "guiusr1@owncloud" without a password using the webUI @@ -85,7 +85,7 @@ Feature: add users Examples: | username | comment | | guiusr1 | simple user-name | - | a@-_.'b | complicated user-name | + | a@-+_.'b | complicated user-name | Scenario Outline: webUI refuses to create users with invalid Email addresses When the administrator creates a user with the name "guiusr1" and the email "" without a password using the webUI diff --git a/tests/lib/User/ManagerTest.php b/tests/lib/User/ManagerTest.php index 5f76f5f94619..3a30e7597edb 100644 --- a/tests/lib/User/ManagerTest.php +++ b/tests/lib/User/ManagerTest.php @@ -302,7 +302,66 @@ public function testUsernameMaxLength() { $this->expectException(\Exception::class); $this->expectExceptionMessage('The username can not be longer than 64 characters'); $this->manager = \OC::$server->getUserManager(); - $user = $this->manager->createUser('testuser123456789012345678901234567890123456789012345678901234567890', 'testuser1'); + $this->manager->createUser('testuser123456789012345678901234567890123456789012345678901234567890', 'testuser1'); + } + + public function testUsernameMinLength() { + $this->expectException(\Exception::class); + $this->expectExceptionMessage('The username must be at least 3 characters long'); + $this->manager = \OC::$server->getUserManager(); + $this->manager->createUser('u2', 'testuser'); + } + + public function testUsernameIsJustWhiteSpace() { + $this->expectException(\Exception::class); + $this->expectExceptionMessage('A valid username must be provided'); + $this->manager = \OC::$server->getUserManager(); + $this->manager->createUser(' ', 'testuser'); + } + + public function usernameWhiteSpaceDataProvider() { + return [ + [' spaceBefore'], + ['spaceAfter '], + [' space before and after '], + ]; + } + + /** + * @dataProvider usernameWhiteSpaceDataProvider + * @param $uid string + */ + public function testUsernameWhiteSpace($uid) { + $this->expectException(\Exception::class); + $this->expectExceptionMessage('Username contains whitespace at the beginning or at the end'); + $this->manager = \OC::$server->getUserManager(); + $this->manager->createUser($uid, 'testuser'); + } + + public function usernameHasInvalidCharsDataProvider() { + return [ + ['John#Smith'], + ['John^Smith'], + ['JohnSmith(CEO)'], + ]; + } + + /** + * @dataProvider usernameHasInvalidCharsDataProvider + * @param $uid string + */ + public function testUsernameHasInvalidChars($uid) { + $this->expectException(\Exception::class); + $this->expectExceptionMessage('Only the following characters are allowed in a username: "a-z", "A-Z", "0-9", and "+_.@-\'"'); + $this->manager = \OC::$server->getUserManager(); + $this->manager->createUser($uid, 'testuser'); + } + + public function testPasswordIsNotJustWhiteSpace() { + $this->expectException(\Exception::class); + $this->expectExceptionMessage('A valid password must be provided'); + $this->manager = \OC::$server->getUserManager(); + $this->manager->createUser('testuser', ' '); } public function testNullUidMakesNoQueryToAccountsTable() {