package WebGUI::Auth; =head1 LEGAL ------------------------------------------------------------------- WebGUI is Copyright 2001-2009 Plain Black Corporation. ------------------------------------------------------------------- Please read the legal notices (docs/legal.txt) and the license (docs/license.txt) that came with this distribution before using this software. ------------------------------------------------------------------- http://www.plainblack.com info@plainblack.com ------------------------------------------------------------------- =cut use CGI::Util qw(rearrange); use DBI; use strict qw(subs vars); use Tie::IxHash; use WebGUI::HTML; use WebGUI::HTMLForm; use WebGUI::International; use WebGUI::Macro; use WebGUI::TabForm; use WebGUI::Asset::Template; use WebGUI::Utility; use WebGUI::User; use WebGUI::Operation::Shared; use WebGUI::Operation::Profile; use WebGUI::Workflow::Instance; use WebGUI::Shop::AddressBook; use WebGUI::Inbox; use WebGUI::Friends; use URI; # Profile field name for the number of times the showMessageOnLogin has been # seen. my $LOGIN_MESSAGE_SEEN = 'showMessageOnLoginSeen'; =head1 NAME Package WebGUI::Auth =head1 DESCRIPTION An abstract class for all authentication modules to extend. =head1 SYNOPSIS use WebGUI::Auth; our @ISA = qw(WebGUI::Auth); =head1 METHODS These methods are available from this class: =cut #------------------------------------------------------------------- sub _isDuplicateUsername { my $self = shift; my $username = shift; #Return false if the user is already logged in, but not changing their username. return 0 if($self->isRegistered && $self->session->user->username eq $username); my ($otherUser) = $self->session->db->quickArray("select count(*) from users where username=".$self->session->db->quote($username)); return 0 if !$otherUser; my $i18n = WebGUI::International->new($self->session); $self->error('
  • '.sprintf($i18n->get(77), $username,$username,$username,$self->session->datetime->epochToHuman(time(),"%y")).'
  • '); return 1; } #------------------------------------------------------------------- =head2 _isValidUsername ( username ) Validates the username passed in. =cut sub _isValidUsername { my $self = shift; my $username = shift; my $error = ""; return 1 if($self->isRegistered && $self->session->user->username eq $username); my $i18n = WebGUI::International->new($self->session); my $filteredUsername = WebGUI::HTML::filter($username, 'all'); if ($username ne $filteredUsername) { $error .= '
  • ' . $i18n->get('username no html') . '
  • '; } if ($username =~ /^\s/ || $username =~ /\s$/) { $error .= '
  • '.$i18n->get(724).'
  • '; } if ($username eq "") { $error .= '
  • '.$i18n->get(725).'
  • '; } $self->error($error); return $error eq ""; } #------------------------------------------------------------------- sub _logLogin { my $self = shift; $self->timeRecordSession; $self->session->db->write("insert into userLoginLog values (?,?,?,?,?,?,?)", [ $_[0], $_[1], time(), $self->session->env->getIp, $self->session->env->get("HTTP_USER_AGENT"), $self->session->getId, time(), ] ); } #------------------------------------------------------------------- =head2 authenticate ( ) Superclass method that performs standard login routines. This method returns true if login success, otherwise returns false. =cut sub authenticate { my $self = shift; my $username = shift; my $i18n = WebGUI::International->new($self->session); my $user = $self->session->db->quickHashRef("select userId,authMethod,status from users where username=".$self->session->db->quote($username)); my $uid = $user->{userId}; #If userId does not exist or is not active, fail login if (!$uid) { $self->authenticationError; return 0; } elsif($user->{status} ne 'Active') { $self->error($i18n->get(820)); $self->_logLogin($uid, "failure"); return 0; } #Set User Id $self->user(WebGUI::User->new($self->session,$uid)); return 1; } #------------------------------------------------------------------- =head2 authenticationError This subroutine is called by authenticate and its subclasses to make sure these subroutines return the same errormessage on login failure. Different errormessages would reveil if a username exists after which only the password has to be guessed by brute force for example. =cut sub authenticationError { my $self = shift; my $i18n = WebGUI::International->new($self->session); return ($self->error('
  • '.$i18n->get(68).'
  • ')); } #------------------------------------------------------------------- =head2 authMethod ( [authMethod] ) Gets or sets the authMethod in the Auth Object. Returns 'WebGUI' as the default method if a user has been created without an authMethod. =head3 authMethod A string which sets the auth method for an instance of this class =cut sub authMethod { my $self = shift; if (!$_[0]) { return $self->{authMethod} || 'WebGUI'; } $self->{authMethod} = $_[0]; } #------------------------------------------------------------------- =head2 createAccount ( method [,vars] ) Superclass method that performs general functionality for creating new accounts. =head3 method Auth method that the form for creating users should call =head3 vars Array ref of template vars from subclass =cut sub createAccount { my $self = shift; my $method = shift; my $vars = shift; my $i18n = WebGUI::International->new($self->session); $vars->{title} = $i18n->get(54); $vars->{'create.form.header'} = WebGUI::Form::formHeader($self->session) . WebGUI::Form::hidden($self->session,{"name"=>"op","value"=>"auth"}) . WebGUI::Form::hidden($self->session,{"name"=>"method","value"=>$method}) ; # User Defined Options my $userInvitation = $self->session->setting->get('inboxInviteUserEnabled'); $vars->{'create.form.profile'} = []; foreach my $field (@{WebGUI::ProfileField->getRegistrationFields($self->session)}) { my $id = $field->getId; my $label = $field->getLabel; my $required = $field->isRequired; my $properties = {}; if ($required) { my $fieldValue = $self->session->form->process($field->getId,$field->get("fieldType")); $properties->{extras} = $self->getExtrasStyle($fieldValue); } my $formField; # Get the default email from the invitation if ($field->get('fieldName') eq "email" && $userInvitation ) { my $code = $self->session->form->get('code') || $self->session->form->get('uniqueUserInvitationCode'); my $defaultValue = $self->session->db->quickScalar( 'SELECT email FROM userInvitations WHERE inviteId=?', [$code] ); $vars->{'create.form.header'} .= WebGUI::Form::hidden($self->session, {name=>"uniqueUserInvitationCode", value=>$code}); $formField = $field->formField($properties, undef, undef, undef, $defaultValue); } else { $formField = $field->formField($properties); } # Old-style field loop. push @{$vars->{'create.form.profile'}}, { 'profile.formElement' => $formField, 'profile.formElement.label' => $label, 'profile.required' => $required, }; # Individual field template vars. my $prefix = 'create.form.profile.'.$id.'.'; $vars->{ $prefix . 'formElement' } = $formField; $vars->{ $prefix . 'formElement.label' } = $label; $vars->{ $prefix . 'required' } = $required; } $vars->{'create.form.submit'} = WebGUI::Form::submit($self->session,{}); $vars->{'create.form.footer'} = WebGUI::Form::formFooter($self->session,); $vars->{'login.url'} = $self->session->url->page('op=auth;method=init'); $vars->{'login.label'} = $i18n->get(58); return WebGUI::Asset::Template->new($self->session,$self->getCreateAccountTemplateId)->process($vars); } #------------------------------------------------------------------- =head2 createAccountSave ( username,properties [,password,profile] ) Superclass method that performs general functionality for saving new accounts. Based on various settings and user actions, it may return output that should be displayed to the user. =head3 username Username for the account being created =head3 properties Properties from the subclass that should be saved as authentication parameters =head3 password Password entered by the user. This is only used in for sending the user a notification by email of his/her username/password =head3 profile Hashref of profile values returned by the function WebGUI::User::validateProfileDataFromForm($fields); =cut sub createAccountSave { my $self = shift; my $username = $_[0]; my $properties = $_[1]; my $password = $_[2]; my $profile = $_[3]; my $i18n = WebGUI::International->new($self->session); my $u = WebGUI::User->new($self->session,"new"); $self->user($u); my $userId = $u->userId; $u->username($username); $u->authMethod($self->authMethod); if (!$profile->{'language'} && $self->session->scratch->getLanguageOverride) { $profile->{'language'} = $self->session->scratch->getLanguageOverride; } $u->karma($self->session->setting->get("karmaPerLogin"),"Login","Just for logging in.") if ($self->session->setting->get("useKarma")); $u->updateProfileFields($profile) if ($profile); #Update the shop address my $address = {}; my $address_mappings = WebGUI::Shop::AddressBook->getProfileAddressMappings; foreach my $fieldId (keys %$profile) { #set the shop address fields my $address_key = $address_mappings->{$fieldId}; $address->{$address_key} = $profile->{$fieldId} if ($address_key); } #Update or create and update the shop address if ( keys %$address ) { $address->{'isProfile' } = 1; #Get home address only mappings to avoid creating addresses with just firstName, lastName, email my %home_address_map = %{$address_mappings}; foreach my $exclude ( qw{ firstName lastName email } ) { delete $home_address_map{$exclude}; } #Add the profile address for the user if there are homeAddress fields if( grep { $address->{$_} } values %home_address_map ) { #Create the address book for the user my $addressBook = WebGUI::Shop::AddressBook->newByUserId($self->session,$userId); $address->{label} = "Profile Address"; my $new_address = $addressBook->addAddress($address); #Set this as the default address if one doesn't already exist $addressBook->update( { defaultAddressId => $new_address->getId } ); } } $self->saveParams($userId,$self->authMethod,$properties); if ($self->getSetting("sendWelcomeMessage")){ my $var; $var->{welcomeMessage} = $self->getSetting("welcomeMessage"); $var->{newUser_username} = $username; $var->{newUser_password} = $password; my $message = WebGUI::Asset::Template->new($self->session,$self->getSetting('welcomeMessageTemplate'))->process($var); WebGUI::Macro::process($self->session,\$message); WebGUI::Inbox->new($self->session)->addMessage({ message => $message, subject => $i18n->get(870), userId => $self->userId, status => 'completed', }); } $self->session->user({user=>$u}); $self->_logLogin($userId,"success"); if ($self->session->setting->get("runOnRegistration")) { WebGUI::Workflow::Instance->create($self->session, { workflowId=>$self->session->setting->get("runOnRegistration"), methodName=>"new", className=>"WebGUI::User", parameters=>$self->session->user->userId, priority=>1 })->start; } ##Finalize the record in the user invitation table. my $inviteId = $self->session->form->get('uniqueUserInvitationCode'); if ($inviteId) { $self->session->db->setRow('userInvitations','inviteId',{ inviteId => $inviteId, newUserId => $u->userId, dateCreated => WebGUI::DateTime->new($self->session, time)->toMysqlDate, }); #Get the invite record my $inviteRecord = $self->session->db->getRow('userInvitations','inviteId',$inviteId); #Get the user my $inviteUser = WebGUI::User->new($self->session,$inviteRecord->{userId}); #Automatically add the friend that invited the user and vice versa if the friend has friends enabled if($inviteUser->acceptsFriendsRequests($u)) { my $friends = WebGUI::Friends->new($self->session,$u); $friends->add([$inviteUser->userId]); } } # If we have something to do after login, do it if ( $self->session->setting->get( 'showMessageOnLogin' ) ) { return $self->showMessageOnLogin; } elsif ($self->session->form->get('returnUrl')) { $self->session->http->setRedirect( $self->session->form->get('returnUrl') ); $self->session->scratch->delete("redirectAfterLogin"); } elsif ($self->session->scratch->get("redirectAfterLogin")) { my $url = $self->session->scratch->delete("redirectAfterLogin"); $self->session->http->setRedirect($url); return undef; } else { $self->session->http->setStatus(201,"Account Registration Successful"); } return undef; } #------------------------------------------------------------------- =head2 deactivateAccount ( method ) Superclass method that displays a confirm message for deactivating a user's account. =head3 method Auth method that the form for creating users should call =cut sub deactivateAccount { my $self = shift; my $method = $_[0]; return $self->session->privilege->vitalComponent() if($self->isVisitor || $self->isAdmin); return $self->session->privilege->adminOnly() if(!$self->session->setting->get("selfDeactivation")); my $i18n = WebGUI::International->new($self->session); my %var; $var{title} = $i18n->get(42); $var{question} = $i18n->get(60); $var{'yes.url'} = $self->session->url->page('op=auth;method='.$method); $var{'yes.label'} = $i18n->get(44); $var{'no.url'} = $self->session->url->page(); $var{'no.label'} = $i18n->get(45); return WebGUI::Asset::Template->new($self->session,$self->getDeactivateAccountTemplateId)->process(\%var); } #------------------------------------------------------------------- =head2 deactivateAccountConfirm ( ) Superclass method that performs general functionality for deactivating accounts. =cut sub deactivateAccountConfirm { my $self = shift; # Cannot deactivate "Visitor" or "Admin" users this way return $self->session->privilege->vitalComponent if $self->isVisitor || $self->isAdmin; my $i18n = WebGUI::International->new($self->session); # Change user's status my $user = $self->user; $user->status("Selfdestructed"); # TODO: Fix displayLogin in all subclasses to have the same prototype. THIS WILL BREAK API! # Show the login form #$self->logout; #return $self->displayLogin(undef, { #'login.message' => sprintf( $i18n->get("deactivateAccount success"), $user->username ) #}); $self->logout; return undef; } #------------------------------------------------------------------- =head2 deleteParams ( ) Removes the user's authentication parameters from the database for all authentication methods. This is primarily useful when deleting the user's account. =cut sub deleteParams { my $self = shift; $self->session->db->write("delete from authentication where userId=".$self->session->db->quote($self->userId)); } #------------------------------------------------------------------- =head2 deleteSingleParam ( ) Removes a single authentication parameter from the database. =cut sub deleteSingleParam { my $self = shift; my ($userId, $authMethod, $fieldName) = @_; $self->session->db->write('delete from authentication where userId = ? and authMethod = ? and fieldName = ?', [$userId, $authMethod, $fieldName]); } #------------------------------------------------------------------- =head2 displayAccount ( method [,vars] ) Superclass method that performs general functionality for viewing editable fields related to a user's account. =head3 method Auth method that the form for updating a user's account should call =head3 vars Array ref of template vars from subclass =cut sub displayAccount { my $self = shift; my $method = shift; my $vars = shift; my $i18n = WebGUI::International->new($self->session); $vars->{title} = $i18n->get(61); $vars->{'account.form.header'} = WebGUI::Form::formHeader($self->session,{}); $vars->{'account.form.header'} .= WebGUI::Form::hidden($self->session,{"name"=>"op","value"=>"auth"}); $vars->{'account.form.header'} .= WebGUI::Form::hidden($self->session,{"name"=>"method","value"=>$method}); if ($self->session->setting->get("useKarma")) { $vars->{'account.form.karma'} = $self->session->user->karma; $vars->{'account.form.karma.label'} = $i18n->get(537); } $vars->{'account.form.submit'} = WebGUI::Form::submit($self->session,{}); $vars->{'account.form.footer'} = WebGUI::Form::formFooter($self->session,); ########### ACCOUNT SHUNT #The following is a shunt which allows the displayAccount page to be displayed in the #Account system. This shunt will be replaced in WebGUI 8 when the API can be broken my $output = WebGUI::Asset::Template->new($self->session,$self->getAccountTemplateId)->process($vars); #If the account system is calling this method, just return the template my $op = $self->session->form->get("op"); if($op eq "account") { return $output; } #Otherwise wrap the template into the account layout my $instance = WebGUI::Content::Account->createInstance($self->session,"user"); return $instance->displayContent($output,1); } #------------------------------------------------------------------- =head2 displayLogin ( [method,vars] ) Superclass method that performs general functionality for creating new accounts. =head3 method Auth method that the form for performing the login routine should call =head3 vars Array ref of template vars from subclass =cut sub displayLogin { my $self = shift; my $method = $_[0] || "login"; my $vars = $_[1]; # Automatically set redirectAfterLogin unless we've linked here directly # or it's already been set to perform another operation unless ( $self->session->form->process("op") eq "auth" || ($self->session->scratch->get("redirectAfterLogin") =~ /op=\w+/) ) { my $returnUrl = $self->session->form->get('returnUrl') || $self->session->url->page( $self->session->env->get('QUERY_STRING') ) ; $self->session->scratch->set("redirectAfterLogin", $returnUrl); } my $i18n = WebGUI::International->new($self->session); $vars->{title} = $i18n->get(66); my $action; if ($self->session->config->get('sslEnabled') && $self->session->setting->get("encryptLogin")) { my $uri = URI->new($self->session->url->page(undef,1)); $uri->scheme('https'); $uri->host_port($uri->host); $action = $uri->as_string; } $vars->{'login.form.header'} = WebGUI::Form::formHeader($self->session,{action=>$action}); $vars->{'login.form.hidden'} = WebGUI::Form::hidden($self->session,{"name"=>"op","value"=>"auth"}); $vars->{'login.form.hidden'} .= WebGUI::Form::hidden($self->session,{"name"=>"method","value"=>$method}); $vars->{'login.form.username'} = WebGUI::Form::text($self->session,{"name"=>"username"}); $vars->{'login.form.username.label'} = $i18n->get(50); $vars->{'login.form.password'} = WebGUI::Form::password($self->session,{"name"=>"identifier"}); $vars->{'login.form.password.label'} = $i18n->get(51); $vars->{'login.form.submit'} = WebGUI::Form::submit($self->session,{"value"=>$i18n->get(52)}); $vars->{'login.form.footer'} = WebGUI::Form::formFooter($self->session,); $vars->{'anonymousRegistration.isAllowed'} = ($self->session->setting->get("anonymousRegistration")); $vars->{'createAccount.url'} = $self->session->url->page('op=auth;method=createAccount'); $vars->{'createAccount.label'} = $i18n->get(67); my $template = $self->getLoginTemplate; return $template->process($vars); } #------------------------------------------------------------------- =head2 editUserForm ( ) Creates user form elements specific to this Auth Method. =cut sub editUserForm { #Added for interface purposes only. Needs to be implemented in the subclass. } #------------------------------------------------------------------- =head2 editUserFormSave ( properties ) Saves user elements unique to this authentication method =cut sub editUserFormSave { my $self = shift; $self->saveParams($self->userId,$self->authMethod,$_[0]); } #------------------------------------------------------------------- =head2 editUserSettingsForm ( ) You need to override this method in your auth module. It needs to return a the rows in a form for the stuff you want to be configured through webgui settings. =cut sub editUserSettingsForm { } #------------------------------------------------------------------- =head2 editUserSettingsFormSave ( ) You need to override this method in your auth module. It's the save for the editUserSettingsFormSave method. =cut sub editUserSettingsFormSave { } #------------------------------------------------------------------- =head2 error ( [errorMsg] ) Sets or returns the error currently stored in the object =cut sub error { my $self = shift; return $self->{error} if (!$_[0]); $self->{error} = $_[0]; } #------------------------------------------------------------------- =head2 getAccountTemplateId ( ) This method should be overridden by the subclass and should return the template ID for the display/edit account screen. =cut sub getAccountTemplateId { return "PBtmpl0000000000000010"; } #------------------------------------------------------------------- =head2 getCreateAccountTemplateId ( ) This method should be overridden by the subclass and should return the template ID for the create account screen. =cut sub getCreateAccountTemplateId { return "PBtmpl0000000000000011"; } #------------------------------------------------------------------- =head2 getDeactivateAccountTemplateId ( ) This method should be overridden by the subclass and should return the template ID for the deactivate account screen. =cut sub getDeactivateAccountTemplateId { return "PBtmpl0000000000000057"; } #------------------------------------------------------------------- =head2 getDefaultLoginTemplateId ( ) This method should be overridden by the subclass and should return the default template ID for the login screen. =cut sub getDefaultLoginTemplateId { return "PBtmpl0000000000000013"; } #------------------------------------------------------------------- =head2 getExtrasStyle ( ) This method returns the proper field to display for required fields. =cut sub getExtrasStyle { my $self = shift; my $value = shift; my $requiredStyleOff = q{class="authfield_required_off"}; my $requiredStyle = q{class="authfield_required"}; my $errorStyle = q{class="authfield_error"}; #Required Field Not Filled In and Error Returend return $errorStyle if($self->error && $value eq ""); return $requiredStyle unless($value); return $requiredStyleOff; } #------------------------------------------------------------------- =head2 getLoginTemplate ( ) Returns a WebGUI::Asset::Template object for the login template. If the configured template cannot be used, then it returns a default template object. =cut sub getLoginTemplate { my $self = shift; my $session = $self->session; my $templateId = $self->getLoginTemplateId; my $template = WebGUI::Asset::Template->newByDynamicClass($session, $templateId); if (!$template) { $templateId = $self->getDefaultLoginTemplateId; $template = WebGUI::Asset::Template->newByDynamicClass($session, $templateId); } return $template; } #------------------------------------------------------------------- =head2 getLoginTemplateId ( ) This method should be overridden by the subclass and should return the template ID for the login screen. =cut sub getLoginTemplateId { return "PBtmpl0000000000000013"; } #------------------------------------------------------------------- =head2 getParams ( ) Returns a hash reference with the user's authentication information. This method uses data stored in the instance of the object. =cut sub getParams { my $self = shift; my $userId = $_[0] || $self->userId; my $authMethod = $_[1] || $self->authMethod; return $self->session->db->buildHashRef("select fieldName, fieldData from authentication where userId=".$self->session->db->quote($userId)." and authMethod=".$self->session->db->quote($authMethod)); } #------------------------------------------------------------------- =head2 getSetting ( setting ) Returns a setting for this authMethod instance. If none is specified, returns the system authMethod setting =head3 setting Specify a setting to retrieve =cut sub getSetting { my $self = shift; my $setting = $_[0]; $setting = lc($self->authMethod).ucfirst($setting); return $self->session->setting->get($setting); } #------------------------------------------------------------------- =head2 init ( ) Initialization function for these auth routines. Default is a superclass function called displayLogin. Override this method in your subclass to change the initialization for custom authentication methods =cut sub init { my $self = shift; return $self->displayLogin; } #------------------------------------------------------------------- =head2 isAdmin () Returns 1 if the user is user 3 (admin). =cut sub isAdmin { my $self = shift; return $self->userId eq '3'; } #------------------------------------------------------------------- =head2 isCallable ( method ) Returns whether or not a method is callable =cut sub isCallable { my $self = shift; return 1 if isIn($_[0],@{$self->{callable}}); return 1 if $self->can( 'www_' . $_[0] ); return 0; } #------------------------------------------------------------------- =head2 isRegistered () Returns 1 if the user is not a visitor. =cut sub isRegistered { my $self = shift; return $self->userId ne '1'; } #------------------------------------------------------------------- =head2 isVisitor () Returns 1 if the user is a visitor. =cut sub isVisitor { my $self = shift; return $self->userId eq '1'; } #------------------------------------------------------------------- =head2 login ( ) Superclass method that performs standard login routines. This is what should happen after a user has been authenticated. Authentication should always happen in the subclass routine. Open version tag is reclaimed if user is in site wide or singlePerUser mode. =cut sub login { my $self = shift; #Create a new user my $uid = $self->userId; my $u = WebGUI::User->new($self->session,$uid); $self->session->user({user=>$u}); $u->karma($self->session->setting->get("karmaPerLogin"),"Login","Just for logging in.") if ($self->session->setting->get("useKarma")); $self->_logLogin($uid,"success"); # Run on login my $command = $self->session->config->get("runOnLogin"); if ($command ne "") { WebGUI::Macro::process($self->session,\$command); my $error = qx($command); $self->session->errorHandler->warn($error) if $error; } # Set the proper redirect if ( $self->session->setting->get( 'showMessageOnLogin' ) && $self->user->profileField( $LOGIN_MESSAGE_SEEN ) < $self->session->setting->get( 'showMessageOnLoginTimes' ) ) { return $self->showMessageOnLogin; } elsif ( $self->session->form->get('returnUrl') ) { $self->session->http->setRedirect( $self->session->form->get('returnUrl') ); $self->session->scratch->delete("redirectAfterLogin"); } elsif ( my $url = $self->session->scratch->delete("redirectAfterLogin") ) { $self->session->http->setRedirect($url); } elsif ( $self->session->setting->get("redirectAfterLoginUrl") ) { $self->session->http->setRedirect($self->session->setting->get("redirectAfterLoginUrl")); $self->session->scratch->delete("redirectAfterLogin"); } elsif ($self->session->config->get('sslEnabled') && $self->session->setting->get('encryptLogin')) { my $currentUrl = URI->new($self->session->url->page(undef,1)); $currentUrl->scheme('http'); $currentUrl->port($self->session->config->get('webServerPort') || 80); $self->session->http->setRedirect($currentUrl->canonical->as_string); } # Get open version tag. This is needed if we want # to reclaim a version right after login (singlePerUser and siteWide mode) # and to have the correct version displayed. WebGUI::VersionTag->getWorking($self->session(), q{noCreate}); return undef; } #------------------------------------------------------------------- =head2 logout ( ) Superclass method that performs standard logout routines. =cut sub logout { my $self = shift; $self->session->var->end($self->session->var->get("sessionId")); $self->session->user({userId=>'1'}); my $u = WebGUI::User->new($self->session,1); $self->{user} = $u; my $command = $self->session->config->get("runOnLogout"); if ($command ne "") { WebGUI::Macro::process($self->session,\$command); my $error = qx($command); $self->session->errorHandler->warn($error) if $error; } # Do not allow caching of the logout page (to ensure the page gets requested) $self->session->http->setCacheControl( "none" ); return undef; } #------------------------------------------------------------------- =head2 new ( session, authMethod [,userId,callable] ) Constructor. =head3 session =head3 authMethod This object's authentication method =head3 userId userId for the user requesting authentication. This defaults to $self->session->user->userId =head3 callable Array reference of methods allowed to be called externally; =cut sub new { my $self = {}; my $class = shift; $self->{_session} = shift; $self->{authMethod} = shift; my $userId = shift || $self->{_session}->user->userId; # Can't do this... if you're updating the account of a user that's not you, this will not work #$self->{user} = $self->{_session}->user; $self->{user} = WebGUI::User->new($self->{_session}, $userId); $self->{error} = ""; $self->{profile} = (); $self->{warning} = ""; my $call = shift; my @callable = ('init', 'showMessageOnLogin', @{$call}); $self->{callable} = \@callable; bless $self, $class; return $self; } #------------------------------------------------------------------- =head2 profile ( ) Sets or returns the Profile hash for a user. =cut sub profile { my $self = shift; return $self->{profile} if (!$_[0]); $self->{profile} = $_[0]; } #------------------------------------------------------------------- sub session { my $self = shift; return $self->{_session}; } #------------------------------------------------------------------- =head2 setCallable ( callableMethods ) adds elements to the callable routines list. This list determines whether or not a method in this instance is allowed to be called externally =head3 callableMethods Array reference containing a list of methods for this authentication instance that can be called externally =cut sub setCallable { my $self = shift; my @callable = @{$self->{callable}}; @callable = (@callable,@{$_[0]}); $self->{callable} = \@callable; } #------------------------------------------------------------------- =head2 saveParams ( userId, authMethod, data ) Saves the user's authentication parameters to the database. =head3 userId Specify a user id. =head3 authMethod Specify the authentication method to save these paramaters under. =head3 data A hash reference containing parameter names and values to be saved. =cut sub saveParams { my $self = shift; my ($uid, $authMethod, $data) = @_; foreach (keys %{$data}) { $self->session->db->write("delete from authentication where userId=".$self->session->db->quote($uid)." and authMethod=".$self->session->db->quote($authMethod)." and fieldName=".$self->session->db->quote($_)); $self->session->db->write("insert into authentication (userId,authMethod,fieldData,fieldName) values (".$self->session->db->quote($uid).",".$self->session->db->quote($authMethod).",".$self->session->db->quote($data->{$_}).",".$self->session->db->quote($_).")"); } } #---------------------------------------------------------------------------- =head2 showMessageOnLogin ( ) Show the requested message after the user logs in. Add another tally to the number of times the message has been displayed. Show a link to the next stage for the user. =cut sub showMessageOnLogin { my $self = shift; my $i18n = WebGUI::International->new( $self->session, 'Auth' ); # Increment the number of time seen. $self->user->profileField( $LOGIN_MESSAGE_SEEN, $self->user->profileField( $LOGIN_MESSAGE_SEEN ) + 1 ); # Show the message, processing for macros my $output = $self->session->setting->get( 'showMessageOnLoginBody' ); WebGUI::Macro::process( $self->session, \$output ); # Add the link to continue my $session = $self->session; my $redirectUrl = $session->form->get( 'returnUrl' ) || $session->setting->get("redirectAfterLoginUrl") || $session->scratch->get( 'redirectAfterLogin' ) || $session->url->getBackToSiteURL ; if ($self->session->config->get('sslEnabled') && $session->setting->get('encryptLogin') && ( ! $redirectUrl =~ /^http/)) { ##A scheme-less URL has been supplied. We need to make it an absolute one ##with a non-encrypted scheme. Otherwise the user will stay in SSL mode. ##We assume that the user put the gateway URL into their URL. my $uri = URI->new_abs($redirectUrl, $session->url->getSiteURL); $uri->scheme('http'); $redirectUrl = $uri->as_string; } $output .= '

    ' . $i18n->get( 'showMessageOnLogin return' ) . '

    ' ; # No matter what, we won't be redirecting after this $session->scratch->delete( 'redirectAfterLogin' ); return $output; } #---------------------------------------------------------------------------- =head2 timeRecordSession Record the last page viewed and the time viewed for the user =cut sub timeRecordSession { my $self = shift; my ($nonTimeRecordedRows) = $self->session->db->quickArray("select count(*) from userLoginLog where lastPageViewed = timeStamp and sessionId = ? ", [$self->session->getId] ); if ($nonTimeRecordedRows eq "1") { # We would normally expect to only find one entry $self->session->db->write("update userLoginLog set lastPageViewed = (select lastPageView from userSession where sessionId = ?) where lastPageViewed = timeStamp and sessionId = ? ", [ $self->session->getId, $self->session->getId]); } elsif ($nonTimeRecordedRows eq "0") { # Do nothing } else { # If something strange happened and we ended up with > 1 matching rows, cut our losses and remove offending userLoginLog rows (otherwise we # could end up with ridiculously long user recorded times) $self->session->errorHandler->warn("More than 1 old userLoginLog rows found, removing offending rows"); $self->session->db->write("delete from userLoginLog where lastPageViewed = timeStamp and sessionId = ? ", [$self->session->getId] ); } } #------------------------------------------------------------------- =head2 user ( [user] ) Sets or Returns the user object stored in the wobject =cut sub user { my $self = shift; return $self->{user} if (!$_[0]); $self->{user} = $_[0]; } #------------------------------------------------------------------- =head2 userId ( ) Returns the userId currently stored in the object =cut sub userId { my $self = shift; my $u = $self->user; return $u->userId; } #------------------------------------------------------------------- =head2 username ( ) Returns the username currently stored in the object =cut sub username { my $self = shift; my $u = $self->user; return $u->username; } #------------------------------------------------------------------- =head2 validUsername ( username ) Validates the a username. =cut sub validUsername { my $self = shift; my $username = shift; my $error = ""; if ($self->_isDuplicateUsername($username)) { $error .= $self->error; } if (!$self->_isValidUsername($username)) { $error .= $self->error; } $self->error($error); return $error eq ""; } #------------------------------------------------------------------- =head2 warning ( [warningMsg] ) Sets or Returns a warning in the object =cut sub warning { my $self = shift; return $self->{warning} if (!$_[0]); $self->{warning} = $_[0]; } 1;