[Bps-public-commit] r17828 - in RT-Authen-ExternalAuth/trunk: . etc html/Callbacks/ExternalAuth/autohandler lib/RT lib/RT/Authen

zordrak at bestpractical.com zordrak at bestpractical.com
Sun Jan 18 09:36:42 EST 2009


Author: zordrak
Date: Sun Jan 18 09:36:42 2009
New Revision: 17828

Modified:
   RT-Authen-ExternalAuth/trunk/ChangeLog
   RT-Authen-ExternalAuth/trunk/MANIFEST
   RT-Authen-ExternalAuth/trunk/Makefile.PL
   RT-Authen-ExternalAuth/trunk/README
   RT-Authen-ExternalAuth/trunk/etc/RT_SiteConfig.pm
   RT-Authen-ExternalAuth/trunk/html/Callbacks/ExternalAuth/autohandler/Auth
   RT-Authen-ExternalAuth/trunk/lib/RT/Authen/ExternalAuth.pm
   RT-Authen-ExternalAuth/trunk/lib/RT/Authen/ExternalAuth/DBI/Cookie.pm
   RT-Authen-ExternalAuth/trunk/lib/RT/User_Vendor.pm

Log:
zordrak | 2009-01-18 14:36 +0000
 * RT::Authen::ExternalAuth 0.08_01
 * pre-alpha

Modified: RT-Authen-ExternalAuth/trunk/ChangeLog
==============================================================================
--- RT-Authen-ExternalAuth/trunk/ChangeLog	(original)
+++ RT-Authen-ExternalAuth/trunk/ChangeLog	Sun Jan 18 09:36:42 2009
@@ -1,17 +1,77 @@
-v0.07_03 2009-01-16    Mike Peachey <zordrak at cpan.org>
+v0.08_01  2009-01-18    Mike Peachey <zordrak at cpan.org>
     
     * ChangeLog
         
-	Added entry for v0.07_01
+        Added entry for v0.08_01
+
+        Tabs-to-spaces conversion made where needed.
 
     * lib/RT/Authen/ExternalAuth.pm
         
-	Version updated to 0.07_03
+        Version updated to 0.08_01
+        
+        DoAuth method created to inherit the work that used to be
+        performed by the Auth callback for autohandler.
+
+        GetAuth reduced to an interface. Its purpose is now just to
+        check what type of service was passed and then call the
+        GetAuth method from the right package.
+
+        SSO Cookie authentication now available following the
+        integration of RT::Authen::CookieAuth. Methods updated
+        to reflect the availability of this service.
+
+    * etc/RT_SiteConfig.pm
+
+        CookieAuth settings have been merged into the ExternalAuth
+	settings hash. Example from CookieAuth has been merged in.
+
+        'auth' and 'info' settings have been deprecated and so have
+        been removed from the examples. The function they served has
+        been replaced by the ExternalAuthPriority and
+        ExternalInfoPriority variables.
+
+    * lib/RT/Authen/User_Vendor.pm
+
+        The override for the IsPassword method has been deprecated
+        and deleted. It is no longer necessary to do password tests
+        as a call to the User object. The equivalent function is
+        now provided by GetAuth in ExternalAuth.pm and is called
+        with an ExternalAuth service name, username and password.
+        Currently, this only needs to be called by DoAuth in
+        ExternalAuth.pm
+
+        While RT::Authen::ExternalAuth used to be used to integrate
+        internal RT authentication with an external method as a single
+        operation, this causes a lack of modularity. Now ExternalAuth
+        is only concerned with its own authentication methods and if
+        they fail then RT will decide to do fallback to internal
+        authentication on its own.
+
+    * html/Callbacks/ExternalAuth/autohandler/Auth
+
+        Workaround for RT versions 3.8.0 and 3.8.1 removed.
+        RT::Authen::ExternalAuth v0.08 will be officially compatible
+        only with versions 3.8.2 and up.
+
+        All functionality has been replaced by a call to ExternalAuth.pm's
+        DoAuth method. This is permitted by the passing of a reference to
+        the current session variable. DoAuth simply modifies that variable
+        as necessary to perform its function. Any data returned is purely
+        informational.
+
+    * README
+
+        Updated to include basic information on SSO cookies.
+
+    * Makefile.PL
+
+        Updated to reflect the integration of RT::Authen::CookieAuth.
 
 v0.07_02 2008-12-22    Kevin Falcone <falcone at cpan.org>
 
     * html/Callbacks/ExternalAuth/autohandler/Auth
-		
+
         Make the workaround needed for 3.8.1 work on 3.8.2
 
 v0.07_01 2008-11-06    Mike Peachey <zordrak at cpan.org>
@@ -20,7 +80,7 @@
     * ALL
       
         Complete code refactoring and updates for RT-3.8.x
-	compatability.
+        compatability.
 
 v0.06    2008-11-01    Mike Peachey <zordrak at cpan.org>
 

Modified: RT-Authen-ExternalAuth/trunk/MANIFEST
==============================================================================
--- RT-Authen-ExternalAuth/trunk/MANIFEST	(original)
+++ RT-Authen-ExternalAuth/trunk/MANIFEST	Sun Jan 18 09:36:42 2009
@@ -13,6 +13,7 @@
 lib/RT/Authen/ExternalAuth.pm
 lib/RT/Authen/ExternalAuth/DBI.pm
 lib/RT/Authen/ExternalAuth/LDAP.pm
+lib/RT/Authen/ExternalAuth/DBI/Cookie.pm
 lib/RT/User_Vendor.pm
 LICENSE
 Makefile.PL

Modified: RT-Authen-ExternalAuth/trunk/Makefile.PL
==============================================================================
--- RT-Authen-ExternalAuth/trunk/Makefile.PL	(original)
+++ RT-Authen-ExternalAuth/trunk/Makefile.PL	Sun Jan 18 09:36:42 2009
@@ -18,6 +18,9 @@
     'Net::LDAP' => 0],
   'External DBI Sources' => [
     -default => 1,
-    'DBI' => 0]
+    'DBI' => 0],
+  'SSO Cookie Sources' => [
+    -default => 1,
+    'CGI::Cookies' => 0]
 );
 &WriteAll;

Modified: RT-Authen-ExternalAuth/trunk/README
==============================================================================
--- RT-Authen-ExternalAuth/trunk/README	(original)
+++ RT-Authen-ExternalAuth/trunk/README	Sun Jan 18 09:36:42 2009
@@ -20,6 +20,12 @@
 LDAP service and ANY DBI-drivable database, based upon the
 configuration given in your $RTHOME/etc/RT_SiteConfig.pm
 
+As of v0.08 ExternalAuth also allows you to pull a browser
+cookie value and test it against a DBI data source allowing
+the use of cookies for Single Sign-On (SSO) authentication.
+This is due to the merging of RT::Authen::ExternalAuth and
+RT::Authen::CookieAuth.
+
 
 INSTALLATION
 

Modified: RT-Authen-ExternalAuth/trunk/etc/RT_SiteConfig.pm
==============================================================================
--- RT-Authen-ExternalAuth/trunk/etc/RT_SiteConfig.pm	(original)
+++ RT-Authen-ExternalAuth/trunk/etc/RT_SiteConfig.pm	Sun Jan 18 09:36:42 2009
@@ -3,7 +3,8 @@
 # if successfully confirmed by any service - no more services
 # are checked.
 Set($ExternalAuthPriority,  [   'My_LDAP',
-                                'My_MySQL'
+                                'My_MySQL',
+                                'My_SSO_Cookie'
                             ]
 );
 
@@ -11,7 +12,10 @@
 # should be used to get information about users. This includes
 # RealName, Tel numbers etc, but also whether or not the user
 # should be considered disabled. 
+#
 # Once user info is found, no more services are checked.
+#
+# You CANNOT use a SSO cookie for authentication.
 Set($ExternalInfoPriority,  [   'My_MySQL',
                                 'My_LDAP'
                             ]
@@ -35,12 +39,8 @@
 #
 Set($ExternalSettings,      {   # AN EXAMPLE DB SERVICE
                                 'My_MySQL'   =>  {      ## GENERIC SECTION
-                                                        # The type of service (db/ldap) 
+                                                        # The type of service (db/ldap/cookie) 
                                                         'type'                      =>  'db',
-                                                        # Should the service be used for authentication?
-                                                        'auth'                      =>  1,
-                                                        # Should the service be used for information?
-                                                        'info'                      =>  1,
                                                         # The server hosting the service
                                                         'server'                    =>  'server.domain.tld',
                                                         ## SERVICE-SPECIFIC SECTION
@@ -91,10 +91,6 @@
                                 'My_LDAP'       =>  {   ## GENERIC SECTION
                                                         # The type of service (db/ldap/cookie) 
                                                         'type'                      =>  'ldap',
-                                                        # Should the service be used for authentication?
-                                                        'auth'                      =>  1,
-                                                        # Should the service be used for information?
-                                                        'info'                      =>  1,
                                                         # The server hosting the service
                                                         'server'                    =>  'server.domain.tld',
                                                         ## SERVICE-SPECIFIC SECTION
@@ -153,6 +149,28 @@
                                                                                             'Country' => 'co'
                                                                                         }
                                                     }
+                                # An example SSO cookie service
+                                'My_SSO_Cookie'  => {   # # The type of service (db/ldap/cookie)
+                                                        'type'                      =>  'cookie',
+                                                        # The name of the cookie to be used
+                                                        'name'                      =>  'loginCookieValue',
+                                                        # The users table
+                                                        'u_table'                   =>  'users',
+                                                        # The username field in the users table
+                                                        'u_field'                   =>  'username',
+                                                        # The field in the users table that uniquely identifies a user
+                                                        # and also exists in the cookies table
+                                                        'u_match_key'               =>  'userID',
+                                                        # The cookies table
+                                                        'c_table'                   =>  'login_cookie',
+                                                        # The field that stores cookie values
+                                                        'c_field'                   =>  'loginCookieValue',
+                                                        # The field in the cookies table that uniquely identifies a user
+                                                        # and also exists in the users table
+                                                        'c_match_key'               =>  'loginCookieUserID',
+                                                        # The DB service in this configuration to use to lookup the cookie information
+                                                        'db_service_name'           =>  'My_MySQL'
+                                                    }
                                 }
 );
 

Modified: RT-Authen-ExternalAuth/trunk/html/Callbacks/ExternalAuth/autohandler/Auth
==============================================================================
--- RT-Authen-ExternalAuth/trunk/html/Callbacks/ExternalAuth/autohandler/Auth	(original)
+++ RT-Authen-ExternalAuth/trunk/html/Callbacks/ExternalAuth/autohandler/Auth	Sun Jan 18 09:36:42 2009
@@ -1,242 +1,9 @@
-<%once>
-my $loaded_user = 0;
-</%once>
 <%init>
-
 use RT::Authen::ExternalAuth;
-######################################################################################
-# Work around a bug in the RT 3.8.0 and 3.8.1 plugin system (fixed in 3.8.2)
-# Temporarily force RT to reload RT::User, since it isn't being loaded
-# correctly as a plugin.
-unless ($loaded_user) {
-    $RT::Logger->error("Working around bug in RT and reloading RT::User");
-    $loaded_user++;
-    delete $INC{'RT/User.pm'};
-    delete $INC{'RT/User_Overlay.pm'};
-    delete $INC{'RT/User_Vendor.pm'};
-    require RT::User;
-}
-######################################################################################
-
-
-
-##########################################################
-##################### CA #################################
-##########################################################
-# 
-# If the user is logging in, let's authenticate; if they can auth but don't load
-# (e.g. they don't have an account but external auth succeeds), we'll autocreate
-# their account.
-unless ($session{'CurrentUser'}) {
-    
-    # Check to see if we've been asked to authenticate from cookies
-    # If so, confirm the username authenticated by the cookies
-    if ($RT::UseExternalCookieAuthService){
-        $RT::Logger->debug( "Cookie Authentication (",
-                            $RT::UseExternalCookieAuthService,
-                            ") requested");
-        
-        # Use the package we need for cookie authentication
-
-        my ($cookie_user, $confirmed_by_cookie) = RT::Authen::ExternalAuth::CheckCookies();
-        
-        # If CheckCookies gave us a user, set it as the global user.
-        $user = $cookie_user if defined($cookie_user);
-        
-        # If CheckCookies is happy the user it gave us is authenticated...
-        if ($confirmed_by_cookie) {
-            
-            # This WAS used to stop a pointless LookupExternalUserInfo 
-            # called by UpdateFromExternal later on since it's already
-            # called by RT::User::Create if the user is autocreated
-            # but this has been deprecated pending a little bit of a 
-            # rewrite since I realised that we're not calling
-            # CanonicalizeUserInfo but UpdateFromExternal which is the
-            # only code that checks whether the user is externally
-            # marked as disabled.
-            my $user_autocreated = 0;
-
-            # Create a new CurrentUser for the session and try and load
-            # a known user with the username given by the cookie check.
-            $session{'CurrentUser'} = RT::CurrentUser->new();
-            $session{'CurrentUser'}->Load($user);
-
-            # Unless we loaded a valid user with a UserID,
-            # autocreate a new user
-            unless ($session{'CurrentUser'}->Id) {
-                
-                # Start with a new SystemUser
-                my $UserObj = RT::User->new($RT::SystemUser);
-                
-                # Set the user's name to the one we were given
-                my ($val, $msg) = $UserObj->SetName($user);
-
-                # Commit the created user to the DB
-                ($val, $msg) = 
-                  $UserObj->Create(%{ref($RT::AutoCreate) ? $RT::AutoCreate : {}},
-                                   Name   => $user,
-                                   Gecos  => $user,
-                                  );
-                                   
-                # Log the creation
-                $RT::Logger->info(  "Autocreated authenticated user",
-                                    $UserObj->Name,
-                                    "(",
-                                    $UserObj->Id,
-                                    ")");
-                
-                # Mark that user was created here so that we 
-                # don't bother looking up their information
-                $user_autocreated = 1;
-
-                # Load the newly-created user as the CurrentUser in $session
-                # To RT, this means we now have a valid, authenticated user
-                $session{'CurrentUser'}->Load($user) if $UserObj->Id;
-            }
-        
-        
-            # If we now have a completely valid RT user to play with,
-            # and the user is not disabled in RT, then...
-            if ($session{'CurrentUser'} && $session{'CurrentUser'}->Id) {
-                    
-                # ALWAYS call UpdateFromExternal otherwise externally-disabled
-                # users could be allowed in.
-                $session{'CurrentUser'}->UserObj->UpdateFromExternal();
-
-                # Now their information is up to date,
-                # check if the user is disabled.
-                
-                # If the user is disabled, kill their session,
-                # otherwise, authentication is successful.
-                if($session{'CurrentUser'}->UserObj->Disabled) {
-                    delete $session{'CurrentUser'};
-                } else {     
-                    # Do not delete the session. User stays logged in.
-                    # Log the success.
-                    $RT::Logger->info(  "Successful login for",
-                                        $user,
-                                        "from",
-                                        $ENV{'REMOTE_ADDR'});
-                }
-            } else {
-                # If we have no complete user.
-                delete $session{'CurrentUser'};
-            }
-        }
-    } else {
-        $RT::Logger->debug("RT is capable of External Cookie Auth, but it has not been enabled.");
-    }
-}
-
-############################################################
-############### EA #########################################
-############################################################
-#
-# If the user is logging in, let's authenticate; if they can auth but don't load
-# (e.g. they don't have an account but external auth succeeds), we'll autocreate
-# their account.
-unless ($session{'CurrentUser'}) {
-    
-    # Password has not been confirmed valid until we say so
-    my $password_validated = 0;
-
-    # If $user has been passed by login page, 
-    # or any other custom code previous to this
-    if (defined ($user)) {
-        $session{'CurrentUser'} = RT::CurrentUser->new();
-        
-        # Does user exist internally?
-        $session{'CurrentUser'}->Load($user);
-
-        # Unless we have loaded a valid user with a UserID
-        # check if user exists externally and autocreate if it does
-        unless ($session{'CurrentUser'}->Id) {
-            if(RT::Authen::ExternalAuth::UserExists($user)){
-				my $UserObj = RT::User->new($RT::SystemUser);
-            	my ($val, $msg) = 
-                  $UserObj->Create(%{ref($RT::AutoCreate) ? $RT::AutoCreate : {}},
-                                   Name   => $user,
-                                   Gecos  => $user,
-                                  );
-                unless ($val) {
-                    $RT::Logger->error( "Couldn't create user $user: $msg" );
-                    return;
-                }
-                $RT::Logger->info(  "Autocreated external user",
-                                    $UserObj->Name,
-                                    "(",
-                                    $UserObj->Id,
-                                    ")");
-                
-                $RT::Logger->debug("Loading new user (",
-                					$user,
-                					") into current session");
-                $session{'CurrentUser'}->Load($user);
-            }
-        } 
-    }
-    
-    # If we now have a completely valid RT user to play with...
-    if ($session{'CurrentUser'} && $session{'CurrentUser'}->Id) {
-	    
-	    # If a password was given on the login page, validate it
-	    if (defined($pass)) {
-	        $RT::Logger->debug("\$pass defined ($pass), Running IsPassword");
-	        $password_validated = $session{'CurrentUser'}->UserObj->IsPassword($pass);
-	    }
-	        
-	    unless($password_validated) {
-	        $RT::Logger->debug("Password Incorrect");
-	        delete $session{'CurrentUser'};
-	    }
-	}
-	    
-    # If we STILL have a completely valid RT user to play with...
-    # and therefore password has been validated...
-    if ($session{'CurrentUser'} && $session{'CurrentUser'}->Id) {
-        
-        # Even if we have JUST created the user in RT, we are going to
-        # reload their information from an external source. This allows us
-        # to be sure that the user the cookie gave us really does exist in
-        # the database, but more importantly, UpdateFromExternal will check 
-        # whether the user is disabled or not which we have not been able to 
-        # do during auto-create
-        my ($updated,$update_msg) = RT::Authen::ExternalAuth::UpdateUserInfo($session{'CurrentUser'}->Name);
-                
-        # Now that we definitely have up-to-date user information,
-        # if the user is disabled, kick them out. Now!
-        if ($session{'CurrentUser'}->UserObj->Disabled) {
-            delete $session{'CurrentUser'};
-        }
-    }
-    # Original thank to Walter Duncan for these session deletes.
-    
-    # If the user has already been authenticated successfully above
-    # then all is well, log the successful user auth
-    # Else, ensure the session dies.
-    
-    # We will not check the password here, because this will be
-    # done by the autohandler this Callback is extending if
-    # we delete the session.
-    
-    # If we **STILL** have a full user and the session hasn't already been deleted
-    if ($session{'CurrentUser'} && $session{'CurrentUser'}->Id) {
-    	# Sanity check
-        if($password_validated) {
-            
-            $RT::Logger->info(  "Successful login for",
-                                $user,
-                                "from",
-                                $ENV{'REMOTE_ADDR'});
-            # Do not delete the session. User stays logged in and
-            # autohandler will not check the password again
-        } else {
-            # Make SURE the session is deleted.
-            delete $session{'CurrentUser'};
-            # This will cause autohandler to request IsPassword 
-            # which will in turn call IsExternalPassword
-        }
-    }
+my ($val,$msg);
+unless($session{'CurrentUser'}->Id) {
+    ($val,$msg) = RT::Authen::ExternalAuth::DoAuth(\$session,\$user,\$pass);
+    # Success if $val == 1
 }
 return;
 </%init>

Modified: RT-Authen-ExternalAuth/trunk/lib/RT/Authen/ExternalAuth.pm
==============================================================================
--- RT-Authen-ExternalAuth/trunk/lib/RT/Authen/ExternalAuth.pm	(original)
+++ RT-Authen-ExternalAuth/trunk/lib/RT/Authen/ExternalAuth.pm	Sun Jan 18 09:36:42 2009
@@ -1,6 +1,6 @@
 package RT::Authen::ExternalAuth;
 
-our $VERSION = '0.07_03';
+our $VERSION = '0.08_01';
 
 =head1 NAME
 
@@ -18,9 +18,6 @@
 =begin testing
 
 ok(require RT::Authen::ExternalAuth);
-ok(require RT::Authen::ExternalAuth::LDAP);
-ok(require RT::Authen::ExternalAuth::DBI);
-ok(require RT::Authen::ExternalAuth::Cookie);
 
 =end testing
 
@@ -28,9 +25,174 @@
 
 use RT::Authen::ExternalAuth::LDAP;
 use RT::Authen::ExternalAuth::DBI;
-use RT::Authen::ExternalAuth::Cookie;
+
 use Data::Dumper;
 
+sub DoAuth {
+    my ($session,$given_user,$given_pass) = shift;
+
+    # This may be used by single sign-on (SSO) authentication mechanisms for bypassing a password check.
+    my $pass_bypass = 0;
+    
+    # Should have checked if user is already logged in before calling this function,
+    # but just in case, we'll check too.
+    return (0, "User already logged in!") if $session{'CurrentUser'}->Id;
+    # We don't have a logged in user. Let's try all our available methods in order.
+    # last if success, next if not.
+    
+    # Get the prioritised list of external authentication services
+    my @auth_services = @$RT::ExternalAuthPriority;
+    
+    # For each of those services..
+    foreach my $service (@auth_services) {
+
+        # Get the full configuration for that service as a hashref
+        my $config = $RT::ExternalSettings->{$service};
+        $RT::Logger->debug( "Attempting to use external auth service:",
+                            $service);
+
+        # $username will be the final username we decide to check
+        # This will not necessarily be $given_user
+        my $username = undef;
+        
+        #############################################################
+        ####################### SSO Check ###########################
+        #############################################################
+        if ($config->{'type'} eq 'cookie') {    
+            # Currently, Cookie authentication is our only SSO method
+            $username = RT::Authen::ExternalAuth::DBI::GetCookieAuth();
+        }
+        #############################################################
+        
+        # If $username is defined, we have a good SSO $username and can
+        # safely bypass the password checking later on; primarily because
+        # it's VERY unlikely we even have a password to check if an SSO succeeded.
+        if defined($username) {
+            $pass_bypass = 1;
+        } else {
+            # We don't have an SSO login, so we will be using the credentials given
+            # on RT's login page to do our authentication.
+            $username = $given_user
+    
+            # Don't continue unless the service works.
+            next unless RT::Authen::ExternalAuth::TestConnection($config);
+
+            # Don't continue unless the $username exists in the external service
+            next unless RT::Authen::ExternalAuth::CheckExist($username, $config);
+        }
+
+        ####################################################################
+        ########## Load / Auto-Create ######################################
+        ####################################################################
+        # We are now sure that we're talking about a valid RT user.
+        # If the user already exists, load up their info. If they don't
+        # then we need to create the user in RT.
+
+        # Does user already exist internally to RT?
+        $session{'CurrentUser'} = RT::CurrentUser->new();
+        $session{'CurrentUser'}->Load($user);
+
+        # Unless we have loaded a valid user with a UserID create one.
+        unless ($session{'CurrentUser'}->Id) {
+			my $UserObj = RT::User->new($RT::SystemUser);
+        	my ($val, $msg) = 
+              $UserObj->Create(%{ref($RT::AutoCreate) ? $RT::AutoCreate : {}},
+                               Name   => $user,
+                               Gecos  => $user,
+                              );
+            unless ($val) {
+                $RT::Logger->error( "Couldn't create user $user: $msg" );
+                next;
+            }
+            $RT::Logger->info(  "Autocreated external user",
+                                $UserObj->Name,
+                                "(",
+                                $UserObj->Id,
+                                ")");
+            
+            $RT::Logger->debug("Loading new user (",
+            					$user,
+            					") into current session");
+            $session{'CurrentUser'}->Load($user);
+        } 
+        
+        ####################################################################
+        ########## Authentication ##########################################
+        ####################################################################
+        # If we successfully used an SSO service, then authentication
+        # succeeded. If we didn't then, success is determined by a password
+        # test.
+        my $success;
+        if($pass_bypass) {
+            $success = 1;
+        } else {
+            $success = RT::Authen::ExternalAuth::GetAuth($service,$username,$given_pass);
+        }
+        
+        # If the password check succeeded then this is our authoritative service
+        # and we proceed to user information update and login.
+        last if $success;
+    }
+    
+    # If we got here and don't have a user loaded we must have failed to
+    # get a full, valid user from an authoritative external source.
+    unless ($session{'CurrentUser'} && $session{'CurrentUser'}->Id) {
+        delete $session{'CurrentUser'};
+        return (0, "Failed to authenticate externally");
+    }
+    
+    # Otherwise we succeeded.
+    $RT::Logger->debug("Authentication successful. Now updating user information and attempting login.");
+        
+    ####################################################################################################
+    ############################### The following is auth-method agnostic ##############################
+    ####################################################################################################
+    
+    # If we STILL have a completely valid RT user to play with...
+    # and therefore password has been validated...
+    if ($session{'CurrentUser'} && $session{'CurrentUser'}->Id) {
+        
+        # Even if we have JUST created the user in RT, we are going to
+        # reload their information from an external source. This allows us
+        # to be sure that the user the cookie gave us really does exist in
+        # the database, but more importantly, UpdateFromExternal will check 
+        # whether the user is disabled or not which we have not been able to 
+        # do during auto-create
+        
+        # Note that UpdateUserInfo does not care how we authenticated the user
+        # It will look up user info from whatever is specified in $RT::ExternalInfoPriority
+        my ($updated,$update_msg) = RT::Authen::ExternalAuth::UpdateUserInfo($session{'CurrentUser'}->Name);
+                
+        # Now that we definitely have up-to-date user information,
+        # if the user is disabled, kick them out. Now!
+        if ($session{'CurrentUser'}->UserObj->Disabled) {
+            delete $session{'CurrentUser'};
+            return (0, "User account disabled, login denied");
+        }
+    }
+    
+    # If we **STILL** have a full user and the session hasn't already been deleted
+    # This If/Else is logically unnecessary, but it doesn't hurt to leave it here
+    # just in case. Especially to be a double-check to future modifications.
+    if ($session{'CurrentUser'} && $session{'CurrentUser'}->Id) {
+            
+            $RT::Logger->info(  "Successful login for",
+                                $user,
+                                "from",
+                                $ENV{'REMOTE_ADDR'});
+            # Do not delete the session. User stays logged in and
+            # autohandler will not check the password again
+    } else {
+            # Make SURE the session is deleted.
+            delete $session{'CurrentUser'};
+            return (0, "Failed to authenticate externally");
+            # This will cause autohandler to request IsPassword 
+            # which will in turn call IsExternalPassword
+    }
+    
+    return (1, "Successful login");
+}
+
 sub UpdateUserInfo {
     my $username        = shift;
 
@@ -110,70 +272,29 @@
     return ($updated, $msg);
 }
 
-sub UserExists {
-
-    my $username = shift;
-    my $user_exists_externally = 0;   
-
-    my @auth_services = @$RT::ExternalAuthPriority;
-
-    foreach my $service (@auth_services) {
-        my $config = $RT::ExternalSettings->{$service};
-
-        if ($config->{'type'} eq 'db') {    
-            $user_exists_externally = RT::Authen::ExternalAuth::DBI::UserExists($username,$service);
-            last if $user_exists_externally;
-        } elsif ($config->{'type'} eq 'ldap') {
-            $user_exists_externally = RT::Authen::ExternalAuth::LDAP::UserExists($username,$service);
-            last if $user_exists_externally;
-        } else {
-            $RT::Logger->error("Invalid type specification (",
-                               $config->{'type'},
-                               ") in config for service:",
-                               $service);
-        }
-    }
-    
-    return $user_exists_externally;
-}
-
 sub GetAuth {
+
+    # Request a username/password check from the specified service
+    # This is only valid for non-SSO services.
     
-    my ($username,$password) = @_;
+    my ($service,$username,$password) = @_;
     
-    # Get the prioritised list of external authentication services
-    my @auth_services = @$RT::ExternalAuthPriority;
+    my $success = 0;
     
-    # For each of those services..
-    foreach my $service (@auth_services) {
-
-        # Get the full configuration for that service as a hashref
-        my $config = $RT::ExternalSettings->{$service};
-        $RT::Logger->debug( "Attempting to use external auth service:",
-                            $service);
-        
-        # And then act accordingly depending on what type of service it is.
-        # Right now, there is only code for DBI and LDAP services
-        if ($config->{'type'} eq 'db') {    
-            my $success = RT::Authen::ExternalAuth::DBI::GetAuth($service,$username,$password);
-            return 1 if $success;
-            next;
-            
-        } elsif ($config->{'type'} eq 'ldap') {
-            my $success = RT::Authen::ExternalAuth::LDAP::GetAuth($service,$username,$password);
-            return 1 if $success;
-            next;
-                    
-        } else {
-            $RT::Logger->error("Invalid type specification in config for service:",
-                                $service,
-                                "- Skipping...");
-        }
+    # Get the full configuration for that service as a hashref
+    my $config = $RT::ExternalSettings->{$service};
+    
+    # And then act accordingly depending on what type of service it is.
+    # Right now, there is only code for DBI and LDAP non-SSO services
+    if ($config->{'type'} eq 'db') {    
+        $success = RT::Authen::ExternalAuth::DBI::GetAuth($service,$username,$password);
+    } elsif ($config->{'type'} eq 'ldap') {
+        $success = RT::Authen::ExternalAuth::LDAP::GetAuth($service,$username,$password);
+    } else {
+        $RT::Logger->error("Invalid service type for GetAuth:",$service);
     }
     
-    # No success by now = failure.
-    return 0; 
-
+    return $success; 
 }
 
 sub UserDisabled {
@@ -225,7 +346,10 @@
                 next;
             }
             $user_disabled = RT::Authen::ExternalAuth::LDAP::UserDisabled($username,$service);
-            
+                    
+        } elsif ($config->{'type'} eq 'cookie') {
+            RT::Logger->error("You cannot use SSO Cookies as an information service.");
+            next;
         } else {
             # The type of external service doesn't currently have any methods associated with it. Or it's a typo.
             RT::Logger->error("Invalid type specification for config %config->{'name'}");
@@ -270,6 +394,11 @@
         # Get the config for the service so that we know what attrs we can canonicalize
         my $config = $RT::ExternalSettings->{$service};
         
+        if($config->{'type'} eq 'cookie'){
+            $RT::Logger->debug("You cannot use SSO cookies as an information service!");
+            next;
+        }  
+        
         # For each attr we've been told to canonicalize in the match list
         foreach my $rt_attr (@{$config->{'attr_match_list'}}) {
             # Jump to the next attr in $args if this one isn't in the attr_match_list
@@ -349,9 +478,4 @@
    
 }
 
-sub CheckCookies {
-
-    return RT::Authen::ExternalAuth::DBI::CheckCookies();    
-
-}
 1;

Modified: RT-Authen-ExternalAuth/trunk/lib/RT/Authen/ExternalAuth/DBI/Cookie.pm
==============================================================================
--- RT-Authen-ExternalAuth/trunk/lib/RT/Authen/ExternalAuth/DBI/Cookie.pm	(original)
+++ RT-Authen-ExternalAuth/trunk/lib/RT/Authen/ExternalAuth/DBI/Cookie.pm	Sun Jan 18 09:36:42 2009
@@ -23,7 +23,6 @@
     }
 
     return $cookie_value;
-
 }
 
 # }}}

Modified: RT-Authen-ExternalAuth/trunk/lib/RT/User_Vendor.pm
==============================================================================
--- RT-Authen-ExternalAuth/trunk/lib/RT/User_Vendor.pm	(original)
+++ RT-Authen-ExternalAuth/trunk/lib/RT/User_Vendor.pm	Sun Jan 18 09:36:42 2009
@@ -2,73 +2,6 @@
 use strict;
 use RT::Authen::ExternalAuth;
 
-# {{{ sub IsPassword 
-
-sub IsPassword {
-    my $self  = shift;
-    my $value = shift;
-
-    # TODO there isn't any apparent way to legitimately ACL this
-
-    # RT does not allow null passwords 
-    if ( ( !defined($value) ) or ( $value eq '' ) ) {
-        return (undef);
-    }
-
-    if ( $self->PrincipalObj && $self->PrincipalObj->Disabled ) {
-        $RT::Logger->info("Disabled user " . $self->Name . 
-                          " tried to log in" );
-        return (undef);
-    }
-
-    $RT::Logger->debug("Trying External Authentication (",$self->Name,")");
-    if(RT::Authen::ExternalAuth::GetAuth($self->Name,$value)) {
-        $RT::Logger->debug( (caller(0))[3], 
-                            "EXTERNAL AUTH OKAY");
-        return(1);
-    } else {
-        $RT::Logger->debug( (caller(0))[3], 
-                            "EXTERNAL AUTH FAILED");
-    }
-    
-    unless ($self->HasPassword) {
-        $RT::Logger->info(  (caller(0))[3], 
-                            "INTERNAL AUTH FAILED (no passwd):", 
-                            $self->Name);
-        return(undef);
-    }
-
-    # generate an md5 password 
-    if ($self->_GeneratePassword($value) eq $self->__Value('Password')) {
-        $RT::Logger->info(  (caller(0))[3], 
-                            "INTERNAL AUTH OKAY:", 
-                            $self->Name);
-        return(1);
-    }
-
-    #  if it's a historical password we say ok.
-    if ($self->__Value('Password') eq crypt($value, $self->__Value('Password'))
-        or $self->_GeneratePasswordBase64($value) eq $self->__Value('Password'))
-      {
-          # ...but upgrade the legacy password inplace.
-          $self->SUPER::SetPassword( $self->_GeneratePassword($value) );
-          $RT::Logger->info((caller(0))[3], 
-                            "INTERNAL AUTH OKAY:", 
-                            $self->Name);
-          return(1);
-      }
-
-    $RT::Logger->info(  (caller(0))[3], 
-                        "INTERNAL AUTH FAILED:", 
-                        $self->Name);
-
-    # If we haven't succeeded by now, fail.
-    return (undef);
-}
-
-# }}}
-
-
 # {{{ sub CanonicalizeUserInfo
 
 =head2 CanonicalizeUserInfo HASHREF



More information about the Bps-public-commit mailing list