1 package OpenILS::WWW::AccessHandler;
2 use strict; use warnings;
5 use Apache2::Const -compile => qw(:common HTTP_OK HTTP_FORBIDDEN HTTP_MOVED_TEMPORARILY HTTP_MOVED_PERMANENTLY);
6 use Apache2::RequestRec;
19 # Configuration options
21 # URL to redirect to for login
22 my $lurl = $r->dir_config('OILSAccessHandlerLoginURL') || '/eg/opac/login';
23 # Redirection variable to come "back" from the previous URL
24 my $lurlvar = $r->dir_config('OILSAccessHandlerLoginURLRedirectVar') || 'redirect_to';
25 # No access page? If not set, just return forbidden.
26 my $failurl = $r->dir_config('OILSAccessHandlerFailURL');
27 # Required permission (if set)
28 my $userperm = $r->dir_config('OILSAccessHandlerPermission');
29 # Need to be in good standing?
30 my $userstanding = $r->dir_config('OILSAccessHandlerGoodStanding') || 0;
31 # Required org unit (if set)
32 my $userou = $r->dir_config('OILSAccessHandlerHomeOU');
33 # OU for permission/standing checks, if not set use home OU
34 my $checkou = $r->dir_config('OILSAccessHandlerCheckOU');
35 # Set referrer based on OU Setting?
36 my $referrersetting = $r->dir_config('OILSAccessHandlerReferrerSetting');
38 my $url = $r->construct_url();
40 # push everyone to the secure site
41 if ($url =~ /^http:/o) {
42 my $target = $r->construct_url($r->unparsed_uri);
43 $target =~ s/^http:/https:/o;
44 $r->headers_out->set(Location => $target);
45 return Apache2::Const::HTTP_MOVED_PERMANENTLY;
48 # We could use CGI....but that creates issues if post data may be submitted
49 my $auth_ses = ($r->headers_in->get('Cookie') =~ /(?:^|\s)ses=([^;]*)/)[0];
50 $auth_ses = ($r->headers_in->get('Cookie') =~ /(?:^|\s)eg.auth.token=%22([^;]*)%22/)[0] unless $auth_ses;
51 my $user = _verify_login($auth_ses);
53 if (!defined($user)) {
54 my $redirect = $r->construct_url($r->unparsed_uri);
55 my $target = $r->construct_url($lurl) . '?' . $lurlvar . '=' . uri_escape($redirect);
56 $target =~ s/^http:/https:/o; # This should never be needed due to the redirect above, but better safe than sorry
57 $r->headers_out->set(Location => $target);
58 # Lets not cache this either, just in case.
59 $r->headers_out->set('Cache-Control' => 'no-cache, no-store, must-revalidate');
60 $r->headers_out->set(Pragma => 'no-cache');
61 $r->headers_out->set(Expires => 0);
62 return Apache2::Const::HTTP_MOVED_TEMPORARILY;
65 # Convert check OU from shortname, if needed
66 $checkou = _get_org_id($checkou);
68 # If we have no check OU at this point, use the user's home OU
69 $checkou ||= $user->home_ou;
74 my @permissions = split(/\s*[ ,]\s*/, $userperm);
75 $failed++ unless _verify_permission($auth_ses, $user, $checkou, \@permissions);
77 if (!$failed && $userstanding) {
78 $failed++ unless _verify_standing($user);
80 if (!$failed && $userou) {
81 $failed++ unless _verify_home_ou($user, $userou);
84 # If we failed one of the above checks they aren't allowed in
87 my $target = $r->construct_url($failurl);
88 $r->headers_out->set(Location => $target);
89 return Apache2::Const::HTTP_MOVED_TEMPORARILY;
91 return Apache2::Const::HTTP_FORBIDDEN;
95 # Forced referrer for some referrer auth services?
96 if ($referrersetting) {
97 my $referrervalue = _get_ou_setting($referrersetting, $checkou);
98 if ($referrervalue && $referrervalue->{value}) {
99 $r->headers_in->set('Referer', $referrervalue->{value});
103 # If we haven't thrown them out yet, let them through
104 return Apache2::Const::OK;
107 # "Private" functions
112 return undef unless $token;
114 my $user = OpenSRF::AppSession
115 ->create('open-ils.auth')
116 ->request('open-ils.auth.session.retrieve', $token)
119 if (ref($user) eq 'HASH' && $user->{ilsevent} == 1001) {
123 return $user if ref($user);
129 my ($org_identifier) = @_;
130 # Does this look like a number?
131 if ($org_identifier !~ '^[0-9]+$') {
133 if ($org_identifier) {
134 # Look up org unit by shortname
135 my $org_unit = OpenSRF::AppSession
136 ->create('open-ils.actor')
137 ->request('open-ils.actor.org_unit.retrieve_by_shortname', $org_identifier)
139 if ($org_unit && ref($org_unit) ne 'HASH') {
140 # We appear to have an org unit! So return the ID.
141 return $org_unit->id;
145 # Looks like a database ID, so leave it alone.
146 return $org_identifier;
148 # If we have reached this point, assume that we found no useful ID.
153 sub _verify_home_ou {
154 my ($user, $home_ou) = @_;
155 my $org_tree = OpenSRF::AppSession
156 ->create('open-ils.actor')
157 ->request('open-ils.actor.org_tree.ancestors.retrieve', $user->home_ou)
159 if ($org_tree && ref($org_tree) ne 'HASH') {
162 $user_orgs{$org_tree->id} = 1;
163 if ($org_tree->children) {
164 $org_tree = @{$org_tree->children}[0];
170 my @home_ous = split(/\s*[ ,]\s*/,$home_ou);
171 for my $cur_ou (@home_ous) {
172 $cur_ou = _get_org_id($cur_ou);
173 if ($user_orgs{$cur_ou}) {
182 sub _verify_permission {
183 my ($token, $user, $org_unit, $permissions) = @_;
185 my $failures = OpenSRF::AppSession
186 ->create('open-ils.actor')
187 ->request('open-ils.actor.user.perm.check', $token, $user->id, $org_unit, $permissions)
190 return !scalar(@$failures);
194 sub _verify_standing {
197 # If barred you are not in good standing
198 return 0 if $user->barred;
199 # If inactive you are also not in good standing
200 return 0 unless $user->active;
202 # Possible addition: Standing Penalty Checks?
207 sub _get_ou_setting {
208 my ($setting, $org_unit) = @_;
210 my $value = OpenSRF::AppSession->create('open-ils.actor')
211 ->request('open-ils.actor.ou_setting.ancestor_default', $org_unit, $setting)