line
stmt
bran
cond
sub
pod
time
code
1
package Authen::Users;
2
3
require 5.004;
4
5
1
1
46529
use strict;
1
2
1
42
6
1
1
4
use warnings;
1
2
1
71
7
1
1
5
use Carp;
1
6
1
218
8
1
1
3761
use DBI;
1
23187
1
85
9
1
1
19340
use Digest::SHA qw(sha1_base64 sha256_base64 sha384_base64 sha512_base64);
1
14117
1
164
10
1
1
15
use vars qw($VERSION);
1
2
1
5705
11
$VERSION = '0.17';
12
13
sub new {
14
0
0
1
my ( $class, %args ) = @_;
15
0
my $self = {};
16
0
bless( $self, $class );
17
0
foreach
18
my $k (qw( dbtype dbname create dbuser dbpass dbhost authen_table digest))
19
{
20
0
0
$self->{$k} = $args{$k} if $args{$k};
21
}
22
0
0
$self->{dbname}
23
or croak "Cannot set up Auth::Users without a dbname: $self->{dbname}.";
24
0
0
$self->{dbtype} = 'SQLite' unless $self->{dbtype};
25
0
0
$self->{authentication} = $self->{authen_table} || 'authentication';
26
0
0
$self->{make_salt} = 1 unless $args{NO_SALT};
27
0
0
my $algo = $self->{digest} || 1;
28
0
0
if ( $algo == 256 ) {
0
0
29
0
0
$self->{sha} = sub { sha256_base64(shift) }
30
0
}
31
elsif ( $algo == 384 ) {
32
0
0
$self->{sha} = sub { sha384_base64(shift) }
33
0
}
34
elsif ( $algo == 512 ) {
35
0
0
$self->{sha} = sub { sha512_base64(shift) }
36
0
}
37
else {
38
0
0
$self->{sha} = sub { sha1_base64(shift) }
39
0
}
40
0
$self->{_error} = ''; # internal error message used by error() func
41
0
$self->{sqlparams} = { PrintError => 0, RaiseError => 1, AutoCommit => 1 };
42
0
0
if ( $self->{dbtype} =~ /^MySQL/i ) {
43
44
# MySQL
45
0
$self->{dsn} = "dbi:mysql:database=$self->{dbname}";
46
0
0
$self->{dsn} .= ";host=$self->{dbhost}" if $self->{dbhost};
47
0
0
$self->{dbh} = DBI->connect(
48
$self->{dsn}, $self->{dbuser},
49
$self->{dbpass}, $self->{sqlparams}
50
)
51
or croak "Can't connect to MySQL database as $self->{dsn} with "
52
. "user $self->{dbuser} and given password and $self->{sqlparams}: "
53
. DBI->errstr;
54
}
55
else {
56
57
# SQLite is the default
58
0
$self->{dsn} = "dbi:SQLite:dbname=$self->{dbname}";
59
0
0
$self->{dbh} = DBI->connect( $self->{dsn}, $self->{sqlparams} )
60
or croak "Can't connect to SQLite database as $self->{dsn} with "
61
. "$self->{sqlparams}: "
62
. DBI->errstr;
63
}
64
65
# check if table exists
66
0
my $sth_tab = $self->{dbh}->table_info();
67
0
my $need_table = 1;
68
0
while ( my $tbl = $sth_tab->fetchrow_hashref ) {
69
0
0
$need_table = 0 if $tbl->{TABLE_NAME} eq $self->{authentication};
70
}
71
0
0
if ($need_table) {
72
0
0
unless ( $self->{create} ) {
73
0
croak
74
"No table in database, and create not specified for new Authen::Users";
75
}
76
77
# try to create the table
78
0
my $ok_create = $self->{dbh}->do(<
79
CREATE TABLE $self->{authentication}
80
( groop VARCHAR(15), user VARCHAR(30), password VARCHAR(60),
81
fullname VARCHAR(40), email VARCHAR(40), question VARCHAR(120),
82
answer VARCHAR(80), created VARCHAR(12), modified VARCHAR(12),
83
pw_timestamp VARCHAR(12), salt VARCHAR(10), gukey VARCHAR (46) UNIQUE )
84
ST_H
85
0
0
carp("Could not make table") unless $ok_create;
86
}
87
0
return $self;
88
}
89
90
sub authenticate {
91
0
0
1
my ( $self, $group, $user, $password ) = @_;
92
0
my $password_sth = $self->{dbh}->prepare(<
93
SELECT password, salt FROM $self->{authentication} WHERE groop = ? AND user = ?
94
ST_H
95
0
$password_sth->execute( $group, $user );
96
0
my $row = $password_sth->fetchrow_arrayref;
97
0
0
if ($row) {
98
0
my $stored_pw_digest = $row->[0];
99
0
my $salt = $row->[1];
100
0
0
my $user_pw_digest = ($salt)
101
? $self->{sha}->($password, $salt)
102
: $self->{sha}->($password);
103
0
0
return 1 if $user_pw_digest eq $stored_pw_digest;
104
}
105
0
return;
106
}
107
108
sub add_user {
109
0
0
1
my ( $self, $group, $user, $password, $fullname, $email, $question,
110
$answer ) = @_;
111
0
0
$self->validate( $group, $user, $password ) or return;
112
0
0
$self->not_in_table( $group, $user ) or return;
113
0
my $r;
114
0
my $salt = 0;
115
0
0
if($self->{make_salt}) {
116
0
$salt = $self->{sha}->( time + rand(10000) );
117
0
$salt = substr( $salt, -8 );
118
0
my $password_sha = $self->{sha}->($password, $salt);
119
0
my $insert_sth = $self->{dbh}->prepare(<
120
INSERT INTO $self->{authentication}
121
(groop, user, password, fullname, email, question, answer,
122
created, modified, pw_timestamp, salt, gukey)
123
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
124
ST_H
125
0
my $t = time;
126
0
$r = $insert_sth->execute( $group, $user, $password_sha,
127
$fullname, $email, $question, $answer, $t, $t, $t, $salt,
128
_g_u_key( $group, $user ) );
129
}
130
else {
131
0
my $password_sha = $self->{sha}->($password);
132
0
my $insert_sth = $self->{dbh}->prepare(<
133
INSERT INTO $self->{authentication}
134
(groop, user, password, fullname, email, question, answer,
135
created, modified, pw_timestamp, gukey)
136
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
137
ST_H
138
0
my $t = time;
139
0
$r = $insert_sth->execute( $group, $user, $password_sha,
140
$fullname, $email, $question, $answer, $t, $t, $t,
141
_g_u_key( $group, $user ) );
142
}
143
0
0
0
return 1 if $r and $r == 1;
144
0
$self->{_error} = $self->{dbh}->errstr;
145
0
return;
146
}
147
148
0
0
1
sub user_add { shift->add_user(@_) }
149
150
sub update_user_all {
151
0
0
1
my ( $self, $group, $user, $password, $fullname, $email, $question,
152
$answer ) = @_;
153
0
0
$self->validate( $group, $user, $password ) or return;
154
0
my $salt = 0;
155
0
0
if($self->{make_salt}) {
156
0
$salt = $self->{sha}->( time + rand(10000) );
157
0
$salt = substr( $salt, -8 );
158
0
my $password_sha = $self->{sha}->($password, $salt);
159
0
my $update_all_sth = $self->{dbh}->prepare(<
160
UPDATE $self->{authentication} SET password = ?, fullname = ?, email = ?,
161
question = ?, answer = ? , modified = ?, pw_timestamp = ?, salt = ?, gukey = ?
162
WHERE groop = ? AND user = ?
163
ST_H
164
0
my $t = time;
165
0
0
return 1
166
if $update_all_sth->execute(
167
$password_sha, $fullname, $email, $question, $answer,
168
$t, $t, $salt, _g_u_key( $group, $user ), $group, $user
169
);
170
}
171
else {
172
0
my $password_sha = $self->{sha}->{password};
173
0
my $update_all_sth = $self->{dbh}->prepare(<
174
UPDATE $self->{authentication} SET password = ?, fullname = ?, email = ?,
175
question = ?, answer = ? , modified = ?, pw_timestamp = ?, gukey = ?
176
WHERE groop = ? AND user = ?
177
ST_H
178
0
my $t = time;
179
0
0
return 1
180
if $update_all_sth->execute(
181
$password_sha, $fullname, $email, $question, $answer,
182
$t, $t, _g_u_key( $group, $user ), $group, $user
183
);
184
}
185
0
return;
186
}
187
188
sub update_user_password {
189
0
0
1
my ( $self, $group, $user, $password ) = @_;
190
0
0
$self->validate( $group, $user, $password ) or return;
191
0
my $salt = 0;
192
0
0
if($self->{make_salt}) {
193
0
$salt = $self->{sha}->( time + rand(10000) );
194
0
$salt = substr( $salt, -8 );
195
0
my $password_sha = $self->{sha}->($password, $salt);
196
0
my $update_pw_sth = $self->{dbh}->prepare(<
197
UPDATE $self->{authentication} SET password = ?, modified = ?, pw_timestamp = ?,
198
salt = ?
199
WHERE groop = ? AND user = ?
200
ST_H
201
0
my $t = time;
202
0
0
return 1
203
if $update_pw_sth->execute( $password_sha,
204
$t, $t, $salt, $group, $user );
205
}
206
else {
207
0
my $password_sha = $self->{sha}->{password};
208
0
my $update_pw_sth = $self->{dbh}->prepare(<
209
UPDATE $self->{authentication} SET password = ?, modified = ?, pw_timestamp = ?
210
WHERE groop = ? AND user = ?
211
ST_H
212
0
my $t = time;
213
0
0
return 1
214
if $update_pw_sth->execute( $password_sha,
215
$t, $t, $group, $user );
216
}
217
0
return;
218
}
219
220
sub update_user_fullname {
221
0
0
1
my ( $self, $group, $user, $fullname ) = @_;
222
0
my $update_fullname_sth = $self->{dbh}->prepare(<
223
UPDATE $self->{authentication} SET fullname = ?, modified = ?,
224
WHERE groop = ? AND user = ?
225
ST_H
226
0
my $t = time;
227
0
0
return 1 if $update_fullname_sth->execute( $fullname, $t, $group, $user );
228
0
return;
229
}
230
231
sub update_user_email {
232
0
0
1
my ( $self, $group, $user, $email ) = @_;
233
0
my $update_email_sth = $self->{dbh}->prepare(<
234
UPDATE $self->{authentication} SET email = ? , modified = ?,
235
WHERE groop = ? AND user = ?
236
ST_H
237
0
my $t = time;
238
0
0
return 1 if $update_email_sth->execute( $email, $t, $group, $user );
239
0
return;
240
}
241
242
sub update_user_question_answer {
243
0
0
1
my ( $self, $group, $user, $question, $answer ) = @_;
244
0
my $update_additional_sth = $self->{dbh}->prepare(<
245
UPDATE $self->{authentication} SET question = ?, answer = ? ,
246
modified = ? WHERE groop = ? AND user = ?
247
ST_H
248
0
my $t = time;
249
0
0
return 1
250
if $update_additional_sth->execute( $question, $answer, $t, $group,
251
$user );
252
0
return;
253
}
254
255
sub delete_user {
256
0
0
1
my ( $self, $group, $user ) = @_;
257
0
my $delete_sth = $self->{dbh}->prepare(<
258
DELETE FROM $self->{authentication} WHERE groop = ? AND user = ?
259
ST_H
260
0
0
return 1 if $delete_sth->execute( $group, $user );
261
0
return;
262
}
263
264
sub count_group {
265
0
0
1
my ( $self, $group ) = @_;
266
0
my $count_sth = $self->{dbh}->prepare(<
267
SELECT COUNT(password) FROM $self->{authentication} WHERE groop = ?
268
ST_H
269
0
$count_sth->execute($group);
270
0
my $nrows = $count_sth->fetchrow_arrayref->[0];
271
0
0
$nrows = 0 if $nrows < 0;
272
0
return $nrows;
273
}
274
275
sub get_group_members {
276
0
0
1
my ( $self, $group ) = @_;
277
0
my ( $row, @members );
278
0
my $members_sth = $self->{dbh}->prepare(<
279
SELECT user FROM $self->{authentication} WHERE groop = ?
280
ST_H
281
0
$members_sth->execute($group);
282
0
while ( $row = $members_sth->fetch ) { push @members, $row->[0] }
0
283
0
return \@members;
284
}
285
286
sub user_info {
287
288
# returns an arrayref:
289
# [ groop, user, password, fullname, email,
290
# question, answer, created, modified, pw_timestamp, salt, gukey ]
291
0
0
1
my ( $self, $group, $user ) = @_;
292
0
my $user_sth = $self->{dbh}->prepare(<
293
SELECT * FROM $self->{authentication} WHERE groop = ? AND user = ?
294
ST_H
295
0
$user_sth->execute( $group, $user );
296
0
return $user_sth->fetch;
297
}
298
299
sub user_info_hashref {
300
301
# returns a hashref:
302
# {groop => $group, user => $user, password => $password, etc. }
303
0
0
1
my ( $self, $group, $user ) = @_;
304
0
my $user_sth = $self->{dbh}->prepare(<
305
SELECT * FROM $self->{authentication} WHERE groop = ? AND user = ?
306
ST_H
307
0
$user_sth->execute( $group, $user );
308
0
return $user_sth->fetchrow_hashref;
309
}
310
311
sub get_user_fullname {
312
0
0
1
my ( $self, $group, $user ) = @_;
313
0
my $row = $self->user_info( $group, $user );
314
0
0
return $row->[3] if $row;
315
0
return;
316
}
317
318
sub get_user_email {
319
0
0
1
my ( $self, $group, $user ) = @_;
320
0
my $row = $self->user_info( $group, $user );
321
0
0
return $row->[4] if $row;
322
0
return;
323
}
324
325
sub get_user_question_answer {
326
0
0
1
my ( $self, $group, $user ) = @_;
327
0
my $row = $self->user_info( $group, $user );
328
0
0
return ( $row->[5], $row->[6] ) if $row;
329
0
return;
330
}
331
332
sub get_password_change_time {
333
0
0
1
my ( $self, $group, $user ) = @_;
334
0
my $row = $self->user_info( $group, $user );
335
0
0
return $row->[9] if $row;
336
0
return;
337
}
338
339
sub errstr {
340
0
0
1
my $self = shift;
341
0
return $self->{dbh}->errstr;
342
}
343
344
sub error {
345
0
0
1
my $self = shift;
346
0
0
return $self->{_error} || $self->{dbh}->errstr;
347
}
348
349
# validation routine for adding users, etc.
350
sub validate {
351
0
0
1
my ( $self, $group, $user, $password ) = @_;
352
0
0
unless ($group) {
353
0
$self->{_error} = "Group is not defined.";
354
0
return;
355
}
356
0
0
unless ($user) {
357
0
$self->{_error} = "Username is not defined.";
358
0
return;
359
}
360
0
0
unless ($password) {
361
0
$self->{_error} = "Password is not defined.";
362
0
return;
363
}
364
0
return 1;
365
}
366
367
# assistance functions
368
369
sub not_in_table {
370
0
0
1
my ( $self, $group, $user ) = @_;
371
0
my $unique_sth = $self->{dbh}->prepare(<
372
SELECT password FROM $self->{authentication} WHERE gukey = ?
373
ST_H
374
0
$unique_sth->execute( _g_u_key( $group, $user ) );
375
0
my @row = $unique_sth->fetchrow_array;
376
0
0
return if @row;
377
0
return 1;
378
}
379
380
sub is_in_table {
381
0
0
1
my ( $self, $group, $user ) = @_;
382
0
0
return if $self->not_in_table( $group, $user );
383
0
return 1;
384
}
385
386
#end of public interface
387
# internal use--not for object use (no $self argument)
388
389
sub _g_u_key {
390
0
0
my ( $group, $user ) = @_;
391
0
return $group . '|' . $user;
392
}
393
394
=head1 NAME
395
396
Authen::Users - DBI Based User Authentication
397
398
=head1 DESCRIPTION
399
400
General password authentication using DBI-capable databases. Currently supports
401
MySQL and SQLite databases. The default is to use a SQLite database to store
402
and access user information.
403
404
This module is not an authentication protocol. For that see something such as
405
Authen::AuthenDBI.
406
407
=head1 RATIONALE
408
409
After several web sites were written which required ongoing DBI or .htpassword
410
file tweaking for user authentication, it seemed we needed a default user
411
password database that would contain not only the user name and password but
412
also such things as the information needed to reset lost passwords.
413
Thus, this module, designed to be as much as possible a drop-in for your
414
website authorization scripting needs.
415
416
=head1 SYNOPSIS
417
418
use Authen::Users;
419
420
my $authen = new Athen::Users(dbtype => 'SQLite', dbname => 'mydbname');
421
422
// for backward compatibility use the call below:
423
my $authen = new Athen::Users(
424
dbtype => 'SQLite', dbname => 'mydbname', NO_SALT => 1 );
425
426
427
my $a_ok = $authen->authenticate($group, $user, $password);
428
429
my $result = $authen->add_user(
430
$group, $user, $password, $fullname, $email, $question, $answer);
431
432
=head1 METHODS
433
434
=over 4
435
436
=item B
437
438
Create a new Authen::Users object.
439
440
my $authen = new Authen::Users(dbname => 'Authentication');
441
442
=over 4
443
444
Defaults are dbname => SQLIte, authen_table => authentication,
445
create => 0 (off), digest => SHA1.
446
447
=back
448
449
my $authen = new Authen::Users( dbtype => 'SQLite', dbname => 'authen.db',
450
create => 1, authen_table => 'authen_table', digest => 512 );
451
452
my $authen = new Authen::Users(
453
dbtype => 'MySQL', dbname => 'authen.db',
454
dbpass => 'myPW', authen_table => 'authen_table',
455
dbhost => 'mysql.server.org', digest => 256 );
456
457
Takes a hash of arguments:
458
459
=over 4
460
461
=item B
462
463
The type of database. Currently supports 'SQLite' and 'MySQL'.
464
Defaults to SQLite.
465
466
=item B
467
468
The name of the database. Required for all database types.
469
470
=item B
471
472
The name of the table containing the user data.
473
474
475
NOTE: If this is omitted, defaults to a table called 'authentication' in the
476
database. If the argument 'create' is passed with a true value, and the
477
authen_table argument is omitted, then a new empty table called 'authentication'
478
will be created in the database.
479
480
The SQL compatible table is currently as follows:
481
482
=over 8
483
484
=item C
485
486
Group of the user. This may signify authorization (trust) level, or could
487
be used to allow one authorization database to serve several applications
488
or sites.
489
490
=item C
491
492
User name
493
494
=item C
495
496
Password, as SHA digest
497
498
=item C
499
500
Full name of user
501
502
=item C
503
504
User email
505
506
=item C
507
508
Challenge question
509
510
=item C
511
512
Challenge answer
513
514
=item C
515
516
Row insertion timestamp
517
518
=item C
519
520
Row modification timestamp
521
522
=item C
523
524
Password modification timestamp
525
526
=item C
527
528
Internal use: key made of user and group--kept unique
529
530
=back
531
532
=over 4
533
534
For convenience, the database has fields to store for each user an email
535
address and a question and answer for user verification if a password is lost.
536
537
=back
538
539
=item B
540
541
If true in value, causes the named authen_table to be created if it was not
542
already present when the database was opened.
543
544
=item B
545
546
The password for the account. Not used by SQLite. Sometimes needed otherwise.
547
548
=item B
549
550
The name of the host for the database. Not used by SQLite.
551
Needed if the database is hosted on a remote server.
552
553
=item B
554
555
The algorithm used for the SHA digest. Currently supports SHA1 and SHA2.
556
B to SHA1. Supported values are 1 for SHA1, 256 for SHA-256,
557
384 for SHA-384, and 512 for SHA-512. See documentation for Digest::SHA for
558
more information. Given that in most cases SHA1 is much more random than most
559
user-typed passwords, any of the above algorithms should be more than
560
sufficient, since most attacks on passwords would likely be dictionary-based,
561
not purely brute force. In recognition that some uses of the package might use
562
long, random passwords, there is the option of up to 512-bit SHA2 digests.
563
564
=back
565
566
=item B
567
568
In version 0.16 and above, a random salt is added to the digest in order
569
to partially defeat hacking passwords with pre-computed rainbow tables.
570
To use later versions of Authen::Users with older SQL tables created by
571
previous versions, you MUST specify the named parameter NO_SALT => 1
572
in your call to new.
573
574
=item B
575
576
=item B
577
578
Authenticate a user. Users may have the same user name as long as they are not
579
also in the same authentication group. Therefore, the user's group should be
580
included in all calls to authenticate the user by password. Passwords are
581
stored as SHA digests, so the authentication is of the digests.
582
583
=item B
584
585
=item B
586
587
588
Add a user to the database. Synonym: B.
589
590
The arguments are as follows:
591
592
$authen->add_user($group, $user, $password, $fullname, $email, $question, $answer)
593
or die $authen->error;
594
595
=over 4
596
597
=item B
598
Scalar. The group of users. Used to classify authorizations, etc.
599
User names may be the same if the groups are different, but in any given group
600
the users must have unique names.
601
602
=item B
603
604
Scalar. User name.
605
606
=item B
607
608
Scalar. SHA digest of user's password.
609
610
=item B
611
612
Scalar. The user's 'real' or full name.
613
614
=item B
615
616
Scalar. User's email address.
617
618
=item B
619
620
Scalar. A question used, for example, for identifying the user if they lose their password.
621
622
=item B
623
624
Scalar. The correct answer to $question.
625
626
=back
627
628
Note: it is up to the user of the module to determine how the fields after group, user, and
629
password fields are used, or if they are used at all.
630
631
=item B
632
633
Update all fields for a given group and user:
634
635
$authen->update_user_all($group, $user, $password, $fullname, $email, $question, $answer) or die "Could not update $user: " . $authen->errstr();
636
637
=item B
638
639
$authen->update_user_password($group, $user, $password)
640
or die "Cannot update password for group $group and user $user: $authen->errstr";
641
642
Update the password.
643
644
=item B
645
646
$authen->update_user_fullname($group, $user, $fullname)
647
or die "Cannot update fullname for group $group and user $user: $authen->errstr";
648
649
Update the full name.
650
651
=item B
652
653
$authen->update_user_email($group, $user, $email)
654
or die "Cannot update email for group $group and user $user: $authen->errstr";
655
656
Update the email address.
657
658
=item B
659
660
$authen->update_user_question_answer($group, $user, $question, $answer) or die "Cannot update question and answer for group $group and user $user: $authen->errstr";
661
662
Update the challenge question and its answer.
663
664
=item B
665
666
$authen->delete_user($group, $user) or die "Cannot delete user in group $group with username $user: $authen->errstr";
667
668
Delete the user entry.
669
670
=item B
671
672
$authen->count_group($group) or die "Cannot count group $group: $authen->errstr";
673
674
Return the number of entries in group $group.
675
676
=item B
677
678
$authen->get_group_members($group) or die "Cannot retrieve list of group $group: $authen->errstr";
679
680
Return a reference to a list of the user members of group $group.
681
682
=item B
683
684
$authen->user_info($group, $user) or die "Cannot retrieve information about $user in group $group: $authen->errstr";
685
686
Return a reference to a list of the information about $user in $group.
687
688
=item B
689
690
my $href = $authen->user_info_hashref($group, $user) or die "Cannot retrieve information about $user in group $group: $authen->errstr";
691
print "The email for $user in $group is $href->{email}";
692
693
Return a reference to a hash of the information about $user in $group, with the field
694
names as keys of the hash.
695
696
=item B
697
698
$authen->get_user_fullname($group, $user) or die "Cannot retrieve full name of $user in group $group: $authen->errstr";
699
700
Return the user full name entry.
701
702
=item B
703
704
$authen->get_user_email($group, $user) or die "Cannot retrieve email of $user in group $group: $authen->errstr";
705
706
Return the user email entry.
707
708
=item B
709
710
$authen->get_user_question_answer($group, $user) or die "Cannot retrieve question and answer for $user in group $group: $authen->errstr";
711
712
Return the user question and answer entries.
713
714
=item B
715
716
$authen->get_password_change_time($group, $user)
717
or die "Cannot retrieve password timestamp for $user in group $group: $authen->errstr";
718
719
There is a timestamp associated with changes in passwords. This may be used to
720
expire passwords that need to be periodically changed. The logic used to do
721
password expiration, if any, is up to the code using the module.
722
723
=item B
724
725
print $auth->errstr();
726
727
Returns the last database error, if any.
728
729
=item B
730
731
print $auth->error;
732
733
Returns the last class internal error message, if any; if none, returns the
734
last database DBI error, if any.
735
736
=item B
737
738
$auth->not_in_table($group, $user);
739
740
True if $user in group $group is NOT already an entry.
741
Useful to rule out an existing user name when adding a user.
742
743
=item B
744
745
$auth->is_in_table($group, $user);
746
747
True if $user in group $group is already in the database.
748
749
=item B
750
751
$auth->validate($group, $user, $password);
752
753
True if the item is a valid entry; internal use
754
755
=back
756
757
=head1 BUGS
758
759
On installation, "make test" may fail if Perl support for MySql or SQLite is
760
installed, but the database itself is not running or is otherwise not available
761
for use by the installing user. MySql by default has a 'test' database which is
762
required under "make test." "Forcing" installation may work around this.
763
764
=head1 AUTHOR
765
766
William Herrera (wherrera@skylightview.com)
767
768
=head1 SUPPORT
769
770
Questions, feature requests and bug reports should go to wherrera@skylightview.com
771
772
=head1 COPYRIGHT
773
774
Copyright (C) 2004, 2008 William Hererra. All Rights Reserved.
775
776
This module is free software; you can redistribute it and/or modify it
777
under the same terms as Perl itself.
778
779
=cut
780
781
1;