File Coverage

blib/lib/CGI/Builder/Auth/Realm.pm
Criterion Covered Total %
statement 123 139 88.4
branch 30 48 62.5
condition 24 59 40.6
subroutine 28 35 80.0
pod 5 6 83.3
total 210 287 73.1


line stmt bran cond sub pod time code
1             package CGI::Builder::Auth::RealmDef;
2 4     4   901 use Carp;
  4         5  
  4         316  
3              
4 4     4   22 use strict;
  4         6  
  4         126  
5 4     4   747 use CGI::Builder::Auth::RealmManager;
  4         6  
  4         244  
6 4     4   20 use vars qw($VERSION);
  4         9  
  4         267  
7              
8             $VERSION = $CGI::Builder::Auth::Realm::VERSION = 1.52;
9              
10 4     4   8387 use overload '""'=>\&name;
  4         5072  
  4         38  
11              
12             sub new {
13 12     12   21 my ($class,$name) = @_;
14 12         43 return bless { 'name' => $name },$class;
15             }
16              
17             sub userdb {
18 18     18   23 my $self = shift;
19 18   33     99 return $self->{users} || $self->{userfile};
20             }
21              
22             sub groupdb {
23 10     10   14 my $self = shift;
24 10   33     56 return $self->{groups} || $self->{groupfile};
25             }
26              
27             # backwards compatability only
28 0     0   0 sub userfile { return &userdb; }
29 0     0   0 sub groupfile { return &groupdb; }
30              
31             sub mode {
32 3   50 3   29 return shift->{mode} || 0644;
33             }
34              
35             sub database {
36 1   50 1   11 return shift->{database} || "www\@localhost";
37             }
38              
39             #
40             # added by John Porter:
41             #
42             sub dblogin {
43 1     1   4 return shift->{dblogin};
44             }
45             sub dbpassword {
46 1     1   3 return shift->{dbpassword};
47             }
48              
49             sub fields {
50 1     1   5 return shift->{fields};
51             }
52              
53             sub usertype {
54 18     18   23 my $self = shift;
55 18   33     113 return $self->{usertype} || $self->{type};
56             }
57              
58             sub grouptype {
59 5     5   7 my $self = shift;
60 5   33     38 return $self->{grouptype} || $self->{type};
61             }
62              
63             sub authentication {
64 10   100 10   87 return shift->{'authentication'} || 'Basic';
65             }
66              
67             sub driver {
68 0   0 0   0 return shift->{'driver'} || 'mSQL';
69             }
70              
71             sub server {
72 4   50 4   48 return shift->{'server'} || 'apache';
73             }
74              
75             sub crypt {
76 9     9   23 my $self = shift;
77 9 50       22 return $self->{'crypt'} if $self->{'crypt'};
78 9 50       520 return 'crypt' if lc($self->authentication) eq 'basic';
79 0 0       0 return 'MD5' if lc($self->authentication) eq 'digest';
80 0         0 return 'crypt'; # default currently
81             }
82              
83             sub name {
84 185     185   443 return shift->{'name'};
85             }
86              
87             # return a pointer to an associative array with mSQL info.
88             # it will contain the keys:
89             # host name of the database host
90             # database name of the database
91             # dblogin
92             # dbpassword
93             # usertable name of the table that user/passwd/other info is in
94             # grouptable name of the table containing user/group pairs
95             # userfield name of the user field (both tables)
96             # groupuserfield
97             # groupfield name of the group field (group table only)
98             # passwdfield name of the password field (user table only)
99             # userfield_len length of the user field
100             # groupfield_len length of the group field
101             # passwdfield_len length of the password field
102             sub SQLdata {
103 1     1   3 my $self = shift;
104 1 50       5 return undef unless $self->usertype=~/sql/i;
105 1         87 my ($u,$g) = ($self->split_parms($self->userdb),$self->split_parms($self->groupdb));
106 1         2 my %result;
107 1         7 @result{qw(database host)} = split('@',$self->database);
108 1   50     5 $result{host} ||= 'localhost';
109             #
110             # Do what Lincoln didn't:
111 1         5 $result{dblogin} = $self->dblogin;
112 1         4 $result{dbpassword} = $self->dbpassword;
113             #
114 1   50     6 $result{usertable} = $u->{table} || 'users';
115 1         12 $result{grouptable} = $g->{table}; # no default
116 1   50     8 $result{userfield} = $u->{uid} || $g->{uid} || 'users';
117 1   50     8 $result{groupuserfield} = $g->{uid} || $u->{uid} || 'users';
118 1         3 $result{groupfield} = $g->{group};
119 1   50     7 $result{passwdfield} = $u->{password} || 'password';
120 1   50     14 $result{userfield_len} = $u->{uid_len} || $u->{user_len} || 12;
121 1   50     5 $result{groupfield_len} = $g->{group_len} || 20;
122 1   33     11 $result{passwdfield_len}= $u->{password_len} ||
123             (lc($self->authentication) eq 'digest' ? 32 + 3 + length($self->name) + $result{userfield_len} : 13);
124 1         16 return \%result;
125             }
126              
127             sub connect {
128 3     3   6 my $self = shift;
129 3         16 my ($writable,$mode,$server) = rearrange([[qw(WRITABLE WRITE MODIFY)],qw(MODE SERVER)],@_);
130              
131 3   33     22 return new CGI::Builder::Auth::RealmManager(-realm => $self,
      50        
132             -writable => $writable,
133             '-mode' => $mode || $self->mode,
134             '-server' => $server || $self->server || 'apache');
135             }
136              
137             # A utility routine
138             sub split_parms {
139 2     2   5 my($self,$j) = @_;
140 2         31 my($junk,%p) = split(/\s*(\w+)=/,$j);
141 2         8 foreach (keys %p) {
142 6         21 $p{$_}=~s/^"//;
143 6         17 $p{$_}=~s/"$//;
144 6 100       25 if ($p{$_}=~/:[a-zA-Z]?(\d+)$/) {
145 4         19 $p{$_}=$`;
146 4         60 $p{"${_}_len"}=$1;
147             }
148             }
149 2         10 \%p;
150             }
151              
152             # ----------------------------------------------------------------------------------------
153             package CGI::Builder::Auth::Realm;
154              
155 4     4   4597 use strict;
  4         8  
  4         155  
156 4     4   20 use CGI::Builder::Auth::RealmManager;
  4         6  
  4         222  
157 4     4   19 use Carp;
  4         19  
  4         4540  
158              
159             *dbm = \&connect;
160              
161             my %CACHE;
162              
163             my %VALID_DIRECTIVES = (
164             'dblogin' =>1,
165             'dbpassword' =>1,
166             'users' =>1, # file or table of user/passwd info
167             'groups' =>1, # file or table of user/group info
168             'database' =>1, # database name (SQL only)
169             'fields' =>1, # other fields (SQL only)
170             'type' =>1, # db type (text|NDBM|DB|mSQL|SQL)
171             'driver' =>1, # SQL db driver type [mSQL]
172             'usertype' =>1, # override db type for users only
173             'grouptype' =>1, # override db type for groups only
174             'default' =>1, # set default realm
175             'authentication' =>1, # authentication scheme (Basic|Digest)
176             'server' =>1, # server type (Apache|NCSA|Netscape)
177             'mode' =>1, # mode for newly-created text & DBM files
178             'crypt' =>1, # override encryption, backward compatability only
179             'userfile' =>1, # synonyms for backward compatability only
180             'groupfile' =>1, # synonyms for backward compatability only
181             );
182              
183             # Security realm parsing utility -- high level interface to Doug MacEachern's
184             # HTTPD utilities.
185              
186             # Pass the location of the configuration file.
187             sub new {
188 3     3 1 36 my $class = shift;
189 3         18 my ($config_file) = rearrange([[qw(CONFIG CONFIG_FILE)]],@_);
190              
191 3 100 66     32 if ($CACHE{$config_file} && -C $config_file == $CACHE{$config_file}{ctime}) {
192 1         7 return $CACHE{$config_file}{obj};
193             }
194              
195 2         24 my $self = { config_file => $config_file, };
196              
197 2         4 my($realm,$realm_name,$directive,$value,$default_realm,$first_realm);
198 2 50       77 open(CONF,$config_file) || croak "Couldn't open $config_file: $!";
199 2         51 while () {
200 94         97 chomp;
201 94         106 s/\#.*$//; # get rid of all comments
202              
203 94 100       188 if (//i) {
204 12 50       25 croak "Syntax error in $config_file, line $.: Missing directive.\n"
205             if $realm;
206 12 50       30 croak "Syntax error in $config_file, line $.: directive without realm name.\n"
207             unless $1;
208 12         38 $realm = new CGI::Builder::Auth::RealmDef($realm_name = $1);
209 12 100       23 $first_realm = $realm unless $first_realm;
210 12         45 next;
211             }
212              
213 82 100       151 if (/<\/Realm\s*>/i) {
214 12 50       21 croak "Syntax error in $config_file, line $.: seen without preceding directive.\n"
215             unless $realm;
216 12 50 33     28 croak "Incomplete definition for realm $realm. Need Users and Type directives at line $.\n"
217             unless $realm->userdb && $realm->usertype;
218 12         32 $self->{realms}->{$realm_name}=$realm;
219 12         11 undef $realm;
220 12         13 undef $realm_name;
221 12         58 next;
222             }
223              
224 70 100       306 next unless ($directive,$value) = /(\w+)\s*(.*)/;
225 60 50       182 croak "Syntax error in $config_file, line $.: $directive directive without preceding tag.\n"
226             unless $realm;
227            
228 60         69 $directive=~tr/A-Z/a-z/;
229 60 50       139 croak "Unknown directive \"$directive\" at line $.\n"
230             unless $VALID_DIRECTIVES{$directive};
231              
232 60 50       140 $realm->{$directive} = $directive =~ /file/ ? untaint($value) : $value;
233 60 100       186 if ($directive eq 'default') {
234 2 50       7 croak "More than one Default directive defined at $config_file, line $.\n"
235             if $default_realm;
236 2         13 $default_realm = $realm_name;
237             }
238              
239             }
240 2         18 close CONF;
241              
242 2   33     8 $self->{default_realm}=$default_realm || $first_realm;
243 2         563 bless $self,$class;
244 2         32 $CACHE{$config_file}{ctime} = -C $config_file;
245 2         11 return $CACHE{$config_file}{obj} = $self;
246             }
247              
248             sub connect {
249 2     2 1 3 my $self = shift;
250 2         11 my ($writable,$realm,$mode) = rearrange([[qw(WRITABLE WRITE MODIFY)],qw(REALM MODE)],@_);
251 2         8 my $r = $self->realm($realm);
252 2 50       7 die "Unknown realm $realm" unless ref($r);
253 2         2 my(@p);
254 2 100       6 push(@p,'-writable'=>$writable) if $writable;
255 2 50       5 push(@p,'-mode'=>$mode) if $mode;
256 2         6 return $r->connect(@p);
257             }
258              
259             sub exists {
260 0     0 1 0 my $self = shift;
261 0         0 my ($realm) = rearrange(['REALM'],@_);
262 0         0 return defined($self->{realms}->{$realm});
263             }
264              
265             sub list {
266 0     0 1 0 my $self = shift;
267 0         0 return sort keys %{$self->{realms}};
  0         0  
268             }
269              
270             sub realm {
271 6     6 1 11 my $self = shift;
272 6         27 my ($realm) = rearrange(['REALM'],@_);
273 6   33     19 $realm ||= $self->{default_realm};
274 6         24 return $self->{realms}->{$realm};
275             }
276              
277             sub untaint {
278 0     0 0   my $taint = shift;
279 0 0 0       croak('Relative paths are not allowed in password and/or group file definitions')
280             if $taint =~ /\.\./ or $taint !~ m|^/|;
281 0           $taint =~ m!(/[a-zA-Z/0-9._-]+)!;
282 0           return $1;
283             }
284              
285             sub DESTROY {
286 0     0     my $self = shift;
287             }
288              
289              
290             1;
291              
292             __END__