Skip to content

Commit 6c09727

Browse files
committed
added the mod_perl stuff
0 parents  commit 6c09727

File tree

4 files changed

+402
-0
lines changed

4 files changed

+402
-0
lines changed

mod_perl/GodAuth.pm

+326
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,326 @@
1+
package GodAuth;
2+
3+
use warnings;
4+
use strict;
5+
6+
use GodAuthConfig;
7+
use Apache2::RequestRec ();
8+
use Apache2::Connection;
9+
use Apache2::Const -compile => qw(OK REDIRECT REMOTE_NOLOOKUP FORBIDDEN);
10+
use APR::Table;
11+
use Digest::SHA1 qw(sha1_hex);
12+
use MIME::Base64;
13+
use Data::Dumper;
14+
15+
use Sys::Hostname;
16+
17+
our $last_reload_time = time();
18+
our $reload_timeout = 60; # per apache process!
19+
20+
$| = 1;
21+
22+
##############################################################################################################
23+
24+
sub handler {
25+
26+
#
27+
# get URL
28+
#
29+
30+
my $r = shift;
31+
32+
my $domain = $r->headers_in->{'Host'} || 'UNKNOWN-HOST';
33+
my $path = $r->unparsed_uri;
34+
35+
my $host = hostname;
36+
37+
$ENV{GodAuth_User} = '';
38+
39+
my $url = $domain . $path;
40+
my $log = "$$ URL : $url";
41+
42+
43+
#########################################################
44+
#
45+
# reload the config?
46+
#
47+
48+
if (time() - $GodAuth::last_reload_time > $GodAuth::reload_timeout){
49+
50+
&GodAuth::reload_config();
51+
$GodAuth::last_reload_time = time();
52+
}
53+
54+
55+
#########################################################
56+
#
57+
# 1) check we have a cookie secret
58+
#
59+
if (!$GodAuthConfig::CookieSecret){
60+
$GodAuthConfig::CookieSecret = 'nottherightsecret';
61+
}
62+
63+
64+
#########################################################
65+
#
66+
# 1) determine if we need to perform access control for this url
67+
#
68+
69+
my $allow = 'none';
70+
71+
for my $obj (@{$GodAuthConfig::PermMap}){
72+
73+
if ($url =~ $obj->{url}){
74+
75+
$allow = $obj->{who};
76+
last;
77+
}
78+
}
79+
80+
$log .= " $allow";
81+
82+
83+
#########################################################
84+
#
85+
# 2) we might need auth - see if we have a valid cookie
86+
#
87+
88+
my $cookie_is_valid = 0;
89+
my $cookie_user = '?';
90+
my $cookie_roles = '_';
91+
92+
my $cookie_is_old = 0;
93+
my $cookie_age = 0;
94+
my $cookie_is_future = 0;
95+
96+
my $cookies = &parse_cookie_jar($r->headers_in->{'Cookie'});
97+
98+
my $cookie = $cookies->{$GodAuthConfig::CookieName};
99+
100+
if ($cookie){
101+
102+
my ($user, $roles, $ts, $hmac) = split '-', $cookie, 4;
103+
104+
my $ua = $r->headers_in->{'User-Agent'};
105+
106+
if ($ua =~ /AppleWebKit/) {
107+
$ua = "StupidAppleWebkitHacksGRRR";
108+
}
109+
$ua =~ s/ FirePHP\/\d+\.\d+//;
110+
111+
my $raw = "$user-$roles-$ts-$ua";
112+
113+
#&xlog("COOKIE: $cookie $raw\n");
114+
115+
my $hmac2 = sha1_hex( $GodAuthConfig::CookieSecret . $raw );
116+
117+
if ($hmac eq $hmac2){
118+
119+
#
120+
# check that our cookie isn't too old
121+
#
122+
123+
$cookie_age = time() - $ts;
124+
$ENV{GodAuth_Cookie_Age} = $cookie_age;
125+
126+
if ($ts < time() - 8 * 60 * 60 && $user !~ /\:/){
127+
128+
#
129+
# cookie is old (only for non-alpha users
130+
#
131+
132+
$cookie_is_old = 1;
133+
$cookie_age = time() - $ts;
134+
135+
$log .= " (bad cookie ts $ts - it's too old - $cookie_age seconds)";
136+
137+
}elsif ($ts > time() + 5 * 60){
138+
139+
#
140+
# cookie starts in the future - wtf
141+
#
142+
143+
$cookie_is_future = 1;
144+
145+
$log .= " (bad cookie ts $ts - it starts in the future)";
146+
147+
}else{
148+
149+
$cookie_is_valid = 1;
150+
$cookie_user = $user;
151+
$cookie_roles = $roles;
152+
153+
$r->headers_in->set('GodAuth-User', $cookie_user);
154+
$r->headers_in->set('GodAuth-Roles', $cookie_roles);
155+
156+
$ENV{GodAuth_User} = $cookie_user;
157+
$ENV{GodAuth_Roles} = $cookie_roles;
158+
159+
$r->notes->add("GodAuth_User" => $cookie_user);
160+
$r->notes->add("GodAuth_Roles" => $cookie_roles);
161+
162+
$log .= " (cookie: $cookie_user $cookie_roles)";
163+
}
164+
}else{
165+
$log .= " (bad cookie hmac [$GodAuthConfig::CookieSecret$user-$ts-$ua] -> $hmac2 vs $hmac)";
166+
}
167+
}else{
168+
$log .= " (no cookie)";
169+
}
170+
171+
&xlog($log."\n");
172+
173+
174+
#########################################################
175+
#
176+
# 3) exit now if we got an 'all'
177+
#
178+
179+
if (ref $allow ne 'ARRAY'){
180+
if ($allow eq 'all'){
181+
182+
return Apache2::Const::OK;
183+
}
184+
}
185+
186+
187+
#########################################################
188+
#
189+
# 4) if we don't have a valid cookie, redirect to the auther
190+
#
191+
192+
if (!$cookie){
193+
return &redir($r, $url, $GodAuthConfig::FailNeedsAuth);
194+
}
195+
196+
if ($cookie_is_old){
197+
return &redir($r, $url, $GodAuthConfig::FailCookieOld);
198+
}
199+
200+
if ($cookie_is_future){
201+
return &redir($r, $url, $GodAuthConfig::FailCookieFuture);
202+
}
203+
204+
if (!$cookie_is_valid){
205+
return &redir($r, $url, $GodAuthConfig::FailCookieInvalid);
206+
}
207+
208+
209+
#########################################################
210+
#
211+
# 5) exit now for authed
212+
#
213+
214+
if (ref $allow ne 'ARRAY'){
215+
if ($allow eq 'authed'){
216+
217+
return Apache2::Const::OK;
218+
}
219+
}
220+
221+
222+
#########################################################
223+
#
224+
# 5) now we need to match usernames and/or roles
225+
#
226+
227+
# get arrayref of allowed roles
228+
unless (ref $allow eq 'ARRAY'){
229+
$allow = [$allow];
230+
}
231+
232+
# get arrayref of our roles
233+
my $matches = [$cookie_user];
234+
for my $role(split /,/, $cookie_roles){
235+
if ($role ne '_'){
236+
push @{$matches}, 'role:'.$role;
237+
}
238+
}
239+
240+
241+
for my $a (@{$allow}){
242+
for my $b (@{$matches}){
243+
244+
if ($a eq $b){
245+
return Apache2::Const::OK;
246+
}
247+
}
248+
}
249+
250+
251+
#
252+
# send the user to the not-on-list page
253+
#
254+
255+
return &redir($r, $url, $GodAuthConfig::FailNotOnList);
256+
}
257+
258+
##############################################################################################################
259+
260+
sub redir {
261+
my ($r, $ref, $url) = @_;
262+
263+
$ref = &urlencode('http://'.$ref);
264+
$url .= ($url =~ /\?/) ? "&ref=$ref" : "?ref=$ref";
265+
266+
$r->headers_out->set('Location', $url);
267+
return Apache2::Const::REDIRECT;
268+
}
269+
270+
##############################################################################################################
271+
272+
sub xlog {
273+
return unless $GodAuthConfig::LogFile;
274+
open F, '>>'.$GodAuthConfig::LogFile;
275+
print F $_[0];
276+
close F;
277+
}
278+
279+
##############################################################################################################
280+
281+
sub parse_cookie_jar {
282+
my ($jar) = @_;
283+
284+
return {} unless defined $jar;
285+
286+
my @bits = split /;\s*/, $jar;
287+
my $out = {};
288+
for my $bit (@bits){
289+
my ($k, $v) = split '=', $bit, 2;
290+
$k = &urldecode($k);
291+
$v = &urldecode($v);
292+
$out->{$k} = $v;
293+
}
294+
return $out;
295+
}
296+
297+
##############################################################################################################
298+
299+
sub urldecode {
300+
$_[0] =~ s!\+! !g;
301+
$_[0] =~ s/%([a-fA-F0-9]{2,2})/chr(hex($1))/eg;
302+
return $_[0];
303+
}
304+
305+
sub urlencode {
306+
$_[0] =~ s!([^a-zA-Z0-9-_ ])! sprintf('%%%02x', ord $1) !gex;
307+
$_[0] =~ s! !+!g;
308+
return $_[0];
309+
}
310+
311+
##############################################################################################################
312+
313+
sub reload_config {
314+
open F, "/usr/local/wwwGodAuth/GodAuthConfig.pm";
315+
my $data = '';
316+
while (<F>){
317+
$data .= $_;
318+
}
319+
close F;
320+
eval $data;
321+
}
322+
323+
##############################################################################################################
324+
325+
1;
326+

mod_perl/GodAuthConfig.pm

+71
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
package GodAuthConfig;
2+
3+
our $LogFile = '/usr/local/wwwGodAuth/auth_log.txt';
4+
our $CookieName = 'ga';
5+
our $CookieSecret = '07a8789e03e21147e09b69f21cd38a8b';
6+
our $FailCookieOld = 'http://auth.myapp.com/login/?fail=old';
7+
our $FailCookieFuture = 'http://auth.myapp.com/login/?fail=future';
8+
our $FailCookieInvalid = 'http://auth.myapp.com/login/?fail=invalid';
9+
our $FailNotOnList = 'http://auth.myapp.com/status/?fail=notonlist';
10+
our $FailNeedsAuth = 'http://auth.myapp.com/login/';
11+
our $FailConfig = 'http://auth.myapp.com/?fail=unknownconfig';
12+
13+
14+
#
15+
# the first matching rule is used, so put sub-folders before
16+
# the root!
17+
#
18+
19+
our $PermMap = [
20+
21+
22+
#
23+
# URLs with no auth
24+
#
25+
26+
{
27+
url => qr!^www\.myapp\.com/!,
28+
who => 'all',
29+
},
30+
31+
32+
#
33+
# URLs that require a role
34+
#
35+
36+
{
37+
url => qr!^dev\.myapp\.com/!,
38+
who => 'role:staff',
39+
},
40+
41+
42+
#
43+
# URLs only for certain users
44+
#
45+
46+
{
47+
url => qr!^debug\.myapp\.com/!,
48+
who => 'cal',
49+
},
50+
51+
52+
#
53+
# combinations are fine too
54+
#
55+
56+
{
57+
url => qr!^debug2\.myapp\.com/!,
58+
who => ['role:devel', 'cal', 'myles'],
59+
},
60+
61+
62+
#
63+
# anyone with a valid auth token
64+
#
65+
66+
{
67+
url => qr!^debug2\.myapp\.com/!,
68+
who => 'authed',
69+
},
70+
71+
];

0 commit comments

Comments
 (0)