File Coverage

blib/lib/CGI/Builder/Auth/User.pm
Criterion Covered Total %
statement 48 48 100.0
branch 18 26 69.2
condition 2 3 66.6
subroutine 20 20 100.0
pod 6 7 85.7
total 94 104 90.3


line stmt bran cond sub pod time code
1             package CGI::Builder::Auth::User
2             ; use strict
3 3     3   26194 ; require Scalar::Util
  3         6  
  3         213  
4              
5             ; our $VERSION = '0.05'
6             ; our $_user_admin;
7              
8              
9             ; use CGI::Builder::Auth::UserAdmin
10 3     3   1833 ; use Digest::MD5 'md5_hex'
  3         8  
  3         27  
  3         299  
11              
12 3     3   19 ; use Class::constr
  3         6  
13 3         38 ( { name => 'load', init => '_real', copy => 1 }
14             , { name => 'anonymous', init => '_anon', copy => 1 }
15             , { name => 'new', init => '_factory' }
16             )
17 3     3   2190 ; use Class::groups
  3         1389  
18 3         36 ( { name => 'config'
19             , default =>
20             { DBType => 'Text' # type of database, one of 'DBM', 'Text', or 'SQL'
21             , DB => '.htpasswd' # database name
22             # , Server => 'apache'
23             # , Encrypt => 'MD5'
24             , Encrypt => 'crypt'
25             # , Locking => 1
26             # , Path => '.'
27             , Debug => 0
28             # read, write and create flags. There are four modes: rwc - the default,
29             # open for reading, writing and creating. rw - open for reading and
30             # writing. r - open for reading only. w - open for writing only.
31             # , Flags => 'rwc'
32              
33             # FOR DBI
34             # , Host => 'localhost'
35             # , Port => ???
36             # , User => ''
37             # , Auth => ''
38             # , Driver => 'SQLite'
39             # , UserTable => 'users'
40             # , NameField => 'user_id'
41             # , PasswordField => 'password'
42            
43             # FOR DBM Files
44             # , DBMF => 'NDBM'
45             # , Mode => 0644
46             }
47             }
48             )
49 3     3   2375 ; use Class::props
  3         7559  
50             ( { name => '_user_admin'
51 18         1303 , default => sub { CGI::Builder::Auth::UserAdmin->new(%{$_[0]->config}) }
  18         77  
52             }
53 3         28 , { name => 'realm'
54             , default => 'main'
55             }
56             )
57 3     3   359 ; use Object::props
  3         7  
58 3         29 ( { name => 'id'
59             , default => 'anonymous'
60             }
61             )
62              
63 3     3   2050 ; use overload
  3         324  
64 3         24 ( '""' => 'as_string'
65             , fallback => 1
66             )
67             # Overload Magic
68 3     3 0 3768 ; sub as_string { $_[0]->id }
  3     68   2415  
  68         5276  
69              
70             # INIT Routines
71              
72             # Cancel construction if requested user does not exist
73 14 100   14   389 ; sub _real { $_[0] = undef unless $_[0]->_exists }
74              
75             # Force anonymous even if caller foolishly passed an ID
76 3     3   174 ; sub _anon { $_[0]->id('anonymous') }
77              
78             # When building a factory, id must be undef
79 6     6   376 ; sub _factory { $_[0]->id(undef) }
80              
81              
82             #---------------------------------------------------------------------
83             # Factory Methods
84             #---------------------------------------------------------------------
85 6     6 1 837 ; sub list { $_[0]->_user_admin->list }
86              
87             ; sub add
88 8     8 1 1984 { my ($self, $data) = @_
89 8         35 ; my $username = delete $data->{'username'}
90 8         20 ; my $password = delete $data->{'password'}
91              
92 8 100       25 ; return if $username eq 'anonymous'
93 7 100       21 ; return if $self->_exists($username)
94            
95 6 50       27 ; $password = join(":",$username,$self->realm,$password)
96             if $self->_user_admin->{ENCRYPT} eq 'MD5'
97              
98 6 50       210 ; return $self->_user_admin->add($username, $password, $data)
99             ? $self->load(id => $username)
100             : undef
101             }
102              
103             #---------------------------------------------------------------------
104             # Instance Methods
105             #---------------------------------------------------------------------
106             ; sub _exists
107 30 100   30   151 { defined $_[1]
108             ? $_[0]->_user_admin->exists($_[1])
109             : $_[0]->_user_admin->exists($_[0]->id)
110             }
111             ; sub delete
112 4 50   4 1 132 { defined $_[1]
113             ? $_[0]->_user_admin->delete($_[1])
114             : $_[0]->_user_admin->delete($_[0]->id)
115             }
116             ; sub suspend
117 1 50   1 1 9 { defined $_[1]
118             ? $_[0]->_user_admin->suspend($_[1])
119             : $_[0]->_user_admin->suspend($_[0]->id)
120             }
121             ; sub unsuspend
122 1 50   1 1 8 { defined $_[1]
123             ? $_[0]->_user_admin->unsuspend($_[1])
124             : $_[0]->_user_admin->unsuspend($_[0]->id)
125             }
126              
127             ; sub password_matches
128 5     5 1 888 { my ($self, $passwd) = @_
129 5 50       12 ; return unless $self->_exists
130 5 50       59 ; $passwd = join(":",$self->id,$self->realm,$passwd)
131             if $self->_user_admin->{ENCRYPT} eq 'MD5'
132            
133 5         166 ; my $stored_passwd = $self->_user_admin->password($self->id)
134 5 50       22 ; return $self->_user_admin->{ENCRYPT} eq 'crypt'
135             ? crypt($passwd,$stored_passwd) eq $stored_passwd
136             : $self->_user_admin->encrypt($passwd) eq $stored_passwd
137             }
138              
139             ; sub DESTROY
140 23 100 66 23   2249 { ref($_user_admin)
141             and !Scalar::Util::isweak($_user_admin)
142             and Scalar::Util::weaken($_user_admin)
143             }
144              
145             =head1 NAME
146              
147             CGI::Builder::Auth::User - Provide access to a user table and its rows
148              
149             =head1 DESCRIPTION
150              
151             This Class provides an API for manipulating a User table. The implementation
152             stores the table in a text file, but developers are free to create their own
153             implementations of this API that wrap SQL databases or other resources.
154              
155             Developers using the library probably will not need to manipulate the user
156             objects directly, since the L
157             provides a wrapper around all the common functions. However, developers
158             creating their own user classes need to pay special attention to implementing
159             this API correctly.
160              
161             This document describes the default implementation, and includes many notes
162             about mandatory and optional features for alternate implementations.
163              
164             WARNING: This interface is experimental. Developers may create their own
165             implementations, but are advised to subscribe to the mailing list to be
166             notified of changes. Backward compatibility is a goal, but is not guaranteed
167             for future releases.
168              
169              
170             =head1 SPECIAL PROPERTIES
171              
172             The user object C's the string operator so that prints the username
173             in string context rather than the usual reference information. As a result, you
174             may use the user object in your code as if it were a (read-only) scalar
175             containing the username.
176              
177             This is required behavior for all implementations. See L for details.
178              
179              
180             =head1 CONSTRUCTORS
181              
182              
183             =head2 C
184              
185             Class method, takes no arguments.
186              
187             Return a user object with id of 'anonymous'. This user belongs to no groups.
188              
189              
190             =head2 C $id)>
191              
192             Class method, takes a hash where the key is 'id' (literal) and the value is the
193             username you wish to load.
194              
195             Return a user object with the username of C<$id>. Return C if the user
196             does not exist in the database. Attempts to C a user with id of
197             'anonymous' must always fail, this username is reserved. To construct an
198             anonymous user, call the 'anonymous' constructor instead.
199            
200             Note that the username is required to be unique in a given table.
201              
202              
203             =head2 C
204              
205             Add a user to the user table.
206              
207             Class method, takes a reference to a hash of user attributes. Attributes
208             supported in this implementation:
209              
210             =over
211              
212             =item B
213              
214             =item B
215              
216             =back
217              
218             All implementations are required to support these two attributes, and may
219             support as many more as they like. Note that the username is required to be
220             unique in a given table.
221              
222             Return the user object on success, undef on failure.
223              
224              
225             =head1 OTHER CLASS METHODS
226              
227              
228             =head2 C
229              
230             Class method, takes one or two scalar arguments.
231              
232             Store and retrieve configuration options. With one argument C<$opt>, returns
233             the value of the config option. With two arguments, stores C<$new_val> as the
234             new value for config option C<$opt>. Returns C if the option is unset.
235              
236              
237             =head2 C
238              
239             Class method, takes no arguments.
240              
241             Return an array of all users (as objects) in the user table, or C on
242             error.
243              
244              
245              
246             =head1 INSTANCE (OBJECT) METHODS
247              
248              
249             =head2 C
250              
251             Instance method, takes no arguments.
252              
253             Delete the user from the user table. After a call to this method, the object
254             should be considered unusable. (In practice this implementation makes the
255             object anonymous, but this behavior is not required and is not guaranteed to be
256             true in future releases. Do not rely on it.)
257              
258              
259             =head2 C
260              
261             Instance method, takes one scalar argument, a string.
262              
263             Return true if the C<$password> argument matches the password stored in the
264             table. This allows the storage class to implement its own one-way hash function
265             to obscure the password in storage if desired. Note that the user object is
266             never required to return the stored password, but implementations may allow
267             this if desired.
268              
269              
270             =head2 C
271              
272             Instance method, takes no arguments.
273              
274             Places this user in a suspended status. When suspended, the user method C
275             always returns false.
276              
277             This method is not currently used by the Context object, but support will be
278             added in a (near) future release. Therefore, implementations are required to
279             support this method.
280              
281              
282             =head2 C
283              
284             Instance method, takes no arguments.
285              
286             Removes this user from suspended status. When suspended, the user method C
287             always returns false.
288              
289             This method is not currently used by the Context object, but support will be
290             added in a (near) future release. Therefore, implementations are required to
291             support this method.
292              
293              
294             =head1 SUPPORT
295              
296             Support for this module and all the modules of the CBF is via the mailing list.
297             The list is used for general support on the use of the CBF, announcements, bug
298             reports, patches, suggestions for improvements or new features. The API to the
299             CBF is stable, but if you use the CBF in a production environment, it's
300             probably a good idea to keep a watch on the list.
301              
302             You can join the CBF mailing list at this url:
303              
304             L
305              
306              
307             =head1 AUTHOR
308              
309             Vincent Veselosky
310              
311              
312             =head1 COPYRIGHT AND LICENSE
313              
314             Copyright 2004 by Vincent Veselosky
315              
316             This library is free software; you can redistribute it and/or modify
317             it under the same terms as Perl itself.
318              
319              
320              
321              
322              
323             =cut
324              
325             "Copyright 2004 Vincent Veselosky [[http://control-escape.com]]";
326             # vim:expandtab:ts=3:sw=3:ft=perl: