# ODP::Passport - ODP::Passport client module (Version 0.01) # Copyright (C)2002-2004 Richard P. Fuller # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA package ODP::Passport; use strict; use ODP::Passport::HTML; use ODP::Passport::Key; use CGI::Cookie; use CGI qw(:standard); use URI::Escape; use ODP::Stradivarius(); # No trailing slash (was: http://passport.rpfuller.com) $ODP::Passport::ServerURL = "http://passport.dmoz.org"; # new - Initialises a new ODP::Passport object # Parameters: none # Returns: none sub new () { my $object = {}; return bless $object; } # checklogin - Checks if the user is logged in validly, if so, continue, else display need to log in box # Parameters: secret, pp_cat, pp_tool, godirect, privs required # Returns: none sub checklogin() { my $self = shift; my $secret = $_[0]; my $pp_cat = $_[1]; my $pp_tool = $_[2]; my $godirect = $_[3]; my $privsreq = $_[4]; my $ppconfig = $_[5]; my $pagename = $_[6]; my $user; my $i_key; my $issued; my $privs; my %cookies = fetch CGI::Cookie; if ($cookies{'user'}) { $user = $cookies{'user'}->value; } if ($cookies{'key'}) { $i_key = $cookies{'key'}->value; } if ($cookies{'issued'}) { $issued = $cookies{'issued'}->value; } if ($cookies{'privs'}) { $privs = $cookies{'privs'}->value; } # Do the language stuff here # We'll happily accept whatever language the user has passed, even if they're an evil would be hacker # So we can give them the failure messages in their language (aren't we kind?) my $language; if ($cookies{'language'}) { $self->initialise_strings($cookies{'language'}->value); $language = $cookies{'language'}->value; } else { $self->initialise_strings('eng'); $language = 'eng'; } my $key = new ODP::Passport::Key ($user, $secret, $issued, $privs); if ($key->isvalidkey($i_key) && ($issued + 86400) >= time()) { if ($ppconfig && $self->isblocked($ppconfig, $user)) { print header(-expires=>'-1d',-type=>'text/html; charset=UTF-8').ODP::Passport::HTML::insufficientprivs($self->{'strings'}); exit; } # For apache basic authentication compatability $ENV{'REMOTE_USER'} = $user; # Priv env variable $ENV{'PP_PRIVS'} = $privs; # Issued env variable $ENV{'PP_ISSUED'} = $issued; # Language env variable $ENV{'PP_LANGUAGE'} = $language; # Now check user has the required privileges if (!$privsreq) { return; } if ($privsreq eq 'e' && $self->iseditallplus()) { return; } if ($privsreq eq 'ce' && $self->canreadpeditall()) { return; } if ($privsreq eq 'j' && $self->canreadjmeta()) { return; } if ($privsreq eq 'k' && $self->canreadkmeta()) { return; } if ($privsreq eq 'm' && $self->canreadpmeta()) { return; } if ($privsreq eq 'k|m' && $self->issomekindofmeta()) { return; } if ($privsreq eq 'a' && $self->isadmin()) { return; } print header(-expires=>'-1d',-type=>'text/html; charset=UTF-8').ODP::Passport::HTML::insufficientprivs($self->{'strings'}); exit; } # User does not have a valid set of key cookies, display a need to login message and exit my $pp_param; foreach my $param (param()) { my $local_param = param($param); $local_param =~ s!\n!%0D%0A!g; $pp_param .= "&pp_p_$param=$local_param"; } if ($pagename) { $pp_param .= "&page=$pagename"; } if ($godirect) { print redirect(-expires=>'-1d',-uri=>"$ODP::Passport::ServerURL/?lang=$self->{'language'}&user=$user&pp_cat=$pp_cat&pp_tool=$pp_tool$pp_param"); } else { print header(-expires=>'-1d',-type=>'text/html; charset=UTF-8').ODP::Passport::HTML::needtologin("?lang=$self->{'language'}&pp_cat=$pp_cat&pp_tool=$pp_tool$pp_param", $self->{'strings'}); } exit; } # checklogin_nohalt - Checks if the user is logged in validly, and sets environment variables only # Parameters: secret, pp_cat, pp_tool # Returns: none sub checklogin_nohalt() { my $self = shift; my $secret = $_[0]; my $pp_cat = $_[1]; my $pp_tool = $_[2]; my $ppconfig = $_[3]; my $user; my $i_key; my $issued; my $privs; my %cookies = fetch CGI::Cookie; if ($cookies{'user'}) { $user = $cookies{'user'}->value; } if ($cookies{'key'}) { $i_key = $cookies{'key'}->value; } if ($cookies{'issued'}) { $issued = $cookies{'issued'}->value; } if ($cookies{'privs'}) { $privs = $cookies{'privs'}->value; } # Do the language stuff here # We'll happily accept whatever language the user has passed, even if they're an evil would be hacker # So we can give them the failure messages in their language (aren't we kind?) my $language; if ($cookies{'language'}) { $self->initialise_strings($cookies{'language'}->value); $language = $cookies{'language'}->value; } else { $self->initialise_strings('eng'); $language = 'eng'; } my $key = new ODP::Passport::Key ($user, $secret, $issued, $privs); if ($key->isvalidkey($i_key) && ($issued + 86400) >= time()) { if ($ppconfig && $self->isblocked($ppconfig, $user)) { return; } # For apache basic authentication compatability $ENV{'REMOTE_USER'} = $user; # Priv env variable $ENV{'PP_PRIVS'} = $privs; # Issued env variable $ENV{'PP_ISSUED'} = $issued; # Language env variable $ENV{'PP_LANGUAGE'} = $language; } } # login - Tries to login # Parameters: secret, user, key, issued, privs, (privsreq) # Returns: none sub login($$$$$$) { my $self = shift; my $secret = $_[0]; my $user = $_[1]; my $i_key = $_[2]; my $issued = $_[3]; my $privs = $_[4]; my $privsreq = $_[5]; my $ppconfig = $_[6]; # NOTE: language is not authenticated as part of the key # (Not that this should ever be a concern) my $language = CGI::param('language'); # Do the language stuff here # We'll happily accept whatever language the user has passed, even if they're an evil would be hacker # So we can give them the failure messages in their language (aren't we kind?) if ($language) { $self->initialise_strings($language); } else { $self->initialise_strings('eng'); $language = 'eng'; } my $key = new ODP::Passport::Key ($user, $secret, $issued, $privs); if ($key->isvalidkey($i_key)) { if ($user eq '!SYSTEM') { $self->system_call($ppconfig); exit; } if ($ppconfig && $self->isblocked($ppconfig, $user)) { print header(-expires=>'-1d',-type=>'text/html; charset=UTF-8').ODP::Passport::HTML::loginfailed($self->{'strings'}); exit; } # Set environment variables so we can use them in login.cgi as well as tools $ENV{'REMOTE_USER'} = $user; $ENV{'PP_PRIVS'} = $privs; $ENV{'PP_ISSUED'} = $issued; $ENV{'PP_LANGUAGE'} = $language; if (!$privsreq || ($privsreq eq 'e' && $self->iseditallplus()) || ($privsreq eq 'ce' && $self->canreadpeditall()) || ($privsreq eq 'j' && $self->canreadjmeta()) || ($privsreq eq 'k' && $self->canreadkmeta()) || ($privsreq eq 'm' && $self->canreadpmeta()) || ($privsreq eq 'k|m' && $self->issomekindofmeta()) || ($privsreq eq 'a' && $self->isadmin()) ) { # Login was valid my $cookie = new CGI::Cookie(-name=>'user', -value=>$user, -path=>'/', -expires=>'+1d'); my $cookie2 = new CGI::Cookie(-name=>'key', -value=>$i_key, -path=>'/', -expires=>'+1d'); my $cookie3 = new CGI::Cookie(-name=>'issued', -value=>$issued, -path=>'/', -expires=>'+1d'); my $cookie4 = new CGI::Cookie(-name=>'privs', -value=>$privs, -path=>'/', -expires=>'+1d'); my $cookie5 = new CGI::Cookie(-name=>'language', -value=>$language, -path=>'/', -expires=>'+1d'); print header(-expires=>'-1d',-type=>'text/html; charset=UTF-8',-cookie=>[$cookie,$cookie2,$cookie3,$cookie4,$cookie5]); return; } print header(-expires=>'-1d',-type=>'text/html; charset=UTF-8').ODP::Passport::HTML::insufficientprivs($self->{'strings'}); exit; } print header(-expires=>'-1d',-type=>'text/html; charset=UTF-8').ODP::Passport::HTML::loginfailed($self->{'strings'}); exit; } # logout - Logs out # Parameters: none # Returns: none sub logout() { my $self = shift; my $cookie = new CGI::Cookie(-name=>'user', -value=>'', -path=>'/', -expires=>'+1d'); my $cookie2 = new CGI::Cookie(-name=>'key', -value=>'', -path=>'/', -expires=>'+1d'); my $cookie3 = new CGI::Cookie(-name=>'issued', -value=>'', -path=>'/', -expires=>'+1d'); my $cookie4 = new CGI::Cookie(-name=>'privs', -value=>'', -path=>'/', -expires=>'+1d'); my $cookie5 = new CGI::Cookie(-name=>'language', -value=>'', -path=>'/', -expires=>'+1d'); print header(-expires=>'-1d',-type=>'text/html; charset=UTF-8',-cookie=>[$cookie,$cookie2,$cookie3,$cookie4,$cookie5]); print ODP::Passport::HTML::message($self->{'strings'}{'strings.ppclient.logged_out'}, $self->{'strings'}{'strings.ppclient.logged_out_txt'}."

ODP::Passport"); } # c_header - Returns the client CGI header # Parameters: Title # Returns: HTML sub c_header($) { my $self = shift; my $title = $_[0]; my $user; my $issued; my %cookies = fetch CGI::Cookie; if ($cookies{'user'}) { $user = $cookies{'user'}->value; } if ($cookies{'issued'}) { $issued = $cookies{'issued'} -> value; } my $expires = $issued + 86400; return ODP::Passport::HTML::c_header_html($title, $user, $expires, $self->{'strings'}); } # c_header - Returns the client CGI footer # Parameters: # Returns: HTML sub c_footer() { my $self = shift; return ODP::Passport::HTML::c_footer_html(); } # currentuser - Returns the current user # Parameters: none # Returns: user sub currentuser() { return $ENV{'REMOTE_USER'}; } # privileges - Returns privilege string # Parameters: none # Returns: privileges sub privileges() { return $ENV{'PP_PRIVS'}; } # language - Returns the user's chosen interface language # Parameters: none # Returns: language code sub language() { return $ENV{'PP_LANGUAGE'}; } # canreadpmeta - Returns whether or not the user can read pmeta # Parameters: none # Returns: boolean sub canreadpmeta() { if ($ENV{'PP_PRIVS'} =~ / root / || $ENV{'PP_PRIVS'} =~ / admin / || $ENV{'PP_PRIVS'} =~ / meta /) { return 1; } else { return 0; } } # canreadjmeta - Returns whether or not the user can read jmeta # Parameters: none # Returns: boolean sub canreadjmeta() { if ($ENV{'PP_PRIVS'} =~ / root / || $ENV{'PP_PRIVS'} =~ / admin / || $ENV{'PP_PRIVS'} =~ / meta / || $ENV{'PP_PRIVS'} =~ / kmeta / || $ENV{'PP_PRIVS'} =~ / catmod:/ || $ENV{'PP_PRIVS'} =~ / kcatmod:/) { return 1; } else { return 0; } } # canreadpeditall - Returns whether or not the user can read peditall # Parameters: none # Returns: boolean # NOTE: This now includes cateditalls and kcateditalls, use iseditallplus() if you want the old functionality sub canreadpeditall() { if ($ENV{'PP_PRIVS'} =~ / root / || $ENV{'PP_PRIVS'} =~ / admin / || $ENV{'PP_PRIVS'} =~ / meta / || $ENV{'PP_PRIVS'} =~ / kmeta / || $ENV{'PP_PRIVS'} =~ / catmod:/ || $ENV{'PP_PRIVS'} =~ / kcatmod:/ || $ENV{'PP_PRIVS'} =~ / editall/ || $ENV{'PP_PRIVS'} =~ / keditall/ || $ENV{'PP_PRIVS'} =~ / k?cateditall:/) { return 1; } else { return 0; } } # iseditallplus - Returns whether or not the user is an editall/catmod or higher # Parameters: none # Returns: boolean sub iseditallplus() { if ($ENV{'PP_PRIVS'} =~ / root / || $ENV{'PP_PRIVS'} =~ / admin / || $ENV{'PP_PRIVS'} =~ / meta / || $ENV{'PP_PRIVS'} =~ / kmeta / || $ENV{'PP_PRIVS'} =~ / catmod:/ || $ENV{'PP_PRIVS'} =~ / kcatmod:/ || $ENV{'PP_PRIVS'} =~ / editall/ || $ENV{'PP_PRIVS'} =~ / keditall/) { return 1; } else { return 0; } } # canreadkmeta - Returns whether or not the user can read kmeta # Parameters: none # Returns: boolean sub canreadkmeta() { if ($ENV{'PP_PRIVS'} =~ / root / || $ENV{'PP_PRIVS'} =~ / admin / || $ENV{'PP_PRIVS'} =~ / kmeta /) { return 1; } else { return 0; } } # issomekindofmeta - Returns whether or not the user is some kind of meta (meta/kmeta/root) # Parameters: none # Returns: boolean sub issomekindofmeta() { if ($ENV{'PP_PRIVS'} =~ / root / || $ENV{'PP_PRIVS'} =~ / admin / || $ENV{'PP_PRIVS'} =~ / meta / || $ENV{'PP_PRIVS'} =~ / kmeta /) { return 1; } else { return 0; } } # isadmin - Returns whether or not the user is an admin (admin/root) # Parameters: none # Returns: boolean sub isadmin() { if ($ENV{'PP_PRIVS'} =~ / root / || $ENV{'PP_PRIVS'} =~ / admin /) { return 1; } else { return 0; } } # initialise_strings - Initialise a set of language strings, given a language code # Parameters: language code # Returns: none sub initialise_strings($) { my $self = shift; my $language = shift; $self->{'strings'} = new ODP::Stradivarius; $self->{'language'} = $language; $self->{'strings'}->setlang($language); $self->{'strings'}->load("main"); $self->{'strings'}->load("ppclient"); } # system_call - Handles system calls from the Passport server # Parameters: ppconfig location # Returns: none sub system_call($) { my $self = shift; my ($ppconfig_location) = @_; print "Content-type: text/plain\n\n"; if (CGI::param('system_call') eq 'update_blocklist') { my $blocklist = CGI::param('block_list'); if (!$ppconfig_location) { print "500 Site Does Not Support Blocklist\n"; } else { if (open (OUTPUT, ">$ppconfig_location")) { foreach my $item (split(/,/,$blocklist)) { print OUTPUT "BLOCK: $item\n"; } close OUTPUT; print "200 OK\n"; print "New List: $blocklist\n"; } else { print "500 Blocklist Update Failed\n"; } } } else { print "500 Unknown System Call\n"; } return; } # isblocked - Returns whether a user has been blocked or not # Parameters: ppconfig location, username # Returns: none sub isblocked($$) { my $self = shift; my $ppconfig = $_[0]; my $user = $_[1]; my $block = 0; open(INPUT, "<$ppconfig"); while () { if (m!^BLOCK: $user$!) { $block = 1; } } close INPUT; return $block; } 1;