Skip to content
Snippets Groups Projects
Unverified Commit accd8d20 authored by Tim van Dijen's avatar Tim van Dijen Committed by GitHub
Browse files

Externalize authcrypt (#1123)

parent 8fed8c05
No related branches found
No related tags found
No related merge requests found
......@@ -48,6 +48,7 @@ php "$TARGET/composer.phar" install --no-dev --prefer-dist -o -d "$TARGET"
# Install external modules
php "$TARGET/composer.phar" require --update-no-dev simplesamlphp/simplesamlphp-module-adfs
php "$TARGET/composer.phar" require --update-no-dev simplesamlphp/simplesamlphp-module-authcrypt
php "$TARGET/composer.phar" require --update-no-dev simplesamlphp/simplesamlphp-module-authfacebook
php "$TARGET/composer.phar" require --update-no-dev simplesamlphp/simplesamlphp-module-authtwitter
php "$TARGET/composer.phar" require --update-no-dev simplesamlphp/simplesamlphp-module-authx509
......
This file indicates that the default state of this module
is disabled. To enable, create a file named enable in the
same directory as this file.
AuthCrypt
=========
This module provides two methods for authentication:
`authcrypt:Hash`
: Username & password authentication with hashed passwords.
`authcrypt:Htpasswd`
: Username & password authentication against an `.htpasswd` file.
`authcrypt:Hash`
----------------
This is based on `exampleAuth:UserPass`, and adds support for hashed passwords.
Hashes can be generated with the included command line tool `bin/pwgen.sh`.
This tool will interactively ask for a password, a hashing algorithm , and whether or not you want to use a salt:
[user@server simplesamlphp]$ bin/pwgen.php
Enter password: hackme
The following hashing algorithms are available:
md2 md4 md5 sha1 sha224 sha256
sha384 sha512 ripemd128 ripemd160 ripemd256 ripemd320
whirlpool tiger128,3 tiger160,3 tiger192,3 tiger128,4 tiger160,4
tiger192,4 snefru snefru256 gost adler32 crc32
crc32b salsa10 salsa20 haval128,3 haval160,3 haval192,3
haval224,3 haval256,3 haval128,4 haval160,4 haval192,4 haval224,4
haval256,4 haval128,5 haval160,5 haval192,5 haval224,5 haval256,5
Which one do you want? [sha256]
Do you want to use a salt? (yes/no) [yes]
{SSHA256}y1mj3xsZ4/+LoQyPNVJzXUFfBcLHfwcHx1xxltxeQ1C5MeyEX/RxWA==
Now create an authentication source in `config/authsources.php` and use the resulting string as the password:
'example-hashed' => array(
'authCrypt:Hash',
'student:{SSHA256}y1mj3xsZ4/+LoQyPNVJzXUFfBcLHfwcHx1xxltxeQ1C5MeyEX/RxWA==' => array(
'uid' => array('student'),
'eduPersonAffiliation' => array('member', 'student'),
),
),
This example creates a user `student` with password `hackme`, and some attributes.
### Compatibility ###
The generated hashes can also be used in `config.php` for the administrative password:
'auth.adminpassword' => '{SSHA256}y1mj3xsZ4/+LoQyPNVJzXUFfBcLHfwcHx1xxltxeQ1C5MeyEX/RxWA==',
Instead of generating hashes, you can also use existing ones from OpenLDAP, provided that the `userPassword` attribute is stored as MD5, SMD5, SHA, or SSHA.
`authCrypt:Htpasswd`
--------------------
Authenticate users against an [`.htpasswd`](http://httpd.apache.org/docs/2.2/programs/htpasswd.html) file. It can be used for example when you migrate a web site from basic HTTP authentication to SimpleSAMLphp.
The simple structure of the `.htpasswd` file does not allow for per-user attributes, but you can define some static attributes for all users.
An example authentication source in `config/authsources.php` could look like this:
'htpasswd' => array(
'authcrypt:Htpasswd',
'htpasswd_file' => '/var/www/foo.edu/legacy_app/.htpasswd',
'static_attributes' => array(
'eduPersonAffiliation' => array('member', 'employee'),
'Organization' => array('University of Foo'),
),
),
<?php
namespace SimpleSAML\Module\authcrypt\Auth\Source;
/**
* Authentication source for username & hashed password.
*
* This class is an authentication source which stores all username/hashes in an array,
* and authenticates users against this array.
*
* @author Dyonisius Visser, TERENA.
* @package SimpleSAMLphp
*/
class Hash extends \SimpleSAML\Module\core\Auth\UserPassBase
{
/**
* Our users, stored in an associative array. The key of the array is "<username>:<passwordhash>",
* while the value of each element is a new array with the attributes for each user.
*/
private $users;
/**
* Constructor for this authentication source.
*
* @param array $info Information about this authentication source.
* @param array $config Configuration.
*
* @throws Exception in case of a configuration error.
*/
public function __construct($info, $config)
{
assert(is_array($info));
assert(is_array($config));
// Call the parent constructor first, as required by the interface
parent::__construct($info, $config);
$this->users = [];
// Validate and parse our configuration
foreach ($config as $userpass => $attributes) {
if (!is_string($userpass)) {
throw new \Exception('Invalid <username>:<passwordhash> for authentication source '.
$this->authId.': '.$userpass);
}
$userpass = explode(':', $userpass, 2);
if (count($userpass) !== 2) {
throw new \Exception('Invalid <username>:<passwordhash> for authentication source '.
$this->authId.': '.$userpass[0]);
}
$username = $userpass[0];
$passwordhash = $userpass[1];
try {
$attributes = \SimpleSAML\Utils\Attributes::normalizeAttributesArray($attributes);
} catch (\Exception $e) {
throw new \Exception('Invalid attributes for user '.$username.
' in authentication source '.$this->authId.': '.
$e->getMessage());
}
$this->users[$username.':'.$passwordhash] = $attributes;
}
}
/**
* Attempt to log in using the given username and password.
*
* On a successful login, this function should return the users attributes. On failure,
* it should throw an exception. If the error was caused by the user entering the wrong
* username OR password, a \SimpleSAML\Error\Error('WRONGUSERPASS') should be thrown.
*
* The username is UTF-8 encoded, and the hash is base64 encoded.
*
* @param string $username The username the user wrote.
* @param string $password The password the user wrote.
*
* @return array Associative array with the users attributes.
*
* @throws \SimpleSAML\Error\Error if authentication fails.
*/
protected function login($username, $password)
{
assert(is_string($username));
assert(is_string($password));
foreach ($this->users as $userpass => $attrs) {
$matches = explode(':', $userpass, 2);
if ($matches[0] === $username) {
if (\SimpleSAML\Utils\Crypto::pwValid($matches[1], $password)) {
return $attrs;
} else {
\SimpleSAML\Logger::debug('Incorrect password "'.$password.'" for user '.$username);
}
}
}
throw new \SimpleSAML\Error\Error('WRONGUSERPASS');
}
}
<?php
namespace SimpleSAML\Module\authcrypt\Auth\Source;
/**
* Authentication source for Apache 'htpasswd' files.
*
* @author Dyonisius (Dick) Visser, TERENA.
* @package SimpleSAMLphp
*/
use WhiteHat101\Crypt\APR1_MD5;
class Htpasswd extends \SimpleSAML\Module\core\Auth\UserPassBase
{
/**
* Our users, stored in an array, where each value is "<username>:<passwordhash>".
*
* @var array
*/
private $users;
/**
* An array containing static attributes for our users.
*
* @var array
*/
private $attributes = [];
/**
* Constructor for this authentication source.
*
* @param array $info Information about this authentication source.
* @param array $config Configuration.
*
* @throws Exception if the htpasswd file is not readable or the static_attributes array is invalid.
*/
public function __construct($info, $config)
{
assert(is_array($info));
assert(is_array($config));
// Call the parent constructor first, as required by the interface
parent::__construct($info, $config);
$this->users = [];
if (!$htpasswd = file_get_contents($config['htpasswd_file'])) {
throw new \Exception('Could not read '.$config['htpasswd_file']);
}
$this->users = explode("\n", trim($htpasswd));
try {
$this->attributes = \SimpleSAML\Utils\Attributes::normalizeAttributesArray($config['static_attributes']);
} catch (\Exception $e) {
throw new \Exception('Invalid static_attributes in authentication source '.
$this->authId.': '.$e->getMessage());
}
}
/**
* Attempt to log in using the given username and password.
*
* On a successful login, this function should return the username as 'uid' attribute,
* and merged attributes from the configuration file.
* On failure, it should throw an exception. A \SimpleSAML\Error\Error('WRONGUSERPASS')
* should be thrown in case of a wrong username OR a wrong password, to prevent the
* enumeration of usernames.
*
* @param string $username The username the user wrote.
* @param string $password The password the user wrote.
*
* @return array Associative array with the users attributes.
*
* @throws \SimpleSAML\Error\Error if authentication fails.
*/
protected function login($username, $password)
{
assert(is_string($username));
assert(is_string($password));
foreach ($this->users as $userpass) {
$matches = explode(':', $userpass, 2);
if ($matches[0] == $username) {
$crypted = $matches[1];
// This is about the only attribute we can add
$attributes = array_merge(['uid' => [$username]], $this->attributes);
// Traditional crypt(3)
if (\SimpleSAML\Utils\Crypto::secureCompare($crypted, crypt($password, $crypted))) {
\SimpleSAML\Logger::debug('User '.$username.' authenticated successfully');
\SimpleSAML\Logger::warning(
'CRYPT authentication is insecure. Please consider using something else.'
);
return $attributes;
}
// Apache's custom MD5
if (APR1_MD5::check($password, $crypted)) {
\SimpleSAML\Logger::debug('User '.$username.' authenticated successfully');
return $attributes;
}
// PASSWORD_BCRYPT
if (\SimpleSAML\Utils\Crypto::pwValid($crypted, $password)) {
\SimpleSAML\Logger::debug('User '.$username.' authenticated successfully');
return $attributes;
}
throw new \SimpleSAML\Error\Error('WRONGUSERPASS');
}
}
throw new \SimpleSAML\Error\Error('WRONGUSERPASS');
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment