Permalink
Newer
Older
100644 187 lines (151 sloc) 7.09 KB
1
## @file
2
# This file contains the implementation of the authentication method loader class.
3
#
4
# @author Chris Page <chris@starforge.co.uk>
5
#
6
# This program is free software: you can redistribute it and/or modify
7
# it under the terms of the GNU General Public License as published by
8
# the Free Software Foundation, either version 3 of the License, or
9
# (at your option) any later version.
10
#
11
# This program is distributed in the hope that it will be useful,
12
# but WITHOUT ANY WARRANTY; without even the implied warranty of
13
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
# GNU General Public License for more details.
15
#
16
# You should have received a copy of the GNU General Public License
17
# along with this program. If not, see <http://www.gnu.org/licenses/>.
18
19
## @class
20
# Dynamic AuthMethod loader class. This provides the facility to load
21
# AuthMethod subclasses on the fly to support the Auth class. It relies
22
# on information stored in the auth_methods and auth_params tables to
23
# load AuthMethod subclasses, initialise them, and pass them back to
24
# the caller to use.
25
package AuthMethods;
26
27
use strict;
29
30
our $errstr;
31
32
BEGIN {
33
$errstr = '';
34
}
35
36
# ============================================================================
37
# Constructor
38
39
## @cmethod $ new(%args)
40
# Construct a new AuthMethods object. This will create a new AuthMethods object
41
# initialised with the provided arguments.
42
#
43
# @param args A hash of arguments to initialise the AuthMethods object with.
44
# @return A new AuthMethods object.
45
sub new {
46
my $invocant = shift;
47
my $class = ref($invocant) || $invocant;
48
my $self = {
49
@_,
50
};
51
52
# Ensure that we have objects that we need
53
return set_error("cgi object not set") unless($self -> {"cgi"});
54
return set_error("dbh object not set") unless($self -> {"dbh"});
55
return set_error("settings object not set") unless($self -> {"settings"});
56
return set_error("app object not set") unless($self -> {"app"});
57
return set_error("logger object not set") unless($self -> {"logger"});
58
59
return bless $self, $class;
60
}
61
62
63
# ============================================================================
64
# Interface code
65
66
## @method $ available_methods($only_active)
67
# Generate a list of available AuthMethod subclasses. This pulls a list of
68
# auth methods from the database, and returns an array containing the internal
69
# ids.
70
#
71
# @param only_active If true, the returned array will only contain methods
72
# flagged as being active. Otherwise it will contain all
73
# known methods.
74
# @return A reference to an array of method ids.
75
sub available_methods {
76
my $self = shift;
77
my $only_active = shift;
78
79
my $methodh = $self -> {"dbh"} -> prepare("SELECT id FROM ".$self -> {"settings"} -> {"database"} -> {"auth_methods"}.
80
($only_active ? " WHERE enabled = 1 " : " ").
81
"ORDER BY priority ASC");
82
$methodh -> execute()
83
or $self -> {"logger"} -> die_log($self -> {"cgi"} -> remote_host(), "Unable to execute auth method list query: ".$self -> {"dbh"} -> errstr);
84
85
my @methods;
86
while(my $method = $methodh -> fetchrow_arrayref()) {
87
push(@methods, $method -> [0]);
88
}
89
90
return \@methods;
91
}
92
93
94
## @method $ load_method($method_id)
95
# Load the auth method with the specified id and initialise it. This will
96
# dynamically load the method with the specified id, provided it is active,
97
# and return a reference to the method object.
98
#
99
# @param method_id The id of the auth method to load.
100
# @return A reference to an AuthMethod subclass implementing the method
101
# on success, undef on failure or if the method is disabled. If this
102
# returns undef, $self -> {"lasterr"} is set to a message indicating
103
# what went wrong. Note that attempting to load a disabled method is
104
# NOT considered an error: this will return undef, but lasterr will
105
# be empty.
106
sub load_method {
107
my $self = shift;
108
my $method_id = shift;
109
110
$self -> {"errstr"} = "";
111
112
# Fetch the module name first
113
my $moduleh = $self -> {"dbh"} -> prepare("SELECT perl_module, enabled FROM ".$self -> {"settings"} -> {"database"} -> {"auth_methods"}."
Mar 16, 2012
115
$moduleh -> execute($method_id)
116
or $self -> {"logger"} -> die_log($self -> {"cgi"} -> remote_host(), "Unable to execute auth method lookup query: ".$self -> {"dbh"} -> errstr);
117
118
my $module = $moduleh -> fetchrow_hashref();
119
return $self -> self_error("Unknown auth method requested in load_method($method_id)") if(!$module);
120
121
# Is the module active? If not, do nothing
122
return undef if(!$module -> {"enabled"});
123
124
# Module is active, fetch its settings
125
my $paramh = $self -> {"dbh"} -> prepare("SELECT name, value FROM ".$self -> {"settings"} -> {"database"} -> {"auth_params"}."
126
WHERE method_id = ?");
Mar 16, 2012
127
$paramh -> execute($method_id)
128
or $self -> {"logger"} -> die_log($self -> {"cgi"} -> remote_host(), "Unable to execute auth method parameter query: ".$self -> {"dbh"} -> errstr);
129
130
# Build up a settings hash using the standard objects, and settings for the
131
# module loaded from the database.
132
my %settings = ( cgi => $self -> {"cgi"},
133
dbh => $self -> {"dbh"},
134
settings => $self -> {"settings"},
135
app => $self -> {"app"}, # Methods shouldn't actually need access to app, but add it anyway in case.
Apr 13, 2012
136
logger => $self -> {"logger"});
137
while(my $param = $paramh -> fetchrow_hashref()) {
138
$settings{$param -> {"name"}} = $param -> {"value"};
139
}
140
Mar 16, 2012
141
# For readability...
142
my $name = $module -> {"perl_module"};
143
144
no strict "refs"; # must disable strict references to allow named module loading.
145
eval { load $name };
146
die "Unable to load auth module $name: $@" if($@);
147
148
my $methodobj = $name -> new(%settings);
149
use strict;
150
151
# Return undef and set error if the call to new returned an error message
152
return $self -> self_error("Unable to load auth module: ".$methodobj)
153
if(!ref($methodobj));
154
155
# Otherwise, return the auth method object.
156
return $methodobj;
157
}
158
159
160
# ============================================================================
161
# Error functions
162
163
## @cmethod private $ set_error($errstr)
164
# Set the class-wide errstr variable to an error message, and return undef. This
165
# function supports error reporting in the constructor and other class methods.
166
#
167
# @param errstr The error message to store in the class errstr variable.
168
# @return Always returns undef.
169
sub set_error { $errstr = shift; return undef; }
170
171
172
## @method private $ self_error($errstr)
173
# Set the object's errstr value to an error message, and return undef. This
174
# function supports error reporting in various methods throughout the class.
175
#
176
# @param errstr The error message to store in the object's errstr.
177
# @return Always returns undef.
178
sub self_error {
179
my $self = shift;
180
$self -> {"errstr"} = shift;