changes to create users and set passwords on win2008r2

This commit is contained in:
Ralf Becker 2013-05-24 17:08:15 +00:00
parent 59f57d69b6
commit 8c6fd8d936
3 changed files with 144 additions and 14 deletions

View File

@ -473,8 +473,7 @@ class accounts
if (($id = $this->backend->save($data)) && $data['account_type'] != 'g')
{
// if we are not on a pure LDAP system, we have to write the account-date via the contacts class now
if (($this->config['account_repository'] != 'ldap' ||
$this->config['contact_repository'] == 'sql-ldap') &&
if (($this->config['account_repository'] == 'sql' || $this->config['contact_repository'] == 'sql-ldap') &&
(!($old = $this->read($data['account_id'])) || // only for new account or changed contact-data
$old['account_firstname'] != $data['account_firstname'] ||
$old['account_lastname'] != $data['account_lastname'] ||

View File

@ -19,7 +19,16 @@ require_once EGW_API_INC.'/adldap/adLDAP.php';
* RID (realtive id / last part of string-SID) is used as nummeric account-id (negativ for groups).
* SID for queries get reconstructed from account_id by prepending domain-SID.
*
* Easiest way to enable SSL on a win2008r2 DC is to install role "Active Director Certificate Services"
* or in German "Active Directory-Zertificatsdienste" AND reboot.
*
* Changing passwords currently requires ads_admin user (configured in setup) to have "Reset Password"
* priveledges, as PHP can not delete unicodePwd attribute with old password and set it in same
* operation with new password!
*
* @access internal only use the interface provided by the accounts class
* @link http://www.selfadsi.org/user-attributes-w2k8.htm
* @link http://www.selfadsi.org/attributes-e2k7.htm
*/
class accounts_ads
{
@ -625,6 +634,11 @@ class accounts_ads
$attributes = array();
foreach($new2adldap as $egw => $adldap)
{
if ($egw == 'account_passwd' && (empty($data[$egw]) ||
!$this->adldap->getUseSSL() && !$this->adldap->getUseTLS()))
{
continue; // do not try to set password, if no SSL or TLS, whole user creation will fail
}
if (isset($data[$egw])) $attributes[$adldap] = $data[$egw];
}
$attributes['enabled'] = !isset($data['account_status']) || $data['account_status'] === 'A';
@ -673,6 +687,12 @@ class accounts_ads
{
switch($egw)
{
case 'account_passwd':
if (!empty($data[$egw]) && ($this->adldap->getUseSSL() || $this->adldap->getUseTLS()))
{
$attributes[$adldap] = $data[$egw]; // only try to set password, if no SSL or TLS
}
break;
case 'account_primary_group':
// setting a primary group seems to fail, if user is no member of that group
if (isset($old['memberships'][$data[$egw]]) ||
@ -684,13 +704,14 @@ class accounts_ads
break;
case 'account_lid':
$ldap[$adldap] = $data[$egw];
$ldap['userPrincipalName'] = $data[$egw].'@'.$this->frontend->config['ads_domain'];
break;
case 'account_expires':
$attributes[$adldap] = $data[$egw] == -1 ? self::EXPIRES_NEVER :
self::convertUnixTimeToWindowsTime($data[$egw]);
break;
case 'account_status':
$attributes[$adldap] = $data[$egw] != 'A';
$attributes[$adldap] = $data[$egw] == 'A';
break;
default:
$attributes[$adldap] = $data[$egw];
@ -710,6 +731,8 @@ class accounts_ads
error_log(__METHOD__."(".array2string($data).") ldap_modify($ds, '$old[account_dn]', ".array2string($ldap).') returned '.array2string($ret));
return false;
}
else error_log(__METHOD__."(".array2string($data).") ldap_modify($ds, '$old[account_dn]', ".array2string($ldap).') returned '.array2string($ret));
return $old['account_id'];
}
@ -979,7 +1002,7 @@ class accounts_ads
}
else if (self::$debug) error_log(__METHOD__.'('.array2string($attr_filter).", '$account_type') ldap_search($ds, '$context', '$filter')=$sri allValues=".array2string($allValues));
error_log(__METHOD__.'('.array2string($attr_filter).", '$account_type') ldap_search($ds, '$context', '$filter') returning ".array2string($accounts).' '.function_backtrace());
//error_log(__METHOD__.'('.array2string($attr_filter).", '$account_type') ldap_search($ds, '$context', '$filter') returning ".array2string($accounts).' '.function_backtrace());
return $accounts;
}
@ -1147,7 +1170,7 @@ class adLDAP_egw extends adLDAP
*
* @var string
*/
protected $charset = 'iso-8859-1';
public $charset = 'iso-8859-1';
function __construct(array $options=array())
{
@ -1225,6 +1248,11 @@ class adLDAPUsers_egw extends adLDAPUsers
*
* Extended to allow to specify $attribute["container"] as string, because array hardcodes "OU=", while Samba4 and win2008r2 uses "CN=Users"
*
* Extended to ensure following creating order required by at least win2008r2:
* - new user without password and deactivated
* - add password, see new method setPassword
* - activate user
*
* @param array $attributes The attributes to set to the user account
* @return bool
*/
@ -1252,6 +1280,7 @@ class adLDAPUsers_egw extends adLDAPUsers
// Additional stuff only used for adding accounts
$add["cn"][0] = $attributes["display_name"];
$add["samaccountname"][0] = $attributes["username"];
$add["userPrincipalName"][0] = $attributes["username"].$this->adldap->getAccountSuffix();
$add["objectclass"][0] = "top";
$add["objectclass"][1] = "person";
$add["objectclass"][2] = "organizationalPerson";
@ -1259,10 +1288,7 @@ class adLDAPUsers_egw extends adLDAPUsers
//$add["name"][0]=$attributes["firstname"]." ".$attributes["surname"];
// Set the account control attribute
$control_options = array("NORMAL_ACCOUNT");
if (!$attributes["enabled"]) {
$control_options[] = "ACCOUNTDISABLE";
}
$control_options = array("NORMAL_ACCOUNT", "ACCOUNTDISABLE");
$add["userAccountControl"][0] = $this->accountControl($control_options);
// Determine the container
@ -1270,12 +1296,31 @@ class adLDAPUsers_egw extends adLDAPUsers
$attributes["container"] = array_reverse($attributes["container"]);
$attributes["container"] = "OU=" . implode(",OU=",$attributes["container"]);
}
// we can NOT set password with ldap_add or ldap_modify, it needs ldap_mod_replace, at least under Win2008r2
unset($add['unicodePwd']);
// Add the entry
$result = @ldap_add($this->adldap->getLdapConnection(), "CN=" . $add["cn"][0] . "," . $attributes["container"] . "," . $this->adldap->getBaseDn(), $add);
$result = ldap_add($ds=$this->adldap->getLdapConnection(), $dn="CN=" . $add["cn"][0] . "," . $attributes["container"] . "," . $this->adldap->getBaseDn(), $add);
if ($result != true) {
error_log(__METHOD__."(".array2string($attributes).") ldap_add($ds, '$dn', ".array2string($add).") returned ".array2string($result)." ldap_error()=".ldap_error($ds));
return false;
}
// now password can be added to still disabled account
if (array_key_exists("password",$attributes))
{
if (!$this->setPassword($dn, $attributes['password'])) return false;
// now account can be enabled
if ($attributes["enabled"])
{
$control_options = array("NORMAL_ACCOUNT");
$mod = array("userAccountControl" => $this->accountControl($control_options));
$result = ldap_modify($ds, $dn, $mod);
if (!$result) error_log(__METHOD__."(".array2string($attributes).") ldap_modify($ds, '$dn', ".array2string($mod).") returned ".array2string($result)." ldap_error()=".ldap_error($ds));
}
}
return true;
}
@ -1292,12 +1337,91 @@ class adLDAPUsers_egw extends adLDAPUsers
$password="\"".$password."\"";
if (function_exists('mb_convert_encoding'))
{
return mb_convert_encoding($password, 'UTF-16LE', $this->adldap->charset);
return mb_convert_encoding($password, 'UTF-16LE', $this->adldap->charset);
}
$encoded="";
for ($i=0; $i <strlen($password); $i++){ $encoded.="{$password{$i}}\000"; }
return $encoded;
}
/**
* Set a password
*
* Requires "Reset password" priviledges from bind user!
*
* We can NOT set password with ldap_add or ldap_modify, it needs ldap_mod_replace, at least under Win2008r2!
*
* @param string $dn
* @param string $password
* @return boolean
*/
public function setPassword($dn, $password)
{
$result = ldap_mod_replace($ds=$this->adldap->getLdapConnection(), $dn, array(
'unicodePwd' => $this->encodePassword($password),
));
if (!$result) error_log(__METHOD__."('$dn', '$password') ldap_mod_replace($ds, '$dn', \$password) returned FALSE: ".ldap_error($ds));
return $result;
}
/**
* Modify a user
*
* @param string $username The username to query
* @param array $attributes The attributes to modify. Note if you set the enabled attribute you must not specify any other attributes
* @param bool $isGUID Is the username passed a GUID or a samAccountName
* @return bool
*/
public function modify($username, $attributes, $isGUID = false)
{
if ($username === NULL) { return "Missing compulsory field [username]"; }
if (array_key_exists("password", $attributes) && !$this->adldap->getUseSSL() && !$this->adldap->getUseTLS()) {
throw new adLDAPException('SSL/TLS must be configured on your webserver and enabled in the class to set passwords.');
}
// Find the dn of the user
$userDn = $this->dn($username, $isGUID);
if ($userDn === false) {
return false;
}
// Translate the update to the LDAP schema
$mod = $this->adldap->adldap_schema($attributes);
// Check to see if this is an enabled status update
if (!$mod && !array_key_exists("enabled", $attributes)){
return false;
}
// Set the account control attribute (only if specified)
if (array_key_exists("enabled", $attributes)){
if ($attributes["enabled"]){
$controlOptions = array("NORMAL_ACCOUNT");
}
else {
$controlOptions = array("NORMAL_ACCOUNT", "ACCOUNTDISABLE");
}
$mod["userAccountControl"][0] = $this->accountControl($controlOptions);
}
// we can NOT set password with ldap_add or ldap_modify, it needs ldap_mod_replace, at least under Win2008r2
unset($mod['unicodePwd']);
if ($mod)
{
// Do the update
$result = @ldap_modify($ds=$this->adldap->getLdapConnection(), $userDn, $mod);
$mod['unicodePwd'] = '***';
error_log(__METHOD__."(".array2string($attributes).") ldap_modify($ds, '$userDn', ".array2string($mod).") returned ".array2string($result)." ldap_error()=".ldap_error($ds));
if ($result == false) {
return false;
}
}
if (array_key_exists("password",$attributes) && !$this->setPassword($userDn, $attributes['password']))
{
return false;
}
return true;
}
}
/**

View File

@ -540,7 +540,11 @@
<td><input name="newsettings[ads_domain]" value="{value_ads_domain}" size="40" /></td>
</tr>
<tr class="row_off">
<td>{lang_Admin_user}<br/>{lang_optional,_if_only_authentication_AND_anonymous_search_is_enabled}:</td>
<td>
{lang_Admin_user}:<br/>
({lang_optional,_if_only_authentication_AND_anonymous_search_is_enabled})<br/>
{lang_Requires_"Reset_Password"_priviledges,_to_change_passwords!}
</td>
<td><input name="newsettings[ads_admin_user]" value="{value_ads_admin_user}" size="40" /></td>
</tr>
<tr class="row_on">
@ -548,8 +552,11 @@
<td><input type="password" name="newsettings[ads_admin_passwd]" value="{value_ads_admin_passwd}" size="40" /></td>
</tr>
<tr class="row_off">
<td>{lang_use_TLS_or_SSL} {lang_required_to_change_passwords}<br/>
<a href="http://adldap.sourceforge.net/wiki/doku.php?id=ldap_over_ssl" target="_blank">{lang_needs_extra_configuration_on_DC_and_webserver!}</a>:</td>
<td>
{lang_use_TLS_or_SSL} {lang_required_to_change_passwords}:<br/>
{lang_Needs_extra_configuration_on_DC_and_webserver!}<br/>
{lang_On_win2008r2_easiest_way_is_to_enable_"Active_Directory_Certivicate_Services"_and_reboot.}
</td>
<td>
<select name="newsettings[ads_connection]">
<option value="">{lang_No}</option>