#!c:/cygwin/bin/perl ################################ # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details, published at # http://www.gnu.org/copyleft/gpl.html # #Author : sdetweil@us.ibm.com #Date : 5/May/2005 # #The basic idea is taken from SessionPlugins's logon script. #The script is modifying ENV{REMOTE_USER} value after authentication # # # This script depends on variables being set in the TWiki.cfg file # # # LDAP Server Name # #$LDAP_Server = 'ourldapserver.company.com'; # # the LDAP_Server port where secure binds can be done to validate the users password # 389 (default LDAP port) would send the password over the net in clear text.. # 636 (typical secure port) would use SSL to send the password during bind # #$LDAP_AuthPort = 636; # # we will use the default port for Search # as searches are done ALL the time in the clear # this is here for documentation purposes, not hard coded in the code # #$LDAP_SearchPort = 389; # # this uses the LDAP search function to locate the users distinguished (dn) name # we do this on the non-secure port (389) cause everything else does it too # # this is the base of the LDAP directory to search for this user # the directory designers/application support team can tell you what this string is for # the directory you need to use. # #$LDAP_SearchBase ='ou=some_organization,o=ourcompany.com'; # # this tells LDAP whether the search is single level 'base' (just in this specific branch) # of if the search can travers the directory to locate the user 'sub' # the choice here depends on the directory implementation and security rules at a particular company # #$LDAP_SearchScope ='sub'; # or 'base' # # this is the filter used on the search. As we have only the userid, that is all we can search on # but how this is coded in the directory will determine this filter string. # # note that the user name is bracketed by %%.. perl will NOT substitute at runtime # so we have to use a replace function to rebuild the string # #$LDAP_SearchFilter ='(&(objectclass=person)(mail=%username%))'; # # this tells the replace function ->s/mask/data what string the userid should replace in the # filter above # #$LDAP_UserNameMask ='%username%'; # # ###################### sub BEGIN { $ENV{PTKDB_STOP_TAG_COLOR} = "yellow" } use CGI::Carp qw(fatalsToBrowser); use CGI; use Net::LDAPS; ## Used only in case of LDAP server is used for authentication ## Feel free to comment if you are not using LDAP. BEGIN { # Set default current working directory (needed for mod_perl) if( $ENV{"SCRIPT_FILENAME"} && $ENV{"SCRIPT_FILENAME"} =~ /^(.+)\/[^\/]+$/ ) { chdir $1; } # Set library paths in @INC, at compile time unshift @INC, '.'; require '../bin/setlib.cfg'; } use TWiki; use TWiki::Plugins::SessionPlugin; $query = new CGI(); my $theRemoteUser = $query->remote_user(); my $theUrl = $query->url; my $theTopic = $query->param( 'topic' ) || ""; my $username = $query->param('username'); my $password = $query->param('password'); main(); sub main { my $thePathInfo = $query->path_info(); # get access to the twiki.cfg Variables my( $topic, $webName, $dummy, $userName ) = TWiki::initialize( $thePathInfo, $username, $theTopic, $theUrl, $query ); # go validate username and password against LDAP directory my $the_user = do_login($username, $password); # if validate is successful, the name string will NOT be empty if ($the_user eq '') { $ENV{REMOTE_USER} ="guest"; my $oopsurl = $query->param('url'); $oopsurl =~ s/https/http/; ## change https to http $oopsurl =~ s/bin-ssl/bin/; ## change https to http my @oopsurlarray = split /logon/, $oopsurl; $oopsurl = $oopsurlarray[0]."oops"; $query->delete_all(); &TWiki::redirect($query, "$oopsurl?template=oopsauth"); } else { $ENV{REMOTE_USER} = $the_user; } my $theRemoteUser = $query->remote_user(); my $theTopic = $query->param( 'url' ); # &TWiki::Func::writeDebug("........$theTopic"); my @topiclisting = split/logon/, $theTopic; ## The logon word is part of ## %SESSIONLOGONURL% variable foreach (@topiclisting) { $theTopic = $_;} $theTopic =~ s/\/+//; ## Remove all "/" from begining of string. my $theUrl = $query->url; $query->delete_all(); ###This was required... reset the $query ( $topic, $web ) = &TWiki::initialize( $thePathInfo, $theRemoteUser, $theTopic, $theUrl, $query ); my $url = &TWiki::getViewUrl( $TWiki::webName, $topic ); $url .= ( '?' . $query->query_string() ) if $query->query_string(); $url =~ s/^https/http/; ## change https to http #$url =~ s/:8887//; ## change https port number, required if you are running https on non-default port. &TWiki::redirect( $query, $url ); } # do_login authenticates users from authentication system. sub do_login { # get username parameter my ($username, $password) = @_; # search the directory for this name, get back the distinguished name (dn) if valid my $dn = &ldap_search($username); # if the user was found in the directory if ($dn ne '') { # setup to the server.. if the port is not 389, then it will be secured with SSL # note # note beware of using the default or non-ssl port as the password WILL flow in clear text # note $ldap = Net::LDAPS->new($TWiki::LDAP_Server, port => $TWiki::LDAP_AuthPort) or &mydie(); # bind with the user DN and password to validate the PW $mesg = $ldap->bind( $dn, password => $password ); $ldap->unbind; # take down session # process the bind return code, 0 = successful if ( $mesg->code ) { # FAILURE (bad password) return ''; } else { # SUCCESS return $username; } } else { # FAILURE (username doesn't exist) return ''; } } sub ldap_search { # get the username parameter ($username) = @_; # connect to the server using the non-secure port # we will only pass the userid in the clear $ldap = Net::LDAP->new($TWiki::LDAP_Server, port => $TWiki::LDAP_SearchPort ) or &mydie(); # bind as no user (anonymous) $mesg = $ldap->bind ; if ( $mesg->code ) { &mydie($mesg->code); } # get the filter string from TWiki.cfg my $filter = $TWiki::LDAP_SearchFilter; # replace the mask with the real user name string $filter =~ s/$TWiki::LDAP_UserNameMask/$username/; # search directory for this user entry $mesg = $ldap->search ( base => $TWiki::LDAP_SearchBase, scope => $TWiki::LDAP_SearchScope, filter => $filter ); # don't need to be connected anymore $ldap->unbind; # take down session # we assume there is only ONE valid match by email address my $dn="" ; if ($mesg->count) { my $entry = $mesg->entry(0); # extract the distinguished name $dn = $entry->dn ; } return $dn ; } sub mydie { exit 2; }