From 2a496ad85e9117b7cfaaa315b208f478eba30ffd Mon Sep 17 00:00:00 2001 From: Moritz Bunkus Date: Tue, 12 Nov 2019 14:09:52 +0100 Subject: [PATCH] Auth: fehlerhafte JSON-Requests mit JSON und richtigem HTTP-Response-Code beantworten --- SL/Auth.pm | 2 ++ SL/Controller/Base.pm | 4 +++- SL/Dispatcher.pm | 34 ++++++++++++++++++++++++++++--- SL/Dispatcher/AuthHandler/User.pm | 3 +-- SL/Form.pm | 2 +- 5 files changed, 38 insertions(+), 7 deletions(-) diff --git a/SL/Auth.pm b/SL/Auth.pm index 930179603..82513b98d 100644 --- a/SL/Auth.pm +++ b/SL/Auth.pm @@ -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.")); } diff --git a/SL/Controller/Base.pm b/SL/Controller/Base.pm index f9db85aaf..5e0fd26cb 100644 --- a/SL/Controller/Base.pm +++ b/SL/Controller/Base.pm @@ -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}); } } diff --git a/SL/Dispatcher.pm b/SL/Dispatcher.pm index fcb3aeaf1..4efcdf692 100644 --- a/SL/Dispatcher.pm +++ b/SL/Dispatcher.pm @@ -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«. diff --git a/SL/Dispatcher/AuthHandler/User.pm b/SL/Dispatcher/AuthHandler/User.pm index 182d65442..3748dc110 100644 --- a/SL/Dispatcher/AuthHandler/User.pm +++ b/SL/Dispatcher/AuthHandler/User.pm @@ -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; } diff --git a/SL/Form.pm b/SL/Form.pm index e815fec12..f162f2095 100644 --- a/SL/Form.pm +++ b/SL/Form.pm @@ -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); -- 2.20.1