diff --git a/.horde.yml b/.horde.yml index 8628602..03231d1 100644 --- a/.horde.yml +++ b/.horde.yml @@ -7,3 +7,57 @@ description: > for the Horde authentication system. list: dev type: library +homepage: https://www.horde.org/libraries/Horde_Auth +authors: + - + name: Chuck Hagenbuch + user: chuck + email: chuck@horde.org + active: true + role: lead + - + name: Jan Schneider + user: jan + email: jan@horde.org + active: true + role: lead + - + name: Michael Slusarz + user: slusarz + email: slusarz@horde.org + active: true + role: lead +version: + release: 2.2.3 + api: 2.2.0 +state: + release: stable + api: stable +license: + identifier: LGPL-2.1 + uri: http://www.horde.org/licenses/lgpl21 +dependencies: + required: + php: ^5.3 || ^7 + pear: + pear.horde.org/Horde_Exception: ^2 + pear.horde.org/Horde_Translation: ^2.2 + pear.horde.org/Horde_Util: ^2 + ext: + hash: '*' + optional: + pear: + pear.horde.org/Horde_Db: ^2 + pear.horde.org/Horde_History: ^2 + pear.horde.org/Horde_Lock: ^2 + pear.horde.org/Horde_Imap_Client: ^2 + pear.horde.org/Horde_Kolab_Session: ^2 + pear.horde.org/Horde_Ldap: ^2 + pear.horde.org/Horde_Imsp: ^2 + pear.horde.org/Horde_Http: ^2 + pear.horde.org/Horde_Test: ^2.1 + pecl.php.net/pam: '*' + pecl.php.net/sasl: '*' + ext: + ctype: '*' + ftp: '*' diff --git a/.travis.yml b/.travis.yml index 1e1ebf7..8fe21b1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,6 +6,7 @@ php: - 5.6 - 7.0 - 7.1 + - 7.2 - nightly matrix: fast_finish: true @@ -13,12 +14,6 @@ matrix: - php: nightly before_script: - phpenv config-rm xdebug.ini || echo "XDebug not enabled" - - if [ "$TRAVIS_PHP_VERSION" == "5.6" ] || [ "$TRAVIS_PHP_VERSION" == "7.0" ]; - then - echo "include_path = .:$HOME/.phpenv/versions/$(phpenv version-name)/lib/php/pear" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini; - pear channel-discover pear.horde.org; - fi - - pear install channel://pear.horde.org/Horde_Test - pear install -a -B package.xml script: diff --git a/composer.json b/composer.json index 1aea59c..2fc69c2 100644 --- a/composer.json +++ b/composer.json @@ -21,8 +21,8 @@ "role": "lead" } ], - "version": "2.2.2", - "time": "2017-06-22", + "version": "2.2.3", + "time": "2017-10-20", "repositories": [ { "type": "pear", @@ -31,21 +31,21 @@ ], "require": { "php": "^5.3 || ^7", - "pear-pear.horde.org/Horde_Exception": "^2@stable", - "pear-pear.horde.org/Horde_Translation": "^2.2@stable", - "pear-pear.horde.org/Horde_Util": "^2@stable", + "pear-pear.horde.org/Horde_Exception": "^2", + "pear-pear.horde.org/Horde_Translation": "^2.2", + "pear-pear.horde.org/Horde_Util": "^2", "ext-hash": "*" }, "suggest": { - "pear-pear.horde.org/Horde_Db": "^2@stable", - "pear-pear.horde.org/Horde_History": "^2@stable", - "pear-pear.horde.org/Horde_Lock": "^2@stable", - "pear-pear.horde.org/Horde_Imap_Client": "^2@stable", - "pear-pear.horde.org/Horde_Kolab_Session": "^2@stable", - "pear-pear.horde.org/Horde_Ldap": "^2@stable", - "pear-pear.horde.org/Horde_Imsp": "^2@stable", - "pear-pear.horde.org/Horde_Http": "^2@stable", - "pear-pear.horde.org/Horde_Test": "^2.1@stable", + "pear-pear.horde.org/Horde_Db": "^2", + "pear-pear.horde.org/Horde_History": "^2", + "pear-pear.horde.org/Horde_Lock": "^2", + "pear-pear.horde.org/Horde_Imap_Client": "^2", + "pear-pear.horde.org/Horde_Kolab_Session": "^2", + "pear-pear.horde.org/Horde_Ldap": "^2", + "pear-pear.horde.org/Horde_Imsp": "^2", + "pear-pear.horde.org/Horde_Http": "^2", + "pear-pear.horde.org/Horde_Test": "^2.1", "pear-pecl.php.net/pam": "*", "pear-pecl.php.net/sasl": "*", "ext-ctype": "*", diff --git a/doc/Horde/Auth/changelog.yml b/doc/Horde/Auth/changelog.yml new file mode 100644 index 0000000..14a9b4b --- /dev/null +++ b/doc/Horde/Auth/changelog.yml @@ -0,0 +1,630 @@ +--- +2.2.3: + api: 2.2.0 + state: + release: stable + api: stable + date: 2017-10-20 + license: + identifier: LGPL-2.1 + uri: http://www.horde.org/licenses/lgpl21 + notes: +2.2.2: + api: 2.2.0 + state: + release: stable + api: stable + date: 2017-06-22 + license: + identifier: LGPL-2.1 + uri: http://www.horde.org/licenses/lgpl21 + notes: | + [jan] Add Turkish translation (İTÜ BİDB ). +2.2.1: + api: 2.2.0 + state: + release: stable + api: stable + date: 2016-12-03 + license: + identifier: LGPL-2.1 + uri: http://www.horde.org/licenses/lgpl21 + notes: | + [jan] Use more efficient database access in SQL backend. +2.2.0: + api: 2.2.0 + state: + release: stable + api: stable + date: 2016-07-28 + license: + identifier: LGPL-2.1 + uri: http://www.horde.org/licenses/lgpl21 + notes: | + [jan] Add searchUsers() method. +2.1.12: + api: 2.1.0 + state: + release: stable + api: stable + date: 2016-04-05 + license: + identifier: LGPL-2.1 + uri: http://www.horde.org/licenses/lgpl21 + notes: | + [mjr] Fix creating/removing mailbox in cyrsql driver (federico.mennite@lifeware.ch, Bug #14295). +2.1.11: + api: 2.1.0 + state: + release: stable + api: stable + date: 2016-02-01 + license: + identifier: LGPL-2.1 + uri: http://www.horde.org/licenses/lgpl21 + notes: | + [jan] Mark PHP 7 as supported. +2.1.10: + api: 2.1.0 + state: + release: stable + api: stable + date: 2015-07-06 + license: + identifier: LGPL-2.1 + uri: http://www.horde.org/licenses/lgpl21 + notes: | + [jan] SECURITY: Don't allow to login to LDAP with an emtpy password. +2.1.9: + api: 2.1.0 + state: + release: stable + api: stable + date: 2015-06-29 + license: + identifier: LGPL-2.1 + uri: http://www.horde.org/licenses/lgpl21 + notes: | + [mjr] Ensure we rebind as configured user after testing auth user credentials. +2.1.8: + api: 2.1.0 + state: + release: stable + api: stable + date: 2015-04-28 + license: + identifier: LGPL-2.1 + uri: http://www.horde.org/licenses/lgpl21 + notes: | + [jan] Fix issues with certain locales like Turkish. +2.1.7: + api: 2.1.0 + state: + release: stable + api: stable + date: 2015-04-13 + license: + identifier: LGPL-2.1 + uri: http://www.horde.org/licenses/lgpl21 + notes: | + [jan] Improve salt generation for Blowfish hashes. +2.1.6: + api: 2.1.0 + state: + release: stable + api: stable + date: 2015-01-08 + license: + identifier: LGPL-2.1 + uri: http://www.horde.org/licenses/lgpl21 + notes: | + [jan] Support loading translations from Composer-installed package. + [jan] Improve PSR-2 compatibility. +2.1.5: + api: 2.1.0 + state: + release: stable + api: stable + date: 2014-06-17 + license: + identifier: LGPL-2.1 + uri: http://www.horde.org/licenses/lgpl21 + notes: | + [jan] Add Polish translation (Maciej Uhlig ). +2.1.4: + api: 2.1.0 + state: + release: stable + api: stable + date: 2014-05-21 + license: + identifier: LGPL-2.1 + uri: http://www.horde.org/licenses/lgpl21 + notes: | + [jan] Add Hungarian translation (Andras Galos ). +2.1.3: + api: 2.1.0 + state: + release: stable + api: stable + date: 2014-04-03 + license: + identifier: LGPL-2.1 + uri: http://www.horde.org/licenses/lgpl21 + notes: | + [jan] Add Danish translation (Erling Preben Hansen ). +2.1.2: + api: 2.1.0 + state: + release: stable + api: stable + date: 2014-03-03 + license: + identifier: LGPL-2.1 + uri: http://www.horde.org/licenses/lgpl21 + notes: | + [jan] Add MySQL password hashing (Request #12962). + [rla] Add joomla encrypted password format (Request #12889). + [mms] Fix parsing salted SHA256 entries (Adam James ). +2.1.1: + api: 2.1.0 + state: + release: stable + api: stable + date: 2013-10-15 + license: + identifier: LGPL-2.1 + uri: http://www.horde.org/licenses/lgpl21 + notes: | + [mms] Password strength testing is now case-insensitive (delrio@mie.utoronto.ca, Request #12708). +2.1.0: + api: 2.1.0 + state: + release: stable + api: stable + date: 2013-09-02 + license: + identifier: LGPL-2.1 + uri: http://www.horde.org/licenses/lgpl21 + notes: | + [mjr] Add X509 authentication driver. +2.0.6: + api: 2.0.0 + state: + release: stable + api: stable + date: 2013-07-16 + license: + identifier: LGPL-2.1 + uri: http://www.horde.org/licenses/lgpl21 + notes: | + [mms] Fix adding/deleting users via IMAP administration (Bug #12426). +2.0.5: + api: 2.0.0 + state: + release: stable + api: stable + date: 2013-07-16 + license: + identifier: LGPL-2.1 + uri: http://www.horde.org/licenses/lgpl21 + notes: | + [jan] Add password policy for minimum number of non-alphabetic characters (Friedrich Haubensak , Request #12243). + [jan] Fix resetting passwords with LDAP driver (Bug #12317). + [mms] Fix authentication with the Http auth driver. +2.0.4: + api: 2.0.0 + state: + release: stable + api: stable + date: 2013-03-05 + license: + identifier: LGPL-2.1 + uri: http://www.horde.org/licenses/lgpl21 + notes: | + [jan] Improve documentation. +2.0.3: + api: 2.0.0 + state: + release: stable + api: stable + date: 2013-01-29 + license: + identifier: LGPL-2.1 + uri: http://www.horde.org/licenses/lgpl21 + notes: | + [jan] Add French translation (Paul De Vlieger ). + [jan] Fix argument reading in Samba drivers (Bug #11926). + [mms] Remove call-time pass-by-reference, which was causing PAM authentication driver to fail in PHP 5.4+ (Bug #10965). +2.0.2: + api: 2.0.0 + state: + release: stable + api: stable + date: 2013-01-09 + license: + identifier: LGPL-2.1 + uri: http://www.horde.org/licenses/lgpl21 + notes: | + [jan] Add Basque translation (Ibon Igartua ). + [jan] Fix updating users in LDAP driver (Bug #11791). +2.0.1: + api: 2.0.0 + state: + release: stable + api: stable + date: 2012-11-19 + license: + identifier: LGPL-2.1 + uri: http://www.horde.org/licenses/lgpl21 + notes: | + [mms] Use new Horde_Test layout. +2.0.0: + api: 2.0.0 + state: + release: stable + api: stable + date: 2012-10-30 + license: + identifier: LGPL-2.1 + uri: http://www.horde.org/licenses/lgpl21 + notes: | + First stable release for Horde 5. +2.0.0beta2: + api: 2.0.0beta1 + state: + release: beta + api: beta + date: 2012-10-12 + license: + identifier: LGPL-2.1 + uri: http://www.horde.org/licenses/lgpl21 + notes: | + [jan] Fix setting IMAP ACLs in IMAP and Cyrsql drivers. + [mms] Fix user management in Passwd driver. + [mms] Fix setting soft expiration in SQL driver. +2.0.0beta1: + api: 2.0.0beta1 + state: + release: beta + api: beta + date: 2012-07-19 + license: + identifier: LGPL-2.1 + uri: http://www.horde.org/licenses/lgpl21 + notes: | + First beta release for Horde 5. + [rla] Use constant for permanent lock and provide more verbose feedback (Request #11254). +2.0.0alpha1: + api: 2.0.0alpha1 + state: + release: alpha + api: alpha + date: 2012-07-05 + license: + identifier: LGPL-2.1 + uri: http://www.horde.org/licenses/lgpl21 + notes: | + First alpha release for Horde 5. + [mms] Removed charset parameter for Imap and Cyrsql drivers. +1.4.10: + api: 1.4.0 + state: + release: stable + api: stable + date: 2012-03-20 + license: + identifier: LGPL-2.1 + uri: http://www.horde.org/licenses/lgpl21 + notes: | + [mms] Fix Horde_Auth_Passwd#updateUser(). +1.4.9: + api: 1.4.0 + state: + release: stable + api: stable + date: 2012-03-20 + license: + identifier: LGPL-2.1 + uri: http://www.horde.org/licenses/lgpl21 + notes: | + [jan] Add Finnish translation (Leena Heino ). +1.4.8: + api: 1.4.0 + state: + release: stable + api: stable + date: 2012-01-31 + license: + identifier: LGPL-2.1 + uri: http://www.horde.org/licenses/lgpl21 + notes: | + [jan] Add optimized exists() implementation to LDAP driver (Marco Ferrante , Request #10944). + [jan] Add Spanish translation (Manuel P. Ayala ). +1.4.7: + api: 1.4.0 + state: + release: stable + api: stable + date: 2011-12-13 + license: + identifier: LGPL-2.1 + uri: http://www.horde.org/licenses/lgpl21 + notes: | + [jan] Add Latvian translation (Jānis Eisaks ). +1.4.6: + api: 1.4.0 + state: + release: stable + api: stable + date: 2011-12-06 + license: + identifier: LGPL-2.1 + uri: http://www.horde.org/licenses/lgpl21 + notes: | + [jan] Add Japanese translation (Hiromi Kimura ). +1.4.5: + api: 1.4.0 + state: + release: stable + api: stable + date: 2011-11-22 + license: + identifier: LGPL-2.1 + uri: http://www.horde.org/licenses/lgpl21 + notes: | + [jan] Add Estonian translation. +1.4.4: + api: 1.4.0 + state: + release: stable + api: stable + date: 2011-11-08 + license: + identifier: LGPL-2.1 + uri: http://www.horde.org/licenses/lgpl21 + notes: | + [jan] Allow to run unit tests from installed package. +1.4.3: + api: 1.4.0 + state: + release: stable + api: stable + date: 2011-10-18 + license: + identifier: LGPL-2.1 + uri: http://www.horde.org/licenses/lgpl21 + notes: | + [jan] Catch exceptions from imap library (Bug #10272). +1.4.2: + api: 1.4.0 + state: + release: stable + api: stable + date: 2011-10-04 + license: + identifier: LGPL-2.1 + uri: http://www.horde.org/licenses/lgpl21 + notes: | + [jan] Fix detecting locale directory from PEAR installation (Bug #10589). +1.4.1: + api: 1.4.0 + state: + release: stable + api: stable + date: 2011-10-03 + license: + identifier: LGPL-2.1 + uri: http://www.horde.org/licenses/lgpl21 + notes: | + [jan] Add missing locale directory (Bug #10589). +1.4.0: + api: 1.4.0 + state: + release: stable + api: stable + date: 2011-09-28 + license: + identifier: LGPL-2.1 + uri: http://www.horde.org/licenses/lgpl21 + notes: | + [jan] Add checkPasswordPolicy() and checkPasswordSimilarity() methods. +1.3.0: + api: 1.3.0 + state: + release: stable + api: stable + date: 2011-09-20 + license: + identifier: LGPL-2.1 + uri: http://www.horde.org/licenses/lgpl21 + notes: | + [jan] Dynamically disable capabilities of Customsql authentication driver if queries are empty (Michael Gröne, Request #10510). + [jan] Fix updating users in LDAP while using preauthenticate hooks. + [jan] Add support for resetting passwords to LDAP driver. +1.2.0: + api: 1.2.0 + state: + release: stable + api: stable + date: 2011-08-31 + license: + identifier: LGPL-2.1 + uri: http://www.horde.org/licenses/lgpl21 + notes: | + [rla] Add bad login blocking and account locking to the base driver. + [rla] Fix SQL driver when using soft_expiration and hard_expiration features. + [rla] No longer enforce lowercase fieldnames. +1.1.0: + api: 1.1.0 + state: + release: stable + api: stable + date: 2011-07-05 + license: + identifier: LGPL-2.1 + uri: http://www.horde.org/licenses/lgpl21 + notes: | + [rla] Add sort parameter to listUsers() method. + [mms] Fix addUser() for Cyrsql driver (vilius@lnk.lt, Bug #10239). +1.0.4: + api: 1.0.0 + state: + release: stable + api: stable + date: 2011-06-08 + license: + identifier: LGPL-2.1 + uri: http://www.horde.org/licenses/lgpl21 + notes: | + [jan] SECURITY: Fix propagating failed login in composite driver (Bug #10211). +1.0.3: + api: 1.0.0 + state: + release: stable + api: stable + date: 2011-05-18 + license: + identifier: LGPL-2.1 + uri: http://www.horde.org/licenses/lgpl21 + notes: | + [mms] Cyrsql driver doesn't support resetting passwords currently (Bug #10060). +1.0.2: + api: 1.0.0 + state: + release: stable + api: stable + date: 2011-05-03 + license: + identifier: LGPL-2.1 + uri: http://www.horde.org/licenses/lgpl21 + notes: | + [jan] Fix listing users in Customsql driver (Bug #9963). +1.0.1: + api: 1.0.0 + state: + release: stable + api: stable + date: 2011-04-20 + license: + identifier: LGPL-2.1 + uri: http://www.horde.org/licenses/lgpl21 + notes: | + [mms] Fix default userhierarchy for Cyrsql driver (Bug #9895). + [cjh] Add crypt-sha256 and crypt-sha512 password hashes (patrickdk@patrickdk.com, Request #6991). + [mms] Fix addUser() in Customsql driver (Bug #9832). +1.0.0: + api: 1.0.0 + state: + release: stable + api: stable + date: 2011-04-06 + license: + identifier: LGPL-2.1 + uri: http://www.horde.org/licenses/lgpl21 + notes: | + First stable release for Horde 4. + [jan] Fix Cyrsql driver (Vilius Sumskas , Bug #9781). + [jan] Add SHA-256 hashing and add SHA as alias for SHA1. +1.0.0RC2: + api: 1.0.0 + state: + release: beta + api: beta + date: 2011-03-29 + license: + identifier: LGPL-2.1 + uri: http://www.horde.org/licenses/lgpl21 + notes: | + Second release candidate for Horde 4. + Remove Cyrus driver. + Remove support for pam_auth (Ticket #6860). +1.0.0RC1: + api: 1.0.0 + state: + release: beta + api: beta + date: 2011-03-22 + license: + identifier: LGPL-2.1 + uri: http://www.horde.org/licenses/lgpl21 + notes: | + First release candidate for Horde 4. +1.0.0beta1: + api: 1.0.0 + state: + release: beta + api: beta + date: 2011-03-16 + license: + identifier: LGPL-2.1 + uri: http://www.horde.org/licenses/lgpl21 + notes: | + First beta release for Horde 4. +1.0.0alpha1: + api: 1.0.0 + state: + release: alpha + api: alpha + date: 2011-03-08 + license: + identifier: LGPL-2.1 + uri: http://www.horde.org/licenses/lgpl21 + notes: | + First alpha release for Horde 4. + Remove dependency on horde/Core. + Remove all non-authentication backend related code. + Removed Krb5 driver. + Moved signup code to horde/Core. + Split Horde_Auth into Horde_Auth and Horde_Auth_Base components. +0.1.1: + api: 0.1.0 + state: + release: beta + api: beta + date: 2008-10-29 + license: + identifier: LGPL-2.1 + uri: http://www.horde.org/licenses/lgpl21 + notes: | + Imap driver now uses Horde_Imap_Client library. + Add signup drivers to package.xml (Bug #7345). + Fix the "overwriting realm info from application auth drivers" (Bug #6749) + Switched Kolab auth handling from IMAP to LDAP by using Kolab_Server. + Added "add user" capability to the Kolab driver. + Adapted the Kolab auth driver to the changes in Kolab_Server. +0.1.0: + api: 0.1.0 + state: + release: beta + api: beta + date: 2008-09-16 + license: + identifier: LGPL-2.1 + uri: http://www.horde.org/licenses/lgpl21 + notes: | + Fixed error handling when removing user data. + Retrieve password where necessary for salt calculations in the custom SQL driver (Bug #3739). + Added a query for checking existance of a user to the custom SQL driver (Request #5151). + Completed Cyrus virtual domain support in the cyrsql driver. + Fixed handling of UID logins in the Kolab driver (Bugs #1317, #4662). + Fixed case handling in the LDAP driver (Bug #2435). + Rewrote PAM driver to use PAM extension from PECL. + Fixed the PAM driver authentication so that it works with both pam and pam_auth extensions (Bug #6860). + Ensured that the LDAP driver always uses the configured filter. + Renamed Auth_sasl to Auth_peclsasl (Bug #4547). + Allow signup hooks to override the user_name and password fields (Request #2904). + Created an SQL driver for signups and allowing backends other than DataTree (Request #7161). + Added smbclient driver as an alternative to the smb driver which requires a PHP extension. + Fix handling of SSHA and SMD5 salts (ulrich-horde@topfen.net, Bug #2863). + Added readSessionData() function to get Horde authentication data from session strings. + Allow drivers to include their own isAdmin() implementations (Request #5521). + Add Active Directory extension of LDAP driver (Request #3769). + Hide the cyrus account in cyrsql driver (vilius@lnk.lt, Request #5626). + Bring the passwd driver into compliance with the Auth API. + Remove dependency on the mhash extension for some encryption types. + Add authentication against a remote HTTP Authentication endpoint (duck@obala.net). + CSRF token protections for logout links. + Call the postauthenticate hook in Horde_Auth::setAuth() instead of authenticate(). + Modified the Kolab driver to use the new Kolab_Server package. + Improved handling of multiple IMAP server setups in the Kolab driver. diff --git a/lib/Horde/Auth/Mock.php b/lib/Horde/Auth/Mock.php new file mode 100644 index 0000000..7ff5262 --- /dev/null +++ b/lib/Horde/Auth/Mock.php @@ -0,0 +1,169 @@ + + * @category Horde + * @license http://www.horde.org/licenses/lgpl21 LGPL-2.1 + * @package Auth + */ + +/** + * The Horde_Auth_Mock class provides an in-memory user list. + * + * It is meant to be used for throwaway setups, satellite systems or for + * providing a source of administrative accounts in Composite or Cascading driver + * The driver can also be used as a mock-like backend for integration tests + * + * @author Ralf Lang + * @category Horde + * @copyright 2017 Horde LLC + * @license http://www.horde.org/licenses/lgpl21 LGPL-2.1 + * @package Auth + */ +class Horde_Auth_Mock extends Horde_Auth_Base +{ + /** + * An array of capabilities, so that the driver can report which + * operations it supports and which it doesn't. + * + * @var array + */ + protected $_capabilities = array( + 'authenticate' => true, + 'list' => true, + 'update' => true, + 'remove' => true, + 'add' => true, + ); + + /** + * Constructor. + * + * @param array $params Optional parameters: + *
+     * 'users' - (array) Usernames are hash keys, passwords are values
+     * 'encryption' - (string) Optionally supply an encryption or hashing
+     * 'show_encryption' - (boolean) prepend encryption info to password string
+     * 
+ */ + public function __construct(array $params = array()) + { + $params = array_merge( + array( + 'encryption' => 'plain', + 'users' => array(), + 'show_encryption' => false + ), + $params + ); + parent::__construct($params); + } + + /** + * Adds a set of authentication credentials. + * + * @param string $userId The userId to add. + * @param array $credentials The credentials to use. + * + * @throws Horde_Auth_Exception + */ + public function addUser($userId, $credentials) + { + // TODO: use persistence callback if given + if ($this->exists($userId)) { + throw new Horde_Auth_Exception('User already exists'); + } + $this->_params['users'][$userId] = Horde_Auth::getCryptedPassword( + $credentials['password'], + '', + $this->_params['encryption'], + $this->_params['show_encryption']); + } + + /** + * Lists all users in the system. + * + * @param boolean $sort Sort the users? + * + * @return mixed The array of userIds. + */ + public function listUsers($sort = false) + { + return $this->_sort(array_keys($this->_params['users']), $sort); + } + + /** + * Updates a set of authentication credentials for the life time of the driver. + * + * @param string $oldID The old userId. + * @param string $newID The new userId. + * @param array $credentials The new credentials + * + * @throws Horde_Auth_Exception + */ + public function updateUser($oldID, $newID, $credentials) + { + if (!$this->exists($oldID)) { + throw new Horde_Auth_Exception('User does not exist'); + } + if ($this->exists($newID) && $newID != $oldID) { + throw new Horde_Auth_Exception('Cannot rename to existing user name'); + } + $this->removeUser($oldID); + $this->addUser($newID, $credentials); + } + + /** + * Deletes a set of authentication credentials for the life of the driver. + * + * @param string $userId The userId to delete. + */ + public function removeUser($userId) + { + // TODO: use persistence callback if given + unset($this->_params['users'][$userId]); + } + + /** + * Authenticate. + * + * @param string $userId The userID to check. + * @param array $credentials An array of login credentials. + * + * @throws Horde_Auth_Exception + */ + protected function _authenticate($userId, $credentials) + { + if (!$this->exists($userId) || + !$this->_comparePasswords( + $this->_params['users'][$userId], + $credentials['password'] + )) { + throw new Horde_Auth_Exception('', Horde_Auth::REASON_BADLOGIN); + } + return; + } + + /** + * Compare an encrypted password to a plaintext string to see if + * they match. + * + * @param string $encrypted The crypted password to compare against. + * @param string $plaintext The plaintext password to verify. + * + * @return boolean True if matched, false otherwise. + */ + protected function _comparePasswords($encrypted, $plaintext) + { + return $encrypted == Horde_Auth::getCryptedPassword( + $plaintext, + $encrypted, + $this->_params['encryption'], + $this->_params['show_encryption']); + } + +} diff --git a/package.xml b/package.xml index f50968f..6af5f3d 100644 --- a/package.xml +++ b/package.xml @@ -23,7 +23,7 @@ slusarz@horde.org yes - 2017-10-20 + 2017-10-29 2.2.3 2.2.0 @@ -34,10 +34,18 @@ LGPL-2.1 -* +* [rla] Add Mock authentication driver. + + + + + + + + @@ -57,6 +65,7 @@ + @@ -173,6 +182,9 @@ + + + @@ -183,6 +195,7 @@ + @@ -304,6 +317,9 @@ + + + @@ -319,6 +335,7 @@ + @@ -364,6 +381,9 @@ + + + @@ -1119,10 +1139,10 @@ stable stable - 2017-10-20 + 2017-10-29 LGPL-2.1 -* +* [rla] Add Mock authentication driver. diff --git a/test/Horde/Auth/Unit/MockCryptShowTest.php b/test/Horde/Auth/Unit/MockCryptShowTest.php new file mode 100644 index 0000000..7b2a164 --- /dev/null +++ b/test/Horde/Auth/Unit/MockCryptShowTest.php @@ -0,0 +1,142 @@ + + * @license http://www.horde.org/licenses/lgpl21 LGPL-2.1 + * @link http://pear.horde.org/index.php?package=Auth + */ +class Horde_Auth_Unit_MockCryptShowTest extends Horde_Auth_TestCase +{ + public function setUp() + { + $this->driver = new Horde_Auth_Mock( + array( + 'users' => array( + 'user1' => '{crypt}$1$S/EKq8Dg$OJvaV8Lu1HgCXKNqAo.wG/', + 'user2' => '{crypt}$1$aCWZiBAW$dK0DCmTGYR1gEX11pMxbi0', + 'tester' => '{crypt}$1$sjSx+Q9x$3WIEdh1Ei16QouYx1Xkct1' + ), + 'encryption' => 'crypt-md5', + 'show_encryption' => true + ) + ); + } + + public function testAuthenticate() + { + $this->assertTrue($this->driver->authenticate('user1', array('password' => 'user1pw'))); + $this->assertTrue($this->driver->authenticate('user2', array('password' => 'user2pw'))); + $this->assertTrue($this->driver->authenticate('tester', array('password' => 'WeirdPW92401#1'))); + // correct password extended by garbage + $this->assertFalse($this->driver->authenticate('user1', array('password' => 'user1pwfalse'))); + // Existing user with all kinds of garbage + $this->assertFalse($this->driver->authenticate('user1', array('password' => 'any'))); + $this->assertFalse($this->driver->authenticate('user1', array('password' => ''))); + $this->assertFalse($this->driver->authenticate('user1', array('password' => null))); + $this->assertFalse($this->driver->authenticate('user1', array('password' => '0'))); + // Unknown user with all kinds of garbage + $this->assertFalse($this->driver->authenticate('unknownuser', array('password' => 'any'))); + $this->assertFalse($this->driver->authenticate('unknownuser', array('password' => ''))); + $this->assertFalse($this->driver->authenticate('unknownuser', array('password' => null))); + $this->assertFalse($this->driver->authenticate('unknownuser', array('password' => '0'))); + } + + public function testRemoveUser() + { + // Delete somebody who doesn't exist + $this->driver->removeUser('user'); + $this->assertCount(3, $this->driver->listUsers()); + $this->driver->removeUser('user1'); + $this->assertCount(2, $this->driver->listUsers()); + $this->driver->removeUser('user2'); + $this->assertCount(1, $this->driver->listUsers()); + $this->driver->removeUser('tester'); + $this->assertCount(0, $this->driver->listUsers()); + // Restore setup + $this->setUp(); + } + + public function testAddUser() + { + // Add somebody who already exist + $this->driver->addUser('user4', array('password' => 'foo')); + $this->assertCount(4, $this->driver->listUsers()); + // Add somebody who already exist + $this->setExpectedException('Horde_Auth_Exception'); + $this->driver->addUser('user4', array('password' => 'foo')); + $this->assertCount(4, $this->driver->listUsers()); + + // Restore setup + $this->setUp(); + } + + public function testUpdateUser() + { + // Try a password change + $this->driver->updateUser('tester', 'tester', array('password' => 'foo')); + $this->assertCount(3, $this->driver->listUsers()); + $this->assertTrue($this->driver->exists('tester')); + // Try renaming + $this->driver->updateUser('tester', 'newname', array('password' => 'foo')); + $this->assertCount(3, $this->driver->listUsers()); + $this->assertTrue($this->driver->exists('newname')); + $this->assertFalse($this->driver->exists('tester')); + $this->setUp(); + } + + public function testUpdateUserFailDoesNotExist() + { + // Try renaming unknown user + $this->setExpectedException('Horde_Auth_Exception'); + $this->driver->updateUser('unknownuser', 'newname', array('password' => 'foo')); + $this->setUp(); + } + + public function testUpdateUserFailNewNameExists() + { + // Try renaming unknown user + $this->setExpectedException('Horde_Auth_Exception'); + $this->driver->updateUser('tester', 'user1', array('password' => 'foo')); + $this->setUp(); + } + + + + public function testExists() + { + $this->assertTrue($this->driver->exists('user1')); + $this->assertTrue($this->driver->exists('user2')); + $this->assertTrue($this->driver->exists('tester')); + $this->assertFalse($this->driver->exists('somebody')); + $this->assertFalse($this->driver->exists('')); + $this->assertFalse($this->driver->exists(null)); + } + + /** + * This is actually a test against Horde_Auth_Base + * TODO: Copy or move to a test with a phpunit mock + */ + + public function testSearchUsers() + { + $this->assertCount(2, $this->driver->searchUsers('user')); + $this->assertCount(1, $this->driver->searchUsers('test')); + $this->assertEquals(array('tester'), $this->driver->searchUsers('test')); + } + + public function testListUsers() + { + $this->assertEquals(array('tester', 'user1', 'user2'), $this->driver->listUsers(true)); + $this->assertEquals(array('user1', 'user2', 'tester'), $this->driver->listUsers(false)); + $this->assertEquals(array('user1', 'user2', 'tester'), $this->driver->listUsers()); + } +} diff --git a/test/Horde/Auth/Unit/MockCryptTest.php b/test/Horde/Auth/Unit/MockCryptTest.php new file mode 100644 index 0000000..a0245d6 --- /dev/null +++ b/test/Horde/Auth/Unit/MockCryptTest.php @@ -0,0 +1,142 @@ + + * @license http://www.horde.org/licenses/lgpl21 LGPL-2.1 + * @link http://pear.horde.org/index.php?package=Auth + */ +class Horde_Auth_Unit_MockCryptTest extends Horde_Auth_TestCase +{ + public function setUp() + { + $this->driver = new Horde_Auth_Mock( + array( + 'users' => array( + 'user1' => '$1$S/EKq8Dg$OJvaV8Lu1HgCXKNqAo.wG/', + 'user2' => '$1$aCWZiBAW$dK0DCmTGYR1gEX11pMxbi0', + 'tester' => '$1$sjSx+Q9x$3WIEdh1Ei16QouYx1Xkct1' + ), + 'encryption' => 'crypt-md5', + 'show_encryption' => false + ) + ); + } + + public function testAuthenticate() + { + $this->assertTrue($this->driver->authenticate('user1', array('password' => 'user1pw'))); + $this->assertTrue($this->driver->authenticate('user2', array('password' => 'user2pw'))); + $this->assertTrue($this->driver->authenticate('tester', array('password' => 'WeirdPW92401#1'))); + // correct password extended by garbage + $this->assertFalse($this->driver->authenticate('user1', array('password' => 'user1pwfalse'))); + // Existing user with all kinds of garbage + $this->assertFalse($this->driver->authenticate('user1', array('password' => 'any'))); + $this->assertFalse($this->driver->authenticate('user1', array('password' => ''))); + $this->assertFalse($this->driver->authenticate('user1', array('password' => null))); + $this->assertFalse($this->driver->authenticate('user1', array('password' => '0'))); + // Unknown user with all kinds of garbage + $this->assertFalse($this->driver->authenticate('unknownuser', array('password' => 'any'))); + $this->assertFalse($this->driver->authenticate('unknownuser', array('password' => ''))); + $this->assertFalse($this->driver->authenticate('unknownuser', array('password' => null))); + $this->assertFalse($this->driver->authenticate('unknownuser', array('password' => '0'))); + } + + public function testRemoveUser() + { + // Delete somebody who doesn't exist + $this->driver->removeUser('user'); + $this->assertCount(3, $this->driver->listUsers()); + $this->driver->removeUser('user1'); + $this->assertCount(2, $this->driver->listUsers()); + $this->driver->removeUser('user2'); + $this->assertCount(1, $this->driver->listUsers()); + $this->driver->removeUser('tester'); + $this->assertCount(0, $this->driver->listUsers()); + // Restore setup + $this->setUp(); + } + + public function testAddUser() + { + // Add somebody who already exist + $this->driver->addUser('user4', array('password' => 'foo')); + $this->assertCount(4, $this->driver->listUsers()); + // Add somebody who already exist + $this->setExpectedException('Horde_Auth_Exception'); + $this->driver->addUser('user4', array('password' => 'foo')); + $this->assertCount(4, $this->driver->listUsers()); + + // Restore setup + $this->setUp(); + } + + public function testUpdateUser() + { + // Try a password change + $this->driver->updateUser('tester', 'tester', array('password' => 'foo')); + $this->assertCount(3, $this->driver->listUsers()); + $this->assertTrue($this->driver->exists('tester')); + // Try renaming + $this->driver->updateUser('tester', 'newname', array('password' => 'foo')); + $this->assertCount(3, $this->driver->listUsers()); + $this->assertTrue($this->driver->exists('newname')); + $this->assertFalse($this->driver->exists('tester')); + $this->setUp(); + } + + public function testUpdateUserFailDoesNotExist() + { + // Try renaming unknown user + $this->setExpectedException('Horde_Auth_Exception'); + $this->driver->updateUser('unknownuser', 'newname', array('password' => 'foo')); + $this->setUp(); + } + + public function testUpdateUserFailNewNameExists() + { + // Try renaming unknown user + $this->setExpectedException('Horde_Auth_Exception'); + $this->driver->updateUser('tester', 'user1', array('password' => 'foo')); + $this->setUp(); + } + + + + public function testExists() + { + $this->assertTrue($this->driver->exists('user1')); + $this->assertTrue($this->driver->exists('user2')); + $this->assertTrue($this->driver->exists('tester')); + $this->assertFalse($this->driver->exists('somebody')); + $this->assertFalse($this->driver->exists('')); + $this->assertFalse($this->driver->exists(null)); + } + + /** + * This is actually a test against Horde_Auth_Base + * TODO: Copy or move to a test with a phpunit mock + */ + + public function testSearchUsers() + { + $this->assertCount(2, $this->driver->searchUsers('user')); + $this->assertCount(1, $this->driver->searchUsers('test')); + $this->assertEquals(array('tester'), $this->driver->searchUsers('test')); + } + + public function testListUsers() + { + $this->assertEquals(array('tester', 'user1', 'user2'), $this->driver->listUsers(true)); + $this->assertEquals(array('user1', 'user2', 'tester'), $this->driver->listUsers(false)); + $this->assertEquals(array('user1', 'user2', 'tester'), $this->driver->listUsers()); + } +} diff --git a/test/Horde/Auth/Unit/MockPlainTest.php b/test/Horde/Auth/Unit/MockPlainTest.php new file mode 100644 index 0000000..51bea2b --- /dev/null +++ b/test/Horde/Auth/Unit/MockPlainTest.php @@ -0,0 +1,140 @@ + + * @license http://www.horde.org/licenses/lgpl21 LGPL-2.1 + * @link http://pear.horde.org/index.php?package=Auth + */ +class Horde_Auth_Unit_MockPlainTest extends Horde_Auth_TestCase +{ + public function setUp() + { + $this->driver = new Horde_Auth_Mock( + array( + 'users' => array( + 'user1' => 'user1pw', + 'user2' => 'user2pw', + 'tester' => 'WeirdPW92401#1' + ) + ) + ); + } + + public function testAuthenticate() + { + $this->assertTrue($this->driver->authenticate('user1', array('password' => 'user1pw'))); + $this->assertTrue($this->driver->authenticate('user2', array('password' => 'user2pw'))); + $this->assertTrue($this->driver->authenticate('tester', array('password' => 'WeirdPW92401#1'))); + // correct password extended by garbage + $this->assertFalse($this->driver->authenticate('user1', array('password' => 'user1pwfalse'))); + // Existing user with all kinds of garbage + $this->assertFalse($this->driver->authenticate('user1', array('password' => 'any'))); + $this->assertFalse($this->driver->authenticate('user1', array('password' => ''))); + $this->assertFalse($this->driver->authenticate('user1', array('password' => null))); + $this->assertFalse($this->driver->authenticate('user1', array('password' => '0'))); + // Unknown user with all kinds of garbage + $this->assertFalse($this->driver->authenticate('unknownuser', array('password' => 'any'))); + $this->assertFalse($this->driver->authenticate('unknownuser', array('password' => ''))); + $this->assertFalse($this->driver->authenticate('unknownuser', array('password' => null))); + $this->assertFalse($this->driver->authenticate('unknownuser', array('password' => '0'))); + } + + public function testRemoveUser() + { + // Delete somebody who doesn't exist + $this->driver->removeUser('user'); + $this->assertCount(3, $this->driver->listUsers()); + $this->driver->removeUser('user1'); + $this->assertCount(2, $this->driver->listUsers()); + $this->driver->removeUser('user2'); + $this->assertCount(1, $this->driver->listUsers()); + $this->driver->removeUser('tester'); + $this->assertCount(0, $this->driver->listUsers()); + // Restore setup + $this->setUp(); + } + + public function testAddUser() + { + // Add somebody who already exist + $this->driver->addUser('user4', array('password' => 'foo')); + $this->assertCount(4, $this->driver->listUsers()); + // Add somebody who already exist + $this->setExpectedException('Horde_Auth_Exception'); + $this->driver->addUser('user4', array('password' => 'foo')); + $this->assertCount(4, $this->driver->listUsers()); + + // Restore setup + $this->setUp(); + } + + public function testUpdateUser() + { + // Try a password change + $this->driver->updateUser('tester', 'tester', array('password' => 'foo')); + $this->assertCount(3, $this->driver->listUsers()); + $this->assertTrue($this->driver->exists('tester')); + // Try renaming + $this->driver->updateUser('tester', 'newname', array('password' => 'foo')); + $this->assertCount(3, $this->driver->listUsers()); + $this->assertTrue($this->driver->exists('newname')); + $this->assertFalse($this->driver->exists('tester')); + $this->setUp(); + } + + public function testUpdateUserFailDoesNotExist() + { + // Try renaming unknown user + $this->setExpectedException('Horde_Auth_Exception'); + $this->driver->updateUser('unknownuser', 'newname', array('password' => 'foo')); + $this->setUp(); + } + + public function testUpdateUserFailNewNameExists() + { + // Try renaming unknown user + $this->setExpectedException('Horde_Auth_Exception'); + $this->driver->updateUser('tester', 'user1', array('password' => 'foo')); + $this->setUp(); + } + + + + public function testExists() + { + $this->assertTrue($this->driver->exists('user1')); + $this->assertTrue($this->driver->exists('user2')); + $this->assertTrue($this->driver->exists('tester')); + $this->assertFalse($this->driver->exists('somebody')); + $this->assertFalse($this->driver->exists('')); + $this->assertFalse($this->driver->exists(null)); + } + + /** + * This is actually a test against Horde_Auth_Base + * TODO: Copy or move to a test with a phpunit mock + */ + + public function testSearchUsers() + { + $this->assertCount(2, $this->driver->searchUsers('user')); + $this->assertCount(1, $this->driver->searchUsers('test')); + $this->assertEquals(array('tester'), $this->driver->searchUsers('test')); + } + + public function testListUsers() + { + $this->assertEquals(array('tester', 'user1', 'user2'), $this->driver->listUsers(true)); + $this->assertEquals(array('user1', 'user2', 'tester'), $this->driver->listUsers(false)); + $this->assertEquals(array('user1', 'user2', 'tester'), $this->driver->listUsers()); + } +}