Dispatcher: Auch Controller ermöglichen, die Admin-Login benötigen
authorMoritz Bunkus <m.bunkus@linet-services.de>
Fri, 17 Aug 2012 10:24:58 +0000 (12:24 +0200)
committerMoritz Bunkus <m.bunkus@linet-services.de>
Fri, 17 Aug 2012 10:24:58 +0000 (12:24 +0200)
Default ist für Controller, dass all ihre Funktionen User-Logins
benötigen. Kann ein Controller ändern, indem er die Sub
"get_auth_level" überschreibt (siehe Doku in
SL::Contrller::Base). Dies schafft die Basis dafür, auch Admin-Dinge
in der neuen Controller-Architektur zu implementieren.

Für die Zukunft kann man leicht ein weiteres Level neben 'user' und
'admin' einbauen, z.B. 'none' für Actions, die definitiv kein Login
benötigen.

Funktionierendes Beispiel für einen solchen Controller (Aufruf dann
über URL ".../controller.pl?action=AdminTest/proof_of_concept"):

package SL::Controller::AdminTest;

use strict;

use parent qw(SL::Controller::Base);

use Rose::Object::MakeMethods::Generic
(
 scalar => [ qw(business) ],
);

#
# actions
#

sub action_proof_of_concept {
  my ($self) = @_;

  $::form->header;
  print $self->render(<<EOHTML, { inline => 1 });
 <body>
  <p>I've been called with an ADMIN login only!</p>
 </body>
</html>
EOHTML
}

#
# overrides
#

sub get_auth_level {
  return 'admin';
}

1;

SL/Controller/Base.pm
SL/Dispatcher.pm
SL/Dispatcher/AuthHandler.pm [new file with mode: 0644]
SL/Dispatcher/AuthHandler/Admin.pm [new file with mode: 0644]
SL/Dispatcher/AuthHandler/User.pm [new file with mode: 0644]
templates/webpages/login/password_error.html

index ac09057..c871395 100644 (file)
@@ -167,6 +167,11 @@ sub delay_flash_on_redirect {
   0;
 }
 
+sub get_auth_level {
+  # Ignore the 'action' parameter.
+  return 'user';
+}
+
 #
 # private functions -- for use in Base only
 #
@@ -503,6 +508,15 @@ May be overridden by a controller. If this method returns true, redirect_to
 will delay all flash messages for the current request. Defaults to false for
 compatibility reasons.
 
+=item C<get_auth_level $action>
+
+May be overridden by a controller. Determines what kind of
+authentication is required for a particular action. Must return either
+C<admin> (which means that authentication as an admin is required),
+C<user> (authentication as a normal user suffices) with a possible
+future value C<none> (which would require no authentication but is not
+yet implemented).
+
 =back
 
 =head2 PRIVATE FUNCTIONS
index 21398cc..8301e56 100644 (file)
@@ -17,6 +17,7 @@ use List::MoreUtils qw(all);
 use List::Util qw(first);
 use POSIX;
 use SL::Auth;
+use SL::Dispatcher::AuthHandler;
 use SL::LXDebug;
 use SL::LxOfficeConf;
 use SL::Locale;
@@ -37,6 +38,7 @@ sub new {
 
   my $self           = bless {}, $class;
   $self->{interface} = lc($interface || 'cgi');
+  $self->{auth_handler} = SL::Dispatcher::AuthHandler->new;
 
   return $self;
 }
@@ -63,6 +65,7 @@ sub show_error {
   $::lxdebug->enter_sub;
   my $template             = shift;
   my $error_type           = shift || '';
+  my %params               = @_;
 
   $::locale                = Locale->new($::lx_office_conf{system}->{language});
   $::form->{error}         = $::locale->text('The session is invalid or has expired.') if ($error_type eq 'session');
@@ -70,7 +73,7 @@ sub show_error {
   $::myconfig{countrycode} = $::lx_office_conf{system}->{language};
 
   $::form->header;
-  print $::form->parse_html_template($template);
+  print $::form->parse_html_template($template, \%params);
   $::lxdebug->leave_sub;
 
   ::end_of_request();
@@ -143,10 +146,11 @@ sub require_main_code {
 sub _require_controller {
   my $controller =  shift;
   $controller    =~ s|[^A-Za-z0-9_]||g;
+  $controller    =  "SL/Controller/${controller}";
 
   eval {
     package main;
-    require "SL/Controller/${controller}.pm";
+    require "${controller}.pm";
   } or die $EVAL_ERROR;
 }
 
@@ -163,8 +167,6 @@ sub handle_request {
 
   my ($script, $path, $suffix, $script_name, $action, $routing_type);
 
-  $script_name = $ENV{SCRIPT_NAME};
-
   $self->unrequire_bin_mozilla;
 
   $::locale        = Locale->new($::lx_office_conf{system}->{language});
@@ -177,7 +179,7 @@ sub handle_request {
 
   $::form->read_cgi_input;
 
-  eval { ($routing_type, $script_name, $action) = _route_request($script_name); 1; } or return;
+  eval { ($routing_type, $script_name, $action) = _route_request($ENV{SCRIPT_NAME}); 1; } or return;
 
   if ($routing_type eq 'old') {
     $::form->{action}  =  lc $::form->{action};
@@ -205,23 +207,15 @@ sub handle_request {
     } else {
       show_error('login/password_error', 'session') if SL::Auth::SESSION_EXPIRED == $session_result;
 
-      my $login = $::auth->get_session_value('login');
-      show_error('login/password_error', 'password') if not defined $login;
-
-      %::myconfig = $::auth->read_user(login => $login);
-
-      show_error('login/password_error', 'password') unless $::myconfig{login};
-
-      $::locale = Locale->new($::myconfig{countrycode});
-
-      show_error('login/password_error', 'password') if SL::Auth::OK != $::auth->authenticate($login, undef);
-
-      $::auth->create_or_refresh_session;
-      $::auth->delete_session_value('FLASH');
-      delete $::form->{password};
+      my $auth_level = $self->{auth_handler}->handle(
+        routing_type => $routing_type,
+        script       => $script,
+        controller   => $script_name,
+        action       => $action,
+      );
 
       if ($action) {
-        $::instance_conf->init;
+        $::instance_conf->init if $auth_level eq 'user';
 
         map { $::form->{$_} = $::myconfig{$_} } qw(charset)
           unless $action eq 'save' && $::form->{type} eq 'preferences';
diff --git a/SL/Dispatcher/AuthHandler.pm b/SL/Dispatcher/AuthHandler.pm
new file mode 100644 (file)
index 0000000..60dc637
--- /dev/null
@@ -0,0 +1,32 @@
+package SL::Dispatcher::AuthHandler;
+
+use strict;
+
+use parent qw(Rose::Object);
+
+use SL::Dispatcher::AuthHandler::Admin;
+use SL::Dispatcher::AuthHandler::User;
+
+sub handle {
+  my ($self, %param) = @_;
+
+  my $auth_level                       = $self->get_auth_level(%param);
+  my $handler_name                     = "SL::Dispatcher::AuthHandler::" . ucfirst($auth_level);
+  $self->{handlers}                  ||= {};
+  $self->{handlers}->{$handler_name} ||= $handler_name->new;
+  $self->{handlers}->{$handler_name}->handle;
+
+  return $auth_level;
+}
+
+sub get_auth_level {
+  my ($self, %param) = @_;
+
+  my $auth_level = $param{routing_type} eq 'old'        ? ($param{script} eq 'admin' ? 'admin' : 'user')
+                 : $param{routing_type} eq 'controller' ? "SL::Controller::$param{controller}"->get_auth_level($param{action})
+                 :                                        'user';
+
+  return $auth_level eq 'user' ? 'user' : 'admin';
+}
+
+1;
diff --git a/SL/Dispatcher/AuthHandler/Admin.pm b/SL/Dispatcher/AuthHandler/Admin.pm
new file mode 100644 (file)
index 0000000..5a92015
--- /dev/null
@@ -0,0 +1,16 @@
+package SL::Dispatcher::AuthHandler::Admin;
+
+use strict;
+
+use parent qw(Rose::Object);
+
+sub handle {
+  %::myconfig = ();
+
+  return if $::auth->authenticate_root($::auth->get_session_value('rpw')) == $::auth->OK();
+
+  $::auth->delete_session_value('rpw');
+  SL::Dispatcher::show_error('login/password_error', 'password', is_admin => 1);
+}
+
+1;
diff --git a/SL/Dispatcher/AuthHandler/User.pm b/SL/Dispatcher/AuthHandler/User.pm
new file mode 100644 (file)
index 0000000..13d6448
--- /dev/null
@@ -0,0 +1,24 @@
+package SL::Dispatcher::AuthHandler::User;
+
+use strict;
+
+use parent qw(Rose::Object);
+
+sub handle {
+  my $login = $::auth->get_session_value('login');
+  SL::Dispatcher::show_error('login/password_error', 'password') if not defined $login;
+
+  %::myconfig = $::auth->read_user(login => $login);
+
+  SL::Dispatcher::show_error('login/password_error', 'password') unless $::myconfig{login};
+
+  $::locale = Locale->new($::myconfig{countrycode});
+
+  SL::Dispatcher::show_error('login/password_error', 'password') if SL::Auth::OK != $::auth->authenticate($login, undef);
+
+  $::auth->create_or_refresh_session;
+  $::auth->delete_session_value('FLASH');
+  delete $::form->{password};
+}
+
+1;
index e1060a0..1ee8ec8 100644 (file)
@@ -5,7 +5,7 @@
 
  <p>[% error %]</p>
 
- <p><a href="login.pl" target="_top">[% 'Login' | $T8 %]</a></p>
+ <p><a href="[% IF is_admin %]admin.pl[% ELSE %]login.pl[% END %]" target="_top">[% 'Login' | $T8 %]</a></p>
 
 </body>
 </html>