Mercurial > pub > Impl
changeset 97:964587c5183c
Added SecureCall to Web QueryHandlers stack
many bug fixes to Security and Web Application modules
author | wizard |
---|---|
date | Tue, 04 May 2010 04:04:37 +0400 |
parents | 4c55aed00ff2 |
children | 00d88c5e8203 |
files | Lib/IMPL/Exception.pm Lib/IMPL/Security/Context.pm Lib/IMPL/Security/Principal.pm Lib/IMPL/Test/Unit.pm Lib/IMPL/Web/Application.pm Lib/IMPL/Web/Application/Response.pm Lib/IMPL/Web/QueryHandler/PageFormat.pm Lib/IMPL/Web/QueryHandler/SecureCall.pm Lib/IMPL/Web/QueryHandler/SecureCookie.pm Lib/IMPL/Web/Security.pm Lib/IMPL/Web/TT/Document.pm _test/Resources/app.xml _test/temp.pl |
diffstat | 13 files changed, 145 insertions(+), 58 deletions(-) [+] |
line wrap: on
line diff
--- a/Lib/IMPL/Exception.pm Fri Apr 30 15:03:38 2010 +0400 +++ b/Lib/IMPL/Exception.pm Tue May 04 04:04:37 2010 +0400 @@ -104,6 +104,10 @@ our @ISA = qw(IMPL::Exception); __PACKAGE__->PassThroughArgs; +package IMPL::AccessDeniedException; +our @ISA = qw(IMPL::SecurityException); +our %CTOR = ( 'IMPL::SecurityException' => sub { 'Access denied' ,@_ } ); + package Exception; our @ISA = qw(IMPL::Exception); __PACKAGE__->PassThroughArgs;
--- a/Lib/IMPL/Security/Context.pm Fri Apr 30 15:03:38 2010 +0400 +++ b/Lib/IMPL/Security/Context.pm Tue May 04 04:04:37 2010 +0400 @@ -30,14 +30,20 @@ my ($this,$code) = @_; my $old = $current; + $current = $this; my $result; - local $@; - eval { - $result = $code->(); - }; + my $e; + + { + local $@; + eval { + $result = $code->(); + }; + $e = $@; + } $current = $old; - if($@) { - die $@; + if($e) { + die $e; } else { return $result; }
--- a/Lib/IMPL/Security/Principal.pm Fri Apr 30 15:03:38 2010 +0400 +++ b/Lib/IMPL/Security/Principal.pm Tue May 04 04:04:37 2010 +0400 @@ -5,6 +5,8 @@ use base qw(IMPL::Object IMPL::Object::Autofill); use IMPL::Class::Property; +__PACKAGE__->PassThroughArgs; + BEGIN { public property name => prop_get; public property description => prop_all;
--- a/Lib/IMPL/Test/Unit.pm Fri Apr 30 15:03:38 2010 +0400 +++ b/Lib/IMPL/Test/Unit.pm Tue May 04 04:04:37 2010 +0400 @@ -39,7 +39,7 @@ sub Cleanup { my ($this,$session) = @_; - $session->{$_} = $this->$_() foreach map $_->DataList, $this->get_meta('IMPL::Test::Unit::SharedData'); + $session->{$_} = $this->$_() foreach map $_->DataList, $this->get_meta('IMPL::Test::Unit::SharedData',undef,1); 1; } @@ -53,7 +53,7 @@ sub InitTest { my ($this,$session) = @_; - $this->$_($session->{$_}) foreach map $_->DataList, $this->get_meta('IMPL::Test::Unit::SharedData'); + $this->$_($session->{$_}) foreach map $_->DataList, $this->get_meta('IMPL::Test::Unit::SharedData',undef,1); } sub FinishUnit {
--- a/Lib/IMPL/Web/Application.pm Fri Apr 30 15:03:38 2010 +0400 +++ b/Lib/IMPL/Web/Application.pm Tue May 04 04:04:37 2010 +0400 @@ -19,6 +19,7 @@ public property responseCharset => prop_all; public property security => prop_all; public property options => prop_all; + public property fetchRequestMethod => prop_all; } sub CTOR { @@ -26,6 +27,8 @@ $this->actionFactory('IMPL::Web::Application::Action') unless $this->actionFactory; $this->responseCharset('utf-8') unless $this->responseCharset; + $this->fetchRequestMethod(\&defaultFetchRequest) unless $this->fetchRequestMethod; + $this->handlerError(\&defaultHandlerError) unless $this->handlerError; } sub Run { @@ -38,26 +41,55 @@ application => $this, ); - $action->response->charset($this->responseCharset); - - $action->ChainHandler($_) foreach $this->handlersQuery; - - $action->Invoke(); - - $action->response->Complete; + eval { + $action->response->charset($this->responseCharset); + + $action->ChainHandler($_) foreach $this->handlersQuery; + + $action->Invoke(); + + $action->response->Complete; + }; + if ($@) { + my $e = $@; + eval { $this->handlerError()->($this,$action,$e); 1;} or warn "Error in handlerError: ",$@; + } } } +sub FetchRequest { + my ($this) = @_; + + if( ref $this->fetchRequestMethod eq 'CODE' ) { + return $this->fetchRequestMethod->($this); + } else { + die new IMPL::Exception("Unknown fetchRequestMethod type",ref $this->fetchRequestMethod); + } +} + { my $hasFetched = 0; - sub FetchRequest { + sub defaultFetchRequest { return undef if $hasFetched; $hasFetched = 1; return CGI->new(); } } +sub defaultHandlerError { + my ($this,$action,$e) = @_; + warn $e; + if ( eval { $action->ReinitResponse(); 1; } ) { + $action->response->contentType('text/plain'); + $action->response->charset($this->responseCharset); + $action->response->status(500); + my $hout = $action->response->streamBody; + print $hout $e; + $action->response->Complete(); + } +} + 1; __END__ @@ -199,6 +231,13 @@ =end code +=item C< [get,set] fetchRequestMethod > + +Метод получения CGI запроса. Возвращает C<CGI> объект следующего запроса, если +запросов больше нет, то возвращает C<undef>. По-умолчанию использует C<defaultFetchRequest>. + +Может быть как ссылкой на функцию, так и объектом типа C<IMPL::Web::Application::RequestFetcher>. + =item C< [get,set,list] handlersQuery > Список обработчиков запросов, которые будут переданы созданному объекту-действию.
--- a/Lib/IMPL/Web/Application/Response.pm Fri Apr 30 15:03:38 2010 +0400 +++ b/Lib/IMPL/Web/Application/Response.pm Tue May 04 04:04:37 2010 +0400 @@ -102,7 +102,7 @@ $opt{-expires} = $this->expires if $this->expires; my $refCookies = $this->cookies; - $opt{-cookie} = [map CGI::Cookie->new(-name => $_, $refCookies->{$_} ), keys %$refCookies] if $refCookies; + $opt{-cookie} = [map _createCookie($_,$refCookies->{$_}), keys %$refCookies] if $refCookies; my $hOut = $this->streamOut; @@ -112,6 +112,10 @@ } } +sub _createCookie { + return UNIVERSAL::isa($_[1], 'CGI::Cookie') ? $_[1] : CGI::Cookie->new(-name => $_[0], -value => $_[1] ); +} + sub setCookie { my ($this,$name,$value) = @_; @@ -157,8 +161,8 @@ my $hOut = $this->streamOut; $this->_PrintHeader(); - - $this->_streamBody(undef); + + close $this->_streamBody(); if ($this->buffered) { print $hOut ${$this->_bufferBody};
--- a/Lib/IMPL/Web/QueryHandler/PageFormat.pm Fri Apr 30 15:03:38 2010 +0400 +++ b/Lib/IMPL/Web/QueryHandler/PageFormat.pm Tue May 04 04:04:37 2010 +0400 @@ -5,19 +5,20 @@ use IMPL::Class::Property; use IMPL::Web::TT::Document; +use IMPL::Security::Context; use File::Spec; use Error qw(:try); BEGIN { public property templatesCharset => prop_all; public property templatesBase => prop_all; + public property defaultTarget => prop_all; } sub CTOR { my ($this) = @_; $this->templatesCharset('utf-8') unless $this->templatesCharset; - $this->templatesBase('.') unless $this->templatesBase; } sub Process { @@ -26,13 +27,25 @@ my $doc = new IMPL::Web::TT::Document(); try { - my @path = split /\//, $ENV{PATH_TRANSLATED}; + + $this->templatesBase($ENV{DOCUMENT_ROOT}) unless $this->templatesBase; + + my $pathInfo = $ENV{PATH_INFO}; + local $ENV{PATH_INFO} = $pathInfo || $this->defaultTarget; + + my @path = split /\//, ($ENV{PATH_INFO} || '') or die new IMPL::Exception("PATH_INFO is empty and no defaultTarget specified" ); $doc->LoadFile ( File::Spec->catfile($this->templatesBase,@path), $this->templatesCharset ); + $doc->AddVar( result => $nextHandler->() ); + { + local $@; + $doc->AddVar( user => eval { IMPL::Security::Context->current->principal; } ); + $doc->AddVar( session => eval { IMPL::Security::Context->current; } ); + warn $@ if $@; + } $action->response->contentType('text/html'); my $hOut = $action->response->streamBody; - print $hOut $doc->Render(); } finally { $doc->Dispose;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Lib/IMPL/Web/QueryHandler/SecureCall.pm Tue May 04 04:04:37 2010 +0400 @@ -0,0 +1,37 @@ +package IMPL::Web::QueryHandler::SecureCall; +use strict; +use base qw(IMPL::Web::QueryHandler); + +use IMPL::Class::Property; +use IMPL::Exception; +use Carp; + +BEGIN { + public property namespace => prop_all; +} + +__PACKAGE__->PassThroughArgs; + +sub Process { + my ($this,$action,$nextHandler) = @_; + + my $namespace = $this->namespace || $action->application->type; + + my @target = grep $_, split /\//, ($ENV{PATH_INFO} || '') or die new IMPL::Exception("No target specified"); + + my $method = pop @target; + $method =~ s/\.\w+$//; + + my $module = join '::',$namespace,@target; + + eval "require $module; 1;"; + carp $@ if $@; + + if(UNIVERSAL::can($module,'InvokeAction')) { + $module->InvokeAction($method,$action); + } else { + die new IMPL::InvalidOperationException("Failed to invoke action",$ENV{PATH_INFO},$module,$method); + } +} + +1; \ No newline at end of file
--- a/Lib/IMPL/Web/QueryHandler/SecureCookie.pm Fri Apr 30 15:03:38 2010 +0400 +++ b/Lib/IMPL/Web/QueryHandler/SecureCookie.pm Tue May 04 04:04:37 2010 +0400 @@ -23,6 +23,8 @@ return undef unless $nextHandler; + local $IMPL::Security::authority = $this; + my $method = $action->query->cookie('method') || 'simple'; if ($method eq 'simple') { @@ -42,8 +44,6 @@ $this->salt ) ) { - local $IMPL::Security::authority = $this; - my $context = $action->application->security->sourceSession->find( { id => $sid } ) or return $nextHandler->(); @@ -56,9 +56,11 @@ } else { return $nextHandler->(); } + } else { + return $nextHandler->(); } } else { - die new IMPL::Exception("Unknown auth method",$method); + return $nextHandler->(); } } @@ -72,10 +74,10 @@ $this->salt ); - $this->setCookie(sid => $sid); - $this->setCookie(sdata => $cookie); - $this->setCookie(sign => $sign); - $this->setCookie(method => $method) if $method; + $response->setCookie(sid => $sid); + $response->setCookie(sdata => $cookie); + $response->setCookie(sign => $sign); + $response->setCookie(method => $method) if $method; } 1;
--- a/Lib/IMPL/Web/Security.pm Fri Apr 30 15:03:38 2010 +0400 +++ b/Lib/IMPL/Web/Security.pm Tue May 04 04:04:37 2010 +0400 @@ -17,7 +17,7 @@ sub AuthUser { my ($this,$name,$package,$challenge) = @_; - my $user = $this->sourceUser->find({name => $name}); + my $user = $this->sourceUser->find({name => $name}) or return { status => AUTH_FAIL, answer => "Can't find a user '$name'" }; my $auth; if ( my $secData = $user->secData($package) ) {
--- a/Lib/IMPL/Web/TT/Document.pm Fri Apr 30 15:03:38 2010 +0400 +++ b/Lib/IMPL/Web/TT/Document.pm Tue May 04 04:04:37 2010 +0400 @@ -86,6 +86,12 @@ $this->template($this->context->template($fileName)); } +sub AddVar { + my ($this,$name,$value) = @_; + + $this->context->stash->set($name,$value); +} + sub title { $_[0]->template->title; }
--- a/_test/Resources/app.xml Fri Apr 30 15:03:38 2010 +0400 +++ b/_test/Resources/app.xml Tue May 04 04:04:37 2010 +0400 @@ -26,19 +26,6 @@ <!-- Set default output encoding, can be changed due query handling --> <responseCharset>utf-8</responseCharset> - <!-- Actions creation configuration --> - <actionFactory type="IMPL::Object::Factory"> - <factory>IMPL::Web::Application::Action</factory> - <parameters type='HASH'> - <responseFactory type='IMPL::Object::Factory'> - <factory>IMPL::Web::Application::Response</factory> - <parameters type='HASH'> - <streamOut>memory</streamOut> - </parameters> - </responseFactory> - </parameters> - </actionFactory> - <!-- Query processing --> <handlersQuery type="IMPL::Object::List"> <item type="IMPL::Web::QueryHandler::PageFormat">
--- a/_test/temp.pl Fri Apr 30 15:03:38 2010 +0400 +++ b/_test/temp.pl Tue May 04 04:04:37 2010 +0400 @@ -1,19 +1,6 @@ #!/usr/bin/perl use strict; -package Boz; - -sub run { - my ($self,$code) = @_; - - $code->('Boz'); -} +use IMPL::Security::Context; -sub speak { - my ($self,$str) = @_; - print "Boz: $str"; -} - -sub type { $_[0]; } - -print type Boz; \ No newline at end of file +print IMPL::Security::Context->current->principal->name; \ No newline at end of file