File Coverage

blib/lib/Authen/PAAS/Context.pm
Criterion Covered Total %
statement 71 76 93.4
branch 23 32 71.8
condition 1 3 33.3
subroutine 8 8 100.0
pod 3 3 100.0
total 106 122 86.8


line stmt bran cond sub pod time code
1             # -*- perl -*-
2             #
3             # Authen::PAAS::Context by Daniel Berrange
4             #
5             # Copyright (C) 2004-2006 Dan Berrange
6             #
7             # This program is free software; you can redistribute it and/or modify
8             # it under the terms of the GNU General Public License as published by
9             # the Free Software Foundation; either version 2 of the License, or
10             # (at your option) any later version.
11             #
12             # This program is distributed in the hope that it will be useful,
13             # but WITHOUT ANY WARRANTY; without even the implied warranty of
14             # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15             # GNU General Public License for more details.
16             #
17             # You should have received a copy of the GNU General Public License
18             # along with this program; if not, write to the Free Software
19             # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20             #
21             # $Id: Context.pm,v 1.5 2005/08/21 10:57:06 dan Exp $
22              
23             =pod
24              
25             =head1 NAME
26              
27             Authen::PAAS::Context - authentication a subject using login modules
28              
29             =head1 SYNOPSIS
30              
31             use Authen::PAAS::Context;
32             use Authen::PAAS::SimpleCallback;
33             use Config::Record;
34              
35             my $config = Config::Record->new("/etc/myapp.cfg");
36              
37             my $context = Authen::PAAS::Context->new($config, "myapp");
38              
39             my $callbacks = {
40             "username" => Authen::PAAS::SimpleCallback->new("joeblogs"),
41             "password" => Authen::PAAS::SimpleCallback->new("123456"),
42             };
43              
44             my $subject = $context->login($callbacks);
45              
46             unless ($subject) {
47             die "could not authenticate subject"
48             }
49              
50             .. do some work using the subject ..
51              
52             $context->logout($subject);
53              
54             =head1 DESCRIPTION
55              
56             The C module provides the controller
57             for invoking a number of login modules, and having them
58             populate a subject with principals and credentials. The
59             authentication process consists of two stages. In the first
60             phase the C method is invoked on all modules to
61             perform the actual authentication process. If a module's
62             authentication process succeded, then it may wish to store
63             state to represent the result of authentication in the
64             supplied instance of C. If the first
65             phase was successful overall, then the C method will
66             be invoked on all modules. The module's C method will
67             check the stored state for the result of the first phase, and
68             if it was successful, then it will add one or more principals
69             and zero or more credentials to the subject. If there is a
70             terminal failure of the authentication process at any point,
71             the abort() method will be invoked on all modules
72              
73              
74             =head1 CONFIGURATION
75              
76             The L module is used for accessing configuration
77             file information. The configuration file defines the set of
78             login modules used for performing authentication. The modules
79             have associated flags controlling operation of the login process
80             upon success/failure of a module. The configuration is stored in
81             a single list, named C where $APP is the name token
82             passed into the constructor of the C object.
83             Each element in the list is a dictionary, with the key C
84             defining the class name of the login module, the key C
85             defining the login flags and C defining any module
86             specific options. For example, a web application may have a
87             a username/password in the main login page, but elsewhere use a
88             cookie as the authentication data. In this case, a configuration
89             look like
90              
91              
92             auth.mail-archive = (
93             {
94             module = Authen::PAAS::DB::PasswdLogin
95             flags = optional
96             }
97             {
98             module = Authen::PAAS::CGI::CookieLogin
99             flags = requisite
100             options = {
101             secret = /etc/authen-paas/authen-paas-cgi-secret.dat
102             user-module = Authen::PAAS::DB::User
103             }
104             }
105             )
106              
107              
108             =head1 METHODS
109              
110             =over 4
111              
112             =cut
113              
114             package Authen::PAAS::Context;
115              
116 1     1   163940 use strict;
  1         3  
  1         38  
117 1     1   5 use warnings;
  1         3  
  1         27  
118              
119 1     1   580 use Authen::PAAS::Subject;
  1         3  
  1         34  
120 1     1   8 use Log::Log4perl;
  1         3  
  1         8  
121              
122             our $VERSION = '1.0.0';
123              
124              
125             =item $obj = Authen::PAAS::Context->new();
126              
127             Create
128              
129             =cut
130              
131             sub new {
132 6     6 1 18043 my $proto = shift;
133 6   33     45 my $class = ref($proto) || $proto;
134 6         12 my $self = {};
135 6         21 my %params = @_;
136              
137 6 50       31 $self->{config} = exists $params{config} ? $params{config} : die "config parameter is required";
138 6 50       20 $self->{name} = exists $params{name} ? $params{name} : die "name parameter is required";
139 6         18 $self->{modules} = [];
140              
141 6         22 bless $self, $class;
142              
143 6         17 $self->_load();
144              
145 6         22 return $self;
146             }
147              
148             sub _load {
149 6     6   11 my $self = shift;
150              
151 6         43 my $logger = Log::Log4perl->get_logger(ref($self));
152              
153 6         634 my $modules = $self->{config}->get("auth/" . $self->{name});
154 6         333 my @modules;
155 6         10 foreach my $module (@{$modules}) {
  6         17  
156 12         28 my $pack = $module->{module};
157 12 50       44 if (!exists $INC{$pack}) {
158 0         0 eval "use $pack;";
159 0 0       0 if ($@) {
160 0         0 die $@;
161             }
162             }
163 12         86 $logger->debug("Loading module $pack with " . $module->{flags});
164 12         3922 my $object = $pack->new(flags => $module->{flags},
165             options => $module->{options});
166              
167 12         85 push @modules, $object;
168             }
169              
170 6         41 $self->{modules} = \@modules;
171             }
172              
173             =item my $subject = $ctx->login(\%callbacks);
174              
175             Attempt to authenticate the user, using data obtained from the
176             callbacks passed in as the first parameter. The callbacks should
177             be a hash reference, where keys are the callback name, and the
178             values are instances of the C module.
179             If authentication succeeded, an instance of the C
180             module will be returned, otherwise an undefined value will be
181             returned.
182              
183             =cut
184              
185             sub login {
186 6     6 1 24 my $self = shift;
187 6         10 my $callbacks = shift;
188              
189 6         25 my $logger = Log::Log4perl->get_logger(ref($self));
190 6         162 my $subject = Authen::PAAS::Subject->new();
191              
192 6         7 my $success;
193 6         11 foreach my $module (@{$self->{modules}}) {
  6         16  
194 11 100       345 if ($module->flags eq "sufficient") {
    100          
    100          
    50          
195 2 100       10 if ($module->login($subject, $callbacks)) {
196 1         8 $logger->info("Sufficient login $module success");
197 1 50       377 if (!defined $success) {
198 1         3 $success = 1;
199             }
200 1         4 last;
201             } else {
202 1         7 $logger->info("Sufficient login $module fail");
203             # continue
204             }
205             } elsif ($module->flags eq "requisite") {
206 5 100       19 if ($module->login($subject, $callbacks)) {
207 4         23 $logger->info("Requisite login $module success");
208 4 100       1105 if (!defined $success) {
209 3         9 $success = 1;
210             }
211             } else {
212 1         7 $logger->info("Requisite login $module fail");
213 1         275 $success = 0;
214 1         2 last;
215             }
216             } elsif ($module->flags eq "required") {
217 1 50       6 if ($module->login($subject, $callbacks)) {
218 0         0 $logger->info("Required login $module success");
219 0         0 $success = 1;
220             } else {
221 1         8 $logger->info("Required login $module fail");
222 1         302 $success = 0;
223             # continue
224             }
225             } elsif ($module->flags eq "optional") {
226 3 100       11 if ($module->login($subject, $callbacks)) {
227 1         7 $logger->info("Optional login $module success");
228 1 50       296 if (!defined $success) {
229 1         4 $success = 1;
230             }
231             } else {
232 2         10 $logger->info("Optional login $module fail");
233             # continue
234             }
235             }
236             }
237              
238 6 100       587 return $success ? $subject : undef;
239             }
240              
241              
242             =item $ctx->logout($subject)
243              
244             Takes an authenticated subject and performs a logout
245             operation. This method would typically destroy any
246             tokens / credentials that might exist beyond the lifetime
247             of the current process.
248              
249             =cut
250              
251             sub logout {
252 4     4 1 3310 my $self = shift;
253 4         8 my $subject = shift;
254              
255 4         24 my $logger = Log::Log4perl->get_logger(ref($self));
256              
257 4         109 foreach my $module (@{$self->{modules}}) {
  4         11  
258 8         51 $logger->info("Logging out $module");
259 8         5867 $module->logout($subject);
260             }
261             }
262              
263              
264             1 # So that the require or use succeeds.
265              
266             __END__