diff options
author | Marcin Łojewski <marcin.lojewski@mlojewski.me> | 2018-10-28 20:30:40 +0300 |
---|---|---|
committer | Marcin Łojewski <marcin.lojewski@mlojewski.me> | 2018-10-28 20:30:40 +0300 |
commit | ac86cf84eb67621e4a6dde805766318c7f33d9fb (patch) | |
tree | e1e7c81682d419208f58c1d13dbbb54aa89e30fd | |
parent | e676ed120a52c1844e73ffc474ae45089b23bde3 (diff) | |
parent | 949543cd750b4dc6df34d6bff7bf78168a2ab864 (diff) |
Merge branch 'release/v4.1.0'v4.1.0
-rw-r--r-- | CHANGELOG.md | 14 | ||||
-rw-r--r-- | README.md | 6 | ||||
-rw-r--r-- | appinfo/info.xml | 2 | ||||
-rw-r--r-- | img/screenshot.png | bin | 44404 -> 47130 bytes | |||
-rw-r--r-- | lib/Action/EmailSync.php | 2 | ||||
-rw-r--r-- | lib/Action/QuotaSync.php | 2 | ||||
-rw-r--r-- | lib/Backend/GroupBackend.php | 4 | ||||
-rw-r--r-- | lib/Backend/UserBackend.php | 41 | ||||
-rw-r--r-- | lib/Constant/Opt.php | 2 | ||||
-rw-r--r-- | lib/Constant/Query.php | 6 | ||||
-rw-r--r-- | lib/Crypto/CryptExtendedDES.php | 2 | ||||
-rw-r--r-- | lib/Crypto/Drupal7.php | 60 | ||||
-rw-r--r-- | lib/Crypto/Phpass.php | 20 | ||||
-rw-r--r-- | lib/Crypto/Whirlpool.php | 58 | ||||
-rw-r--r-- | lib/Query/QueryProvider.php | 31 | ||||
-rw-r--r-- | lib/Repository/UserRepository.php | 75 | ||||
-rw-r--r-- | templates/admin.php | 6 | ||||
-rw-r--r-- | tests/Crypto/CryptExtendedDESTest.php | 2 | ||||
-rw-r--r-- | tests/Crypto/Drupal7Test.php | 61 | ||||
-rw-r--r-- | tests/Crypto/WhirlpoolTest.php | 62 |
20 files changed, 403 insertions, 53 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index bd50fe3..80f5f60 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,18 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). -## [4.0.1] - 2018-08-11 +## [4.1.0] - 2018-10-28 +### Added +- Whirlpool hash algorithm +- 'Prepend salt' toggle +- Drupal 7 hash algorithm +- 'Case-insensitive username' option +### Fixed +- Error when 'Display name' not set +- Encoding of iteration for 'Extended DES (Crypt)' +- 'Trying to get property of non-object' warning + +## [4.0.1] - 2018-08-16 ### Fixed - Leftover lines break the admin page @@ -87,6 +98,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ### Changed - Supported version of ownCloud, Nextcloud: ownCloud 10, Nextcloud 12 +[4.1.0]: https://github.com/nextcloud/user_sql/compare/v4.0.1...v4.1.0 [4.0.1]: https://github.com/nextcloud/user_sql/compare/v4.0.0...v4.0.1 [4.0.0]: https://github.com/nextcloud/user_sql/compare/v4.0.0-rc2...v4.0.0 [4.0.0-rc2]: https://github.com/nextcloud/user_sql/compare/v4.0.0-rc1...v4.0.0-rc2 @@ -49,6 +49,7 @@ Name | Description | Details --- | --- | --- **Allow display name change** | With this option enabled user can change its display name. The display name change is propagated to the database. | Optional.<br/>Default: false.<br/>Requires: user *Display name* column. **Allow password change** | Can user change its password. The password change is propagated to the database. See [Hash algorithms](#hash-algorithms). | Optional.<br/>Default: false. +**Case-insensitive username** | Whether user query should be case-sensitive or case-insensitive. | Optional.<br/>Default: false. **Use cache** | Use database query results cache. The cache can be cleared any time with the *Clear cache* button click. | Optional.<br/>Default: false. **Hash algorithm** | How users passwords are stored in the database. See [Hash algorithms](#hash-algorithms). | Mandatory. **Email sync** | Sync e-mail address with the Nextcloud.<br/>- *None* - Disables this feature. This is the default option.<br/>- *Synchronise only once* - Copy the e-mail address to the Nextcloud preferences if its not set.<br/>- *Nextcloud always wins* - Always copy the e-mail address to the database. This updates the user table.<br/>- *SQL always wins* - Always copy the e-mail address to the Nextcloud preferences. | Optional.<br/>Default: *None*.<br/>Requires: user *Email* column. @@ -72,6 +73,7 @@ Name | Description | Details **Active** | Flag indicating if user can log in. | Optional.<br/>Default: true. **Provide avatar** | Flag indicating if user can change its avatar. | Optional.<br/>Default: false. **Salt** | Salt which is appended to password when checking or changing the password. | Optional. +**Prepend salt** | Prepend a salt to the password instead of appending it. | Optional.<br/>Default: false. #### Group table @@ -184,11 +186,12 @@ Courier base64-encoded SHA256 | No salt supported. | {SHA256}XohImNooBHFR0OVvjcY Unix (Crypt) | See [crypt](http://php.net/manual/en/function.crypt.php). | $2y$10$5rsN1fmoSkaRy9bqhozAXOr0mn0QiVIfd2L04Bbk1Go9MjdvotwBq Argon2 (Crypt) | Requires PHP >= 7.2.<br/>Uses default parameters. See [password_hash](http://php.net/manual/en/function.password-hash.php). | $argon2i$v=19$m=1024,t=2,p=2$NnpSNlRNLlZobnJHUDh0Sw$oW5E1cfdPzLWfkTvQFUyzTR00R0aLwEdYwldcqW6Pmo Blowfish (Crypt) | Uses default parameters. See [password_hash](http://php.net/manual/en/function.password-hash.php). | $2y$10$5rsN1fmoSkaRy9bqhozAXOr0mn0QiVIfd2L04Bbk1Go9MjdvotwBq -Extended DES (Crypt) | | ..UZoIyj/Hy/c +Extended DES (Crypt) | | cDRpdxPmHpzS. MD5 (Crypt) | | $1$RzaFbNcU$u9adfTY/Q6za6nu0Ogrl1/ SHA256 (Crypt) | Generates hash with 5000 rounds. | $5$rounds=5000$VIYD0iHkg7uY9SRc$v2XLS/9dvfFN84mzGvW9wxnVt9Xd/urXaaTkpW8EwD1 SHA512 (Crypt) | Generates hash with 5000 rounds. | $6$rounds=5000$yH.Q0OL4qbCOUJ3q$Xry5EVFva3wKnfo8/ktrugmBd8tcl34NK6rXInv1HhmdSUNLEm0La9JnA57rqwQ.9/Bz513MD4tvmmISLUIHs/ Standard DES (Crypt) | | yTBnb7ab/N072 +Drupal 7 | See [phpass](http://www.openwall.com/phpass/). | $S$DC7eCpJQ3SUQtW4Bp.vKb2rpeaffi4iqk9OpYwJyEoSMsezn67Sl Joomla MD5 Encryption | Generates 32 chars salt. | 14d21b49b0f13e2acba962b6b0039edd:haJK0yTvBXTNMh76xwEw5RYEVpJsN8us MD5 | No salt supported. | 5f4dcc3b5aa765d61d8327deb882cf99 Portable PHP password | See [phpass](http://www.openwall.com/phpass/). | $P$BxrwraqNTi4as0EI.IpiA/K.muk9ke/ @@ -197,6 +200,7 @@ SHA512 Whirlpool | No salt supported. | a96b16ebb691dbe968b0d66d0d924cff5cf5de5e SSHA256 | Generates 32 chars salt. | {SSHA256}+WxTB3JxprNteeovsuSYtgI+UkVPA9lfwGoYkz3Ff7hjd1FSdmlTMkNsSExyR21KM3NvNTZ5V0p4WXJMUjFzUg== SSHA512 | Generates 32 chars salt. | {SSHA512}It+v1kAEUBbhMJYJ2swAtz+RLE6ispv/FB6G/ALhK/YWwEmrloY+0jzrWIfmu+rWUXp8u0Tg4jLXypC5oXAW00IyYnRVdEZJbE9wak96bkNRVWFCYmlJNWxrdTA0QmhL WoltLab Community Framework 2.x | Double salted bcrypt. | $2a$08$XEQDKNU/Vbootwxv5Gp7gujxFX/RUFsZLvQPYM435Dd3/p17fto02 +Whirlpool | | 74dfc2b27acfa364da55f93a5caee29ccad3557247eda238831b3e9bd931b01d77fe994e4f12b9d4cfa92a124461d2065197d8cf7f33fc88566da2db2a4d6eae ## Development diff --git a/appinfo/info.xml b/appinfo/info.xml index b032ba3..77b7291 100644 --- a/appinfo/info.xml +++ b/appinfo/info.xml @@ -8,7 +8,7 @@ Retrieve the users and groups info. Allow the users to change their passwords. Sync the users' email addresses with the addresses stored by Nextcloud. </description> - <version>4.0.1</version> + <version>4.1.0</version> <licence>agpl</licence> <author>Marcin Łojewski</author> <author>Andreas Böhler</author> diff --git a/img/screenshot.png b/img/screenshot.png Binary files differindex a8825c1..2edaf9a 100644 --- a/img/screenshot.png +++ b/img/screenshot.png diff --git a/lib/Action/EmailSync.php b/lib/Action/EmailSync.php index cded1c2..f6ceba4 100644 --- a/lib/Action/EmailSync.php +++ b/lib/Action/EmailSync.php @@ -111,7 +111,7 @@ class EmailSync implements IUserAction } $user->email = $ncMail; - $result = $this->userRepository->save($user); + $result = $this->userRepository->save($user, UserRepository::EMAIL_FIELD); } break; diff --git a/lib/Action/QuotaSync.php b/lib/Action/QuotaSync.php index 7f73c9b..699b1e4 100644 --- a/lib/Action/QuotaSync.php +++ b/lib/Action/QuotaSync.php @@ -111,7 +111,7 @@ class QuotaSync implements IUserAction } $user->quota = $ncQuota; - $result = $this->userRepository->save($user); + $result = $this->userRepository->save($user, UserRepository::QUOTA_FIELD); } break; diff --git a/lib/Backend/GroupBackend.php b/lib/Backend/GroupBackend.php index 6174b26..0f1ef05 100644 --- a/lib/Backend/GroupBackend.php +++ b/lib/Backend/GroupBackend.php @@ -403,10 +403,6 @@ final class GroupBackend extends ABackend implements "Entering getGroupDetails($gid)", ["app" => $this->appName] ); - if (empty($this->properties[DB::GROUP_NAME_COLUMN])) { - return []; - } - $group = $this->getGroup($gid); if (!($group instanceof Group)) { diff --git a/lib/Backend/UserBackend.php b/lib/Backend/UserBackend.php index a39b8fd..e26f708 100644 --- a/lib/Backend/UserBackend.php +++ b/lib/Backend/UserBackend.php @@ -292,14 +292,14 @@ final class UserBackend extends ABackend implements return false; } - $user = $this->userRepository->findByUid($uid); - if (!($user instanceof User)) { + $caseSensitive = empty($this->properties[Opt::CASE_INSENSITIVE_USERNAME]); + $user = $this->userRepository->findByUid($uid, $caseSensitive); + if (!($user instanceof User) || ($caseSensitive && $user->uid !== $uid)) { return false; } - if ($user->salt !== null) { - $password .= $user->salt; - } + $uid = $user->uid; + $password = $this->addSalt($user, $password); $isCorrect = $passwordAlgorithm->checkPassword( $password, $user->password @@ -351,6 +351,27 @@ final class UserBackend extends ABackend implements } /** + * Append or prepend salt from external column if available. + * + * @param User $user The user instance. + * @param string $password The password. + * + * @return string Salted password. + */ + private function addSalt(User $user, string $password): string + { + if ($user->salt !== null) { + if (empty($this->properties[Opt::PREPEND_SALT])) { + return $password . $user->salt; + } else { + return $user->salt . $password; + } + } + + return $password; + } + + /** * @inheritdoc */ public function getDisplayNames($search = "", $limit = null, $offset = null) @@ -368,7 +389,7 @@ final class UserBackend extends ABackend implements $names = []; foreach ($users as $user) { - $names[$user->uid] = $user->name; + $names[$user] = $user->name; } $this->logger->debug( @@ -457,9 +478,7 @@ final class UserBackend extends ABackend implements return false; } - if ($user->salt !== null) { - $password .= $user->salt; - } + $password = $this->addSalt($user, $password); $passwordHash = $passwordAlgorithm->getPasswordHash($password); if ($passwordHash === false) { @@ -467,7 +486,7 @@ final class UserBackend extends ABackend implements } $user->password = $passwordHash; - $result = $this->userRepository->save($user); + $result = $this->userRepository->save($user, UserRepository::PASSWORD_FIELD); if ($result === true) { $this->logger->info( @@ -571,7 +590,7 @@ final class UserBackend extends ABackend implements } $user->name = $displayName; - $result = $this->userRepository->save($user); + $result = $this->userRepository->save($user, UserRepository::DISPLAY_NAME_FIELD); if ($result === true) { $this->logger->info( diff --git a/lib/Constant/Opt.php b/lib/Constant/Opt.php index a1f6617..75b0da6 100644 --- a/lib/Constant/Opt.php +++ b/lib/Constant/Opt.php @@ -28,12 +28,14 @@ namespace OCA\UserSQL\Constant; */ final class Opt { + const CASE_INSENSITIVE_USERNAME = "opt.case_insensitive_username"; const CRYPTO_CLASS = "opt.crypto_class"; const EMAIL_SYNC = "opt.email_sync"; const HOME_LOCATION = "opt.home_location"; const HOME_MODE = "opt.home_mode"; const NAME_CHANGE = "opt.name_change"; const PASSWORD_CHANGE = "opt.password_change"; + const PREPEND_SALT = "opt.prepend_salt"; const QUOTA_SYNC = "opt.quota_sync"; const USE_CACHE = "opt.use_cache"; } diff --git a/lib/Constant/Query.php b/lib/Constant/Query.php index 86511e0..8cbff2c 100644 --- a/lib/Constant/Query.php +++ b/lib/Constant/Query.php @@ -35,9 +35,13 @@ final class Query const FIND_GROUP_USERS = "find_group_users"; const FIND_GROUPS = "find_groups"; const FIND_USER = "find_user"; + const FIND_USER_CASE_INSENSITIVE = "find_user_case_insensitive"; const FIND_USER_GROUPS = "find_user_groups"; const FIND_USERS = "find_users"; - const SAVE_USER = "save_user"; + const UPDATE_DISPLAY_NAME = "update_display_name"; + const UPDATE_EMAIL = "update_email"; + const UPDATE_PASSWORD = "update_password"; + const UPDATE_QUOTA = "update_quota"; const EMAIL_PARAM = "email"; const GID_PARAM = "gid"; diff --git a/lib/Crypto/CryptExtendedDES.php b/lib/Crypto/CryptExtendedDES.php index d6654c4..c91e04c 100644 --- a/lib/Crypto/CryptExtendedDES.php +++ b/lib/Crypto/CryptExtendedDES.php @@ -76,7 +76,7 @@ class CryptExtendedDES extends AbstractCrypt while ($number) { $rem = $number % $base; $number = (int)($number / $base); - $arr[] = $alphabet[$rem]; + $chars[] = $alphabet[$rem]; } return str_pad(implode($chars), 4, ".", STR_PAD_RIGHT); diff --git a/lib/Crypto/Drupal7.php b/lib/Crypto/Drupal7.php new file mode 100644 index 0000000..567e342 --- /dev/null +++ b/lib/Crypto/Drupal7.php @@ -0,0 +1,60 @@ +<?php +/** + * Nextcloud - user_sql + * + * @copyright 2018 Marcin Łojewski <dev@mlojewski.me> + * @author Marcin Łojewski <dev@mlojewski.me> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +namespace OCA\UserSQL\Crypto; + +/** + * Drupal 7 overrides of phpass hash implementation. + * + * @author BrandonKerr + * @author Marcin Łojewski <dev@mlojewski.me> + */ +class Drupal7 extends Phpass +{ + /** + * The expected (and maximum) number of characters in a hashed password. + */ + const DRUPAL_HASH_LENGTH = 55; + + /** + * @inheritdoc + */ + protected function crypt($password, $setting) + { + return substr(parent::crypt($password, $setting), 0, self::DRUPAL_HASH_LENGTH); + } + + /** + * @inheritdoc + */ + protected function hash($input) + { + return hash('sha512', $input, true); + } + + /** + * @inheritdoc + */ + protected function getAlgorithmName() + { + return "Drupal 7"; + } +} diff --git a/lib/Crypto/Phpass.php b/lib/Crypto/Phpass.php index d193917..a430ae3 100644 --- a/lib/Crypto/Phpass.php +++ b/lib/Crypto/Phpass.php @@ -61,7 +61,7 @@ class Phpass extends AbstractAlgorithm * * @return string|null Generated hash. Null on invalid settings. */ - private function crypt($password, $setting) + protected function crypt($password, $setting) { $countLog2 = strpos(self::ITOA64, $setting[3]); if ($countLog2 < 7 || $countLog2 > 30) { @@ -75,18 +75,30 @@ class Phpass extends AbstractAlgorithm return null; } - $hash = md5($salt . $password, true); + $hash = $this->hash($salt . $password); do { - $hash = md5($hash . $password, true); + $hash = $this->hash($hash . $password); } while (--$count); $output = substr($setting, 0, 12); - $output .= $this->encode64($hash, 16); + $output .= $this->encode64($hash, strlen($hash)); return $output; } /** + * Apply hash function to input. + * + * @param string $input Input string. + * + * @return string Hashed input. + */ + protected function hash($input) + { + return md5($input, true); + } + + /** * Encode binary input to base64 string. * * @param string $input Binary data. diff --git a/lib/Crypto/Whirlpool.php b/lib/Crypto/Whirlpool.php new file mode 100644 index 0000000..7ae6360 --- /dev/null +++ b/lib/Crypto/Whirlpool.php @@ -0,0 +1,58 @@ +<?php +/** + * Nextcloud - user_sql + * + * @copyright 2018 Marcin Łojewski <dev@mlojewski.me> + * @author Marcin Łojewski <dev@mlojewski.me> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +namespace OCA\UserSQL\Crypto; + +use OCP\IL10N; + +/** + * Whirlpool hash implementation. + * + * @author Marcin Łojewski <dev@mlojewski.me> + */ +class Whirlpool extends AbstractAlgorithm +{ + /** + * The class constructor. + * + * @param IL10N $localization The localization service. + */ + public function __construct(IL10N $localization) + { + parent::__construct($localization); + } + + /** + * @inheritdoc + */ + public function getPasswordHash($password) + { + return hash('whirlpool', $password); + } + + /** + * @inheritdoc + */ + protected function getAlgorithmName() + { + return "Whirlpool"; + } +} diff --git a/lib/Query/QueryProvider.php b/lib/Query/QueryProvider.php index 85a9f95..cd027d0 100644 --- a/lib/Query/QueryProvider.php +++ b/lib/Query/QueryProvider.php @@ -88,11 +88,11 @@ class QueryProvider implements \ArrayAccess $groupColumns = "$gGID AS gid, " . - (empty($gName) ? "null" : $gName) . " AS name, " . + (empty($gName) ? $gGID : $gName) . " AS name, " . (empty($gAdmin) ? "false" : $gAdmin) . " AS admin"; $userColumns = "$uUID AS uid, " . - (empty($uName) ? "null" : $uName) . " AS name, " . + (empty($uName) ? $uUID : $uName) . " AS name, " . (empty($uEmail) ? "null" : $uEmail) . " AS email, " . (empty($uQuota) ? "null" : $uQuota) . " AS quota, " . (empty($uHome) ? "null" : $uHome) . " AS home, " . @@ -144,6 +144,11 @@ class QueryProvider implements \ArrayAccess "FROM $user " . "WHERE $uUID = :$uidParam", + Query::FIND_USER_CASE_INSENSITIVE => + "SELECT $userColumns, $uPassword AS password " . + "FROM $user " . + "WHERE lower($uUID) = lower(:$uidParam)", + Query::FIND_USER_GROUPS => "SELECT $groupColumns " . "FROM $group, $userGroup " . @@ -157,12 +162,24 @@ class QueryProvider implements \ArrayAccess "WHERE $uUID LIKE :$searchParam " . "ORDER BY $uUID", - Query::SAVE_USER => + Query::UPDATE_DISPLAY_NAME => + "UPDATE $user " . + "SET $uName = :$nameParam " . + "WHERE $uUID = :$uidParam", + + Query::UPDATE_EMAIL => + "UPDATE $user " . + "SET $uEmail = :$emailParam " . + "WHERE $uUID = :$uidParam", + + Query::UPDATE_PASSWORD => + "UPDATE $user " . + "SET $uPassword = :$passwordParam " . + "WHERE $uUID = :$uidParam", + + Query::UPDATE_QUOTA => "UPDATE $user " . - "SET $uPassword = :$passwordParam, " . - "$uName = :$nameParam, " . - "$uEmail = :$emailParam, " . - "$uQuota = :$quotaParam " . + "SET $uQuota = :$quotaParam " . "WHERE $uUID = :$uidParam", ]; } diff --git a/lib/Repository/UserRepository.php b/lib/Repository/UserRepository.php index 8ba593b..9841cf0 100644 --- a/lib/Repository/UserRepository.php +++ b/lib/Repository/UserRepository.php @@ -32,6 +32,11 @@ use OCA\UserSQL\Query\DataQuery; */ class UserRepository { + const DISPLAY_NAME_FIELD = 0b0001; + const EMAIL_FIELD = 0b0010; + const PASSWORD_FIELD = 0b0100; + const QUOTA_FIELD = 0b1000; + /** * @var DataQuery The data query object. */ @@ -48,18 +53,26 @@ class UserRepository } /** - * Get a user entity object. + * Get an user entity object. * - * @param string $uid The user ID. + * @param string $uid The user ID. + * @param bool $caseSensitive TRUE for case sensitive search, + * FALSE for case insensitive search. * * @return User The user entity, NULL if it does not exists or * FALSE on failure. */ - public function findByUid($uid) + public function findByUid($uid, $caseSensitive = true) { - return $this->dataQuery->queryEntity( - Query::FIND_USER, User::class, [Query::UID_PARAM => $uid] - ); + if ($caseSensitive) { + return $this->dataQuery->queryEntity( + Query::FIND_USER, User::class, [Query::UID_PARAM => $uid] + ); + } else { + return $this->dataQuery->queryEntity( + Query::FIND_USER_CASE_INSENSITIVE, User::class, [Query::UID_PARAM => $uid] + ); + } } /** @@ -97,20 +110,48 @@ class UserRepository /** * Save an user entity object. * - * @param User $user The user entity. + * @param User $user The user entity. + * @param int $fields Fields to update. * * @return bool TRUE on success, FALSE otherwise. */ - public function save($user) + public function save($user, $fields) { - return $this->dataQuery->update( - Query::SAVE_USER, [ - Query::NAME_PARAM => $user->name, - Query::PASSWORD_PARAM => $user->password, - Query::EMAIL_PARAM => $user->email, - Query::QUOTA_PARAM => $user->quota, - Query::UID_PARAM => $user->uid - ] - ); + $status = true; + + if ($fields & self::DISPLAY_NAME_FIELD) { + $status =& $this->dataQuery->update( + Query::UPDATE_DISPLAY_NAME, [ + Query::NAME_PARAM => $user->name, + Query::UID_PARAM => $user->uid + ] + ); + } + if ($fields & self::PASSWORD_FIELD) { + $status =& $this->dataQuery->update( + Query::UPDATE_PASSWORD, [ + Query::PASSWORD_PARAM => $user->password, + Query::UID_PARAM => $user->uid + ] + ); + } + if ($fields & self::EMAIL_FIELD) { + $status =& $this->dataQuery->update( + Query::UPDATE_EMAIL, [ + Query::EMAIL_PARAM => $user->email, + Query::UID_PARAM => $user->uid + ] + ); + } + if ($fields & self::QUOTA_FIELD) { + $status =& $this->dataQuery->update( + Query::UPDATE_QUOTA, [ + Query::QUOTA_PARAM => $user->quota, + Query::UID_PARAM => $user->uid + ] + ); + } + + return $status; } } diff --git a/templates/admin.php b/templates/admin.php index 8f05648..b722b8b 100644 --- a/templates/admin.php +++ b/templates/admin.php @@ -109,7 +109,8 @@ function print_select_options( <p class="settings-hint"><?php p($l->t("Here are all currently supported options.")); ?></p> <fieldset><?php print_checkbox_input($l, "opt-name_change", "Allow display name change", $_["opt.name_change"]); - print_checkbox_input($l, "opt-password_change", "Allow password change", $_["opt.password_change"]); ?> + print_checkbox_input($l, "opt-password_change", "Allow password change", $_["opt.password_change"]); + print_checkbox_input($l, "opt-case_insensitive_username", "Case-insensitive username", $_["opt.case_insensitive_username"]); ?> <div class="button-right"><?php print_checkbox_input($l, "opt-use_cache", "Use cache", $_["opt.use_cache"], false); ?> <input type="submit" id="user_sql-clear_cache" value="<?php p($l->t("Clear cache")); ?>"> @@ -151,7 +152,8 @@ function print_select_options( print_text_input($l, "db-table-user-column-name", "Display name", $_["db.table.user.column.name"]); print_text_input($l, "db-table-user-column-active", "Active", $_["db.table.user.column.active"]); print_text_input($l, "db-table-user-column-avatar", "Provide avatar", $_["db.table.user.column.avatar"]); - print_text_input($l, "db-table-user-column-salt", "Salt", $_["db.table.user.column.salt"]); ?> + print_text_input($l, "db-table-user-column-salt", "Salt", $_["db.table.user.column.salt"]); + print_checkbox_input($l, "opt-prepend_salt", "Prepend salt", $_["opt.prepend_salt"]); ?> </fieldset> </div> <div class="section"> diff --git a/tests/Crypto/CryptExtendedDESTest.php b/tests/Crypto/CryptExtendedDESTest.php index c5627e0..5f820b6 100644 --- a/tests/Crypto/CryptExtendedDESTest.php +++ b/tests/Crypto/CryptExtendedDESTest.php @@ -41,7 +41,7 @@ class CryptExtendedDESTest extends TestCase public function testCheckPassword() { $this->assertTrue( - $this->crypto->checkPassword("password", "..UZoIyj/Hy/c") + $this->crypto->checkPassword("password", "cDRpdxPmHpzS.") ); } diff --git a/tests/Crypto/Drupal7Test.php b/tests/Crypto/Drupal7Test.php new file mode 100644 index 0000000..834fcff --- /dev/null +++ b/tests/Crypto/Drupal7Test.php @@ -0,0 +1,61 @@ +<?php +/** + * Nextcloud - user_sql + * + * @copyright 2018 Marcin Łojewski <dev@mlojewski.me> + * @author Marcin Łojewski <dev@mlojewski.me> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +namespace Tests\UserSQL\Crypto; + +use OCA\UserSQL\Crypto\Drupal7; +use OCA\UserSQL\Crypto\IPasswordAlgorithm; +use OCP\IL10N; +use Test\TestCase; + +/** + * Unit tests for class <code>Drupal7</code>. + * + * @author Marcin Łojewski <dev@mlojewski.me> + */ +class Drupal7Test extends TestCase +{ + /** + * @var IPasswordAlgorithm + */ + private $crypto; + + public function testCheckPassword() + { + $this->assertTrue( + $this->crypto->checkPassword( + "password", "\$S\$DC7eCpJQ3SUQtW4Bp.vKb2rpeaffi4iqk9OpYwJyEoSMsezn67Sl" + ) + ); + } + + public function testPasswordHash() + { + $hash = $this->crypto->getPasswordHash("password"); + $this->assertTrue($this->crypto->checkPassword("password", $hash)); + } + + protected function setUp() + { + parent::setUp(); + $this->crypto = new Drupal7($this->createMock(IL10N::class)); + } +} diff --git a/tests/Crypto/WhirlpoolTest.php b/tests/Crypto/WhirlpoolTest.php new file mode 100644 index 0000000..ff92af0 --- /dev/null +++ b/tests/Crypto/WhirlpoolTest.php @@ -0,0 +1,62 @@ +<?php +/** + * Nextcloud - user_sql + * + * @copyright 2018 Marcin Łojewski <dev@mlojewski.me> + * @author Marcin Łojewski <dev@mlojewski.me> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +namespace Tests\UserSQL\Crypto; + +use OCA\UserSQL\Crypto\IPasswordAlgorithm; +use OCA\UserSQL\Crypto\Whirlpool; +use OCP\IL10N; +use Test\TestCase; + +/** + * Unit tests for class <code>SHA512Whirlpool</code>. + * + * @author Marcin Łojewski <dev@mlojewski.me> + */ +class WhirlpoolTest extends TestCase +{ + /** + * @var IPasswordAlgorithm + */ + private $crypto; + + public function testCheckPassword() + { + $this->assertTrue( + $this->crypto->checkPassword( + "password", + "74dfc2b27acfa364da55f93a5caee29ccad3557247eda238831b3e9bd931b01d77fe994e4f12b9d4cfa92a124461d2065197d8cf7f33fc88566da2db2a4d6eae" + ) + ); + } + + public function testPasswordHash() + { + $hash = $this->crypto->getPasswordHash("password"); + $this->assertTrue($this->crypto->checkPassword("password", $hash)); + } + + protected function setUp() + { + parent::setUp(); + $this->crypto = new Whirlpool($this->createMock(IL10N::class)); + } +} |