diff options
author | cyeh%bluemartini.com <> | 2000-09-16 03:35:16 +0200 |
---|---|---|
committer | cyeh%bluemartini.com <> | 2000-09-16 03:35:16 +0200 |
commit | 391664703db43356450e6e471e30f4053a2e62a2 (patch) | |
tree | ff6fea075afa01e5d49f464288c36d9b9fdbed13 | |
parent | c89c74e34e758d9eb7050f416e788eb82e71691a (diff) | |
download | bugzilla-391664703db43356450e6e471e30f4053a2e62a2.tar.gz bugzilla-391664703db43356450e6e471e30f4053a2e62a2.tar.xz |
fixes for 51184, 51185, 51186: allow for ldap authentication. patches
by jmrobins@tgix.com (Joe Robins). LDAP sections haven't been
tested yet, but the code is arranged such that it shouldn't disturb
existing user authentication system.
-rw-r--r-- | CGI.pl | 250 | ||||
-rwxr-xr-x | createaccount.cgi | 9 | ||||
-rw-r--r-- | defparams.pl | 30 | ||||
-rwxr-xr-x | editusers.cgi | 31 |
4 files changed, 261 insertions, 59 deletions
@@ -19,6 +19,7 @@ # # Contributor(s): Terry Weissman <terry@mozilla.org> # Dan Mosedale <dmose@mozilla.org> +# Joe Robins <jmrobins@tgix.com> # Contains some global routines used throughout the CGI scripts of Bugzilla. @@ -27,6 +28,9 @@ use strict; # use Carp; # for confess # Shut up misguided -w warnings about "used only once". For some reason, # "use vars" chokes on me when I try it here. +# We want to check for the existence of the LDAP modules here. +eval "use Mozilla::LDAP::Conn"; +my $have_ldap = $@ ? 0 : 1; sub CGI_pl_sillyness { my $zz; @@ -623,60 +627,179 @@ sub confirm_login { # print "Content-type: text/plain\n\n"; ConnectToDatabase(); + # I'm going to reorganize some of this stuff a bit. Since we're adding + # a second possible validation method (LDAP), we need to move some of this + # to a later section. -Joe Robins, 8/3/00 + my $enteredlogin = ""; + my $realcryptpwd = ""; if (defined $::FORM{"Bugzilla_login"} && defined $::FORM{"Bugzilla_password"}) { - my $enteredlogin = $::FORM{"Bugzilla_login"}; - my $enteredpwd = $::FORM{"Bugzilla_password"}; - CheckEmailSyntax($enteredlogin); - - my $realcryptpwd = PasswordForLogin($::FORM{"Bugzilla_login"}); - - if (defined $::FORM{"PleaseMailAPassword"}) { - my $realpwd; - if ($realcryptpwd eq "") { - $realpwd = InsertNewUser($enteredlogin, ""); - } else { - SendSQL("select password from profiles where login_name = " . - SqlQuote($enteredlogin)); - $realpwd = FetchOneColumn(); - } - print "Content-type: text/html\n\n"; - PutHeader("Password has been emailed"); - MailPassword($enteredlogin, $realpwd); - PutFooter(); - exit; - } - - SendSQL("SELECT encrypt(" . SqlQuote($enteredpwd) . ", " . - SqlQuote(substr($realcryptpwd, 0, 2)) . ")"); - my $enteredcryptpwd = FetchOneColumn(); - - if ($realcryptpwd eq "" || $enteredcryptpwd ne $realcryptpwd) { - print "Content-type: text/html\n\n"; - PutHeader("Login failed"); - print "The username or password you entered is not valid.\n"; - print "Please click <b>Back</b> and try again.\n"; - PutFooter(); - exit; - } - $::COOKIE{"Bugzilla_login"} = $enteredlogin; - if (!defined $ENV{'REMOTE_HOST'}) { - $ENV{'REMOTE_HOST'} = $ENV{'REMOTE_ADDR'}; - } - SendSQL("insert into logincookies (userid,cryptpassword,hostname) values (@{[DBNameToIdAndCheck($enteredlogin)]}, @{[SqlQuote($realcryptpwd)]}, @{[SqlQuote($ENV{'REMOTE_HOST'})]})"); - SendSQL("select LAST_INSERT_ID()"); - my $logincookie = FetchOneColumn(); - - $::COOKIE{"Bugzilla_logincookie"} = $logincookie; - print "Set-Cookie: Bugzilla_login=$enteredlogin ; path=/; expires=Sun, 30-Jun-2029 00:00:00 GMT\n"; - print "Set-Cookie: Bugzilla_logincookie=$logincookie ; path=/; expires=Sun, 30-Jun-2029 00:00:00 GMT\n"; - - # This next one just cleans out any old bugzilla passwords that may - # be sitting around in the cookie files, from the bad old days when - # we actually stored the password there. - print "Set-Cookie: Bugzilla_password= ; path=/; expires=Sun, 30-Jun-80 00:00:00 GMT\n"; - + $enteredlogin = $::FORM{"Bugzilla_login"}; + my $enteredpwd = $::FORM{"Bugzilla_password"}; + CheckEmailSyntax($enteredlogin); + + $realcryptpwd = PasswordForLogin($::FORM{"Bugzilla_login"}); + + if (defined $::FORM{"PleaseMailAPassword"}) { + my $realpwd; + if ($realcryptpwd eq "") { + $realpwd = InsertNewUser($enteredlogin, ""); + } else { + SendSQL("select password from profiles where login_name = " . + SqlQuote($enteredlogin)); + $realpwd = FetchOneColumn(); + } + print "Content-type: text/html\n\n"; + PutHeader("Password has been emailed"); + MailPassword($enteredlogin, $realpwd); + PutFooter(); + exit; + } + + SendSQL("SELECT encrypt(" . SqlQuote($enteredpwd) . ", " . + SqlQuote(substr($realcryptpwd, 0, 2)) . ")"); + my $enteredcryptpwd = FetchOneColumn(); + + if ($realcryptpwd eq "" || $enteredcryptpwd ne $realcryptpwd) { + print "Content-type: text/html\n\n"; + PutHeader("Login failed"); + print "The username or password you entered is not valid.\n"; + print "Please click <b>Back</b> and try again.\n"; + PutFooter(); + exit; + } + } elsif (Param("useLDAP") && + defined $::FORM{"LDAP_login"} && + defined $::FORM{"LDAP_password"}) { + # If we're using LDAP for login, we've got an entirely different + # set of things to check. + # First, if we don't have the LDAP modules available to us, we can't + # do this. + if(!$have_ldap) { + print "Content-type: text/html\n\n"; + PutHeader("LDAP not enabled"); + print "The necessary modules for LDAP login are not installed on "; + print "this machine. Please send mail to ".Param("maintainer"); + print " and notify him of this problem.\n"; + PutFooter(); + exit; + } + + # Next, we need to bind anonymously to the LDAP server. This is + # because we need to get the Distinguished Name of the user trying + # to log in. Some servers (such as iPlanet) allow you to have unique + # uids spread out over a subtree of an area (such as "People"), so + # just appending the Base DN to the uid isn't sufficient to get the + # user's DN. For servers which don't work this way, there will still + # be no harm done. + my $LDAPserver = Param("LDAPserver"); + if ($LDAPserver eq "") { + print "Content-type: text/html\n\n"; + PutHeader("LDAP server not defined"); + print "The LDAP server for authentication has not been defined. "; + print "Please contact ".Param("maintainer")." "; + print "and notify him of this problem.\n"; + PutFooter(); + exit; + } + + my $LDAPport = "389"; #default LDAP port + if($LDAPserver =~ /:/) { + ($LDAPserver, $LDAPport) = split(":",$LDAPserver); + } + my $LDAPconn = new Mozilla::LDAP::Conn($LDAPserver,$LDAPport); + if(!$LDAPconn) { + print "Content-type: text/html\n\n"; + PutHeader("Unable to connect to LDAP server"); + print "I was unable to connect to the LDAP server for user "; + print "authentication. Please contact ".Param("maintainer"); + print " and notify him of this problem.\n"; + PutFooter(); + exit; + } + + # We've got our anonymous bind; let's look up this user. + my $dnEntry = $LDAPconn->search(Param("LDAPBaseDN"),"subtree","uid=".$::FORM{"LDAP_login"}); + if(!$dnEntry) { + print "Content-type: text/html\n\n"; + PutHeader("Login Failed"); + print "The username or password you entered is not valid.\n"; + print "Please click <b>Back</b> and try again.\n"; + PutFooter(); + exit; + } + + # Now we get the DN from this search. Once we've got that, we're + # done with the anonymous bind, so we close it. + my $userDN = $dnEntry->getDN; + $LDAPconn->close; + + # Now we attempt to bind as the specified user. + $LDAPconn = new Mozilla::LDAP::Conn($LDAPserver,$LDAPport,$userDN,$::FORM{"LDAP_password"}); + if(!$LDAPconn) { + print "Content-type: text/html\n\n"; + PutHeader("Login Failed"); + print "The username or password you entered is not valid.\n"; + print "Please click <b>Back</b> and try again.\n"; + PutFooter(); + exit; + } + + # And now we're going to repeat the search, so that we can get the + # mail attribute for this user. + my $userEntry = $LDAPconn->search(Param("LDAPBaseDN"),"subtree","uid=".$::FORM{"LDAP_login"}); + if(!$userEntry->exists(Param("LDAPmailattribute"))) { + print "Content-type: text/html\n\n"; + PutHeader("LDAP authentication error"); + print "I was unable to retrieve the ".Param("LDAPmailattribute"); + print " attribute from the LDAP server. Please contact "; + print Param("maintainer")." and notify him of this error.\n"; + PutFooter(); + exit; + } + + # Mozilla::LDAP::Entry->getValues returns an array for the attribute + # requested, even if there's only one entry. + $enteredlogin = ($userEntry->getValues(Param("LDAPmailattribute")))[0]; + + # We're going to need the cryptpwd for this user from the database + # so that we can set the cookie below, even though we're not going + # to use it for authentication. + $realcryptpwd = PasswordForLogin($enteredlogin); + + # If we don't get a result, then we've got a user who isn't in + # Bugzilla's database yet, so we've got to add them. + if($realcryptpwd eq "") { + # We'll want the user's name for this. + my $userRealName = ($userEntry->getValues("displayName"))[0]; + if($userRealName eq "") { + $userRealName = ($userEntry->getValues("cn"))[0]; + } + InsertNewUser($enteredlogin, $userRealName); + $realcryptpwd = PasswordForLogin($enteredlogin); + } + } # end LDAP authentication + + # And now, if we've logged in via either method, then we need to set + # the cookies. + if($enteredlogin ne "") { + $::COOKIE{"Bugzilla_login"} = $enteredlogin; + if (!defined $ENV{'REMOTE_HOST'}) { + $ENV{'REMOTE_HOST'} = $ENV{'REMOTE_ADDR'}; + } + SendSQL("insert into logincookies (userid,cryptpassword,hostname) values (@{[DBNameToIdAndCheck($enteredlogin)]}, @{[SqlQuote($realcryptpwd)]}, @{[SqlQuote($ENV{'REMOTE_HOST'})]})"); + SendSQL("select LAST_INSERT_ID()"); + my $logincookie = FetchOneColumn(); + + $::COOKIE{"Bugzilla_logincookie"} = $logincookie; + print "Set-Cookie: Bugzilla_login=$enteredlogin ; path=/; expires=Sun, 30-Jun-2029 00:00:00 GMT\n"; + print "Set-Cookie: Bugzilla_logincookie=$logincookie ; path=/; expires=Sun, 30-Jun-2029 00:00:00 GMT\n"; + + # This next one just cleans out any old bugzilla passwords that may + # be sitting around in the cookie files, from the bad old days when + # we actually stored the password there. + print "Set-Cookie: Bugzilla_password= ; path=/; expires=Sun, 30-Jun-80 00:00:00 GMT\n"; } @@ -701,7 +824,11 @@ Content-type: text/html } print "Content-type: text/html\n\n"; PutHeader("Login", undef, undef, undef, 1); - print "I need a legitimate e-mail address and password to continue.\n"; + if(Param("useLDAP")) { + print "I need a legitimate LDAP username and password to continue.\n"; + } else { + print "I need a legitimate e-mail address and password to continue.\n"; + } if (!defined $nexturl || $nexturl eq "") { # Sets nexturl to be argv0, stripping everything up to and # including the last slash. @@ -715,13 +842,25 @@ Content-type: text/html print " <FORM action=$nexturl method=$method> <table> +<tr>"; + if(Param("useLDAP")) { + print " +<td align=right><b>Username:</b></td> +<td><input size=10 name=LDAP_login></td> +</tr> <tr> +<td align=right><b>Password:</b></td> +<td><input type=password size=10 name=LDAP_password></td>"; + } else { + print " <td align=right><b>E-mail address:</b></td> <td><input size=35 name=Bugzilla_login></td> </tr> <tr> <td align=right><b>Password:</b></td> -<td><input type=password size=35 name=Bugzilla_password></td> +<td><input type=password size=35 name=Bugzilla_password></td>"; + } + print " </tr> </table> "; @@ -733,11 +872,16 @@ Content-type: text/html } print " <input type=submit value=Login name=GoAheadAndLogIn><hr> +"; + # If we're using LDAP, we can't request that a password be mailed... + unless(Param("useLDAP")) { + print " If you don't have a password, or have forgotten it, then please fill in the e-mail address above and click here:<input type=submit value=\"E-mail me a password\" name=PleaseMailAPassword> </form>\n"; + } # This seems like as good as time as any to get rid of old # crufty junk in the logincookies table. Get rid of any entry diff --git a/createaccount.cgi b/createaccount.cgi index 8a905c465..2ff2c0b1f 100755 --- a/createaccount.cgi +++ b/createaccount.cgi @@ -20,6 +20,7 @@ # # Contributor(s): Terry Weissman <terry@mozilla.org> # David Gardiner <david.gardiner@unisa.edu.au> +# Joe Robins <jmrobins@tgix.com> use diagnostics; use strict; @@ -42,6 +43,14 @@ Content-type: text/html "; +# If we're using LDAP for login, then we can't create a new account here. +if(Param('useLDAP')) { + PutHeader("Can't create LDAP accounts"); + print "This site is using LDAP for authentication. Please contact an LDAP "; + print "administrator to get a new account created.\n"; + PutFooter(); + exit; +} my $login = $::FORM{'login'}; my $realname = $::FORM{'realname'}; diff --git a/defparams.pl b/defparams.pl index 695bd2c9c..3a767f84f 100644 --- a/defparams.pl +++ b/defparams.pl @@ -203,6 +203,36 @@ sub check_despotbaseurl { } +# Adding in four parameters for LDAP authentication. -JMR, 7/28/00 +DefParam("useLDAP", + "Turn this on to use an LDAP directory for user authentication ". + "instead of the Bugzilla database. (User profiles will still be ". + "stored in the database, and will match against the LDAP user by ". + "email address.)", + "b", + 0); + + +DefParam("LDAPserver", + "The name (and optionally port) of your LDAP server. (e.g. ldap.company.com, or ldap.company.com:portnum)", + "t", + ""); + + +DefParam("LDAPBaseDN", + "The BaseDN for authenticating users against. (e.g. \"ou=People,o=Company\")", + "t", + ""); + + +DefParam("LDAPmailattribute", + "The name of the attribute of a user in your directory that ". + "contains the email address.", + "t", + "mail"); +#End of LDAP parameters + + DefParam("headerhtml", "Additional HTML to add to the HEAD area of documents, eg. links to stylesheets.", "l", diff --git a/editusers.cgi b/editusers.cgi index 73ee8f131..3af80a86a 100755 --- a/editusers.cgi +++ b/editusers.cgi @@ -20,6 +20,7 @@ # # Contributor(s): Holger Schurig <holgerschurig@nikocity.de> # Dave Miller <dave@intrec.com> +# Joe Robins <jmrobins@tgix.com> # # Direct any questions on this source code to # @@ -109,8 +110,11 @@ sub EmitFormElements ($$$$$$$) if ($editall) { print "</TR><TR>\n"; print " <TH ALIGN=\"right\">Password:</TH>\n"; - print " <TD><INPUT TYPE=\"PASSWORD\" SIZE=16 MAXLENGTH=16 NAME=\"password\" VALUE=\"$password\"></TD>\n"; - + if(Param('useLDAP')) { + print " <TD><FONT COLOR=RED>This site is using LDAP for authentication!</FONT></TD>\n"; + } else { + print " <TD><INPUT TYPE=\"PASSWORD\" SIZE=16 MAXLENGTH=16 NAME=\"password\" VALUE=\"$password\"></TD>\n"; + } print "</TR><TR>\n"; print " <TH ALIGN=\"right\">Email notification:</TH>\n"; print qq{<TD><SELECT NAME="emailnotification">}; @@ -341,7 +345,7 @@ if ($action eq 'list') { } print "</TR>"; } - if ($editall) { + if ($editall && !Param('useLDAP')) { print "<TR>\n"; my $span = $candelete ? 3 : 2; print qq{ @@ -375,6 +379,13 @@ if ($action eq 'add') { exit; } + if(Param('useLDAP')) { + print "This site is using LDAP for authentication. To add a new user, "; + print "please contact the LDAP administrators."; + PutTrailer(); + exit; + } + print "<FORM METHOD=POST ACTION=editusers.cgi>\n"; print "<TABLE BORDER=0 CELLPADDING=4 CELLSPACING=0><TR>\n"; @@ -406,6 +417,13 @@ if ($action eq 'new') { exit; } + if(Param('useLDAP')) { + print "This site is using LDAP for authentication. To add a new user, "; + print "please contact the LDAP administrators."; + PutTrailer(); + exit; + } + # Cleanups and valididy checks my $realname = trim($::FORM{realname} || ''); my $password = trim($::FORM{password} || ''); @@ -667,7 +685,7 @@ if ($action eq 'edit') { print "</TR></TABLE>\n"; print "<INPUT TYPE=HIDDEN NAME=\"userold\" VALUE=\"$user\">\n"; - if ($editall) { + if ($editall && !Param('useLDAP')) { print "<INPUT TYPE=HIDDEN NAME=\"passwordold\" VALUE=\"$password\">\n"; } print "<INPUT TYPE=HIDDEN NAME=\"realnameold\" VALUE=\"$realname\">\n"; @@ -764,13 +782,14 @@ if ($action eq 'update') { WHERE login_name=" . SqlQuote($userold)); print "Updated email notification.<BR>\n"; } - - if ($editall && $password ne $passwordold) { + if(!Param('useLDAP')) { + if ($editall && $password ne $passwordold) { my $q = SqlQuote($password); SendSQL("UPDATE profiles SET password= $q, cryptpassword = ENCRYPT($q) WHERE login_name=" . SqlQuote($userold)); print "Updated password.<BR>\n"; + } } if ($editall && $realname ne $realnameold) { SendSQL("UPDATE profiles |