View Juho Jaakkola's plugins
info@elgg.org
Security issues should be reported to security@elgg.org!
©2014 the Elgg Foundation
Elgg is a registered trademark of Thematic Networks.
Cover image by Raül Utrera is used under Creative Commons license.
Icons by Flaticon and FontAwesome.
Strugging to get it working, as no feedback appears to be provided for the failure.
Checked apache logs & /var/log folder for any sort of log.
Hoping for a bit of info.... :-)
If you turn on Elgg debug (in administration), you should get some messages in error_log. A few pointers
1) Make sure your PHP is compiled with the LDAP module (line if (!function_exists('ldap_connect')) return false; in start.php)
2) Make sure you do not have TLS turned on (needs a lot more configuration, CA certificates, etc)
3) Use network sniffer (wireshark, tcpdump) to check a connection is being initiated to the LDAP host
Thanks Bruno... I got somewhere.
Just a note for others - After enabling Elgg debug, use the linux commandline to see the apache log:
tail -f -n 50 /var/log/apache2/error.log
I originally had authentication problems, these are now fixed
The error I am getting now is:
-----
Deprecated in 1.8: find_plugin_setting() is deprecated by elgg_get_calling_plugin_entity() or elgg_get_plugin_from_id() Called from [#6] /var/www/XXX/mod/ldap_auth/start.php:44, referer: http://XXX/
PHP WARNING: 2012-03-20 10:25:33 (UTC): "ldap_search(): Search: Operations error" in file /var/www/XXX/mod/ldap_auth/start.php (line 259), referer: http://XXX/
ERROR: Unable to perform LDAP search: Operations error, referer: http://XXX/
----
I have hit a wall now, as I have no idea how to fix this.
Many thanks.
I will fix the deprecated message but it is only a warning.
As far as the other error, this tells me you probably connected properly to the LDAP server, but the Distinguished Name (DN) you authenticated with could not perform the search. I also note that you seem to be getting an LDAP referral back. Possible issues: wrong search base DN or user is not allowed to perform the search.
Do you have access to an LDAP client? I use jXplorer. The first thing I would try is to point jXplorer at the LDAP directory, bind as the user configured in the plugin and try to perform the search on the base DN configured in the plugin. If this works, then it means the problem is with the plugin. Otherwise, it's a permission or configuration problem.
OK then.. Used Jxplorer & authenticated with the credentials & base DN.
Did a search for a sAMAccountName user & it returned details successfully.
P.S. These are the details I am using to authenticate phpBB on the same virtualhost.
So you use SAMAcountName in the username filter attribute. What do you use for the search attributes? You obvisouly got the connectivity part right since you are getting an operation error message from your AD. At this point, I can only speculate at what it could be: mispelled attribute, ACL. Basically, the plugin will perform an authenticated bind with the DN and password, then perform an LDAP search like "SAMAcountName" = "bruno" and ask for the list of attributes in the search attribute box. If a match is found, it tries to bind with username "bruno" and the password typed in the Elgg password textbox. I suspect the operation error comes from the search operation (not the bind) but I could be wrong. Any logs on the AD side to help you? Is wireshark or tcpdump a possibility?
Found it.. Its working! I will share my findings:
My search path base dn was the entire domain. It was obviously too much for the poor thing!
My users are in two places so I used the following base DN search:
OU=Pupils,DC=w,DC=x,DC=y,DC=z : OU=Staff,DC=w,DC=x,DC=y,DC=z
(Obviously I have obscured my domain in the example)
Many Thanks Bruno for your help.
Hi
Thanks a lot for your plugin.
We modified the plugin to integrate an LDAP filter.
Would you be interested in integrating it into the future version of ldap_auth?
Regards
Stan
Is there any facility for NTLM and/or Kerberos transparent authentication with this plugin?
No. As you probably know, NTLM/Kerberos authentication is usually handled by the Web server with a combination of NTLM or Kerberos support (e.g. winbind). Once you have access to the PHP_AUTH_USER variable, you can make use of it in any module, including this one.
I found the URL below to be useful.
http://adldap.sourceforge.net/wiki/doku.php?id=mod_auth_ntlm_winbind
Thanks for the quick reply - we're just evaluating ELGG for use on out Windows network so if we do I'll probably need to add support for transparent login so I'll be sure to share. For now however, unfortunately I can't even get the forms based login to work with our Active Directory. Do you know how the plugin behaves in a forest - can we point the plugin at the Global Catalog?
The plugin engine is a standard LDAP client. In other word, if you can do something with an LDAP client (e.g., jXplorer), you should be able to do the same thing with the plugin. If the forest is composed of multiple base DNs, you can actually configure the plugin to read them one after the other (colon-separated). As you can see from the previous post, make sure you are not retrieving too many entries - you may hit a server limit.
Doh! Forgot to restart apache after installing php5_ldap. Facepalm...
Cool so I now have LDAP working lovely with the standard forms auth, and have mod_auth_kerb all playing nicely with $_SERVER["REMOTE_USER"] populated with my active directory UPN. I was wondering if you have any thoughts on where to start with hacking in support for this within Elgg - it seems I could add a config option into your plugin to pickup REMOTE_USER instead of binding the user's password. But also it seems I'd have to make a change to the core of Elgg to get it to attempt a transparent auth instead of displaying the login form. Does that sound accurate? Would be very grateful to have your thoughts on this. I have a reasonable amount of PHP experience so if I implement this I will definitely share what I have. Cheers
Just spotted elgg_trigger_plugin_hook, looks promising
Using PAM makes it pretty easy. Below is my start.php The rest of the code is exactly the same as in the LDAP module. I have just rename my module to ntlm_sso and my functions ntlm_ instead of ldap_
function ntlm_auth_init()
{
global $CONFIG;
$credentials['username'] = 'dummy';
$credentials['password'] = 'user';
// Override save method
elgg_register_action('ntlm_sso/settings/save',$CONFIG->pluginspath . 'ntlm_sso/actions/plugins/settings/save.php');
// Register the authentication handler
register_pam_handler('ntlm_auth_authenticate');
register_translations($CONFIG->pluginspath . "ntlm_sso/languages/");
if (!elgg_is_logged_in() && $_SERVER['PHP_AUTH_USER'])
{
$username = $_SERVER['PHP_AUTH_USER'];
$result=elgg_authenticate($username,'dummy');
if ($result !== true) {
register_error($result);
}
else
{
forward(REFERER);
}
}
}
/**
* NTLM authentication
*
* @param mixed $credentials PAM handler specific credentials
* @return boolean
*/
function ntlm_auth_authenticate($credentials = null)
{
// Nothing to do if LDAP module not installed
$user_create = elgg_get_plugin_setting('user_create', 'ntlm_sso');
// Get configuration settings
$config = find_plugin_settings('ntlm_sso');
// Nothing to do if not configured
if (!$config)
{
return false;
}
$username = null;
// Check SERVER variables to check if user was authenticated (nothing to do otherwise)
//if ($_SERVER['PHP_AUTH_USER'] && ($_SERVER['AUTH_TYPE'] == 'NTLM'))
if ($_SERVER['PHP_AUTH_USER'])
{
$username = $_SERVER['PHP_AUTH_USER'];
} else {
return false;
}
// Perform the authentication
return ldap_auth_check($config, $username,$user_create);
}
/**
* Perform an LDAP authentication check
*
* @param ElggPlugin $config
* @param string $username
* @param string $password
* @return boolean
*/
function ldap_auth_check($config, $username,$user_create)
{
if ($user = get_user_by_username($username))
{
return login($user);
}
else
{
if ($user_create == 'on')
{
if (!function_exists('ldap_connect'))
{
elgg_log("BRUNO ntlm_sso no ldap_connect", 'NOTICE');
return false;
}
$host = elgg_get_plugin_setting('hostname', 'ntlm_sso');
// No point continuing
if(empty($host))
{
elgg_log("LDAP error: no host configured.",'ERROR');
return;
}
$port = elgg_get_plugin_setting('port', 'ntlm_sso');
$version = elgg_get_plugin_setting('version', 'ntlm_sso');
$basedn = elgg_get_plugin_setting('basedn', 'ntlm_sso');
$filter_attr = elgg_get_plugin_setting('filter_attr', 'ntlm_sso');
$search_attr = elgg_get_plugin_setting('search_attr', 'ntlm_sso');
$bind_dn = elgg_get_plugin_setting('ldap_bind_dn', 'ntlm_sso');
$bind_pwd = elgg_get_plugin_setting('ldap_bind_pwd', 'ntlm_sso');
$user_create = elgg_get_plugin_setting('user_create', 'ntlm_sso');
$start_tls = elgg_get_plugin_setting('start_tls', 'ntlm_sso');
($user_create == 'on') ? $user_create = true : $user_create = false;
($start_tls == 'on') ? $start_tls = true : $start_tls = false;
$port ? $port : $port = 389;
$version ? $version : $version = 3;
$filter_attr ? $filter_attr : $filter_attr = 'uid';
$basedn ? $basedn = array_map('trim', explode(':', $basedn)) : $basedn = array();
if (!empty($search_attr))
{
// $search_attr as in "email:email_address, name:name_name";
$pairs = array_map('trim',explode(',', $search_attr));
$values = array();
foreach ($pairs as $pair)
{
$parts = array_map('trim', explode(':', $pair));
$values[$parts[0]] = $parts[1];
}
$search_attr = $values;
} else {
$search_attr = array('dn' => 'dn');
}
// Create a connection
if ($ds = ldap_auth_connect($host, $port, $version, $bind_dn, $bind_pwd))
{
if ($start_tls and !ldap_start_tls($ds)) return false;
// Perform a search
foreach ($basedn as $this_ldap_basedn)
{
$ldap_user_info = ldap_auth_do_auth($ds, $this_ldap_basedn, $username, $filter_attr, $search_attr);
if($ldap_user_info)
{
// Valid login but user doesn't exist
$name = $ldap_user_info['lastname'];
if (isset($ldap_user_info['firstname']))
{
$name = $ldap_user_info['lastname']." ".$name;
}
($ldap_user_info['mail']) ? $email = $ldap_user_info['mail'] : $email = null;
//Need to do something with password field since password cannot be empty
$password=rand();
if ($user_guid = register_user($username, $password, $name, $email))
{
// Success, credentials valid and account has been created
return true;
} else {
register_error(elgg_echo('ntlm_sso:no_register'));
return false;
}
}
}
// Close the connection
ldap_close($ds);
register_error(elgg_echo("ntlm_sso:no_account"));
return false;
}
else
{
return false;
}
}
else
{
return false;
}
}
}
/**
* Create an LDAP connection
*
* @param string $host
* @param int $port
* @param int $version
* @param string $bind_dn
* @param string $bind_pwd
* @return mixed LDAP link identifier on success, or false on error
*/
function ldap_auth_connect($host, $port, $version, $bind_dn, $bind_pwd)
{
$ds = ldap_connect($host, $port);
ldap_set_option($ds, LDAP_OPT_PROTOCOL_VERSION, $version);
// Start the LDAP bind process
$ldapbind = null;
if ($ds)
{
if ($bind_dn != '')
{
$ldapbind = ldap_bind($ds, $bind_dn, $bind_pwd);
}
else
{
// Anonymous bind
$ldapbind = ldap_bind($ds);
}
}
else
{
// Unable to connect
elgg_log('Unable to connect to the LDAP server: '.ldap_error($ds),'ERROR');
return false;
}
if (!$ldapbind)
{
elgg_log('Unable to bind to the LDAP server with provided credentials: '.ldap_error($ds),'ERROR');
ldap_close($ds);
return false;
}
return $ds;
}
/**
* Performs LDAP search to find user entry
*
* @param object $ds LDAP link identifier
* @param string $basedn
* @param string $username
* @param string $password
* @param string $filter_attr
* @param string $search_attr
* @return mixed array with search attributes or false on error
*/
function ldap_auth_do_auth($ds, $basedn, $username, $filter_attr, $search_attr)
{
$sr = ldap_search($ds, $basedn, $filter_attr ."=". $username, array_values($search_attr));
if(!$sr)
{
elgg_log('Unable to perform LDAP search: '.ldap_error($ds),'ERROR');
return false;
}
$entry = ldap_get_entries($ds, $sr);
if(!$entry or !$entry[0])
{
return false; // didn't find username
}
foreach (array_keys($search_attr) as $attr)
{
$ldap_user_info[$attr] = $entry[0][$search_attr[$attr]][0];
}
return $ldap_user_info;
}
elgg_register_event_handler('init','system','ntlm_auth_init');
?>
That looks spot on, is there any chance you could send me your ntlm_sso mod folder as a zip?
Thanks so much for you help!
Cheers
No worries if you don't have time, I've renamed enough stuff to get it working. One thing I've spotted is that it uses last name twice for new accounts:
$name = $ldap_user_info['lastname'];
if (isset($ldap_user_info['firstname']))
{
$name = $ldap_user_info['lastname']." ".$name;
}
1) Need your email address to email the zip file
2) Bug. Thanks :-)
Do you have the ntlm_sso available ?
Could you please share the mod ?
Thanks in advance
https://github.com/rekado/ntlm-sso
http://en.wikipedia.org/wiki/NTLM
http://sivel.net/2007/05/sso-apache-ad-1/
I made some changes to the code of version 0.2 to include:
If anyone is interested i can send you the size file
Hi Burno,
i tried configuring this plugin with our elgg setup yet there is no response when AD user login who not exists in Elgg DB. It's much apperciated if youcould you kindly advise us on this issue. i have also posted my config below
:Apps.dp.ad
LDAP port: 389
LDAP version:3
LDAP bind cn: DN path of admin account
Bind password: password of above admin acc
Based DN: OU=DP Users,DC=APPS,DC=DP,DC=AD
filter attribute : SAMNameAccount
: firstname:givenname, lastname:sn, mail:mail
Create use: enabled
start TLS: Disabled
Hello,
I do not think I can test from where I am. My first question would be: are you sure you are connecting and binding properly? You can either use Wireshark or check your AD logs to make ure you are indeed connecting and authenticating.
I also remember someone having a problem with performing a search from too high in the DIT. Make sure your search base allows you to perform a subtree search.
And note that the filter attribute for AD should be SAMAccountName, not SAMNameAccount
Does this plugin work?
it does not seem to register or even run the init (i put some print statements in there to be sure).