[Bps-public-commit] r17776 - in RT-Authen-ExternalAuth/trunk: html/Callbacks/ExternalAuth/autohandler lib/RT/Authen lib/RT/Authen/ExternalAuth
zordrak at bestpractical.com
zordrak at bestpractical.com
Fri Jan 16 07:18:57 EST 2009
Author: zordrak
Date: Fri Jan 16 07:18:56 2009
New Revision: 17776
Added:
RT-Authen-ExternalAuth/trunk/lib/RT/Authen/ExternalAuth/DBI/
RT-Authen-ExternalAuth/trunk/lib/RT/Authen/ExternalAuth/DBI/Cookie.pm
Modified:
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.pm
Log:
RT::Authen::ExternalAuth // 2009-01-16 Zordrak <zordrak at cpan.org> // CookieAuth pulled in as subpackage of DBI
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 Fri Jan 16 07:18:56 2009
@@ -4,7 +4,7 @@
<%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.
@@ -18,6 +18,120 @@
}
######################################################################################
+
+
+##########################################################
+##################### 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.
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 Fri Jan 16 07:18:56 2009
@@ -20,6 +20,7 @@
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
@@ -27,6 +28,7 @@
use RT::Authen::ExternalAuth::LDAP;
use RT::Authen::ExternalAuth::DBI;
+use RT::Authen::ExternalAuth::Cookie;
use Data::Dumper;
sub UpdateUserInfo {
@@ -346,4 +348,10 @@
return($found || $RT::AutoCreateNonExternalUsers);
}
+
+sub CheckCookies {
+
+ return RT::Authen::ExternalAuth::Cookie::CheckCookies();
+
+}
1;
Modified: RT-Authen-ExternalAuth/trunk/lib/RT/Authen/ExternalAuth/DBI.pm
==============================================================================
--- RT-Authen-ExternalAuth/trunk/lib/RT/Authen/ExternalAuth/DBI.pm (original)
+++ RT-Authen-ExternalAuth/trunk/lib/RT/Authen/ExternalAuth/DBI.pm Fri Jan 16 07:18:56 2009
@@ -312,7 +312,7 @@
sub _GetBoundDBIObj {
- # Config as hashref.
+ # Config as hashref. #### Or is this a hash?
my $config = shift;
# Extract the relevant information from the config.
Added: RT-Authen-ExternalAuth/trunk/lib/RT/Authen/ExternalAuth/DBI/Cookie.pm
==============================================================================
--- (empty file)
+++ RT-Authen-ExternalAuth/trunk/lib/RT/Authen/ExternalAuth/DBI/Cookie.pm Fri Jan 16 07:18:56 2009
@@ -0,0 +1,127 @@
+package RT::Authen::ExternalAuth::DBI::Cookie;
+
+use strict;
+use RT::Authen::ExternalAuth::DBI;
+use CGI::Cookie;
+
+# {{{ sub CheckCookies
+sub CheckCookies {
+
+# We are not a User object any more!
+# my $self = RT::User->new($RT::SystemUser);
+
+ $RT::Logger->debug( (caller(0))[3],
+ "Checking Browser Cookies for an Authenticated User");
+
+ my $confirmed_by_cookie = 0;
+ my $username; # $user changed to $username as not object but string
+
+ # Pull in all cookies from browser within our cookie domain
+ my %cookies = CGI::Cookie->fetch();
+
+ # Get our cookie and database info...
+ my $config = $RT::CookieSettings;
+
+ unless ($RT::UseExternalCookieAuthService){
+ $RT::Logger->debug( "External Cookie Auth is not enabled.",
+ "Please check your config for \$UseExternalCookieAuthService");
+ return (undef,0);
+ }
+
+ # The name of the cookie
+ my $cookie_name = $config->{'name'};
+
+ # If the cookie is set, get the value, if it's not set, get out now!
+ my $cookie_value;
+ if (defined $cookies{$cookie_name}) {
+ $cookie_value = $cookies{$cookie_name}->value;
+ $RT::Logger->debug( "Cookie Found!",
+ ":: $cookie_name ::",
+ "Attempting to use for authentication");
+ } else {
+ $RT::Logger->debug( "Cookie Auth Failed:",
+ "Cookie Not Assigned");
+ return ($user,$confirmed_by_cookie);
+ }
+
+ # The table mapping usernames to the Username Match Key
+ my $u_table = $config->{'u_table'};
+ # The username field in that table
+ my $u_field = $config->{'u_field'};
+ # The field that contains the Username Match Key
+ my $u_match_key = $config->{'u_match_key'};
+
+ # The table mapping cookie values to the Cookie Match Key
+ my $c_table = $config->{'c_table'};
+ # The cookie field in that table - The same as the cookie name if unspecified
+ my $c_field = $config->{'c_field'};
+ # The field that connects the Cookie Match Key
+ my $c_match_key = $config->{'c_match_key'};
+
+ # These are random characters to assign as table aliases in SQL
+ # It saves a lot of garbled code later on
+ my $u_table_alias = "u";
+ my $c_table_alias = "c";
+
+ # $tables will be passed straight into the SQL query
+ # I don't see this as a security issue as only the admin may modify the config file anyway
+ my $tables;
+
+ # If the tables are the same, then the aliases should be the same
+ # and the match key becomes irrelevant. Ensure this all works out
+ # fine by setting both sides the same. In either case, set an
+ # appropriate value for $tables.
+ if ($u_table eq $c_table) {
+ $u_table_alias = $c_table_alias;
+ $u_match_key = $c_match_key;
+ $tables = "$c_table $c_table_alias";
+ } else {
+ $tables = "$c_table $c_table_alias, $u_table $u_table_alias";
+ }
+
+ my $select_fields = "$u_table_alias.$u_field";
+ my $where_statement = "$c_table_alias.$c_field = ? AND $c_table_alias.$c_match_key = $u_table_alias.$u_match_key";
+
+ my $query = "SELECT $select_fields FROM $tables WHERE $where_statement";
+ my @params = ($cookie_value);
+ my $service = 'Auth';
+
+ # Use this if you need to debug the DBI SQL process
+ # DBI->trace(1,'/tmp/dbi.log');
+
+ my $dbh = RT::Authen::ExternalAuth::DBI::_GetBoundDBIObj($RT::ExternalSettings->{$config->{'db_service_name'}});
+ my $query_result_arrayref = $dbh->selectall_arrayref($query,{}, at params);
+ $dbh->disconnect();
+
+ # The log messages say it all here...
+ my $num_rows = scalar @$query_result_arrayref;
+ my $confirmed_user;
+ if ($num_rows < 1) {
+ $RT::Logger->info( "AUTH FAILED",
+ $cookie_name,
+ "Cookie value not found in database.",
+ "User passed an authentication token they were not given by us!",
+ "Is this nefarious activity?");
+ } elsif ($num_rows > 1) {
+ $RT::Logger->error( "AUTH FAILED",
+ $cookie_name,
+ "Cookie's value is duplicated in the database! This should not happen!!");
+ } else {
+ $user = $query_result_arrayref->[0][0];
+ $confirmed_by_cookie = 1;
+ }
+
+ if ($confirmed_by_cookie == 1) {
+ $RT::Logger->debug( "User (",
+ $user,
+ ") was authenticated by a browser cookie");
+ } else {
+ $RT::Logger->debug( "No user was authenticated by browser cookie");
+ }
+
+ return ($user,$confirmed_by_cookie);
+}
+
+# }}}
+
+1;
More information about the Bps-public-commit
mailing list