Add support for hashed passwords & add authcrypt:Hash authsource.
Thanks to Dyonisius Visser for implementing this. git-svn-id: http://simplesamlphp.googlecode.com/svn/trunk@2962 44740490-163a-0410-bde0-09ae8108e29a
This commit is contained in:
parent
ee383de867
commit
1f722c9f26
|
@ -0,0 +1,48 @@
|
|||
#!/usr/bin/env php
|
||||
<?php
|
||||
/*
|
||||
* $Id$
|
||||
* Interactive script to generate password hashes.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
/* This is the base directory of the simpleSAMLphp installation. */
|
||||
$baseDir = dirname(dirname(__FILE__));
|
||||
|
||||
/* Add library autoloader. */
|
||||
require_once($baseDir . '/lib/_autoload.php');
|
||||
|
||||
|
||||
echo "Enter password: ";
|
||||
$password = trim(fgets(STDIN));
|
||||
|
||||
if(empty($password)) {
|
||||
echo "Need at least one character for a password\n";
|
||||
exit(1);
|
||||
}
|
||||
|
||||
$table = '';
|
||||
foreach (array_chunk(hash_algos(), 6) as $chunk) {
|
||||
foreach($chunk as $algo) {
|
||||
$table .= sprintf('%-13s', $algo);
|
||||
}
|
||||
$table .= "\n";
|
||||
}
|
||||
|
||||
echo "The following hashing algorithms are available:\n" . $table . "\n";
|
||||
echo "Which one do you want? [sha256] ";
|
||||
$algo = trim(fgets(STDIN));
|
||||
if(empty($algo)) {
|
||||
$algo = 'sha256';
|
||||
}
|
||||
|
||||
if(!in_array(strtolower($algo), hash_algos())) {
|
||||
echo "Hashing algorithm '$algo' is not supported\n";
|
||||
exit(1);
|
||||
}
|
||||
|
||||
echo "Do you want to use a salt? (yes/no) [yes] ";
|
||||
$s = (trim(fgets(STDIN)) == 'no') ? '' : 'S';
|
||||
|
||||
echo "\n " . SimpleSAML_Utils_Crypto::pwHash($password, strtoupper( $s . $algo ) ). "\n\n";
|
|
@ -63,6 +63,17 @@ $config = array(
|
|||
),
|
||||
*/
|
||||
|
||||
/*
|
||||
'crypto-hash' => array(
|
||||
'authcrypto:Hash',
|
||||
// hashed version of 'verysecret', made with bin/pwgen.php
|
||||
'professor:{SSHA256}P6FDTEEIY2EnER9a6P2GwHhI5JDrwBgjQ913oVQjBngmCtrNBUMowA==' => array(
|
||||
'uid' => array('prof_a'),
|
||||
'eduPersonAffiliation' => array('member', 'employee', 'board'),
|
||||
),
|
||||
),
|
||||
*/
|
||||
|
||||
/*
|
||||
// This authentication source serves as an example of integration with an
|
||||
// external authentication engine. Take a look at the comment in the beginning
|
||||
|
|
|
@ -67,6 +67,7 @@ $config = array (
|
|||
* This password must be kept secret, and modified from the default value 123.
|
||||
* This password will give access to the installation page of simpleSAMLphp with
|
||||
* metadata listing and diagnostics pages.
|
||||
* You can also put a hash here; run "bin/pwgen.php" to generate one.
|
||||
*/
|
||||
'auth.adminpassword' => '123',
|
||||
'admin.protectindexpage' => false,
|
||||
|
|
|
@ -0,0 +1,83 @@
|
|||
<?
|
||||
/**
|
||||
* A class for crypto related functions
|
||||
*
|
||||
* @author Dyonisius Visser, TERENA. <visser@terena.org>
|
||||
* @package simpleSAMLphp
|
||||
* @version $Id$
|
||||
*/
|
||||
class SimpleSAML_Utils_Crypto {
|
||||
|
||||
/**
|
||||
* This function generates a password hash
|
||||
* @param $password The unencrypted password
|
||||
* @param $algo The hashing algorithm, capitals, optionally prepended with 'S' (salted)
|
||||
* @param $salt Optional salt
|
||||
*/
|
||||
public static function pwHash($password, $algo, $salt = NULL) {
|
||||
assert('is_string($algo)');
|
||||
assert('is_string($password)');
|
||||
|
||||
if(in_array(strtolower($algo), hash_algos())) {
|
||||
$php_algo = strtolower($algo); // 'sha256' etc
|
||||
// LDAP compatibility
|
||||
return '{' . preg_replace('/^SHA1$/', 'SHA', $algo) . '}'
|
||||
.base64_encode(hash($php_algo, $password, TRUE));
|
||||
}
|
||||
|
||||
// Salt
|
||||
if(!$salt) {
|
||||
// Default 8 byte salt, but 4 byte for LDAP SHA1 hashes
|
||||
$bytes = ($algo == 'SSHA1') ? 4 : 8;
|
||||
$salt = SimpleSAML_Utilities::generateRandomBytes($bytes, TRUE);
|
||||
}
|
||||
|
||||
if($algo[0] == 'S' && in_array(substr(strtolower($algo),1), hash_algos())) {
|
||||
$php_algo = substr(strtolower($algo),1); // 'sha256' etc
|
||||
// Salted hash, with LDAP compatibility
|
||||
return '{' . preg_replace('/^SSHA1$/', 'SSHA', $algo) . '}' .
|
||||
base64_encode(hash($php_algo, $password.$salt, TRUE) . $salt);
|
||||
}
|
||||
|
||||
throw new Exception('Hashing algoritm \'' . strtolower($algo) . '\' not supported');
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This function checks if a password is valid
|
||||
* @param $crypted Password as appears in password file, optionally prepended with algorithm
|
||||
* @param $clear Password to check
|
||||
*/
|
||||
public static function pwValid($crypted, $clear) {
|
||||
assert('is_string($crypted)');
|
||||
assert('is_string($clear)');
|
||||
|
||||
// Match algorithm string ('{SSHA256}', '{MD5}')
|
||||
if(preg_match('/^{(.*?)}(.*)$/', $crypted, $matches)) {
|
||||
|
||||
// LDAP compatibility
|
||||
$algo = preg_replace('/^(S?SHA)$/', '${1}1', $matches[1]);
|
||||
|
||||
$cryptedpw = $matches[2];
|
||||
|
||||
if(in_array(strtolower($algo), hash_algos())) {
|
||||
// Unsalted hash
|
||||
return ( $crypted == self::pwHash($clear, $algo) );
|
||||
}
|
||||
|
||||
if($algo[0] == 'S' && in_array(substr(strtolower($algo),1), hash_algos())) {
|
||||
$php_algo = substr(strtolower($algo),1);
|
||||
// Salted hash
|
||||
$hash_length = strlen(hash($php_algo, 'whatever', TRUE));
|
||||
$salt = substr(base64_decode($cryptedpw), $hash_length);
|
||||
return ( $crypted == self::pwHash($clear, $algo, $salt) );
|
||||
}
|
||||
|
||||
throw new Exception('Hashing algoritm \'' . strtolower($algo) . '\' not supported');
|
||||
|
||||
} else {
|
||||
return $crypted === $clear;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
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.
|
|
@ -0,0 +1,95 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* 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
|
||||
* @version $Id$
|
||||
*/
|
||||
class sspmod_authcrypt_Auth_Source_Hash extends sspmod_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.
|
||||
*/
|
||||
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 = array();
|
||||
|
||||
/* 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_Utilities::parseAttributes($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.
|
||||
*/
|
||||
protected function login($username, $password) {
|
||||
assert('is_string($username)');
|
||||
assert('is_string($password)');
|
||||
|
||||
foreach($this->users as $userpass=>$attrs) {
|
||||
if(preg_match("/^$username:(.*)$/", $userpass, $matches)) {
|
||||
if(SimpleSAML_Utils_Crypto::pwValid($matches[1], $password)) {
|
||||
return $this->users[$userpass];
|
||||
} else {
|
||||
SimpleSAML_Logger::debug('Incorrect password "' . $password . '" for user '. $username);
|
||||
}
|
||||
}
|
||||
}
|
||||
throw new SimpleSAML_Error_Error('WRONGUSERPASS');
|
||||
}
|
||||
|
||||
}
|
|
@ -55,7 +55,7 @@ class sspmod_core_Auth_Source_AdminPassword extends sspmod_core_Auth_UserPassBas
|
|||
throw new SimpleSAML_Error_Error('WRONGUSERPASS');
|
||||
}
|
||||
|
||||
if ($password !== $adminPassword) {
|
||||
if (!SimpleSAML_Utils_Crypto::pwValid($adminPassword, $password)) {
|
||||
throw new SimpleSAML_Error_Error('WRONGUSERPASS');
|
||||
}
|
||||
|
||||
|
|
|
@ -33,7 +33,7 @@ if (isset($_POST['password'])) {
|
|||
|
||||
/* Validate and sanitize form data. */
|
||||
|
||||
if ($_POST['password'] === $correctpassword) {
|
||||
if (SimpleSAML_Utils_Crypto::pwValid($correctpassword, $_POST['password'])) {
|
||||
$username = 'admin';
|
||||
$password = $_POST['password'];
|
||||
|
||||
|
|
Reference in New Issue