Auth: fehlerhafte JSON-Requests mit JSON und richtigem HTTP-Response-Code beantworten
authorMoritz Bunkus <m.bunkus@linet-services.de>
Tue, 12 Nov 2019 13:09:52 +0000 (14:09 +0100)
committerMoritz Bunkus <m.bunkus@linet-services.de>
Mon, 25 Nov 2019 08:42:53 +0000 (09:42 +0100)
SL/Auth.pm
SL/Controller/Base.pm
SL/Dispatcher.pm
SL/Dispatcher/AuthHandler/User.pm
SL/Form.pm

index 9301796..82513b9 100644 (file)
@@ -1237,6 +1237,8 @@ sub assert {
   }
 
   if (!$dont_abort) {
+    $::dispatcher->reply_with_json_error(error => 'access') if $::request->type eq 'json';
+
     delete $::form->{title};
     $::form->show_generic_error($::locale->text("You do not have the permissions to access this function."));
   }
index f9db85a..5e0fd26 100644 (file)
@@ -75,6 +75,7 @@ sub render {
     header     => 1,
     layout     => 1,
     process    => 1,
+    status     => '200 ok',
   );
   $options->{$_} //= $defaults{$_} for keys %defaults;
   $options->{type} = lc $options->{type};
@@ -131,7 +132,8 @@ sub render {
                         :                              'application/json';
 
       print $::form->create_http_response(content_type => $content_type,
-                                          charset      => 'UTF-8');
+                                          charset      => 'UTF-8',
+                                          (status      => $options->{status}) x !!$options->{status});
     }
   }
 
index fcb3aea..4efcdf6 100644 (file)
@@ -291,7 +291,7 @@ sub handle_request {
     if (   (($script eq 'login') && !$action)
         || ($script eq 'admin')
         || (SL::Auth::SESSION_EXPIRED() == $session_result)) {
-      $self->redirect_to_login(script => $script, error => 'session');
+      $self->handle_login_error(script => $script, error => 'session');
 
     }
 
@@ -360,8 +360,36 @@ sub handle_request {
   $::lxdebug->leave_sub;
 }
 
-sub redirect_to_login {
+sub reply_with_json_error {
   my ($self, %params) = @_;
+
+  my %errors = (
+    session  => { code => '401 Unauthorized',          text => 'session expired' },
+    password => { code => '401 Unauthorized',          text => 'incorrect username or password' },
+    action   => { code => '400 Bad request',           text => 'incorrect or missing action' },
+    access   => { code => '403 Forbidden',             text => 'no permissions for accessing this function' },
+    _default => { code => '500 Internal server error', text => 'general server-side error' },
+  );
+
+  my $error = $errors{$params{error}} // $errors{_default};
+  my $reply = SL::JSON::to_json({ status => 'failed', error => $error->{text} });
+
+  print $::request->cgi->header(
+    -type    => 'application/json',
+    -charset => 'utf-8',
+    -status  => $error->{code},
+  );
+
+  print $reply;
+
+  $self->end_request;
+}
+
+sub handle_login_error {
+  my ($self, %params) = @_;
+
+  return $self->reply_with_json_error(error => $params{error}) if $::request->type eq 'json';
+
   my $action          = ($params{script} // '') =~ m/^admin/i ? 'Admin/login' : 'LoginScreen/user_login';
   $action            .= '&error=' . $params{error} if $params{error};
 
@@ -432,7 +460,7 @@ sub _route_controller_request {
   eval {
     # Redirect simple requests to controller.pl without any GET/POST
     # param to the login page.
-    $self->redirect_to_login(error => 'action') if !$::form->{action};
+    $self->handle_login_error(error => 'action') if !$::form->{action};
 
     # Show an error if the »action« parameter doesn't match the
     # pattern »Controller/action«.
index 182d654..3748dc1 100644 (file)
@@ -46,9 +46,8 @@ sub _error {
   my $self = shift;
 
   $::auth->punish_wrong_login;
+  $::dispatcher->handle_login_error(error => 'password');
 
-  require SL::Controller::Base;
-  SL::Controller::Base->new->redirect_to('controller.pl?action=LoginScreen/user_login&error=password');
   return 0;
 }
 
index e815fec..f162f20 100644 (file)
@@ -397,7 +397,7 @@ sub create_http_response {
   $cgi_params{'-charset'} = $params{charset} if ($params{charset});
   $cgi_params{'-cookie'}  = $session_cookie  if ($session_cookie);
 
-  map { $cgi_params{'-' . $_} = $params{$_} if exists $params{$_} } qw(content_disposition content_length);
+  map { $cgi_params{'-' . $_} = $params{$_} if exists $params{$_} } qw(content_disposition content_length status);
 
   my $output = $cgi->header(%cgi_params);