Extension:LDAP Authentication/User Provided Information

From MediaWiki.org
Jump to: navigation, search

About - Requirements - Examples - Configuration Options - Changelog - Roadmap - Suggestions - User provided info - FAQ - Support


MediaWiki extensions manualManual:Extensions
Crystal Clear action run.png
LDAP Authentication

Release status:Extension status stable

ImplementationTemplate:Extension#type User identity
DescriptionTemplate:Extension#description Provides LDAP authentication, and some authorization functionality for MediaWiki
Author(s)Template:Extension#username Ryan Lane (Ryan lanetalk)
Latest versionTemplate:Extension#version 2.1.0 (2014-03-28)
MediaWikiTemplate:Extension#mediawiki 1.19+
Database changesTemplate:Extension#needs-updatephp Yes
LicenseTemplate:Extension#license GNU General Public License 2.0 or later
Download
Hooks usedTemplate:Extension#hook
LoadExtensionSchemaUpdatesManual:Hooks/LoadExtensionSchemaUpdates

Translate the LDAP Authentication extension if it is available at translatewiki.net

Check usage and version matrix.

IssuesPhabricator

Open tasks · Report a bug


Ability to use both Kerberos/SSO AutoAuth and standard LDAP http login page[edit]

I wanted to get both the ability to seamlessly auto-login with Kerberos/GSSAPI SSO mechanisms, without disabling the ability to login normally via Kerb/LDAP with the standard Special:UserLogin form. The following seemed to allow me to get his ability without a lot of patching.

Warning: There is no implied warranty/safety with using this method. I have only tested it on a cursory basis, and it seems to work. More rigorous testing should be applied before putting this into production. Also, I am not entirely certain if this overburdens the server with LDAP requests.

To get it working, I just changed LocalSettings.php to be a mix/hybrid of the AutoLogin capabilities as shown from Extension:LDAP Authentication/AD Configuration Examples and the Extension:LDAP_Authentication/Kerberos_Configuration_Examples.

LocalSettings.php:

// the rest of the $wgLDAPxxx configuration variables should be ABOVE this.
// Mixed login abilities - allows you to switch between Kerberos + AutoLogin and standard LDAP/AD Domain login via webpage
// Note: must use example Kerberos login config with mod_auth_kerb and ldap proxyagent
//
// Situation #1: autologin - if coming from mod_auth_kerb protected page, and $_SERVER["REMOTE_USER"] is set
if ($_SERVER['REQUEST_URI'] == "/wiki/index.php/Kerberos_Login" && isset($_SERVER["REMOTE_USER"]) ){
 $wgLDAPAutoAuthUsername = preg_replace( '/@.*/', '', $_SERVER["REMOTE_USER"]);
 AutoAuthSetup();
}else{
// Situation #2: standard login - otherwise, remove the AutoAuth variables and start the authentication object normally (allowing normal logins to happen)
    unset($wgLDAPAutoAuthUsername);
    unset($wgLDAPAutoAuthDomain);
    $wgAuth = new LdapAuthenticationPlugin();
}

Require user patch[edit]

You'll want to patch this by hand, not using the patch command

Here's a quick patch which allows an associative array of required users like so

   $wgLDAPRequireUser = array( "Foo"=>true, "Bar"=>true, );

this allows authentication to be done in the LDAP whilst the authorization is done locally.

  --- LdapAuthentication.php~     2006-02-28 18:24:41.152769000 +0100
  +++ LdapAuthentication.php      2006-03-01 12:30:44.685474331 +0100
  @@ -135,6 +135,7 @@
                  global $wgLDAPProxyAgent;
                  global $wgLDAPGroupDN;
                  global $wgLDAPRequireAuthAttribute, $wgLDAPAuthAttribute;
  +               global $wgLDAPRequireUser;
                                                                                                                                          
                  //We don't handle local authentication
                  if ( 'local' == $_SESSION['wsDomain'] ) {
  @@ -144,6 +145,13 @@
                  if ( '' == $password ) {
                          return false;
                  }
  +
  +               if ( $wgLDAPRequireUser ) {
  +                       if ( ! $wgLDAPRequireUser[$username] ) {
  +                               return false;
  +                       }
  +               }
  +
                   $ldapconn = $this->connect( );
                   if ( $ldapconn ) {
                           ldap_set_option( $ldapconn, LDAP_OPT_PROTOCOL_VERSION, 3);

I tried experimenting with other methods to achieve this, but none of them seemed to work right. If I turn off auto-user-creation, there's no way for admins to do it manually. Creating directly in the database seems a hassle. Setting up a group isn't really an option in this case. Is there a better way? What I really wanted to find was an admin special page for creating new users.

Patch considered to small and obvious to be copyright, use it if you like without need for attribution. This isn't a totally general solution since it doesn't deal with different policies for different domains. E.g. everybody in a group + exceptions.

Hmm, can't set up an LDAP group? Seems like the easiest method, but if it isn't possibly in your enviroment, this is probably a viable option. Let's change your code up a little here though:
   $wgLDAPRequireUser = array( "DomainName"=>"<user1>,<user2>", "DomainName2"=>"<user3>,<user4>" ); //where <user1> would be "Foo"

  +
  +               if ( isset( $wgLDAPRequireUser ) && isset( $wgLDAPRequireUser[$_SESSION['wsDomain']] ) ) {
  +                       $users = explode( ",", $wgLDAPRequireUser[$_SESSION['wsDomain']] );
  +                       if ( ! in_array( $username, $users ) ) {
  +                               return false;
  +                       }
  +               }
  +
Now it is generic ;). Make sure to check my code for stupid errors, as I didn't actually try this, but it should work.
-- Ryan Lane

Trusting self-signed SSL certificates[edit]

Anybody know how to have LdapAuthentication trust self-signed certificates, as alluded to in the "Requirements" section? It doesn't currently appear to be able to trust certs that haven't been signed by a trusted provider.

This is dependant upon what type of OS you are using. I'm not sure if this is the right spot for the documentation of how to do this...
--Ryan Lane
For Fedora Core 4 I added a line to /etc/openldap/ldap.conf:
TLS_REQCERT never
A similar change to this should work for any system using OpenLDAP. Be advised this tells OpenLDAP NOT to do any checking on the certificate (not the default), which will make you suceptible to a man-in-the middle attack.
A more secure option is to add this line:
TLS_CACERT /etc/openldap/cacerts/myselfsigned.crt
You can also add "myselfsigned.crt" to /usr/share/ssl/certs and set the following in /etc/ldap.conf:
tls_cacertdir /usr/share/ssl/certs
If you use TLS_CACERT, you may need to also add the same info on TLS_CACERTFILE, depending on the OS (RHEL 3 seems to need this).

_____________

I think the issue is can your ldap even recognize your self-signed certs; it may be just a matter of adding the public key of the CA you used to sign your certs to your ldap configuration.


I think this is the same problem I am having. My ldap.conf is configured for TLS_REQCERT=never. The ldaps is working fine for ssh authentication and other(verified with ssldump and ethereal). But for some reason it seems that the /etc/ldap.conf is ignored by php.

Hmmmmmm.

I believe ALL of /etc/ldap.conf is ignored by php. php uses /etc/openldap/ldap.conf I believe. I run into this problem every time I set up a system by hand. The easy solution (and a generally safe solution) is to remove /etc/openldap/ldap.conf and symlink it to /etc/ldap.conf. Of course, you can't do that if you are using openLDAP server on that system, but no one in their right mind would run a webserver on their LDAP server right? :)
-- Ryan Lane

Right. And I have symlinked it. I guess it is just odd behavior how the php is behaving. I wonder if there is a case sensitivity issue with php? I did notice tls_reqcert in my ldap.conf is all lowercase.

I will test and post back.


Just tested. No joy.


I wrote this up after I finally figured out this issue: [1]


Here is some documentation from microsoft for enabling LDAP over SSL: [2]
--Ryan Lane


/etc/ldap.conf belongs to the operation system authorization and authentification interfaces pam_ldap and nss_ldap. It would not be used from PHP in this case. /etc/openldap/ldap.conf belongs to the openldap client libraries and would be used indirect from PHP. Both files should have different content. TLS_CACERTDIR could be used with all CA certificates in own files. It should be necessary to use c_rehash on a directory with CA certificates and TLS_CACERTDIR.

-- Ralf Hansen

Adding WikiSysop[edit]

Finally you'll need to add a WikiSysop user to LDAP. Which is a little tricky because WikiSysop isn't a real user. This is what I used.

 dn: ou=applications,dc=example,dc=org
 objectClass: top
 objectClass: organizationalUnit
 ou: applications
 
 dn: uid=WikiSysop,ou=applications,dc=example,dc=org
 uid: WikiSysop
 cn: WikiSysop
 userPassword: secret
 objectClass: shadowAccount
 objectClass: simpleSecurityObject
 objectClass: applicationProcess

Full instructions here http://caldergroup.com/configure/wikildapauthentication.html

You can also create your own user before the system is configured for LDAP (make sure to use all lowercase letters...), and give your user sysop privileges, then configure it for LDAP. After doing so, you can give anyone else sysop privileges with your user.
-- Ryan Lane
If you are feeling adventurous you can also modify the 'user_groups' table in the database. First find your user id in the 'user' table:
SELECT user_id, user_name FROM `user` where `user_name` REGEXP '^MYNAME';
then do something like
INSERT INTO `user_groups` ( `ug_user` , `ug_group` ) VALUES ( 'UID', 'bureaucrat');
INSERT INTO `user_groups` ( `ug_user` , `ug_group` ) VALUES ( 'UID', 'sysop')
All of this assumes you have write access to the DB and that you are pretty proficient/comfortable with SQL.
--James Candalino


Allow LDAP users to act as SysOps or Bureaucrat based on groups[edit]

If you want Mediawiki authorization to based solely on LDAP and still allow multiple Bureaucrat or Sysops roles you'll need to create a group in LDAP and retrieve associated groups on login.

actually this can easily be done with autopromote in your localsettings.php, no need to create any special groups.

Windows configuration[edit]

If your instance of MediaWiki is hosted on a Windows machine running IIS, Apache, etc, there are some key items to configure to confirm that PHP has secure LDAP functionality enabled.

  1. In php.ini (in your apache/bin directory NOT your php directory!!!) make sure the following lines are uncommented
    • extension=php_ldap.dll
    • extension=php_openssl.dll
  2. Also in PHP.ini; Confirm those dll's are in the directory referenced by extension_dir (ex. c:\php\ext)
  3. Copy several files from the DLL folder of the PHP/Win32 binary package to the SYSTEM folder of your windows machine. (Ex: C:\WINNT\SYSTEM32, or C:\WINDOWS\SYSTEM). For PHP <= 4.2.0 copy libsasl.dll, for PHP >= 4.3.0 copy libeay32.dll and ssleay32.dll to your SYSTEM folder.
  4. Create a text file called ldap.conf in the directory C:\openldap\sysconf\. The first line must be TLS_REQCERT never . (For some reason OpenLdap has this as a hard-coded required file.)

Deactivating manual password change[edit]

Since I disabled usage of the passwords stored in the MediaWiki database and since there is no way for me to write into our LDAP directory I chose to deactivate the passwort fields in Special:Preferences and to write a message into them how to change your password. Simply insert these lines into MediaWiki:Monobook.js:

document.addEventListener("DOMContentLoaded", function() 
{
 if(document.getElementById('wpOldpass')!=null)
 {
  document.getElementById('wpOldpass').disabled=true;     
  document.getElementById('wpOldpass').type='text';     
  document.getElementById('wpOldpass').value='call helpdesk';     
  document.getElementById('wpNewpass').disabled=true;  
  document.getElementById('wpRetypePass').disabled=true; 
 }
}, false);
  • Note: This works on Firefox, but not on IE 6 --Flominator 07:04, 6 August 2007 (UTC)
  • Note: This will only work if the user has javascript enabled --Ryan lane 19:12, 6 August 2007 (UTC)
  • So is there other means to hide password changes and new user registration? --User:Anonymous 13:31, 23 December 2008 (UTC)

Password change is disabled by default

Deactivating New User Signup / Registration[edit]

Insert the following into LocalSettings.php

#Prevent new user registrations
$wgWhitelistAccount = array ( "user" => 0, "sysop" => 1, "developer" => 1 );
$wgGroupPermissions['*'    ]['createaccount']   = false;

Testing LDAP binding and searching[edit]

LDAP Browser is a good way to test your searching and binding configuration. --Flominator 18:59, 10 August 2007 (UTC)

Active Directory Primary Group Patch[edit]

Active Directory does not list the Primary Group of the user when getting members from the group object. This patch fixes that by getting the primary group id from the user object, creating a SID to find the group and then add the group to the rest of the user's groups. There is no easier way of doing this through LDAP. This code has not been tested on non-AD LDAPs, but should just skip if it is not querying an AD LDAP. This also fixes an issue where the groups are not added soon enough when using $wgLDAPGroupsPrevail and the Group Based Access Control extension. This prevented new groups added to AD from being available for access control.

--- LdapAuthentication.old/LdapAuthentication.php	2008-02-22 17:21:31.000000000 -0700
+++ LdapAuthentication.new/LdapAuthentication.php	2008-02-22 17:15:11.000000000 -0700
@@ -1405,10 +1405,6 @@
                 if ( $value != "*" )
                         $value = $this->getLdapEscapedString( $value );
 
-		$filter = "(&($attribute=$value)(objectclass=$objectclass))";
-
-		$this->printDebug( "Search string: $filter", SENSITIVE );
-
 		if ( isset( $wgLDAPProxyAgent[$_SESSION['wsDomain']] ) ) {
 			//We'll try to bind as the proxyagent as the proxyagent should normally have more
 			//rights than the user. If the proxyagent fails to bind, we will still be able
@@ -1417,6 +1413,51 @@
 			$bind = $this->bindAs( $ldapconn, $wgLDAPProxyAgent[$_SESSION['wsDomain']], $wgLDAPProxyAgentPassword[$_SESSION['wsDomain']] );
 		}
 
+		$groups = array();
+		$shortnamegroups = array();
+
+		// AD does not include the primary group in the list of groups, we have to find it ourselves.
+		
+		if ($dn != "*"){
+			$PGfilter = "(&(distinguishedName=$value)(objectclass=user))";
+			$this->printDebug ( "User Filter: $PGfilter", SENSITIVE);
+			$PGinfo = @ldap_search ( $ldapconn, $base, $PGfilter );
+			$PGentries = @ldap_get_entries ($ldapconn, $PGinfo);
+			if ($PGentries ){
+				$Usid = $PGentries[0]['objectsid'][0];
+				$PGrid = $PGentries[0]['primarygroupid'][0];
+				$PGsid = bin2hex ($Usid);
+				for ($i=0; $i < 56; $i += 2) {
+					$PGSID[] = substr($PGsid, $i, 2);
+				}
+				$dPGrid = dechex($PGrid);
+				$dPGrid = str_pad ( $dPGrid, 8, '0', STR_PAD_LEFT);
+				$PGRID = array();
+				for ($i = 0; $i < 8; $i += 2){
+					array_push( $PGRID, substr($dPGrid, $i, 2));
+				}
+				for ($i = 24; $i < 28; $i++){
+					$PGSID[$i] = array_pop($PGRID);
+				}
+				foreach ($PGSID as $PGsid_bit) {
+					$PGsid_string .= "\\" . $PGsid_bit;
+				}
+				$PGfilter = "(&(objectSid=$PGsid_string)(objectclass=$objectclass))";
+				$this->printDebug ( "Primary Group Filter: $PGfilter", SENSITIVE);
+				$info = @ldap_search ( $ldapconn, $base, $PGfilter );
+				$PGentries = @ldap_get_entries ($ldapconn, $info);
+				array_shift( $PGentries );
+				$mem = strtolower( $PGentry[0]['dn']);
+				$shortnamemem = strtolower( $PGentries[0][$nameattribute][0] );
+				array_push( $groups, $mem );
+				array_push( $shortnamegroups, $shortnamemem );
+			}
+		}
+
+		$filter = "(&($attribute=$value)(objectclass=$objectclass))";
+
+		$this->printDebug( "Search string: $filter", SENSITIVE );
+
 		$info = @ldap_search( $ldapconn, $base, $filter );
 		if ( !$info ) {
 			$this->printDebug( "No entries returned from search.", SENSITIVE );
@@ -1432,8 +1473,6 @@
 		array_shift( $entries );
 
 		//Let's get a list of both full dn groups and shortname groups
-		$groups = array();
-		$shortnamegroups = array();
 		foreach ( $entries as $entry ) {
 			$mem = strtolower( $entry['dn'] );
 			$shortnamemem = strtolower( $entry[$nameattribute][0] );
@@ -1492,6 +1531,14 @@
 
 		$this->printDebug( "Entering setGroups.", NONSENSITIVE );
 
+                # Add ldap groups as local groups
+                if ( isset( $wgLDAPGroupsPrevail[$_SESSION['wsDomain']] ) && $wgLDAPGroupsPrevail[$_SESSION['wsDomain']] ) {
+			$this->printDebug( "Adding all groups to wgGroupPermissions: " . implode( ",", $this->allLDAPGroups ) . "", SENSITIVE );
+                        foreach ( $this->allLDAPGroups as $ldapgroup )
+                                if ( !array_key_exists( $ldapgroup, $wgGroupPermissions ) )
+                                        $wgGroupPermissions[$ldapgroup] = array();
+		}
+
 		# add groups permissions
 		$localAvailGrps = $user->getAllGroups();
 		$localUserGrps = $user->getEffectiveGroups();
@@ -1507,15 +1554,6 @@
 			$this->printDebug( "Locally managed groups is unset, using defaults: " . implode( ",", $locallyManagedGrps ) . "", SENSITIVE );
 		}
 			
-
-                # Add ldap groups as local groups
-                if ( isset( $wgLDAPGroupsPrevail[$_SESSION['wsDomain']] ) && $wgLDAPGroupsPrevail[$_SESSION['wsDomain']] ) {
-			$this->printDebug( "Adding all groups to wgGroupPermissions: " . implode( ",", $this->allLDAPGroups ) . "", SENSITIVE );
-                        foreach ( $this->allLDAPGroups as $ldapgroup )
-                                if ( !array_key_exists( $ldapgroup, $wgGroupPermissions ) )
-                                        $wgGroupPermissions[$ldapgroup] = array();
-		}
-
 		$this->printDebug( "Available groups are: " . implode( ",", $localAvailGrps ) . "", NONSENSITIVE );
 		$this->printDebug( "Effective groups are: " . implode( ",", $localUserGrps ) . "", NONSENSITIVE );

REMOTE_USER[edit]

Is there a posibility to use the REMOTE_USER given by IE to automatically login a user available in the AD? I found an extension but it did not work for me. Can someone help? - JB

Yes. This extension can do this; but, if you only want to do authentication, and no authorization, or preference pulling, this extension is overkill. See the kerberos examples for information on how to do this with this plugin. See the HttpAuth extension for something that will only do authentication. BTW, you really should put stuff like this into the support section.
--Ryan lane 22:06, 15 June 2009 (UTC)

Separate Authentication and Authorization Providers Patch[edit]

I needed a way to authenticate with our LDAP environment, but use Active Directory groups to authorize users. This patch will add this functionality to the plugin.

Define both providers in the LocalSettings.php as the plugin instructions suggest. But instead of adding your authorization provider to $wgLDAPDomainNames, define a new array with a mapping to the authentication provider.

// The names of one or more authentication domains you wish to use
$wgLDAPDomainNames = array(
  "TestAuthnProvider"
);

// The names of one or more authorization domains you wish to use
$wgLDAPAuthzDomains = array(
  "TestAuthnProvider" => "TestAuthzProvider"
);

where TestAuthnProvider is the authentication provider and TestAuthzProvider is the authorization provider.

--- LdapAuthentication.php.old	2008-08-26 09:49:46.000000000 -0400
+++ LdapAuthentication.php.new	2008-08-26 14:29:36.000000000 -0400
@@ -226,6 +226,7 @@
 		global $wgLDAPSearchStrings;
 		global $wgLDAPUniqueAttribute, $wgLDAPUniqueBlockLogin, $wgLDAPUniqueRenameUser;
 		global $wgLDAPGroupsPrevail;
+		global $wgLDAPAuthzDomains;
 
 		$this->printDebug( "Entering authenticate", NONSENSITIVE );
 
@@ -329,11 +330,35 @@
 				}
 			}
 
+			// Connect to the authorization provider
+			$authndom = $_SESSION['wsDomain'];
+			if( isset($wgLDAPAuthzDomains[$_SESSION['wsDomain']]) ) {	
+				$authzdom = $wgLDAPAuthzDomains[$_SESSION['wsDomain']];
+
+				$authz = new LdapAuthenticationPlugin();
+				$authz->setDomain( $authzdom );
+				$authzconn = $authz->connect();
+
+				if( !$authzconn ) {
+					$authz->cleanupFailedAuth();
+
+					$this->printDebug( "Failed to connect to authorization provider", NONSENSITIVE );
+					$this->cleanupFailedAuth();
+					return false;
+				}
+
+				$authzuserdn = $this->getSearchString( $authzconn, $username );
+			} else {
+				$authzdom = $authndom;
+				$authzconn = $ldapconn;
+				$authzuserdn = $userdn;
+			}
+
 			//Old style groups, non-nestable and fairly limited on group type (full DN
 			//versus username). DEPRECATED
 			if ( $wgLDAPGroupDN ) {
 				$this->printDebug( "Checking for (old style) group membership", NONSENSITIVE );
-				if ( !$this->isMemberOfLdapGroup( $ldapconn, $userdn, $wgLDAPGroupDN ) ) {
+				if ( !$this->isMemberOfLdapGroup( $authzconn, $authzuserdn, $wgLDAPGroupDN ) ) {
 					$this->printDebug( "Failed (old style) group membership check", NONSENSITIVE );
 
 					//No point in going on if the user isn't in the required group
@@ -349,16 +374,16 @@
 				$this->printDebug( "Checking for (new style) group membership", NONSENSITIVE );
 
 				if ( isset( $wgLDAPGroupUseFullDN[$_SESSION['wsDomain']] ) && $wgLDAPGroupUseFullDN[$_SESSION['wsDomain']] ) {
-					$inGroup = $this->isMemberOfRequiredLdapGroup( $ldapconn, $userdn );
+					$inGroup = $this->isMemberOfRequiredLdapGroup( $authzconn, $authzuserdn );
 				} else {
 					if ( ( isset( $wgLDAPGroupUseRetrievedUsername[$_SESSION['wsDomain']] ) 
 						&& $wgLDAPGroupUseRetrievedUsername[$_SESSION['wsDomain']] )
 						&& $this->LDAPUsername != '' ) {
 
 						$this->printDebug( "Using the username retrieved from the user's entry.", NONSENSITIVE );
-						$inGroup = $this->isMemberOfRequiredLdapGroup( $ldapconn, $this->LDAPUsername );
+						$inGroup = $this->isMemberOfRequiredLdapGroup( $authzconn, $this->LDAPUsername );
 					} else {
-						$inGroup = $this->isMemberOfRequiredLdapGroup( $ldapconn, $username );
+						$inGroup = $this->isMemberOfRequiredLdapGroup( $authzconn, $username );
 					}
 				}
 
@@ -377,24 +402,26 @@
 
 				//Let's get the user's LDAP groups
 				if ( isset( $wgLDAPGroupUseFullDN[$_SESSION['wsDomain']] ) && $wgLDAPGroupUseFullDN[$_SESSION['wsDomain']] ) {
-					$this->userLDAPGroups = $this->getUserGroups( $ldapconn, $userdn, true );
+					$this->userLDAPGroups = $this->getUserGroups( $authzconn, $authzuserdn, true );
 				} else {
 					if ( ( isset( $wgLDAPGroupUseRetrievedUsername[$_SESSION['wsDomain']] ) && $wgLDAPGroupUseRetrievedUsername[$_SESSION['wsDomain']] )
 						&& $this->LDAPUsername != '' ) {
 
-						$this->userLDAPGroups = $this->getUserGroups( $ldapconn, $this->LDAPUsername, true );
+						$this->userLDAPGroups = $this->getUserGroups( $authzconn, $this->LDAPUsername, true );
 					} else {
-						$this->userLDAPGroups = $this->getUserGroups( $ldapconn, $username, true );
+						$this->userLDAPGroups = $this->getUserGroups( $authzconn, $username, true );
 					}
 				}
 
 				//Only find all groups if the user has any groups; otherwise, we are
 				//just wasting a search.
 				if ( $this->foundUserLDAPGroups && ( isset( $wgLDAPGroupsPrevail[$_SESSION['wsDomain']] ) && $wgLDAPGroupsPrevail[$_SESSION['wsDomain']] ) ) {
-					$this->allLDAPGroups = $this->getAllGroups( $ldapconn, true );
+					$this->allLDAPGroups = $this->getAllGroups( $authzconn, true );
 				}
 			}
 
+			$this->setDomain( $authndom );
+
 			//Retrieve preferences
 			if ( isset( $wgLDAPRetrievePrefs[$_SESSION['wsDomain']] ) && $wgLDAPRetrievePrefs[$_SESSION['wsDomain']] ) {
 				$this->printDebug( "Retrieving preferences", NONSENSITIVE );

Capitalize user name as in LDAP[edit]

We use long user names in LDAP with proper capitalization (e.g. first name and surname is capitalized, such as "John Miller"). The module, as it is now, forces capital first letter, and everything else lowercase. I patched the module so that getCanonicalName() gets the properly capitalized name from LDAP, and then uses that name for logging in to the Wiki.

The patch is very simple, but it has the downside that it connects to the LDAP server twice during authentication. Getting rid of that would have required much more extensive code changes. -- Andre.Spiegel 08:40, 20 July 2009 (UTC)

In addition to the patch below, you need the following implementation of the hook SetUsernameAttributeFromLDAP:

$wgHooks['SetUsernameAttributeFromLDAP'][] = 'mySetUser';
function mySetUser (&$LDAPUsername, $info) {
  $name = $info[0]['uid'][0];
  if ($name) $LDAPUsername = $name; else $LDAPUsername = '';
  return true;
}

And here is the patch:

--- LdapAuthentication.php.org  2009-07-20 10:14:51.000000000 +0200
+++ LdapAuthentication.php      2009-07-16 16:32:39.000000000 +0200
@@ -68,7 +68,7 @@
        var $email, $lang, $realname, $nickname, $externalid;

        //username pulled from ldap
-       var $LDAPUsername;
+       var $LDAPUsername, $searchstring;

        //groups pulled from ldap
        var $userLDAPGroups, $foundUserLDAPGroups;
@@ -1060,8 +1060,7 @@
        }

        /**
-        * Munge the username to always have a form of uppercase for the first letter,
-        * and lowercase for the rest of the letters.
+        * Get the username with the capitalization that is used in LDAP.
         *
         * @param string $username
         * @return string
@@ -1074,6 +1073,10 @@
                if ( $username != '' ) {
                        $this->printDebug( "Username isn't empty.", NONSENSITIVE );

+                       $ldapconn = $this->connect();
+                       $userdn = $this->getSearchString ($ldapconn, $username);
+                       @ldap_unbind();
+
                        //We want to use the username returned by LDAP
                        //if it exists
                        if ( $this->LDAPUsername != '' ) {
@@ -1081,19 +1084,12 @@
                                $username = $this->LDAPUsername;
                        }

-                       if ( isset($_SESSION['wsDomain']) && 'local' != $_SESSION['wsDomain']) {
-                               //Change username to lowercase so that multiple user accounts
-                               //won't be created for the same user.
-                               //But don't do it for the local domain!
-                               $username = strtolower( $username );
-                       }
-
                        //The wiki considers an all lowercase name to be invalid; need to
                        //uppercase the first letter
                        $username[0] = strtoupper( $username[0] );
                }

-               $this->printDebug( "Munged username: $username", NONSENSITIVE );
+               $this->printDebug( "Canonical username: $username", NONSENSITIVE );

                return $username;
        }
@@ -1125,6 +1121,11 @@

                $this->printDebug( "Entering getSearchString", NONSENSITIVE );

+               if ($this->searchstring) {
+                 $this->printDebug ("Using cached search string", NONSENSITIVE);
+                 return $this->searchstring;
+                }
+
                if ( isset( $wgLDAPSearchStrings[$_SESSION['wsDomain']] ) ) {
                        //This is a straight bind
                        $this->printDebug( "Doing a straight bind", NONSENSITIVE );
@@ -1151,6 +1152,7 @@
                        $userdn = $this->getUserDN( $ldapconn, $username );
                }
                $this->printDebug( "userdn is: $userdn", SENSITIVE );
+               $this->searchstring = $userdn;
                return $userdn;
        }


Fetching All Groups Fails in Large AD Installations[edit]

In the alpha version of the plugin 1.2(b), search for all groups will effectively bomb out for a large Active Directory deployment. By the time this line is called, userdn is already defined, so the following patch worked for us:

# diff -u LdapAuthentication.php /usr/share/mediawiki-extensions/LdapAuthentication.php
--- LdapAuthentication.php      2009-10-14 12:10:23.000000000 -0400
+++ /usr/share/mediawiki-extensions/LdapAuthentication.php      2009-10-14 14:02:54.000000000 -0400
@@ -1327,7 +1327,8 @@
                        //Only find all groups if the user has any groups; otherwise, we are
                        //just wasting a search.
                        if ( ( isset( $wgLDAPGroupsPrevail[$_SESSION['wsDomain']] ) && $wgLDAPGroupsPrevail[$_SESSION['wsDomain']] ) && count( $this->userLDAPGroups ) != 0 ) {
-                               $this->allLDAPGroups = $this->searchGroups( '*' );
+                               // FIXME: '*' arg breaks our AD
+                               $this->allLDAPGroups = $this->searchGroups($this->userdn || '*');
                        }
                }
        }

This avoids doing a costly

(&(member=*)(objectClass=group))

search, during authentication.

The idea behind $wgLDAPGroupsPrevail is that you can avoid this search completely nearly all of the time. $wgLDAPGroupsPrevail allows you to populate the entire list of groups - this was done for compatibility with another extension. If you want to avoid the search, don't set "$wgLDAPGroupsPrevail = array( "mydomain" => true );". The default for this is false.
If you do, for some reason, need to pull all of the groups, then this patch breaks the functionality.
--Ryan lane 21:09, 14 October 2009 (UTC)

Group name limitations[edit]

If you want to use the group syncronization option $wgLDAPUseLDAPGroups combined with the $wgGroupPermissions usage... there is a default 16 character limit on the length of the group name. The group name gets stored in the database, in the user_groups table, ug_group column. The datatype of this column is varbinary(16). The behavior that I saw was that the user could authenticate, the groups would appear Special:ListGroupRights page, but the user would not be in the appropriate groups.

I didn't want to be stuck with 16 character group names, so to fix this alter the existing column to increase the size:

ALTER TABLE `wikidb`.`myoptionaltableprefix_user_groups` CHANGE COLUMN `ug_group` `ug_group` VARBINARY(255) NOT NULL DEFAULT ''  ;

Otherwise, you can alter the maintenance\table.sql script before you create the wiki site:

  -- ug_group varbinary(16) NOT NULL default ''
  ug_group varbinary(255) NOT NULL default ''

Using v1.2d and MediaWiki 1.16.