Open xloouch opened 1 week ago
If I understood you correctly, the user name is stored in the uid attribute in your LDAP. I have built the function into the username_ldap_attribute branch. You can now make the settings in the .env:
authldap.username_ldap_attribute = uid
Please test whether it meets your requirements.
Hi @rakoitde
I've walked through it. I had additionally a lot of changes done. Because it's ment to connect to an AD-LDAP and not a "normal" LDAP.
I haven't done the changes in a "beautifull" way.. if you want, i can send you the changed sources
regards
Xloouch
hi @xloouch If I can help with a manageable effort so that the code does not have to be adjusted manually, please send me the desired changes. Otherwise please close the issue.
hi @rakoitde
i've had to do a lot of "changes" .. beacuse, it seems, your library is ment to be for "AD-LDAP"..
Firstly: If you have any question, about my changed. please don't hesitate to ask.
/**
* The ldap attributes
*
* @var list<string>
*/
public array $attributes = [
'objectSID', 'distinguishedname', 'displayName', 'title', 'description','givenName', 'sn', 'mail', 'co', 'telephoneNumber', 'mobile', 'company', 'department', 'l', 'postalCode', 'streetAddress', 'displayName', 'samaccountname', 'thumbnailPhoto', 'userAccountControl'];
/**
* The ldap attributes
*
* @var list<string>
*/
public array $attributes = [
'dn','uid', 'displayname', 'cn', 'givenname', 'sn', 'mail', 'o', 'telephonenumber', 'mobile', 'roomnumber', 'departmentnumber', 'l', 'postalcode', 'street','c','uidnumber'];
i left the "jpegphoto" out. because I never got it to work.. (instead of "thumbnailPhoto"
i needed to extend the ".env" variables with the following:
authldap.ldap_type = ldap
authldap.login_attribute = uid
authldap.use_proxyuser = true // if you need a proxy-user to access the ldap
authldap.proxy_username = // full dn of the proxy user
authldap.proxy_password = // password of the proxy user
CLI::write(' attributes: ' . CLI::color(implode(', ', $ldapConfig->attributes), 'white'), 'green');
//extension:
CLI::write(' ldap_type: ' . CLI::color($ldapConfig->ldap_type, 'white'), 'green');
CLI::write(' login_attribute: ' . CLI::color($ldapConfig->login_attribute, 'white'), 'green');
CLI::write(' use_proxyuser: ' . CLI::color($ldapConfig->use_proxyuser ? 'true' : 'false', 'white'), 'green');
CLI::write(' proxy_username: ' . CLI::color($ldapConfig->proxy_username, 'white'), 'green');
CLI::write(' proxy_password: ' . CLI::color($ldapConfig->proxy_password, 'white'), 'green');
CLI::newLine();
Here I extended it with the ldap-switch and the proxy-user
public function bind()
{
if(config('AuthLDAP')->ldap_type=="ad"){
$ldap_domain = config('AuthLDAP')->ldap_domain;
$ldap_user = $ldap_domain . '\\' . $this->username;
}else{
$ldap_user = $this->username;
}
if(config('AuthLDAP')->use_proxyuser){
CLI::write(' proxy_username: ' . CLI::color(config('AuthLDAP')->proxy_username, 'white'), 'green');
CLI::write(' proxy_password: ' . CLI::color(config('AuthLDAP')->proxy_password, 'white'), 'green');
}
CLI::write(' bind user: ' . CLI::color($this->username, 'white'), 'green');
if(config('AuthLDAP')->ldap_type=="ad"){
CLI::write(' bind domain: ' . CLI::color($ldap_domain, 'white'), 'green');
CLI::write(' bind ldap_user: ' . CLI::color($ldap_user, 'white'), 'green');
}else{
CLI::write(' bind ldap_user: ' . CLI::color($this->username, 'white'), 'green');
}
ldap_set_option($this->connection, LDAP_OPT_PROTOCOL_VERSION, 3);
ldap_set_option($this->connection, LDAP_OPT_REFERRALS, 0);
if(config('AuthLDAP')->use_proxyuser){
#$bind = @ldap_bind($this->connection, config('AuthLDAP')->proxy_username, config('AuthLDAP')->proxy_password);
try{$bind_proxy = ldap_bind($this->connection, config('AuthLDAP')->proxy_username, config('AuthLDAP')->proxy_password);}
catch (Exception $e){echo 'Exception in function _authenticate: '. $e->getMessage().'\n';}
$filter = '('.config('AuthLDAP')->login_attribute.'='.$this->username.')';
CLI::write(' ldap filter: ' . CLI::color($filter, 'white'), 'green');
$search = ldap_search($this->connection, config('AuthLDAP')->search_base, $filter, config('AuthLDAP')->attributes);
$entries = ldap_get_entries($this->connection, $search);
$binddn = $entries[0]['dn'];
CLI::write(' full dn: ' . CLI::color($binddn, 'white'), 'green');
$bind = @ldap_bind($this->connection, $binddn, $this->password);
}else{
$bind = @ldap_bind($this->connection, $ldap_user, $this->password);
}
if ($bind !== false) {
CLI::write(' isAuthenticated: ' . CLI::color('true', 'white'), 'green');
CLI::write(' Ldap_connect: ' . CLI::color(ldap_error($this->connection), 'white'), 'green');
} else {
CLI::write(' isAuthenticated: ' . CLI::color('false', 'red'), 'green');
CLI::write(' Ldap_connect: ' . CLI::color(ldap_error($this->connection), 'red'), 'green');
}
return $bind;
}
now, to the "bigger" changes, which i had to do.. (but they aren't very beautifull
/**
* Authenticate user against LDAP host
*/
public function auth()
{
ldap_set_option($this->connection, LDAP_OPT_PROTOCOL_VERSION, 3);
ldap_set_option($this->connection, LDAP_OPT_REFERRALS, 0);
$ldapAttributes ??= $this->config->attributes;
log_message('debug', 'Starting Auth');
if($this->config->ldap_type == "ad"){
log_message('debug', 'LDAPManager.php - auth(): Using AD connector');
$ldap_domain = config('AuthLDAP')->ldap_domain;
$ldap_user = $ldap_domain . '\\' . $this->username;
$ldap_user = $this->username;
$this->bind = @ldap_bind($this->connection, $ldap_user, $this->password);
}elseif($this->config->ldap_type == "ldap"){
log_message('debug', 'LDAPManager.php - auth(): Using LDAP connector');
if($this->config->use_proxyuser){
try{
$this->bind = ldap_bind($this->connection, $this->config->proxy_username, $this->config->proxy_password);
log_message('debug', 'LDAPManager.php - auth(): Using Proxy User for pre-authentication');
}
catch (Exception $e){log_message('error', 'LDAPManager.php - auth(): Exception in function auth(): '. $e->getMessage().'\n');}
}else{
try{$this->bind = ldap_bind($this->connection, $this->username, $this->password);}
catch (Exception $e){log_message('error', 'LDAPManager.php - auth(): Exception in function auth(): '. $e->getMessage().'\n');}
}
if(!$this->bind){
log_message('error', 'LDAPManager.php - auth(): Unable to perform anonymous/proxy bind');
die();
}
log_message('debug', 'LDAPManager.php - auth(): Successfully bound to directory. Performing dn lookup for '.$this->username);
$filter = '('.$this->config->login_attribute.'='.$this->username.')';
$search = ldap_search($this->connection, $this->config->search_base, $filter, $ldapAttributes);
$entries = ldap_get_entries($this->connection, $search);
$binddn = $entries[0]['dn'];
$this->bind = @ldap_bind($this->connection, $binddn, $this->password);
if(! $this->bind) {
log_message('error',"LDAPManager.php - auth(): Failed login attempt: ".$this->username." from ".$_SERVER['REMOTE_ADDR']);
return FALSE;
}
}else{
log_message('error', json_encode(ldap_error($this->connection)));
}
log_message('error', json_encode(ldap_error($this->connection)));
}
In the following method, i still get errors, when i try to "load" the jpegphoto from the LDAP. Additionally i've lect the part with the AD commented out:
/**
* Get user attributes
*/
public function loadAttributes(?string $username = null, ?array $ldapAttributes = null): ?array
{
$samaccountname = $username ?? $this->username;
//log_message('debug',"LDAPManager.php - loadAttributes(): ".$samaccountname." - ".$username." - ".$this->username."\n");
$ldapAttributes ??= $this->config->attributes;
//log_message('debug',"LDAPManager.php - loadAttributes(): ".json_encode($ldapAttributes)."\n");
if($this->config->ldap_type == "ad"){
$filter = "(samaccountname={$samaccountname})";
}elseif($this->config->ldap_type == "ldap"){
$filter = '('.$this->config->login_attribute.'='.$this->username.')';
}else{
log_message('error', json_encode(ldap_error($this->connection)));
}
//log_message('debug',"LDAPManager.php - loadAttributes() - this->config: ".print_r($this->config,true)."\n");
$result = ldap_search($this->connection, $this->config->search_base, $filter, $ldapAttributes);
if ($result === false) {
$this->ldap_error = ldap_error($this->connection);
ldap_get_option($this->connection, LDAP_OPT_DIAGNOSTIC_MESSAGE, $err);
$this->ldap_diagnostic_message = $err;
return [];
}
$entries = ldap_get_entries($this->connection, $result);
$countEntries = (int) $entries['count'];
/*
$aduser = ldap_first_entry($this->connection, $result);
if ($aduser === false) {
return null;
}
$adattributes = ldap_get_attributes($this->connection, $aduser);
$dn = ldap_get_dn($this->connection, $aduser);
$this->dn = $dn;
$adCount = (int) $adattributes['count'];
*/
$attributes = [];
foreach($ldapAttributes as $key){
//log_message('debug',"LDAPManager.php - loadAttributes() - key: ".$key."\n");
if(!isset($entries[0][$key])){
$attributes[$key] = 0;
}elseif($key == "dn"){
$attributes[$key] = $entries[0][$key];
}elseif($key == "jpegphoto"){
$attributes[$key] = base64_encode($entries[0][$key][0]);
} else{
if($entries[0][$key]['count']==1){
$attributes[$key] = $entries[0][$key][0];
}else{
unset($entries[0][$key]['count']);
foreach($entries[0][$key] as $value){
$attributes[$key][]=$value;
}
}
}
}
//log_message('debug',"LDAPManager.php - loadAttributes() - attributes: ".json_encode($attributes)."\n");
/*
for ($i = 0; $i < $countEntries; $i++) {
$key = $adattributes[$i];
switch ($key) {
case 'objectSid':
$value = $this->sid_decode($adattributes[$key][0]);
break;
case 'jpegPhoto':
$value = base64_encode($adattributes[$key][0]);
break;
default:
$value = $adattributes[$key][0];
break;
}
$attributes[$key] = $value;
}
*/
$this->attributes = $attributes;
return $attributes;
}
I tried this Method, but never used it
public function getThumbnailImage()
{
if (! isset($this->attributes['jpegphoto'])) {
log_message('debug',"LDAPManager.php - getThumbnailImage(): no jpegphoto in attributes\n");
return '';
}
log_message('debug',"LDAPManager.php - getThumbnailImage(): ".json_encode($this->attributes['jpegphoto'])."\n");
return '<img src="data:image/jpeg;base64,' . $this->attributes['jpegphoto'] . '">';
}
I've only partionally implemented the loadTokengroups, cause I currently don't need id:
public function loadTokengroups(bool $return_group_sids = true)
{
if (! isset($this->dn)) {
return [];
}
if($this->config->ldap_type == "ad"){
$result = ldap_read($this->connection, $this->dn, 'CN=*', ['tokengroups']);
}else{
$result = ldap_read($this->connection, $this->dn, 'CN=*', ['memberOf']);
}
$tokegroups = ldap_get_entries($this->connection, $result);
log_message('debug', "LDAPManager.php - loadTokengroups(): ".json_encode($tokegroups));
$groups = [];
if ((int) $tokegroups['count'] > 0) {
if($this->config->ldap_type == "ad"){
$groups = $tokegroups[0]['tokengroups'];
}else{
$groups = $tokegroups[0]['memberof'];
}
unset($groups['count']);
/*
foreach ($groups as $i => &$sid) {
$sid = $this->sid_decode($sid);
if ($return_group_sids) {
$groups[$i] = $sid;
continue;
}
$sid_dn = ldap_read($this->connection, "<SID={$sid}>", 'CN=*', ['dn']);
if ($sid_dn !== false) {
$group = ldap_get_entries($this->connection, $sid_dn);
$group = $group['count'] === 1 ? $group[0]['dn'] : null;
$groups[$i] = $group;
}
}*/
}
return $groups;
}
i needed to partially update the Function "check()"
if ($ldapManager->isAuthenticated()) {
// Update user entity with ldap attributes and group sids
$ldapAttributes = $ldapManager->getAttributes();
//log_message('debug', "LDAP.php - check(): ".json_encode($ldapAttributes)."\n");
$user->mail = $ldapAttributes['mail'];
if(config('AuthLDAP')->ldap_type=="ad"){
$user->dn = $ldapAttributes['distinguishedName'];
$user->object_sid = $ldapAttributes['objectSid'];
}else{
$user->dn = $ldapAttributes['dn'];
}
$user->ldap_attributes = json_encode($ldapAttributes);
$user->ldap_group_sids = json_encode($ldapManager->getGroupSids());
$this->provider->update($user->id, $user);
if (config('AuthLDAP')->storePasswordInSession) {
$encrypter = Services::encrypter();
session()->set('password', $encrypter->encrypt($givenPassword));
}
return new Result([
'success' => true,
'extraInfo' => $user,
]);
}
As mentioned in the title, we have this variable "samaccountname" not in our LDAP.
We identify by "uid" ..
So, is there a possibility tho add a "user_login_attribute" = "uid" , if not set -> user_login_attribute = samaccountname in the .env..
So in the rakoitde/shieldldap/src/Autentication/LDAPManager.php , on Line 139, the filter will me more dynamically?
$filter = "({$user_login_attribute}={$samaccountname})";
?
(So i don't neet to change your source-code, for our needs) Thanks in Advance
Xloouch