File Coverage

lib/Bio/Graphics/Browser2/AuthorizedFeatureFile.pm
Criterion Covered Total %
statement 7 9 77.7
branch n/a
condition n/a
subroutine 3 3 100.0
pod n/a
total 10 12 83.3


line stmt bran cond sub pod time code
1             package Bio::Graphics::Browser2::AuthorizedFeatureFile;
2              
3 6     6   27 use strict;
  6         7  
  6         125  
4 6     6   18 use warnings;
  6         7  
  6         164  
5 6     6   2292 use Bio::Graphics 2.24;
  0            
  0            
6             use base 'Bio::Graphics::FeatureFile';
7              
8             use Socket 'AF_INET','inet_aton'; # for inet_aton() call
9             use Carp 'croak','cluck';
10             use CGI();
11              
12             =head1 NAME
13              
14             Bio::Graphics::Browser2::AuthorizedFeatureFile -- Add HTTP authorization features to FeatureFile
15              
16             =head1 SYNOPSIS
17              
18             GBrowse internal module.
19              
20             =head1 DESCRIPTION
21              
22             GBrowse internal module.
23              
24             =head2 METHODS
25              
26             =over 4
27              
28             =cut
29              
30             # override setting to default to 'general'
31             sub setting {
32             my $self = shift;
33             my ($label,$option,@rest) = @_ >= 2 ? @_ : ('general',@_);
34             $label ||= 'general';
35             $label = 'general' if lc $label eq 'general'; # buglet
36             $self->SUPER::setting($label,$option,@rest);
37             }
38              
39             sub label_options {
40             my $self = shift;
41             my $label = shift;
42             return $self->SUPER::_setting($label);
43             }
44              
45             # get or set the authenticator used to map usernames onto groups
46             sub set_authenticator {
47             my $self = shift;
48             $self->{'.authenticator'} = shift;
49             }
50             sub authenticator {
51             shift->{'.authenticator'};
52             }
53              
54             # get or set the username used in authentication processes
55             sub set_username {
56             my $self = shift;
57             my $username = shift;
58             $self->{'.authenticated_username'} = $username;
59             }
60              
61             sub username {
62             my $self = shift;
63             return $self->{'.authenticated_username'} || CGI->remote_user;
64             }
65              
66             # implement the "restrict" option
67             sub authorized {
68             my $self = shift;
69             my $label = shift;
70            
71             my $restrict = $self->code_setting($label=>'restrict')
72             || ($label ne 'general' && $self->code_setting('TRACK DEFAULTS' => 'restrict'));
73             return 1 unless $restrict;
74              
75             my $host = CGI->remote_host;
76             my $addr = CGI->remote_addr;
77             my $user = $self->username;
78              
79             undef $host if $host eq $addr;
80             return $restrict->($host,$addr,$user) if ref $restrict eq 'CODE';
81             my @tokens = split /\s*(satisfy|order|allow from|deny from|require user|require group|require valid-user)\s*/i,$restrict;
82             shift @tokens unless $tokens[0] =~ /\S/;
83             my $mode = 'allow,deny';
84             my $satisfy = 'all';
85             my $user_directive;
86              
87             my (@allow,@deny,%users);
88             while (@tokens) {
89             my ($directive,$value) = splice(@tokens,0,2);
90             $directive = lc $directive;
91             $value ||= '';
92             if ($directive eq 'order') {
93             $mode = $value;
94             next;
95             }
96             my @values = split /[^\w.@-]/,$value;
97              
98             if ($directive eq 'allow from') {
99             push @allow,@values;
100             next;
101             }
102             if ($directive eq 'deny from') {
103             push @deny,@values;
104             next;
105             }
106             if ($directive eq 'satisfy') {
107             $satisfy = $value;
108             next;
109             }
110             if ($directive eq 'require user') {
111             $user_directive++;
112             foreach (@values) {
113             if ($_ eq 'valid-user' && defined $user) {
114             $users{$user}++; # ensures that this user will match
115             } else {
116             $users{$_}++;
117             }
118             }
119             next;
120             }
121             if ($directive eq 'require valid-user') {
122             $user_directive++;
123             $users{$user}++ if defined $user;
124             }
125             if ($directive eq 'require group' && defined $user) {
126             $user_directive++;
127             if (my $auth_plugin = $self->authenticator) {
128             for my $grp (@values) {
129             $users{$user} ||= $auth_plugin->user_in_group($user,$grp);
130             }
131             } else {
132             warn "To use the 'require group' limit you must load an authentication plugin. Otherwise use a subroutine to implement role-based authentication.";
133             }
134             }
135             }
136              
137             my $allow = $mode eq 'allow,deny' ? match_host(\@allow,$host,$addr) && !match_host(\@deny,$host,$addr)
138             : 'deny,allow' ? !match_host(\@deny,$host,$addr) || match_host(\@allow,$host,$addr)
139             : croak "$mode is not a valid authorization mode";
140             return $allow unless $user_directive;
141             $satisfy = 'any' if !@allow && !@deny; # no host restrictions
142              
143             # prevent unint variable warnings
144             $user ||= '';
145             $allow ||= '';
146             $users{$user} ||= '';
147              
148             return $satisfy eq 'any' ? $allow || $users{$user}
149             : $allow && $users{$user};
150             }
151              
152             sub match_host {
153             my ($matches,$host,$addr) = @_;
154             my $ok;
155             for my $candidate (@$matches) {
156             if ($candidate eq 'all') {
157             $ok ||= 1;
158             } elsif ($candidate =~ /^[\d.]+$/) { # ip match
159             $addr .= '.' unless $addr =~ /\.$/; # these lines ensure subnets match correctly
160             $candidate .= '.' unless $candidate =~ /\.$/;
161             $ok ||= $addr =~ /^\Q$candidate\E/;
162             } else {
163             $host ||= gethostbyaddr(inet_aton($addr),AF_INET);
164             next unless $host;
165             $candidate = ".$candidate" unless $candidate =~ /^\./; # these lines ensure domains match correctly
166             $host = ".$host" unless $host =~ /^\./;
167             $ok ||= $host =~ /\Q$candidate\E$/;
168             }
169             return 1 if $ok;
170             }
171             $ok;
172             }
173              
174             1;
175