Initial version of AppUser base class added.
This commit is contained in:
parent
7c0661ddae
commit
9a762ea119
306
AppUser.pm
Normal file
306
AppUser.pm
Normal file
@ -0,0 +1,306 @@
|
||||
## @file
|
||||
# This file contains the implementation of the base class for application-specific
|
||||
# user operations.
|
||||
#
|
||||
# @author Chris Page <chris@starforge.co.uk>
|
||||
# @version 1.0
|
||||
# @date 5 March 2012
|
||||
# @copy 2012, Chris Page <chris@starforge.co.uk>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
## @class
|
||||
# The base class for application-specific user actions that must be performed
|
||||
# during authentication. This provides the functions, potentially minimally
|
||||
# implemented, that the Auth class relies on to interact with user records
|
||||
# in the wider system in which it is being used. Subclasses of AppUser may
|
||||
# provide more complex facilities to support application-specific requirements.
|
||||
#
|
||||
# This class assumes that the user data is stored in a table whose name is
|
||||
# set in the 'users' variable in the 'database' section of the settings, and
|
||||
# that the following fields are present in the table:
|
||||
#
|
||||
# * user_id - unsigned int, unique to each user
|
||||
# * user_type - unsigned tinyint, 0 = normal, 1 = disabled, 3 = admin usually
|
||||
# * user_auth - unsigned tinyint, the id of the user's auth method, must allow null
|
||||
# * username - varchar or text, contains the user's username, must be unique per user
|
||||
# * created - unsigned int, stores the user's creation unix timestamp
|
||||
# * last_login - unsigned int, stores the user's last login unix timestamp
|
||||
#
|
||||
# In general, most subclasses of this class will only really be concerned with
|
||||
# overriding the post_authenticate() function - the other functions will usually
|
||||
# be sufficient for most purposes, and system-specific work will usually happen
|
||||
# in post_authenticate(). However, subclasses may wish to call the function in
|
||||
# this class via $self -> SUPER::post_authenticate() to extend the default
|
||||
# behaviour with system-specifics rather than entirely replacing it.
|
||||
package AppUser;
|
||||
|
||||
use strict;
|
||||
|
||||
use constant ANONYMOUS_ID => 1; # Default anonymous user id.
|
||||
use constant ADMIN_TYPE => 3; # User type for admin users.
|
||||
|
||||
our $errstr;
|
||||
|
||||
BEGIN {
|
||||
$errstr = '';
|
||||
}
|
||||
|
||||
# ============================================================================
|
||||
# Constructor
|
||||
|
||||
## @cmethod AppUser new(%args)
|
||||
# Create a new AppUser object. This will create an AppUser object that may be
|
||||
# passed to the Auth class to provide application-specific user handling. The
|
||||
# following arguments must be provided:
|
||||
#
|
||||
# - cgi, a reference to a CGI object.
|
||||
# - dbh, a reference to the DBI object to issue database queries through.
|
||||
# - settings, a reference to the global settings object.
|
||||
# @param args A hash of arguments to initialise the UserApp object with.
|
||||
# @return A new AuthMethod object.
|
||||
sub new {
|
||||
my $invocant = shift;
|
||||
my $class = ref($invocant) || $invocant;
|
||||
my $self = {
|
||||
@_,
|
||||
};
|
||||
|
||||
# Ensure that we have objects that we need
|
||||
return set_error("cgi object not set") unless($self -> {"cgi"});
|
||||
return set_error("dbh object not set") unless($self -> {"dbh"});
|
||||
return set_error("settings object not set") unless($self -> {"settings"});
|
||||
|
||||
return bless $self, $class;
|
||||
}
|
||||
|
||||
|
||||
# ============================================================================
|
||||
# Constants access
|
||||
|
||||
## @method $ anonymous_user()
|
||||
# Obtain the ID of the anonymous user in the system.
|
||||
#
|
||||
# @return The ID of the anonymous user account.
|
||||
sub anonymous_user {
|
||||
return ANONYMOUS_USER;
|
||||
}
|
||||
|
||||
|
||||
## @method $ adminuser_type()
|
||||
# Obtain the user type that corresponds to admin users.
|
||||
#
|
||||
# @return The admin user type number.
|
||||
sub adminuser_type {
|
||||
return ADMIN_TYPE;
|
||||
}
|
||||
|
||||
|
||||
# ============================================================================
|
||||
# User access
|
||||
|
||||
## @method $ user_disabled($username)
|
||||
# Determine whether the specified user's account is disabled. This will check
|
||||
# that the user's type is 0 or 3, and return false if it is not.
|
||||
#
|
||||
# @param username The name of the user to check
|
||||
# @return true if the user's account is disabled, false if the account is active
|
||||
# or does not exist.
|
||||
sub user_disabled {
|
||||
my $self = shift;
|
||||
my $username = shift;
|
||||
|
||||
my $user = $self -> get_user($username);
|
||||
|
||||
return ($user && !($user -> {"user_type"} == 0 || $user -> {"user_type"} == 3));
|
||||
}
|
||||
|
||||
|
||||
## @method $ get_user_byid($userid, $onlyreal)
|
||||
# Obtain the user record for the specified user, if they exist. This returns a
|
||||
# reference to a hash of user data corresponding to the specified userid,
|
||||
# or undef if the userid does not correspond to a valid user. If the onlyreal
|
||||
# argument is set, the userid must correspond to 'real' user - bots or inactive
|
||||
# users are not be returned.
|
||||
#
|
||||
# @param userid The id of the user to obtain the data for.
|
||||
# @param onlyreal If true, only users of type 0 or 3 are returned.
|
||||
# @return A reference to a hash containing the user's data, or undef if the user
|
||||
# can not be located (or is not real)
|
||||
sub get_user_byid {
|
||||
my $self = shift;
|
||||
my $userid = shift;
|
||||
my $onlyreal = shift;
|
||||
|
||||
# Return the user record
|
||||
return $self -> _get_user("user_id", $userid, $onlyreal);
|
||||
}
|
||||
|
||||
|
||||
## @method $ get_user($username, $onlyreal)
|
||||
# Obtain the user record for the specified user, if they exist. This returns a
|
||||
# reference to a hash of user data corresponding to the specified userid,
|
||||
# or undef if the userid does not correspond to a valid user. If the onlyreal
|
||||
# argument is set, the userid must correspond to 'real' user - bots or inactive
|
||||
# users are not be returned.
|
||||
#
|
||||
# @param username The username of the user to obtain the data for.
|
||||
# @param onlyreal If true, only users of type 0 or 3 are returned.
|
||||
# @return A reference to a hash containing the user's data, or undef if the user
|
||||
# can not be located (or is not real)
|
||||
sub get_user {
|
||||
my $self = shift;
|
||||
my $username = shift;
|
||||
my $onlyreal = shift;
|
||||
|
||||
return $self -> _get_user("username", $username, $onlyreal, 1);
|
||||
}
|
||||
|
||||
|
||||
## @method $ get_user_authmethod($username)
|
||||
# Attempt to obtain the auth method id set for the user with the specified
|
||||
# username. If the user does not exist, or does not have an authmethod set,
|
||||
# this returns undef, otherwise it returns the id of the auth method the
|
||||
# user last logged in using.
|
||||
#
|
||||
# @param username The username of the user to fetch the auth method id for.
|
||||
# @return The auth method id to try to authenticate the user with, or undef.
|
||||
sub get_user_authmethod {
|
||||
my $self = shift;
|
||||
my $username = shift;
|
||||
|
||||
my $user = $self -> get_user($username);
|
||||
return $user -> {"user_auth"} if($user);
|
||||
|
||||
return undef;
|
||||
}
|
||||
|
||||
|
||||
## @method $ set_user_authmethod($username, $methodid)
|
||||
# Set the auth method id for the specified user. This attempts to update
|
||||
# the user_auth field for the user with the specified username, it does
|
||||
# not verify that the methodid corresponds to a valid method, so the
|
||||
# caller needs to check it. Also note that methodid may be undef, in
|
||||
# which case the user's auth_method is set to NULL.
|
||||
#
|
||||
# @param username The username of the user to update the user_auth field for.
|
||||
# @param methodid The id of the auth method to set for this user, or undef.
|
||||
# @return true if the user's user_auth field was updated, false on error.
|
||||
sub set_user_authmethod {
|
||||
my $self = shift;
|
||||
my $username = shift;
|
||||
my $methodid = shift;
|
||||
|
||||
my $seth = $self -> {"dbh"} -> prepare("UPDATE ".$self -> {"settings"} -> {"database"} -> {"users"}."
|
||||
SET user_auth = ?
|
||||
WHERE username LIKE ?");
|
||||
my $result = $seth -> execute($methodid, $username)
|
||||
or die_log($self -> {"cgi"} -> remote_host(), "Unable to execute user auth update query. Error was: ".$self -> {"dbh"} -> errstr);
|
||||
|
||||
$self -> {"lasterr"} = "Unable to update user auth method, unkown user selected"
|
||||
if($result != 1);
|
||||
|
||||
return ($result == 1);
|
||||
}
|
||||
|
||||
|
||||
# ============================================================================
|
||||
# Post-auth functions.
|
||||
|
||||
## @method $ post_authenticate($username)
|
||||
# Perform any system-specific post-authentication tasks on the specified
|
||||
# user's data. This function allows each system to tailor post-auth tasks
|
||||
# to the requirements of the system.
|
||||
#
|
||||
# @note The implementation provided here will create an empty user record
|
||||
# if one with the specified username does not already exist. The
|
||||
# user is initialised as a type 0 ('normal') user, with default
|
||||
# values for all the fields. If this behaviour is not required or
|
||||
# desirable, subclasses may wish to override this function completely.
|
||||
#
|
||||
# @param username The username of the user to update the user_auth field for.
|
||||
# @return An empty string on success, otherwise an error message.
|
||||
sub post_authenticate {
|
||||
my $self = shift;
|
||||
my $username = shift;
|
||||
|
||||
# Determine whether the user exists. If not, create the user.
|
||||
my $user = $self -> get_user($username);
|
||||
if(!$user) {
|
||||
# No record for this user, need to make one...
|
||||
my $newuser = $self -> {"dbh"} -> prepare("INSERT INTO ".$self -> {"settings"} -> {"database"} -> {"users"}."
|
||||
(username, created, last_login)
|
||||
VALUES(?, UNIX_TIMESTAMP(), UNIX_TIMESTAMP())");
|
||||
$newuser -> execute($username)
|
||||
or die_log($self -> {"cgi"} -> remote_host(), "FATAL: Unable to create new user record: ".$self -> {"dbh"} -> errstr);
|
||||
|
||||
$user = $self -> get_user($username);
|
||||
}
|
||||
|
||||
return "User addition failed" if(!$user);
|
||||
|
||||
# Touch the user's record...
|
||||
my $pokeh = $self -> {"dbh"} -> prepare("UPDATE ".$self -> {"settings"} -> {"database"} -> {"users"}."
|
||||
SET last_login = UNIX_TIMESTAMP()
|
||||
WHERE user_id = ?");
|
||||
$pokeh -> execute($user -> {"user_id"})
|
||||
or die_log($self -> {"cgi"} -> remote_host(), "FATAL: Unable to update user record: ".$self -> {"dbh"} -> errstr);
|
||||
|
||||
# All done...
|
||||
return '';
|
||||
}
|
||||
|
||||
|
||||
# ============================================================================
|
||||
# Internal functions
|
||||
|
||||
## @method private $ _get_user($field, $value, $onlyreal)
|
||||
# Internal implementation of the get_user facility. This allows users to be
|
||||
# searched for on any given user field, and if the user is found it returns
|
||||
# the user's data, undef otherwise. If the onlyreal argument is set, the user
|
||||
# must correspond to 'real' user - bots or inactive users are not be returned.
|
||||
#
|
||||
# @param field The name of the column to search for users on. If the column
|
||||
# contains values that are not unique per user, only the first
|
||||
# match is returned (ie: don't search on non-unique columns.)
|
||||
# @param value The value to search for in the user table.
|
||||
# @param onlyreal If true, only users of type 0 or 3 are returned.
|
||||
# @param uselike If true the search uses 'LIKE' instead of exact comparison.
|
||||
# @return A reference to a hash containing the user's data, or undef if the user
|
||||
# can not be located (or is not real)
|
||||
sub _get_user {
|
||||
my $self = shift;
|
||||
my $field = shift;
|
||||
my $value = shift;
|
||||
my $onlyreal = shift;
|
||||
my $uselike = shift;
|
||||
|
||||
my $userh = $self -> {"dbh"} -> prepare("SELECT * FROM ".$self -> {"settings"} -> {"database"} -> {"users"}."
|
||||
WHERE $field ".($uselike ? "LIKE" : "=")." ?".
|
||||
($onlyreal ? " AND user_type IN (0,3)" : ""));
|
||||
$userh -> execute($value)
|
||||
or die_log($self -> {"cgi"} -> remote_host(), "Unable to execute user lookup query. Error was: ".$self -> {"dbh"} -> errstr);
|
||||
|
||||
return $userh -> fetchrow_hashref();
|
||||
}
|
||||
|
||||
|
||||
# ============================================================================
|
||||
# Error functions
|
||||
|
||||
sub get_error { return $errstr; }
|
||||
|
||||
sub set_error { $errstr = shift; return undef; }
|
||||
|
||||
1;
|
Loading…
x
Reference in New Issue
Block a user