- fixed with ssha not working migration from sql <--> ldap

- using 16 char salt for ssha and smd5 as eclipse ldap admin does
- remove auth::hash_sql2ldap() method, as it is now in setup/inc/class.setup_cmd_ldap.inc.php
- added ability to create uid dn in setup_cmd_ldap subcommand create_ldap
This commit is contained in:
Ralf Becker 2011-05-04 09:42:50 +00:00
parent 457e79454d
commit 57fc9c63fc
3 changed files with 53 additions and 105 deletions

View File

@ -319,12 +319,14 @@ class auth
* uses the encryption type set in setup and calls the appropriate encryption functions * uses the encryption type set in setup and calls the appropriate encryption functions
* *
* @param $password password to encrypt * @param $password password to encrypt
* @param $type=null default to $GLOBALS['egw_info']['server']['ldap_encryption_type']
* @return string
*/ */
static function encrypt_ldap($password) static function encrypt_ldap($password, $type=null)
{ {
$type = strtolower($GLOBALS['egw_info']['server']['ldap_encryption_type']); if (is_null($type)) $type = $GLOBALS['egw_info']['server']['ldap_encryption_type'];
$salt = ''; $salt = '';
switch($type) switch(strtolower($type))
{ {
default: // eg. setup >> config never saved default: // eg. setup >> config never saved
case 'des': case 'des':
@ -366,7 +368,7 @@ class auth
$e_password = '{md5}' . base64_encode(pack("H*",md5($password))); $e_password = '{md5}' . base64_encode(pack("H*",md5($password)));
break; break;
case 'smd5': case 'smd5':
$salt = self::randomstring(8); $salt = self::randomstring(16);
$hash = md5($password . $salt,true); $hash = md5($password . $salt,true);
$e_password = '{SMD5}' . base64_encode($hash . $salt); $e_password = '{SMD5}' . base64_encode($hash . $salt);
break; break;
@ -374,7 +376,7 @@ class auth
$e_password = '{SHA}' . base64_encode(sha1($password,true)); $e_password = '{SHA}' . base64_encode(sha1($password,true));
break; break;
case 'ssha': case 'ssha':
$salt = self::randomstring(8); $salt = self::randomstring(16);
$hash = sha1($password . $salt,true); $hash = sha1($password . $salt,true);
$e_password = '{SSHA}' . base64_encode($hash . $salt); $e_password = '{SSHA}' . base64_encode($hash . $salt);
break; break;
@ -386,35 +388,6 @@ class auth
return $e_password; return $e_password;
} }
/**
* Create an ldap hash from an sql hash
*
* @param string $hash
*/
static function hash_sql2ldap($hash)
{
switch(strtolower($GLOBALS['egw_info']['server']['sql_encryption_type']))
{
case '': // not set sql_encryption_type
case 'md5':
$hash = '{md5}' . base64_encode(pack("H*",$hash));
break;
case 'crypt':
$hash = '{crypt}' . $hash;
break;
case 'plain':
$saved_h = $hash;
if (preg_match('/^\\{([a-z_5]+)\\}(.+)$/i',$hash,$matches))
{
$hash= $matches[2];
} else {
$hash = $saved_h;
}
break;
}
return $hash;
}
/** /**
* Create a password for storage in the accounts table * Create a password for storage in the accounts table
* *
@ -466,13 +439,13 @@ class auth
self::$error = 'no ext crypt'; self::$error = 'no ext crypt';
break; break;
case 'smd5': case 'smd5':
$salt = self::randomstring(8); $salt = self::randomstring(16);
$hash = md5($password . $salt,true); $hash = md5($password . $salt,true);
return '{SMD5}' . base64_encode($hash . $salt); return '{SMD5}' . base64_encode($hash . $salt);
case 'sha': case 'sha':
return '{SHA}' . base64_encode(sha1($password,true)); return '{SHA}' . base64_encode(sha1($password,true));
case 'ssha': case 'ssha':
$salt = self::randomstring(8); $salt = self::randomstring(16);
$hash = sha1($password . $salt,true); $hash = sha1($password . $salt,true);
return '{SSHA}' . base64_encode($hash . $salt); return '{SSHA}' . base64_encode($hash . $salt);
case 'md5': case 'md5':

View File

@ -30,31 +30,6 @@ $setup_tpl->set_file(array(
'T_alert_msg' => 'msg_alert_msg.tpl' 'T_alert_msg' => 'msg_alert_msg.tpl'
)); ));
function hash_sql2ldap($hash)
{
$type = $GLOBALS['egw_info']['server']['sql_encryption_type'];
if (preg_match('/^\\{(.*)\\}(.*)$/',$hash,$matches))
{
$type = $matches[1];
$hash = $matches[2];
}
switch(strtolower($type))
{
case '': // not set sql_encryption_type
case 'md5':
$hash = '{md5}' . base64_encode(pack("H*",$hash));
break;
case 'crypt':
$hash = '{crypt}' . $hash;
break;
case 'plain':
break;
}
return $hash;
}
// determine from where we migrate to what // determine from where we migrate to what
if (!is_object($GLOBALS['egw_setup']->db)) if (!is_object($GLOBALS['egw_setup']->db))
{ {
@ -94,7 +69,7 @@ $cmd = new setup_cmd_ldap(array(
if (!$_POST['migrate']) if (!$_POST['migrate'])
{ {
$accounts = $cmd->accounts($from == 'ldap'); $accounts = $cmd->accounts($from == 'ldap');
// now outputting the account selection // now outputting the account selection
$setup_tpl->set_block('migration','header','header'); $setup_tpl->set_block('migration','header','header');
$setup_tpl->set_block('migration','user_list','user_list'); $setup_tpl->set_block('migration','user_list','user_list');

View File

@ -12,9 +12,9 @@
/** /**
* setup command: test or create the ldap connection and hierarchy * setup command: test or create the ldap connection and hierarchy
* *
* All commands can be run via setup-cli eg: * All commands can be run via setup-cli eg:
* *
* setup/setup-cli.php --setup_cmd_ldap stylite.de,config-user,config-pw sub_command=set_mailbox \ * setup/setup-cli.php --setup_cmd_ldap stylite.de,config-user,config-pw sub_command=set_mailbox \
* ldap_base=dc=local ldap_admin=cn=admin,dc=local ldap_admin_pw=secret ldap_host=localhost test=1 * ldap_base=dc=local ldap_admin=cn=admin,dc=local ldap_admin_pw=secret ldap_host=localhost test=1
*/ */
@ -46,7 +46,7 @@ class setup_cmd_ldap extends setup_cmd
* @param string $ldap_context=null ou for accounts, default "ou=accounts,$base" * @param string $ldap_context=null ou for accounts, default "ou=accounts,$base"
* @param string $ldap_search_filter=null search-filter for accounts, default "(uid=%user)" * @param string $ldap_search_filter=null search-filter for accounts, default "(uid=%user)"
* @param string $ldap_group_context=null ou for groups, default "ou=groups,$base" * @param string $ldap_group_context=null ou for groups, default "ou=groups,$base"
* @param string $sub_command='create_ldap' 'create_ldap', 'test_ldap', 'test_ldap_root' * @param string $sub_command='create_ldap' 'create_ldap', 'test_ldap', 'test_ldap_root', see exec method
* @param string $ldap_encryption_type='des' * @param string $ldap_encryption_type='des'
*/ */
function __construct($domain,$ldap_host=null,$ldap_suffix=null,$ldap_admin=null,$ldap_admin_pw=null, function __construct($domain,$ldap_host=null,$ldap_suffix=null,$ldap_admin=null,$ldap_admin_pw=null,
@ -122,10 +122,10 @@ class setup_cmd_ldap extends setup_cmd
} }
return $msg; return $msg;
} }
/** /**
* Migrate to other account storage * Migrate to other account storage
* *
* @param boolean $to_ldap true: sql --> ldap, false: ldap --> sql * @param boolean $to_ldap true: sql --> ldap, false: ldap --> sql
* @return string with success message * @return string with success message
* @throws Exception on error * @throws Exception on error
@ -144,10 +144,10 @@ class setup_cmd_ldap extends setup_cmd
} }
// read accounts from old store // read accounts from old store
$accounts = $this->accounts(!$to_ldap); $accounts = $this->accounts(!$to_ldap);
// instanciate accounts obj for new store // instanciate accounts obj for new store
$accounts_obj = $this->accounts_obj($to_ldap); $accounts_obj = $this->accounts_obj($to_ldap);
$accounts_created = $groups_created = $errors = 0; $accounts_created = $groups_created = $errors = 0;
$target = $to_ldap ? 'LDAP' : 'SQL'; $target = $to_ldap ? 'LDAP' : 'SQL';
foreach($accounts as $account_id => $account) foreach($accounts as $account_id => $account)
@ -181,7 +181,7 @@ class setup_cmd_ldap extends setup_cmd
$account['account_passwd'] = self::hash_ldap2sql($account['account_pwd']); $account['account_passwd'] = self::hash_ldap2sql($account['account_pwd']);
} }
unset($account['person_id']); unset($account['person_id']);
if (!$accounts_obj->save($account)) if (!$accounts_obj->save($account))
{ {
$msg[] = lang('Creation of %1 in %2 failed !!!',$what,$target); $msg[] = lang('Creation of %1 in %2 failed !!!',$what,$target);
@ -191,7 +191,7 @@ class setup_cmd_ldap extends setup_cmd
$accounts_obj->set_memberships($account['memberships'],$account_id); $accounts_obj->set_memberships($account['memberships'],$account_id);
$msg[] = lang('%1 created in %2.',$what,$target); $msg[] = lang('%1 created in %2.',$what,$target);
$accounts_created++; $accounts_created++;
// should we run any or some addAccount hooks // should we run any or some addAccount hooks
if ($this->add_account_hook) if ($this->add_account_hook)
{ {
@ -204,7 +204,7 @@ class setup_cmd_ldap extends setup_cmd
} }
//error_log(__METHOD__."() setup up egw_info[server]: ldap_host='{$GLOBALS['egw_info']['server']['ldap_host']}', ldap_root_dn='{$GLOBALS['egw_info']['server']['ldap_root_dn']}', ldap_root_pw='{$GLOBALS['egw_info']['server']['ldap_root_pw']}', ldap_context='{$GLOBALS['egw_info']['server']['ldap_context']}', mail_suffix='{$GLOBALS['egw_info']['server']['mail_suffix']}', mail_logig_type='{$GLOBALS['egw_info']['server']['mail_login-type']}'"); //error_log(__METHOD__."() setup up egw_info[server]: ldap_host='{$GLOBALS['egw_info']['server']['ldap_host']}', ldap_root_dn='{$GLOBALS['egw_info']['server']['ldap_root_dn']}', ldap_root_pw='{$GLOBALS['egw_info']['server']['ldap_root_pw']}', ldap_context='{$GLOBALS['egw_info']['server']['ldap_context']}', mail_suffix='{$GLOBALS['egw_info']['server']['mail_suffix']}', mail_logig_type='{$GLOBALS['egw_info']['server']['mail_login-type']}'");
} }
try try
{ {
$account['location'] = 'addAccount'; $account['location'] = 'addAccount';
// running all addAccount hooks (currently NOT working, as not all work in setup) // running all addAccount hooks (currently NOT working, as not all work in setup)
@ -217,7 +217,7 @@ class setup_cmd_ldap extends setup_cmd
call_user_func($this->add_account_hook,$account); call_user_func($this->add_account_hook,$account);
} }
} }
catch(Exception $e) catch(Exception $e)
{ {
$msg[] = $e->getMessage(); $msg[] = $e->getMessage();
$errors++; $errors++;
@ -259,41 +259,39 @@ class setup_cmd_ldap extends setup_cmd
return lang('%1 users and %2 groups created, %3 errors',$accounts_created,$groups_created,$errors). return lang('%1 users and %2 groups created, %3 errors',$accounts_created,$groups_created,$errors).
($errors || $this->verbose ? "\n- ".implode("\n- ",$msg) : ''); ($errors || $this->verbose ? "\n- ".implode("\n- ",$msg) : '');
} }
/** /**
* Convert SQL hash to LDAP hash * Convert SQL hash to LDAP hash
* *
* @param string $hash * @param string $hash
* @return string * @return string
*/ */
public static function hash_sql2ldap($hash) public static function hash_sql2ldap($hash)
{ {
$type = $GLOBALS['egw_info']['server']['sql_encryption_type']; if (!($type = $GLOBALS['egw_info']['server']['sql_encryption_type'])) $type = 'md5';
if (preg_match('/^\\{(.*)\\}(.*)$/',$hash,$matches)) if (preg_match('/^\\{(.*)\\}(.*)$/',$hash,$matches))
{ {
$type = $matches[1]; list(,$type,$hash) = $matches;
$hash = $matches[2];
} }
switch(strtolower($type)) switch(strtolower($type))
{ {
case '': // not set sql_encryption_type
case 'md5':
$hash = '{md5}' . base64_encode(pack("H*",$hash));
break;
case 'crypt':
$hash = '{crypt}' . $hash;
break;
case 'plain': case 'plain':
// ldap stores plaintext passwords without {plain} prefix
break; break;
case 'md5':
$hash = base64_encode(pack("H*",$hash));
// fall through
default:
$hash = '{'.strtoupper($type).'}'.$hash;
} }
return $hash; return $hash;
} }
/** /**
* Convert LDAP hash to SQL hash * Convert LDAP hash to SQL hash
* *
* @param string $hash * @param string $hash
* @return string * @return string
*/ */
@ -308,7 +306,7 @@ class setup_cmd_ldap extends setup_cmd
/** /**
* Read all accounts from sql or ldap * Read all accounts from sql or ldap
* *
* @param boolean $from_ldap=true true: ldap, false: sql * @param boolean $from_ldap=true true: ldap, false: sql
* @return array * @return array
*/ */
@ -316,7 +314,7 @@ class setup_cmd_ldap extends setup_cmd
{ {
$accounts_obj = $this->accounts_obj($from_ldap); $accounts_obj = $this->accounts_obj($from_ldap);
//error_log(__METHOD__."(from_ldap=".array2string($from_ldap).') get_class(accounts_obj->backend)='.get_class($accounts_obj->backend)); //error_log(__METHOD__."(from_ldap=".array2string($from_ldap).') get_class(accounts_obj->backend)='.get_class($accounts_obj->backend));
$accounts = $accounts_obj->search(array('type' => 'both')); $accounts = $accounts_obj->search(array('type' => 'both'));
foreach($accounts as $account_id => &$account) foreach($accounts as $account_id => &$account)
@ -327,7 +325,7 @@ class setup_cmd_ldap extends setup_cmd
$account_id = $account['account_id']; $account_id = $account['account_id'];
} }
$account = $accounts_obj->read($account_id); $account = $accounts_obj->read($account_id);
if ($account['account_type'] == 'g') if ($account['account_type'] == 'g')
{ {
$account['members'] = $accounts_obj->members($account_id,true); $account['members'] = $accounts_obj->members($account_id,true);
@ -341,17 +339,17 @@ class setup_cmd_ldap extends setup_cmd
return $accounts; return $accounts;
} }
/** /**
* Instancate accounts object from either sql of ldap * Instancate accounts object from either sql of ldap
* *
* @param boolean $ldap true: ldap, false: sql * @param boolean $ldap true: ldap, false: sql
* @return accounts * @return accounts
*/ */
private function accounts_obj($ldap) private function accounts_obj($ldap)
{ {
static $enviroment_setup; static $enviroment_setup;
if (!$enviroment_setup) if (!$enviroment_setup)
{ {
parent::_setup_enviroment($this->domain); parent::_setup_enviroment($this->domain);
$enviroment_setup = true; $enviroment_setup = true;
@ -405,7 +403,7 @@ class setup_cmd_ldap extends setup_cmd
} }
return lang('Successful connected to LDAP server on %1 using DN %2.',$this->ldap_host,$dn); return lang('Successful connected to LDAP server on %1 using DN %2.',$this->ldap_host,$dn);
} }
/** /**
* Count active (not expired) users * Count active (not expired) users
* *
@ -415,7 +413,7 @@ class setup_cmd_ldap extends setup_cmd
private function users() private function users()
{ {
$this->connect(); $this->connect();
$sr = ldap_list($this->test_ldap->ds,$this->ldap_context,'ObjectClass=posixAccount',array('dn','shadowExpire')); $sr = ldap_list($this->test_ldap->ds,$this->ldap_context,'ObjectClass=posixAccount',array('dn','shadowExpire'));
if (!($entries = ldap_get_entries($this->test_ldap->ds, $sr))) if (!($entries = ldap_get_entries($this->test_ldap->ds, $sr)))
{ {
@ -430,7 +428,7 @@ class setup_cmd_ldap extends setup_cmd
} }
return $num; return $num;
} }
/** /**
* Check and if does not yet exist create the new database and user * Check and if does not yet exist create the new database and user
* *
@ -445,7 +443,7 @@ class setup_cmd_ldap extends setup_cmd
$this->ldap_base => array(), $this->ldap_base => array(),
$this->ldap_context => array(), $this->ldap_context => array(),
$this->ldap_group_context => array(), $this->ldap_group_context => array(),
$this->ldap_root_dn => array('userPassword' => '{crypt}'.crypt($this->ldap_root_pw)), $this->ldap_root_dn => array('userPassword' => auth::encrypt_ldap($this->ldap_root_pw,'ssha')),
) as $dn => $extra) ) as $dn => $extra)
{ {
if (!$this->_create_node($dn,$extra,$check_only) && $dn == $this->ldap_root_dn) if (!$this->_create_node($dn,$extra,$check_only) && $dn == $this->ldap_root_dn)
@ -467,7 +465,7 @@ class setup_cmd_ldap extends setup_cmd
private function delete_base() private function delete_base()
{ {
$this->connect($this->ldap_admin,$this->ldap_admin_pw); $this->connect($this->ldap_admin,$this->ldap_admin_pw);
// if base not set, use context minus one hierarchy, eg. ou=accounts,(o=domain,dc=local) // if base not set, use context minus one hierarchy, eg. ou=accounts,(o=domain,dc=local)
if (empty($this->ldap_base) && $this->ldap_context) if (empty($this->ldap_base) && $this->ldap_context)
{ {
@ -486,10 +484,10 @@ class setup_cmd_ldap extends setup_cmd
return lang('LDAP dn="%1" with %2 entries deleted.', return lang('LDAP dn="%1" with %2 entries deleted.',
$this->ldap_base,$this->rdelete($this->ldap_base)); $this->ldap_base,$this->rdelete($this->ldap_base));
} }
/** /**
* Recursive delete a dn * Recursive delete a dn
* *
* @param string $dn * @param string $dn
* @return int integer number of deleted entries * @return int integer number of deleted entries
* @throws egw_exception if dn not listable or delete fails * @throws egw_exception if dn not listable or delete fails
@ -518,7 +516,7 @@ class setup_cmd_ldap extends setup_cmd
* Set mailbox attribute in $this->ldap_base according to given format * Set mailbox attribute in $this->ldap_base according to given format
* *
* Uses $this->ldap_host, $this->ldap_admin and $this->ldap_admin_pw to connect. * Uses $this->ldap_host, $this->ldap_admin and $this->ldap_admin_pw to connect.
* *
* @param string $this->object_class='qmailUser' * @param string $this->object_class='qmailUser'
* @param string $this->mbox_attr='mailmessagestore' lowercase!!! * @param string $this->mbox_attr='mailmessagestore' lowercase!!!
* @param string $this->mail_login_type='email' 'email', 'vmailmgr', 'standard' or 'uidNumber' * @param string $this->mail_login_type='email' 'email', 'vmailmgr', 'standard' or 'uidNumber'
@ -528,7 +526,7 @@ class setup_cmd_ldap extends setup_cmd
private function set_mailbox() private function set_mailbox()
{ {
$this->connect($this->ldap_admin,$this->ldap_admin_pw); $this->connect($this->ldap_admin,$this->ldap_admin_pw);
// if base not set, use context minus one hierarchy, eg. ou=accounts,(o=domain,dc=local) // if base not set, use context minus one hierarchy, eg. ou=accounts,(o=domain,dc=local)
if (empty($this->ldap_base) && $this->ldap_context) if (empty($this->ldap_base) && $this->ldap_context)
{ {
@ -574,7 +572,7 @@ class setup_cmd_ldap extends setup_cmd
return $this->test ? lang('%1 entries would have been modified.',$modified) : return $this->test ? lang('%1 entries would have been modified.',$modified) :
lang('%1 entries modified.',$modified); lang('%1 entries modified.',$modified);
} }
/** /**
* array with objectclasses for the objects we can create * array with objectclasses for the objects we can create
* *
@ -584,6 +582,7 @@ class setup_cmd_ldap extends setup_cmd
'o' => 'organization', 'o' => 'organization',
'ou' => 'organizationalUnit', 'ou' => 'organizationalUnit',
'cn' => array('organizationalRole','simpleSecurityObject'), 'cn' => array('organizationalRole','simpleSecurityObject'),
'uid' => array('uidObject','organizationalRole','simpleSecurityObject'),
'dc' => array('organization','dcObject'), 'dc' => array('organization','dcObject'),
); );
@ -597,7 +596,7 @@ class setup_cmd_ldap extends setup_cmd
*/ */
private function _create_node($dn,$extra=array()) private function _create_node($dn,$extra=array())
{ {
//echo "<p>_create_node($dn,".print_r($extra,true).")</p>\n"; //echo "<p>_create_node($dn,".array2string($extra).")</p>\n";
// check if the node already exists and return if it does // check if the node already exists and return if it does
if (@ldap_read($this->test_ldap->ds,$dn,'objectClass=*')) if (@ldap_read($this->test_ldap->ds,$dn,'objectClass=*'))
{ {
@ -618,6 +617,7 @@ class setup_cmd_ldap extends setup_cmd
lang('Supported node types:').implode(', ',array_keys(self::$requiredObjectclasses))); lang('Supported node types:').implode(', ',array_keys(self::$requiredObjectclasses)));
} }
if ($name == 'dc') $extra['o'] = $value; // required by organisation if ($name == 'dc') $extra['o'] = $value; // required by organisation
if ($name == 'uid') $extra['cn'] = $value; // required by organizationalRole
if (!@ldap_add($this->test_ldap->ds,$dn,$attr = array( if (!@ldap_add($this->test_ldap->ds,$dn,$attr = array(
$name => $value, $name => $value,