package Apache2::TicketTool; use strict; use Apache2::RequestRec qw(user); use Apache2::Access (); use Apache2::ServerUtil (); use Apache2::Reload; use Apache2::Const -compile => qw(:log OK); use Apache2::Log (); use Apache2::URI qw(parse uri); use CGI::Cookie (); use Cluster::Loader; my %CACHE; # cache objects by their parameters to minimize time-consuming operations # Set up default parameters by passing in a request object sub new { my($class, $r) = @_; my %self = (); $self{TicketDomain} = '30'; $self{ServerName} = $r->server->server_hostname; ($self{TicketDomain} = $r->server->server_hostname) =~ s/^[^.]+//; bless(\%self,$class); } # TicketTool::authenticate() # ($result,$explanation) = $ticketTool->authenticate($user,$passwd) sub authenticate { my($self, $user, $passwd) = @_; my $entite =Cluster::Entite->retrieve( email => $user, passwd => $passwd, domain => $self->{TicketDomain}, ); unless (defined $entite) {return (undef, "password mismatch");} return (1, ''); } # TicketTool::fetch_secret() # Call as: # $ticketTool->fetch_secret(); sub fetch_secret { my $self = shift; unless ($self->{SECRET_KEY}) { $self->{SECRET_KEY} = "hlaghlaghlaghlag"; } $self->{SECRET_KEY}; } # invalidate the cached secret sub invalidate_secret { undef shift->{SECRET_KEY}; } # TicketTool::make_ticket() # Call as: # $cookie = $ticketTool->make_ticket($r); # sub make_ticket { my($self, $r, $user_name) = @_; my $ip_address = $r->connection->remote_ip; my $expires = $self->{TicketExpires}; my $now = time; my $secret = $self->fetch_secret() or return undef; # SHAKE IT... my $hash = MD5->hexhash($secret . MD5->hexhash(join ':', $secret, $ip_address, $now, $expires, $user_name) ); # ...BEFORE YOU BAKE IT ! return CGI::Cookie->new(-name => 'Ticket', -path => '/', -domain => $self->{TicketDomain}, -value => { 'ip' => $ip_address, 'time' => $now, 'user' => $user_name, 'hash' => $hash, 'expires' => $expires, }); } # TicketTool::verify_ticket() # ($result,$msg) = $ticketTool->verify_ticket($r) sub verify_ticket { my($self, $r) = @_; my %cookies = CGI::Cookie->parse($r->headers_in('Cookie')); # Got cookies ? unless (%cookies) { return (0, 'user has no cookies'); } unless ($cookies{'Ticket'}) { return (0, 'user has no ticket') } # Now we have a ticket my %ticket = $cookies{'Ticket'}->value; unless ( $ticket{'hash'} && $ticket{'user'} && $ticket{'time'} && $ticket{'expires'} ) { return (0, 'malformed ticket') } unless ($ticket{'ip'} eq $r->connection->remote_ip) { return (0, 'IP address mismatch in ticket') } unless ( (time - $ticket{'time'})/60 < $ticket{'expires'}) { return (0, 'ticket has expired') } my $secret; unless ($secret = $self->fetch_secret) { return (0, "can't retrieve secret") } # HLAGHLAGHLAGHLAG my $newhash = MD5->hexhash($secret . MD5->hexhash(join ':', $secret, @ticket{qw(ip time expires user)}) ); unless ($newhash eq $ticket{'hash'}) { $self->invalidate_secret; #maybe it's changed? return (0, 'ticket mismatch'); } $r->connection->user($ticket{'user'}); return (1, 'ok'); } # $cookie = $ticketTool->make_return_address() sub make_return_address { my($self, $r) = @_; my $uri = Apache2::URI->parse($r, $r->uri); $uri->scheme("http"); $uri->hostname($r->get_server_name); $uri->port($r->get_server_port); $uri->query(scalar $r->args); return CGI::Cookie->new ( -name => 'request_uri', -value => $uri->unparse, -domain => $self->{TicketDomain}, -path => '/' ); } 1; __END__