I have added LDAP authentication to MediaWiki. Unfortunately, I'm not sure
where to go to get the newest unstable cvs version of the software, so I
have added it to the 1.3.7 version. I'm sure the difference in
includes/SpecialUserLogin.php between the versions isn't great, but can
anyone tell me an easy way to get the latest unstable (through a web browser
preferably)?
I also have a few problems with using LDAP authentication in certain
circumstances, and would like to get some input from the community on them.
First let me describe how i've implemented it:
I've added 6 options to DefaultSettings.php and LocalSettings.php which are
the following when used by an admin:
$wgUseLDAP = true;
$wgLDAPDomainNames = array("testADdomain","testLDAPdomain");
$wgLDAPServerNames =
array("testADdomain"=>"testADserver.example.com","testLDAPdomain"=>"testLDAP
server.example.com testLDAPserver2.example.com");
$wgLDAPSearchStrings = array("testADdomain"=>"TDOMAIN\\USER-NAME",
"testLDAPdomain"=>"cn=USER-NAME,ou=people,dc=example,dc=com");
$wgLDAPUseSSL = true;
$wgLDAPUseLocal = true;
In this example, there are three different domains, one is local, one is an
Active Directory domain, and the other is a normal LDAP domain (Sun
directory server, openLDAP, etc). The user must provide the search string
for a user's distinguished name (USER-NAME is substituted in
SpecialUserLogin.php with the actual user's loginname). Using SSL is
optional (although it is the default) and so is using the local domain
(which is the wiki itself, and is not on by default). Of course, using LDAP
is off by default.
When using LDAP, passwords are not stored in the database (unless users
create accounts on the local domain). Blank passwords are no longer allowed
since we wouldn't want people using the local domain logging in as domain
users.
The interface for logging in is slightly different when using LDAP as well.
Since the LDAP directory will be managing user accounts and passwords, I
have removed the "mail me a new password" button, and the validate password
field (unless $wgLDAPUseLocal is true). I have added a selection box that
will allow users to choose which domain they wish to authenticate against
(in the above example, the options would be "testADdomain",
"testLDAPdomain", and "local").
My problems are not how I have it currently implemented, but with features
that could be added later. For instance, large sites (wikipedia, and the
like) i'm sure do not want to handle user accounts manually; small sites,
and organizations that use it internally probably do. A feature that could
be added to the basic LDAP authentication is the ability for the wiki to add
user accounts and manage passwords like it does currently. The problem with
this is that most LDAP directories cannot work in this fashion. For
instance, if the wiki was to mail a new password to a user, it would need to
change the password on the LDAP directory which would cause the user's old
password to no longer work. Obviously this is a huge DoS situation. Adding
user accounts is less of a problem, but because of time considerations, I
cannot implement it.
Below is my patch (let me know if my formatting is unusable):
DefaultSettings.php (add):
$wgUseLDAP = false;
$wgLDAPDomainNames = array("");
$wgLDAPServerNames = array("");
$wgLDAPSearchStrings = array("");
$wgLDAPUseSSL = true;
$wgLDAPUseLocal = false;
Language.php (add):
'yourdomainname' => 'Your LDAP Domain'
'blankpasswordnotallowed' => 'Blank passwords are not allowed.'
SpecialUserLogin.php (diff old new):
20c20
< var $mLoginattempt, $mRemember, $mEmail;
---
var $mLoginattempt, $mRemember, $mEmail, $mDomain;
24a25
$this->mDomain = $request->getVal(
'wpDomain' );
130a132
global $wgUseLDAP, $wgLDAPUseLocal;
137,138c139,140
< if ( 0 != strcmp( $this->mPassword, $this->mRetype ) ) {
< $this->mainLoginForm( wfMsg( "badretype" ) );
---
if ( "" == $this->mPassword ) {
$this->mainLoginForm( wfMsg(
"blankpasswordnotallowed" ) );
140a143,149
if ( !$wgUseLDAP || "local" == $this->mDomain ) {
if ( 0 != strcmp( $this->mPassword, $this->mRetype )
) {
$this->mainLoginForm( wfMsg(
"badretype" )
);
return;
}
}
173c182,188
<
---
> if ( $wgUseLDAP &&
"local" != $this->mDomain ) {
> if ( !$this->ldapBind() ) {
return;
}
}
175c190
< $u->setPassword( $this->mPassword );
---
if ( !$wgUseLDAP ) { $u->setPassword(
$this->mPassword ); }
192c207,208
<
---
global $wgUseLDAP;
205,208d220
< if (!$u->checkPassword( $this->mPassword )) {
< $this->mainLoginForm( wfMsg( "wrongpassword" ) );
< return;
< }
209a222,231
if ( $wgUseLDAP && "local" !=
$this->mDomain ) {
if ( !$this->ldapBind() ) {
return;
}
} else {
if (!$u->checkPassword( $this->mPassword || "" ==
$this->mPassword )) {
$this->mainLoginForm( wfMsg(
"wrongpassword"
) );
return;
}
}
231a254,297
/* private */ function ldapBind()
{
global $wgLDAPDomainNames, $wgLDAPServerNames,
$wgLDAPSearchStrings;
global $wgLDAPUseLocal, $wgLDAPUseSSL;
if ( $wgLDAPUseSSL ) {
$serverpre = "ldaps://";
} else {
$serverpre = "ldap://";
}
$tmpservers = $wgLDAPServerNames["{$this->mDomain}"];
$tok = strtok($tmpservers, " ");
while ($tok) {
$servers = $servers . " " . $serverpre . $tok;
$tok = strtok(" ");
}
$servers = rtrim($servers);
$tmpuserdn = $wgLDAPSearchStrings["{$this->mDomain}"];
$userdn =
str_replace("USER-NAME",$this->mName,$tmpuserdn);
$userpass = $this->mPassword;
$ldapconn = @ldap_connect( $servers ) or die( "Could not
connect
to LDAP server.");
if ( $ldapconn ) {
ldap_set_option( $ldapconn,
LDAP_OPT_PROTOCOL_VERSION, 3
);
# Some LDAP Servers will do an anonymous bind if a
# blank password is used, no matter what the
username
# is. To avoid this, it shouldn't be allowed.
if ( "" == $userpass ) {
$this->mainLoginForm( wfMsg(
"wrongpassword" ) );
return false;
}
$bind = @ldap_bind( $ldapconn, $userdn, $userpass
);
if (!$bind) {
$this->mainLoginForm( wfMsg(
"wrongpassword" ) );
return false;
}
return true;
}
}
323a390
global $wgUseLDAP, $wgLDAPDomainNames,
$wgLDAPUseLocal;
328a396
$ydn = wfMsg( "yourdomainname" );
385a454
$encDomain = wfEscapeHTML( $this->mDomain );
413a483,497
if ($wgUseLDAP) {
foreach ($wgLDAPDomainNames as $dom) {
$doms = $doms . "<option>$dom</option>";
}
if ($wgLDAPUseLocal) {
$doms = $doms . "<option>local</option>";
}
$wgOut->addHTML("<tr><td align='right'>$ydn:</td>
<td align='left'>
<select tabindex='9' name=\"wpDomain\"
value=\"{$encDomain}\">
$doms
</select>
</td></tr>");
}
415,416d498
< $encRetype = htmlspecialchars( $this->mRetype );
< $encEmail = htmlspecialchars( $this->mEmail );
418c500,505
< <td align='right'>$ypa:</td>
---
<td
align='right'>$nuo</td></tr>");
if (!$wgUseLDAP || $wgLDAPUseLocal) {
$encRetype = htmlspecialchars( $this->mRetype );
$wgOut->addHTML("<tr><td align='right'>$ypa:</td>
422,424c509,513
< </td><td>$nuo</td></tr>
< <tr>
< <td align='right'>$ye:</td>
---
</td></tr>");
}
$encEmail = htmlspecialchars( $this->mEmail );
$wgOut->addHTML("<tr><td
align='right'>$ye:</td>
427a517
443,445c533,534
<
< $wgOut->addHTML("
< <tr><td colspan='3'> </td></tr><tr>
---
$wgOut->addHTML("<tr><td
colspan='3'> </td></tr><tr>
447c536,538
< <p>$efl<br />
---
<p>$efl<br />");
if (!wgUseLDAP) {
$wgOut->addHTML("
449,451c540,546
< </td></tr></table>
< </form>\n" );
< $wgOut->addHTML( $endText );
---
</td></tr>");
} else {
$wgOut->addHTML("</td></tr>");
}
$wgOut->addHtml("</table></form>\n" );
$wgOut->addHTML( $endText );
----------------
Ryan Lane
NAVOCEANO