diff --git a/docs/changelog/7.x.x.txt b/docs/changelog/7.x.x.txt index 15b3e36d9..da8858682 100644 --- a/docs/changelog/7.x.x.txt +++ b/docs/changelog/7.x.x.txt @@ -15,6 +15,8 @@ easily. - Added comments aspect to wiki. - Removed cart icon from ViewCart macro. + - Added a basic auth mechanism to WebGUI, which will allow WebGUI to handle + authenticated web service queries. - Updated WebGUI::Shop::PayDriver::processTransaction() to accept a transaction as a param. - fixed: Select Slider borked in Thingy (SDH Consulting Group) diff --git a/lib/WebGUI.pm b/lib/WebGUI.pm index 5bc02a1e3..134eecb8e 100644 --- a/lib/WebGUI.pm +++ b/lib/WebGUI.pm @@ -20,12 +20,18 @@ our $STATUS = "beta"; =cut use strict; -use Apache2::Const -compile => qw(OK DECLINED); +use Apache2::Access (); +use Apache2::Const -compile => qw(OK DECLINED HTTP_UNAUTHORIZED SERVER_ERROR); use Apache2::Request; use Apache2::RequestIO; +use Apache2::RequestUtil (); use Apache2::ServerUtil (); +use APR::Request::Apache2; +use MIME::Base64; use WebGUI::Config; use WebGUI::Pluggable; +use WebGUI::Session; +use WebGUI::User; =head1 NAME @@ -47,6 +53,67 @@ These subroutines are available from this package: #------------------------------------------------------------------- +=head2 basicAuth ( requestObject, user, pass ) + +HTTP Basic auth for WebGUI. + +=head3 requestObject + +The Apache2::RequestRec object passed in by Apache's mod_perl. + +=cut + + +sub basicAuth { + my ($request, $username, $password) = @_; + my $server = Apache2::ServerUtil->server; + + my $config = WebGUI::Config->new($server->dir_config('WebguiRoot'),$request->dir_config('WebguiConfig')); + my $cookies = APR::Request::Apache2->handle($request)->jar(); + + # determine session id + my $sessionId = $cookies->{$config->getCookieName}; + my $session = WebGUI::Session->open($server->dir_config('WebguiRoot'),$request->dir_config('WebguiConfig'), $request, $server, $sessionId); + my $log = $session->log; + $request->pnotes(wgSession => $session); + + if (defined $sessionId && $session->user->isRegistered) { # got a session id passed in or from a cookie + $log->info("BASIC AUTH: using cookie"); + return; + } + elsif (defined $username && $username ne "") { # no session cookie, let's try to do basic auth + $log->info("BASIC AUTH: using user/pass"); + my $user = WebGUI::User->newByUsername($session, $username); + if (defined $user) { + my $authMethod = $user->authMethod; + if ($authMethod) { # we have an auth method, let's try to instantiate + my $auth = eval { WebGUI::Pluggable::instanciate("WebGUI::Auth::".$authMethod, "new", [ $session, $authMethod ] ) }; + if ($@) { # got an error + $log->error($@); + return; + } + elsif ($auth->authenticate($username, $password)) { # lets try to authenticate + $sessionId = $session->db->quickScalar("select sessionId from userSession where userId=?",[$user->userId]); + unless (defined $sessionId) { # no existing session found + $sessionId = $session->id->generate; + $auth->_logLogin($user->userId, "success (HTTP Basic)"); + } + $session->{_var} = WebGUI::Session::Var->new($session, $sessionId); + $session->user({user=>$user}); + return; + } + } + } + $log->security($username." failed to login using HTTP Basic Authentication"); + $request->note_basic_auth_failure; + return; + } + $log->info("BASIC AUTH: skipping"); + return; +} + +#------------------------------------------------------------------- + =head2 handler ( requestObject ) Primary http init/response handler for WebGUI. This method decides whether to hand off the request to contentHandler() or uploadsHandler() @@ -68,6 +135,15 @@ sub handler { my $gateway = $config->get("gateway"); $matchUri =~ s{^$gateway}{/}; my $gotMatch = 0; + + # handle basic auth + my $auth = $request->headers_in->{'Authorization'}; + if ($auth) { + $auth =~ s/Basic //; + basicAuth($request, split(":",MIME::Base64::decode_base64($auth))); + } + + # url handlers WEBGUI_FATAL: foreach my $handler (@{$config->get("urlHandlers")}) { my ($regex) = keys %{$handler}; if ($matchUri =~ m{$regex}i) { diff --git a/lib/WebGUI/URL/Content.pm b/lib/WebGUI/URL/Content.pm index 75fba546c..1a188ba26 100644 --- a/lib/WebGUI/URL/Content.pm +++ b/lib/WebGUI/URL/Content.pm @@ -51,7 +51,10 @@ The Apache request handler for this package. sub handler { my ($request, $server, $config) = @_; $request->push_handlers(PerlResponseHandler => sub { - my $session = WebGUI::Session->open($server->dir_config('WebguiRoot'), $config->getFilename, $request, $server); + my $session = $request->pnotes('wgSession'); + unless (defined $session) { + $session = WebGUI::Session->open($server->dir_config('WebguiRoot'), $config->getFilename, $request, $server); + } WEBGUI_FATAL: foreach my $handler (@{$config->get("contentHandlers")}) { my $output = eval { WebGUI::Pluggable::run($handler, "handler", [ $session ] )}; if ( my $e = WebGUI::Error->caught ) { diff --git a/lib/WebGUI/URL/Uploads.pm b/lib/WebGUI/URL/Uploads.pm index cf1067a26..2c9e41112 100644 --- a/lib/WebGUI/URL/Uploads.pm +++ b/lib/WebGUI/URL/Uploads.pm @@ -60,7 +60,10 @@ sub handler { close($FILE); my @privs = split("\n", $fileContents); unless ($privs[1] eq "7" || $privs[1] eq "1") { - my $session = WebGUI::Session->open($server->dir_config('WebguiRoot'), $config->getFilename, $request, $server); + my $session = $request->pnotes('wgSession'); + unless (defined $session) { + $session = WebGUI::Session->open($server->dir_config('WebguiRoot'), $config->getFilename, $request, $server); + } my $hasPrivs = ($session->var->get("userId") eq $privs[0] || $session->user->isInGroup($privs[1]) || $session->user->isInGroup($privs[2])); $session->close(); if ($hasPrivs) {