Extension:LDAP Authentication

Plugin downloads
The plugin is now located in MediaWiki's svn. The mediazilla page will no longer be updated with releases.


 * Version 1.1f (alpha) can be downloaded here
 * Version 1.1e can be downloaded here
 * Version 1.0h can be downloaded here

LDAP Authentication configuration examples
Examples of how to use this plugin can be found here:


 * /Configuration Examples/
 * /Smartcard Configuration Examples/

The documentation has been updated to reflect version 1.1c and higher
Some options changed from 1.1b to 1.1c, make sure when configuring a new version that the options you are currently using are still valid. The changelog mentions which options have changed.

Support will no longer be given for version 1.0; the prior version of the documentation was lost in the move from meta to mediawiki.org. I apologize for the inconvenience.

Post support questions on the discussion page or on the mediawiki-enterprise list
Please post all support questions on this page's discussion page or on the mediawiki-enterprise list. If a problem needs special attention, I can contact you directly by email. Posting the questions on the discussion page allows everyone to see how the problem was resolved.

Posting anywhere else will usually cause your problem to be ignored, or cause people to get upset with you.

Current version tested on
Current Version (1.1) has been tested on:


 * MediaWiki
 * MediaWiki 1.6 (does not work on 1.5, but version 1.0 does!)
 * MediaWiki 1.7
 * MediaWiki 1.8
 * MediaWiki 1.9 (NOTE: there are some bugs here (including a fatal source code bug for 1.9.3), a couple workarounds should be used for the time being, see the talk page)
 * Operating Systems
 * Red Hat Enterprise Linux v4 AS
 * Red Hat Enterprise Linux v4 ES
 * Red Hat Enterprise Linux v4 WS
 * Fedora Core 6
 * Solaris 10
 * Suse Linux Enterprise Server 10
 * Microsoft Windows 2003
 * Gentoo Linux (extension revision 20306)
 * CentOS 5
 * LDAP Directories
 * CA Directory (eTrust Directory)
 * Sun Directory Server 5.2
 * Active Directory 2003
 * Novell eDirectory (NDS) v8.7.3
 * OpenLDAP (extension revision 20306)
 * Mac OS X Open Directory v10.4.9
 * Fedora Directory Server 1.0.4
 * Web Servers
 * Apache 2.0
 * IIS6+PHP ISAPI
 * Combinations
 * Solaris 10, Mediawiki 1.9.x, PHP, MySQL, Apache2, CA Directory
 * RHEL v4 AS, Mediawiki 1.6.8, PHP 4.3.9, MySQL 4.1.12-3, Apache 2.0.52-22, Sun Directory Server 5.2 patch 4
 * Windows 2003, Mediawiki 1.8.3, PHP 5.2.0, MySQL 5.0, IIS6, Microsoft Active Directory
 * Gentoo Linux, Mediawiki 1.9.x, PHP, MySQL, Apache 2, OpenLDAP, extension revision 20306, Samba LDAP schema
 * CentOS 5, Mediawiki 1.10.0, PHP 5, MySQL 5, Fedora Directory Server 1.0.4

If you have a working wiki with a working version of the patch on something not listed above, please add it to the list!

Requirements

 * Mediawiki 1.6+ for current version of the plugin (I will no longer be backporting to the 1.5 series)
 * PHP must be compiled with LDAP support for any functionality at all
 * PHP must be compiled with SSL support if you wish to authenticate over SSL (HIGHLY Recommended!!)
 * Your server must trust the LDAP server's Certificate's Root CA for SSL to work (mostly affects you if you are using self signed certificates)
 * The DNS name for your LDAP server must match the name in the LDAP server's certificate for SSL to work
 * Smartcard/CAC authentication requires a PEM encoded list of CAs, proxy or anonymous (if allowed) LDAP credentials, and an SSL enabled webserver
 * If you would like to use LDAP as a backend for MediaWiki (creating users, changing passwords, etc), you must provide a user who has write permissions to specific user attributes (please only give this user the minimum amount of access that is required)

Current version
Version 1.1e of the LdapAuthentication.php plugin (for Mediawiki 1.6+)

This plugin should be scalable for use in small to large organizations, and provides the following functionality:


 * Single and multi domain authentication (including local database)
 * Simple bind authentication
 * Proxy bind authentication
 * Smartcard/CAC authentication
 * SSL/TLS or non-SSL/TLS binding allowed
 * Nested/Unnested Group based restriction support
 * Filter based restriction support
 * Retrieval of user information from LDAP
 * Email address
 * Real name
 * Nickname
 * Language
 * Syncronization of LDAP groups to MediaWiki security groups (LDAP->MediaWiki only)
 * Storing preferences in LDAP
 * Update passwords (1)
 * Mail me a password (1)
 * Update all preferences that are currently retrievable

(1) Does not work with Active Directory

Next version
I have a bad memory, and need a to-do list. If I have promised to add something for you in the next version, and it isn't in the list below, please add it.

1.1f

 * Add options to specifiy search bases for users, and groups
 * Special:Preferences prints PHP warning, "Undefined index: wsDomain in PATH/LdapAuthentication.php", for lines 591 and 594. MediaWiki 1.9.3, Windows 2003 server, PHP 5.2.2-dev snapshot. 66.147.182.92 14:27, 29 March 2007 (UTC)
 * To whomever added this: I can't replicate this, please provide more info on the discussion page --Ryan lane 01:44, 8 April 2007 (UTC)
 * fix Extension_talk:LDAP_Authentication
 * Automatically rename user when the username has changed in LDAP
 * Add a hook, and integrate some of the code from Extension:LDAP_Authentication

Future version

 * NTLM authentication support
 * Allow changes to LDAP groups via Special:Userrights
 * Support for choosing default search scope, and defining it for multiple domains.
 * Support for adding users/changing passwords in Active Directory.
 * Support for using LDAP as a complete user backend (including user options and such). Using ldap as a backend will require a custom schema to be loaded in the LDAP server.

Explanation of options
The following are options that are usable in "LocalSettings.php":

(These are examples of the extension options, this is not a working example however)

When using password authentication
If the plugin is dropped in includes:

require_once( 'LdapAuthentication.php' ); $wgAuth = new LdapAuthenticationPlugin;

If the plugin is dropped in extensions:

require_once( "$IP/extensions/LdapAuthentication.php" ); $wgAuth = new LdapAuthenticationPlugin;

When using smartcard authentication
If the plugin is dropped in includes:

require_once( 'LdapAuthentication.php' ); //options go here AutoAuthSetup;

If the plugin is dropped in extensions:

require_once( "$IP/extensions/LdapAuthentication.php" ); //options go here AutoAuthSetup;

Domain, server and connection configuration options
//The names of one or more domains you wish to use //These names will be used for the other options, it is freely choosable and not dependent //on your system. These names will show in the Login-Screen, so it is important that the user //understands the meaning. $wgLDAPDomainNames = array( "testADdomain","testLDAPdomain"  );

//The fully qualified name of one or more servers per domain you wish to use. If you are //going to use SSL or StartTLS, it is important that the server names provided here exactly //match the name provided by the SSL certificate returned by the server; otherwise, you may //have problems. $wgLDAPServerNames = array( "testADdomain"=>"testADserver.AD.example.com",  "testLDAPdomain"=>"testLDAPserver.LDAP.example.com testLDAPserver2.LDAP.example.com"  );

//Allow the use of the local database as well as the LDAP database. //Good for transitional purposes. $wgLDAPUseLocal = false;

//The type of encryption you would like to use when connecting to the LDAP server. //Available options are "tls", "ssl", and "clear" $wgLDAPEncryptionType = array( "testADdomain"=>"tls",  "testLDAPdomain"=>"clear"  );

Straight DN bind options
//The search string to be used for straight binds to the directory; USER-NAME will be //replaced by the username of the user logging in. //This option is not required (and shouldn't be provided) if you are using a proxyagent //and proxyagent password. //If you are using AD style binding (TDOMAIN\\USER-NAME or USER-NAME@TDOMAIN) and //want to be able to use group syncing, preference pulling, etc., you'll need to set //$wgLDAPBaseDNs and $wgLDAPSearchAttributes for the domain. $wgLDAPSearchStrings = array( "testADdomain"=>"TDOMAIN\\USER-NAME",  "testLDAPdomain"=>"uid=USER-NAME,ou=people,dc=LDAP,dc=example,dc=com"  );

Proxied or search based bind options
//User and password used for proxyagent access. //Please use a user with limited access, NOT your directory manager! //You are able to use clear text passwords, but please try not to. $wgLDAPProxyAgent = array( "testLDAPdomain"=>"cn=proxyagent,ou=profile,dc=LDAP,dc=example,dc=com"  ); $wgLDAPProxyAgentPassword = array( "testLDAPdomain"=>"{SHA}KqYKj/f81HPTIeAUav2eJt85UUc="  );

//Search filter. //These options are only needed if you want to search for users to bind with them. In otherwords, //if you cannot do direct binds based upon $wgLDAPSearchStrings, then you'll need these two options. //If you need a proxyagent to search, remember to set $wgLDAPProxyAgent, and $wgLDAPProxyAgentPassword. //Anonymous searching is supported. To do an anonymous search, use SearchAttibutes and don't set a Proxy //agent for the domain required. $wgLDAPSearchAttributes = array( "testADdomain"=>"sAMAccountName",  "testLDAPdomain"=>"uid"  );

//Base DNs. Group and User base DNs will be used if available; if they are not defined, the search //will default to $wgLDAPBaseDNs $wgLDAPBaseDNs = array( "testADdomain"=>"dc=AD,dc=example,dc=com",  "testLDAPdomain"=>"dc=LDAP,dc=example,dc=com"  ); $wgLDAPGroupBaseDNs = array( "testADdomain"=>"ou=Domain Groups,dc=AD,dc=example,dc=com",  "testLDAPdomain"=>"ou=group,dc=LDAP,dc=example,dc=com"  ); $wgLDAPUserBaseDNs; = array( "testADdomain"=>"ou=Domain Users,dc=AD,dc=example,dc=com",  "testLDAPdomain"=>"ou=people,dc=LDAP,dc=example,dc=com"  );

Options for using LDAP as a user backend
//User and password used for writing to the directory. //Please use a user with limited access, NOT your directory manager! //You are able to use clear text passwords, but please try not to. $wgLDAPWriterDN = array( "testLDAPdomain"=>"uid=priviledgedUser,ou=people,dc=LDAP,dc=example,dc=com"  ); $wgLDAPWriterPassword = array( "testLDAPdomain"=>"{SHA}KqYKj/f81HPTIeAUav2eJt85UUc="  );

//A location to add users to if you are using $wgLDAPSearchAttributes and $wgLDAPAddLDAPUsers. //This option requires $wgLDAPWriterDN and $wgLDAPWriterPassword to be set. $wgLDAPWriteLocation = array( "testLDAPdomain"=>"ou=people,dc=LDAP,dc=example,dc=com"  );

//Options for adding users, and/or updating user preferences in LDAP. If you use these options //you must set $wgLDAPWriterDN and $wgLDAPWriterPassword. $wgLDAPAddLDAPUsers = array( "testADdomain"=>false,  "testLDAPdomain"=>true  ); $wgLDAPUpdateLDAP = array( "testADdomain"=>false,  "testLDAPdomain"=>true  );

//Change the hashing algorithm that is used when changing passwords or creating //user accounts. The default (not setting this variable) will use a base64 encoded //SHA encrypted password. I do not recommend setting this variable unless you need to //store clear text or crypt passwords. $wgLDAPPasswordHash = array( "testLDAPdomain"=>"crypt"  );

//Option for mailing temporary passwords to users //(notice, this will store the temporary password in the local directory // if you cannot write LDAP passwords because writing is turned off, // this probably won't help you much since users will not be able to change // their password) //This option requires $wgLDAPWriterDN, $wgLDAPWriterPassword and $wgLDAPUpdateLDAP $wgLDAPMailPassword = true;

//Option for allowing the retreival of user preferences from LDAP. //Only pulls a small amount of info currently. $wgLDAPRetrievePrefs = array( "testADdomain"=>true,  "testLDAPdomain"=>true  );

MediaWiki user creation options
//Don't automatically create an account for a user if the account exists in LDAP //but not in MediaWiki. Default is false. $wgLDAPDisableAutoCreate = array( "testADdomain"=>true  );

//Shortest password a user is allowed to login using. Notice that 1 is the minimum so that //when using a local domain, local users cannot login as domain users (as domain user's //passwords are not stored) $wgMinimalPasswordLength = 1;

Debugging options
//Option for getting debug output from the plugin. 1-3 available. 1 will show //non-sensitive info, 2 will show possibly sensitive user info, 3+ will show //sensitive system info. Setting this on a live public site is probably a bad //idea. $wgLDAPDebug = 1;

Group options
Using LDAP groups in any way requires $wgLDAPBaseDNs to be set!

The following settings pertain to both syncronizing groups, and group based login restriction.

//Whether the username in the group is a full DN (AD generally does this), or //just the username (posix groups generally do this) $wgLDAPGroupUseFullDN = array( "testLDAPdomain"=>true,  "testADdomain"=>true  );

//Munge the case of the username to lowercase when doing searches in groups $wgLDAPLowerCaseUsername = array( "testLDAPdomain"=>true,  "testADdomain"=>true  );

//Use the exact name retrieved from LDAP after the user has authenticated to search for groups. //This requires the SetUsernameAttributeFromLDAP hook to be used (see the smartcard section). $wgLDAPGroupUseRetrievedUsername = array( "testLDAPdomain"=>false,  "testADdomain"=>false  );

//The objectclass of the groups we want to search for $wgLDAPGroupObjectclass = array( "testLDAPdomain"=>"groupofuniquenames",  "testADdomain"=>"group"  );

//The attribute used for group members $wgLDAPGroupAttribute = array( "testLDAPdomain"=>"uniquemember",  "testADdomain"=>"member"  );

//The naming attribute of the group $wgLDAPGroupNameAttribute = array( "testLDAPdomain"=>"cn",  "testADdomain"=>"cn"  );

Syncronizing LDAP groups with MediaWiki security groups
//Pull LDAP groups a user is in, and update local wiki security group. $wgLDAPUseLDAPGroups = array( "testADdomain"=>true,  "testLDAPdomain"=>true  );

Group based login restriction configuration options
//An array of the groups the user is required to be a member of. $wgLDAPRequiredGroups = array( "testLDAPdomain"=>array( "cn=testgroup,ou=groups,dc=LDAP,dc=example,dc=com", "cn=testgroup2,ou=groups,dc=LDAP,dc=example,dc=com" ), "testADdomain"=>array( "cn=testgroup,ou=groups,dc=AD,dc=example,dc=com" ) );

//Whether or not the plugin should search in nested groups //Not currently used for group syncronization $wgLDAPGroupSearchNestedGroups = array( "testLDAPdomain"=>false,  "testADdomain"=>true  );

Search based login restriction configuration options
This must be used with a proxy search. //Require a search attribute $wgLDAPRequireAuthAttribute = array( "testADdomain"=>"true",  "testLDAPdomain"=>"true"  );

//Require the following additional search string. $wgLDAPAuthAttribute = array( "testADdomain"=>"!(userAccountControl:1.2.840.113556.1.4.803:=2)",  "testLDAPdomain"=>"!(nsaccountlock=true)"  );

Smartcard authentication options
It is highly recommended to see the /Smartcard Configuration Examples/ page before messing with these options.

If you use smartcard authentication, it would be foolish not to use HTTPS and SSL/TLS

//Enable smartcard authentication $wgLDAPAutoAuthMethod = "smartcard";

//The domain that will be using smartcard authentication $wgLDAPSmartcardDomain = "testADdomain-smartcard";

//The attribute from the smartcard you wish to search LDAP for $wgLDAPSSLUsername = $_SERVER['SSL_CLIENT_S_DN_CN'];

//This hook is called by the LdapAuthentication plugin. It is a configuration hook. Here we //are specifying what attibute we want to use for a username in the wiki. //The hook calls the function defined below. $wgHooks['SetUsernameAttributeFromLDAP'][] = 'SetUsernameAttribute';

//This function allows you to get the username from LDAP however you need to do it. //This is the username MediaWiki will use. function SetUsernameAttribute(&$LDAPUsername, $info) { $LDAPUsername = $info[0]['samaccountname'][0]; }

Configuration for non-AD Directory Servers
To use the group based restrictions with a non-AD directory, add:

$wgLDAPGroupDN = "cn=test,ou=groups,dc=mycompany,dc=com";

where "cn=test,ou=groups,dc=mycompany,dc=com" is the dn of the group you wish to restrict access to.

Note: The plugin searches for users in the "member" attribute in groups. If you are not using the "member" attribute for your group members, then you will have to change what attribute is being searched for in the plugin.

Configuration for AD
Although the plugin does support group and role based restrictions (in version 1.0c), it was really written for non-AD style groups. It is actually pretty hard to write this for AD and non-AD style since AD uses groups in a smart way (although hard to use for other purposes way). AD does use the "member" attribute like used in the script, but it stores the members as their actual entry in the directory server ie:

cn=Lane\, Ryan,ou=Test_Group,ou=Domain_users,dc=example,dc=com

The problem lies in finding this member based upon the user's uid (or sAMAccountName). Now, this is possible if you add some code to the patch. If you pull preferences already, this should be pretty easy. If you do not pull preferences, you'll have to pull one. You'll need to pull the user's "distinguishedName" attribute, and search for that as a member in the function that checks for group membership. So, you could make the following changes:

(this example shows how to change the plugin to work with AD when you are not already pulling preferences, although it will work even if you are pulling preferences, just not as efficiently)

At the class definition, change:

class LdapAuthenticationPlugin extends AuthPlugin { var $email, $lang, $realname, $nickname, $SearchType;

to

class LdapAuthenticationPlugin extends AuthPlugin { var $distinguishedName, $email, $lang, $realname, $nickname, $SearchType;

In function "authenticate" change:

if ($wgLDAPGroupDN) { return $this->isMemberOfLdapGroup($ldapconn, $userdn, $wgLDAPGroupDN); }

to:

if ($wgLDAPGroupDN) { $entry = @ldap_read($ldapconn, $userdn, "objectclass=*"); $info = @ldap_get_entries($ldapconn, $entry); $this->distinguishedName = $info[0]["distinguishedname"][0]; return $this->isMemberOfLdapGroup($ldapconn, $userdn, $wgLDAPGroupDN); }

In function "isMemberOfLdapGroup" change

//we need to do a subbase search for the entry $filter = "(member=".$userDN.")";

to:

//we need to do a subbase search for the entry $filter = "(member=".$this->distinguishedName.")";

In LocalSettings.php add:

$wgLDAPGroupDN = "cn=test,ou=groups,dc=mycompany,dc=com";

where "cn=test,ou=groups,dc=mycompany,dc=com" is the dn of the group you wish to restrict access to.

Let me know if this is working for you or not.

$wgLDAPSearchStrings = array( "domain"=>"USER-NAME@domain" ); So the modification in the file LDAPAuthentication.php, the function "authenticate" was not working for me (wgLDAPSearchStrings does not return the user DN but the userPrincipalName) I changed the modification to : global $wgLDAPBaseDNs; $entry = @ldap_search($ldapconn,$wgLDAPBaseDNs[$_SESSION['wsDomain']], "(&(objectclass=*)(userPrincipalName=$userdn))"); $info = @ldap_get_entries($ldapconn, $entry); $this->distinguishedName = $info[0]["distinguishedname"][0]; return $this->isMemberOfLdapGroup($ldapconn, $userdn, $wgLDAPGroupDN);
 * 2006-04-26 : it was not working for because I used this configuration in LocalSettings.php :

and it is now working for me.

Configuration for non-AD domains
You'll need to change around the options some depending on your setup. The below example is a configuration to find "testuser" in the following group:

dn: cn=testgroup,ou=groups,dc=LDAP,dc=example,dc=com cn: testgroup objectclass: groupofuniquenames uniqueMember: uid=testuser,ou=people,dc=LDAP,dc=example,dc=com uniqueMember: uid=testuser2,ou=people,dc=LDAP,dc=example,dc=com uniqueMember: uid=testuser3,ou=people,dc=LDAP,dc=example,dc=com

Example:

$wgLDAPRequiredGroups = array( "testLDAPdomain"=>array("cn=testgroup,ou=groups,dc=LDAP,dc=example,dc=com") ); $wgLDAPGroupUseFullDN = array( "testLDAPdomain"=>true ); $wgLDAPGroupObjectclass = array( "testLDAPdomain"=>"groupofuniquenames" ); $wgLDAPGroupAttribute = array( "testLDAPdomain"=>"uniquemember" ); $wgLDAPGroupSearchNestedGroups = array( "testLDAPdomain"=>false ); $wgLDAPBaseDNs = array( "testLDAPdomain"=>"dc=LDAP,dc=example,dc=com" );

The below example is a configuration to find "testuser" in the following group:

dn: cn=testgroup,ou=groups,dc=LDAP,dc=example,dc=com cn: testgroup objectclass: posixgroup gidnumber: 10000 memberuid: testuser memberuid: testuser2 memberuid: testuser3

Example:

$wgLDAPRequiredGroups = array( "testLDAPdomain"=>array("cn=testgroup,ou=group,dc=LDAP,dc=example,dc=com") ); $wgLDAPGroupUseFullDN = array( "testLDAPdomain"=>false ); $wgLDAPGroupObjectclass = array( "testLDAPdomain"=>"posixgroup" ); $wgLDAPGroupAttribute = array( "testLDAPdomain"=>"memberuid" ); $wgLDAPGroupSearchNestedGroups = array( "testLDAPdomain"=>false ); $wgLDAPBaseDNs = array( "testLDAPdomain"=>"dc=LDAP,dc=example,dc=com" );

Configuration for AD domains
Notice that if you have a multi-domain or multi-forest environment, you need to make sure your configuration is pointing at your global catalog!

Example:

$wgLDAPRequiredGroups = array( "testADLDAPdomain"=>array("cn=testgroup,ou=groups,dc=adldap,dc=example,dc=com") ); $wgLDAPGroupUseFullDN = array( "testADLDAPdomain"=>true ); $wgLDAPGroupObjectclass = array( "testADLDAPdomain"=>"group" ); $wgLDAPGroupAttribute = array( "testADLDAPdomain"=>"member" ); $wgLDAPGroupSearchNestedGroups = array( "testADLDAPdomain"=>false ); $wgLDAPBaseDNs = array( "testADLDAPdomain"=>"dc=ADLDAP,dc=example,dc=com" );
 * 1) DNs in $wgLDAPRequiredGroups must be lowercase, as search result attribute values are...

If you are using straight binds to AD, using AD-style straight binds (DOMAIN\\USER-NAME or USER-NAME@DOMAIN), you'll need one more option to make this work correctly:

$wgLDAPSearchAttributes = array( "testADLDAPdomain"=>"sAMAccountName" );

This allows the plugin to find the user's full DN for searching groups. Without finding the user's full DN, the plugin will search groups with (member=DOMAIN\username), which is not what is in your groups.

LDAP attributes used for preference pulling
The following four attributes can be set in LDAP on a user for the wiki to use as user preferences:


 * mail (email address)
 * displayName (nickname)
 * cn (real name)
 * preferredLanguage (language)

preferredLanguage must use the language code as it would be found in "languages/Names.php"

Changelog
It is probably a good idea for me to keep a changelog. Kind of late in the game, but late is better than never.

1.1e

 * Fixed ldap_get_entries resource error when searching groups issue
 * Fixed Extension talk:LDAP Authentication
 * Fixed getGroups problem when empty searches occur (code cleanliness problem)

1.1d

 * Now get the user's DN if straight binds are used with AD style binds (DOMAIN\\USER-NAME, USER-NAME@DOMAIN) to allow for group checking, group pulling, retrieving preferences, etc.
 * Fixed the problem with using group based restrictions.
 * Now allow $wgLDAPRequiredGroups to have uppercase letters, and automatically convert to lowercase for comparison to search results.
 * Fixed part of the compability issues with MediaWiki 1.9
 * Fixed Extension Talk:LDAP_Authentication

1.1c

 * Added support for Mediawiki security groups based upon LDAP groups
 * Added an option to disable auto-creation of accounts ($wgLDAPDisableAutoCreate - defaults to false)
 * Fixed TLS/SSL issue discussed in the Suggestions section on the Meta page
 * Removed options $wgLDAPUseSSL and $wgLDAPUseTLS; added option $wgLDAPEncryptionType (a string) with allowed values "ssl", "tls", and "clear"
 * Moved $wgLDAPLowerCaseUsername a little higher up in the authentication chain
 * Added $wgLDAPGroupUseRetrievedUsername so that you can use the exact username pulled from LDAP to search for groups
 * Changed $wgLDAPUseSmartcardAuth to $wgLDAPAutoAuthMethod (a string); this will allow users to define which type of auto authenticate methods they would like to use. Smartcard auth will only be available at first, but other methods will follow.
 * Changed $wgLDAPLowerCaseUsername to allow for multiple domains
 * Moved authenticate part of smartcard login out of getCanonicalName to the SSLAuth function (I have no clue what I was thinking before ;) )

1.1b

 * Fixed bug in 1.1a with user's preferences being overwritten when $wgLDAPRetrievePrefs was not set, or was set to false. The issue should only have affected 1.1a; 1.0h should not be affected.

1.1a

 * TLS is now the default encryption mode. To disable SSL/TLS, you need to specifically disable both.
 * Fixed bug in getGroups, searchNestedGroups, and isMemberOfRequiredLdapGroup where warnings are thrown if no groups are found. This was a symptom of a problem in Comment #133 (this would not fix that issue however).
 * Fixed bug with pulled preferences not being saved in the local database.
 * Options have changed to work for multiple domains. All options that make sense with multi-domain support can be configured to work for multiple domains.
 * Smartcard/CAC support has been added to the plugin using the AutoAuthenticate hook.
 * Most options supported by password authentication are supported in smartcard authentication
 * Only a single smartcard domain can be used due to the way AutoAuthenticate works; however, smartcard authentication and password authentication can be mixed allowing multiple domains through the use of clever hackery
 * Smartcard authentication does not have to be turned on for the entire server, but can instead be turned on for certain locations, or even specific wiki pages

Smartcard authentication requires the getCanonicalName function which is only available in MediaWiki 1.6+. Do not use this version of the plugin for mediawiki 1.5 as it has not been tested and will not be supported; instead, please use version 1.0h.

Many options have changed syntax in this version. Please check the new syntax rules before upgrading to this version.

1.0h

 * Fixed #118 on the bugzilla page (lowercasing the username in the groups checking)
 * The fix proposed may have caused issues with other users who need case sensitive searches. I've added the fix as a boolean option ($wgLDAPGroupLowerCaseUsername).
 * Fixed #125 on the bugzilla page (redundant auth attr check)
 * This fix disabled the check, it did not remove it. If you would like to re-enable it for performance reasons, just uncomment the section that was commented.
 * Fixed #126 on the bugzilla page (setPassword function erasing the user's password in LDAP)

1.0g

 * Added a new group based restrictions method
 * Added a number of new options to support this method
 * This method will try to use proxyagent credentials if available to search for groups; the plugin falls back on user credentials if proxyagent credentials fail
 * Support for nested groups is available with this new method as long as the attribute for nested groups is the same attribute used for holding users in groups (such as member=testuser, and member=nestedgroup)
 * Support for username or DNs in groups (testuser vs cn=testuser,ou=people,dc=example,dc=com)
 * Support for multiple groups
 * Support for multiple domains

1.0f

 * Fixed the version number at the top of the file.
 * Fixed the preferences bug from: Talk:LDAP Authentication#Problem with preferences from LDAP
 * Added function in for changing usernames to lowercase to fix: Extension Talk:LDAP_Authentication (only works in versions 1.6+)
 * Fixed an undeclared global variable $wgLDAPWriteLocation in addUsers
 * Cleaned out some unused global variables (I think there may be a couple still hanging around. I'll try to clean them out next version)
 * Added debugging code (let me know what extra debugging info you want, or if some things should be showing at a different debug level)
 * Added the password switching statement from comment #111 in the bugzilla (notice I added it for changing passwords, and for creating users)
 * Added the ability to use TLS as well as LDAPS (I'm not 100% sure this is working, let me know!)

Suggestions

 * The mail password problem could be solved by emailing a link to a temporary URL that allows a password change. Not sure if this would be easier or harder to impliment than the temporary local password idea (though maybe a tiny bit less hackish). --Dack 20:55, 19 Jan 2005 (UTC)
 * Good idea. We could also probably use the email authentication plugin as well... It may need modification to work, but since Thomas is merging his code with mine, it should be a pretty easy addition. --Ryan Lane
 * This is working now. It is using the email authentication code to do this. --Ryan Lane


 * Please reflect in the documentation that LocalSettings.php/$wgLDAPWriterDN = "cn=admin,dc=example,dc=com" does work, while LocalSettings.php/$wgLDAPWriterDN = "uid=admin,dc=example,dc=com" does not. --Jan de Haan
 * Why would "cn" work, but not "uid"? Well, on an openldap install, it is most likely "cn" right? I'll update the documentation to use "cn", but in general you really shouldn't be using a user that has rights over everything in the database (you should create a user who just has write/delete/modify access on user accounts). Thanks for noticing the error though. --Ryan Lane
 * Hmm, looking back, I don't notice where I used "uid=admin,dc=example,dc=com". Actually, I'm not using an admin specific to any directory server. "cn=admin,dc=example,dc=com" would only work in OpenLDAP. In Sun Directory Server or Netscape Directory Server, the admin user in somewhere under the "NetscapeRoot", or is "cn=Directory Manager". In AD, there is no normal specified admin user like the others from what I can remember. This is why I recommend creating a user, and giving that user read/write/delete/modify permissions on the ou with your user entries (if you need to be able to use mediawiki as a backend, not otherwise). --Ryan Lane


 * Would be nice to get Group-Support (checking, if user is in group 'wiki' or else)....
 * Is this what you are looking for? Or are you looking for something a little more advanced? I've had requests for something more advanced, and hopefully I'll get the time to work on it. But this will allow you to restrict login to a specific group. --Ryan Lane


 * Should allow for the prevent of auto creation of accounts even if LDAP Authentication is successful if $wgGroupPermissions['*']['createaccount'] = false;
 * I'll look into this for next release. If I don't have something like this for next release I'll try to have it in the next 2 or 3. -- Ryan Lane
 * This was added in 1.1c --Ryan Lane 20:29, 2 February 2007 (UTC)


 * Is there any way to automagically add users authenticated via LDAP to some given mediawiki group? Say I have multiple Domains ("Staff", "Students") I would like staff to become members of the sysop and bureaucrat groups and students to become members of some new students group.  Then I might use something like $wgGroupPermissions['user']['edit'] = false; to disallow editing to some other local anonymous user/group while still giving students edit privilages with $wgGroupPermissions['students']['edit'] = true;, etc.  Such a mechenism might be handy if it were capable of associating any given LDAP domain and/or group to some arbitrary local wikigroup... Something like:
 * $wgLDAPWikiGroups = array(
 * "Students.Domain"=>"students",
 * "Staff.Domain"=>"sysop, bureaucrat");
 * What do you think? --D0li0 02:19, 9 September 2006 (UTC)
 * I've been trying to think of a sane manner of setting mediawiki group permissions based on LDAP groups, I'll try to tackle multi-domain based permissions at the same time. I hadn't thought of this before, but it does make sense. Thanks for the idea. --Ryan Lane
 * Any progress? Dohh, I see it now on the Extension:LDAP_Authentication. I'm more than willing to test early versions of this feature! --D0li0 00:06, 7 December 2006 (UTC)
 * It may take me a while, I need to integrate a patch someone gave me; however, the patch was against a much older version so I'll have to patch it by hand and test everything. I'd imagine it'll be a few weeks minumum. --Ryan Lane
 * This is in. Take a look at it and tell me if it works for you. I didn't put in support for generic groups based upon domain, but it will sync groups from LDAP. --Ryan Lane 16:56, 26 December 2006 (UTC)

$wgLDAPGroupPurge = array( "Domain1"=>"dev, author, sysop", "Domain2"=>"dev, author" );
 * Groups seem to be working, I'm using MW1.6.7. Not exactly as described above but I can recreate permissions for new LDAP groups that reflect those held by the stock set of MW groups!  Once I define a new MW groups if the user is a member in LDAP they are added when they log in!  Perfect!  Unfortunately it appears that if they are removed from that group in LDAP they do not get removed in MW, because the extension has no way of determining if MW groups they are currently members of are local or LDAP groups.  ie. A user Joe is a member of the dev group in LDAP,  I've defined the matching dev group in MW so once logged in Joe becomes a member of the MW dev group and all of it's associated permissions.  Later Joe is removed from the LDAP group dev, however he remains in the MW dev group.  It appears that we need a list of local MW groups to purge users from if they are no longer members in LDAP.  Notice that we may not want to simply purge all groups, for example the Bureaucrat group may not map to any LDAP groups, so purging it might cause problems, likewise the sysop group may not be mapped, etc... How about an array like: --D0li0 04:51, 27 June 2007 (UTC)
 * Alright, got to test in a MW1.10.0 environment, noticed a Checking to see if we need to remove user from: dev line although the user was not removed. It appears that the getAllGroups function was using an inappropriate search string, having escaped the '*' character, ie: Search string: (&(memberUid=\5c2a)(objectclass=posixGroup)).  So I added an if statement such that if ($dn == '*') then the search string simply doesn't include the attribute portion which is essentially the same as searching with an '*', ie: Search string: (objectclass=posixGroup).  This seems to be working for me, here's the code change for 1.1e at about row 1246: --D0li0 21:18, 27 June 2007 (UTC)

//Search for the groups this user is in + if ($dn == '*') { + $filter = "(objectclass=$objectclass)"; + } else { $filter = "(&($attribute=". $this->getLdapEscapedString($dn). ")(objectclass=$objectclass))"; + }


 * Had an issue authenticating against AD with a TLS error even though it was disabled in LocalSettings.php. Works fine after the following change.
 * Warning: ldap_start_tls: Unable to start TLS: DSA is unavailable in /var/www/html/healthwiki/includes/LdapAuthentication.php on line 147
 * Line 143 in LdapAuthentication.php
 * -!(isset($wgLDAPUseSSL[$_SESSION['wsDomain']])
 * +(!isset($wgLDAPUseSSL[$_SESSION['wsDomain']])
 * Well, I changed the behavior to use TLS unless both SSL and TLS are false, or SSL is true. My logic was a little faulty though. The next version of the plugin will fix this. Instead of having to define both as false, you'll only have to define one or the other as false to disable encryption. --Ryan Lane
 * I think I finally have a sane way of configuring this in 1.1c, have a look at the configuration options section. --Ryan Lane 20:29, 2 February 2007 (UTC)

Better support for groups
The following is a simple patch that allows better integration with Group Based Access Control. Without this patch, groups that do not exist in the userrights page are not imported from LDAP, as that would not make sense (they would give their members no extra rights) when not using the Group Based Access Control extension. This patch adds a configuration switch $wgLDAPGroupsPrevail that when set to true, makes the LDAP authentication extension add all LDAP groups to the set of mediawiki groups, of course with no extra or special rights given to them, so that they can be used in page ACLs with the Group Based Access Control extension.


 * Patch code


 * Looks good. This may actually be useful for other extensions as well, so the area of code that sets the $wgGroupPermission stuff will probably work better as a hook that can be defined in your extension. I'll add this in the next release, thanks for the code addition! --Ryan lane 04:01, 26 May 2007 (UTC)

Require user patch
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 authorisation 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"=>", ", "DomainName2"=>" , " ); //where 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
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:

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

Adding WikiSysop
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

Windows configuration
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 make sure the following lines are uncommented
 * 2) *extension=php_ldap.dll
 * 3) *extension=php_openssl.dll
 * 4) Also in PHP.ini; Confirm those dll's are in the directory referenced by extension_dir (ex. c:\php\ext)
 * 5) 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.
 * 6) 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.)