Manage Ajax requests redirection with 401 (new parameter noAjaxHook)
This commit is contained in:
parent
0e51658c6f
commit
4f3a42ba48
7
debian/NEWS
vendored
7
debian/NEWS
vendored
|
@ -9,6 +9,13 @@ lemonldap-ng (1.9.0-1) UNRELEASED; urgency=low
|
|||
user and if users use the menu);
|
||||
* manager server
|
||||
|
||||
To request for authentication, handlers sent a 302 HTTP code even if request
|
||||
was an Ajax one. For now, a 401 code will be send with a WWW-Authenticate
|
||||
header containing portal URL. This is a little HTTP protocol hook created
|
||||
because browsers follow redirection tranparently.
|
||||
If you want to keep old behaviour, set noAjaxHook to 1 (in General Parameters
|
||||
-> Advanced -> Handler redirections -> Keep redirections for Ajax).
|
||||
|
||||
-- Xavier Guimard <x.guimard@free.fr> Thu, 21 Jan 2016 17:13:07 +0100
|
||||
|
||||
lemonldap-ng (1.4.6-1) unstable; urgency=medium
|
||||
|
|
|
@ -127,6 +127,7 @@ sub defaultValues {
|
|||
'managerDn' => '',
|
||||
'managerPassword' => '',
|
||||
'multiValuesSeparator' => '; ',
|
||||
'noAjaxHook' => 0,
|
||||
'notification' => 0,
|
||||
'notificationStorage' => 'File',
|
||||
'notificationStorageOptions' => {
|
||||
|
|
|
@ -8,7 +8,7 @@ our ( %EXPORT_TAGS, @EXPORT_OK, @EXPORT );
|
|||
BEGIN {
|
||||
%EXPORT_TAGS = (
|
||||
httpCodes => [
|
||||
qw( MP OK REDIRECT FORBIDDEN DONE DECLINED SERVER_ERROR AUTH_REQUIRED MAINTENANCE )
|
||||
qw( MP OK REDIRECT HTTP_UNAUTHORIZED FORBIDDEN DONE DECLINED SERVER_ERROR AUTH_REQUIRED MAINTENANCE )
|
||||
],
|
||||
functions => [
|
||||
qw( &hostname &remote_ip &uri &uri_with_args
|
||||
|
|
|
@ -13,14 +13,15 @@ use Apache2::Const;
|
|||
use Apache2::Filter;
|
||||
use APR::Table;
|
||||
|
||||
use constant FORBIDDEN => Apache2::Const::FORBIDDEN;
|
||||
use constant REDIRECT => Apache2::Const::REDIRECT;
|
||||
use constant OK => Apache2::Const::OK;
|
||||
use constant DECLINED => Apache2::Const::DECLINED;
|
||||
use constant DONE => Apache2::Const::DONE;
|
||||
use constant SERVER_ERROR => Apache2::Const::SERVER_ERROR;
|
||||
use constant AUTH_REQUIRED => Apache2::Const::AUTH_REQUIRED;
|
||||
use constant MAINTENANCE => Apache2::Const::HTTP_SERVICE_UNAVAILABLE;
|
||||
use constant FORBIDDEN => Apache2::Const::FORBIDDEN;
|
||||
use constant HTTP_UNAUTHORIZED => Apache2::Const::HTTP_UNAUTHORIZED;
|
||||
use constant REDIRECT => Apache2::Const::REDIRECT;
|
||||
use constant OK => Apache2::Const::OK;
|
||||
use constant DECLINED => Apache2::Const::DECLINED;
|
||||
use constant DONE => Apache2::Const::DONE;
|
||||
use constant SERVER_ERROR => Apache2::Const::SERVER_ERROR;
|
||||
use constant AUTH_REQUIRED => Apache2::Const::AUTH_REQUIRED;
|
||||
use constant MAINTENANCE => Apache2::Const::HTTP_SERVICE_UNAVAILABLE;
|
||||
|
||||
eval { require threads::shared; };
|
||||
print STDERR
|
||||
|
|
|
@ -3,14 +3,15 @@ package Lemonldap::NG::Handler::API::CGI;
|
|||
our $VERSION = '1.4.0';
|
||||
|
||||
# Specific modules and constants for Test or CGI
|
||||
use constant FORBIDDEN => 403;
|
||||
use constant REDIRECT => 302;
|
||||
use constant OK => 0;
|
||||
use constant DECLINED => 0;
|
||||
use constant DONE => 0;
|
||||
use constant SERVER_ERROR => 500;
|
||||
use constant AUTH_REQUIRED => 401;
|
||||
use constant MAINTENANCE => 503;
|
||||
use constant FORBIDDEN => 403;
|
||||
use constant HTTP_UNAUTHORIZED => 401;
|
||||
use constant REDIRECT => 302;
|
||||
use constant OK => 0;
|
||||
use constant DECLINED => 0;
|
||||
use constant DONE => 0;
|
||||
use constant SERVER_ERROR => 500;
|
||||
use constant AUTH_REQUIRED => 401;
|
||||
use constant MAINTENANCE => 503;
|
||||
|
||||
# Log level, since it can't be set in server config
|
||||
# Default value 'notice' can be changed in lemonldap-ng.ini or in init args
|
||||
|
|
|
@ -2,14 +2,15 @@ package Lemonldap::NG::Handler::API::Nginx;
|
|||
|
||||
our $VERSION = '1.9.0';
|
||||
|
||||
use constant FORBIDDEN => 403;
|
||||
use constant REDIRECT => 302;
|
||||
use constant OK => 0;
|
||||
use constant DECLINED => -1;
|
||||
use constant DONE => -2;
|
||||
use constant SERVER_ERROR => 500;
|
||||
use constant AUTH_REQUIRED => 401;
|
||||
use constant MAINTENANCE => 503;
|
||||
use constant FORBIDDEN => 403;
|
||||
use constant HTTP_UNAUTHORIZED => 401;
|
||||
use constant REDIRECT => 302;
|
||||
use constant OK => 0;
|
||||
use constant DECLINED => -1;
|
||||
use constant DONE => -2;
|
||||
use constant SERVER_ERROR => 500;
|
||||
use constant AUTH_REQUIRED => 401;
|
||||
use constant MAINTENANCE => 503;
|
||||
|
||||
my $request; # Nginx object for current request
|
||||
|
||||
|
|
|
@ -4,16 +4,23 @@ use strict;
|
|||
our $VERSION = '1.9.0';
|
||||
|
||||
# Specific modules and constants for Test or CGI
|
||||
use constant FORBIDDEN => 403;
|
||||
use constant REDIRECT => 302;
|
||||
use constant OK => 0;
|
||||
use constant DECLINED => 0;
|
||||
use constant DONE => 0;
|
||||
use constant SERVER_ERROR => 500;
|
||||
use constant AUTH_REQUIRED => 401;
|
||||
use constant MAINTENANCE => 503;
|
||||
use constant FORBIDDEN => 403;
|
||||
use constant HTTP_UNAUTHORIZED => 401;
|
||||
use constant REDIRECT => 302;
|
||||
use constant OK => 0;
|
||||
use constant DECLINED => 0;
|
||||
use constant DONE => 0;
|
||||
use constant SERVER_ERROR => 500;
|
||||
use constant AUTH_REQUIRED => 401;
|
||||
use constant MAINTENANCE => 503;
|
||||
|
||||
our $request;
|
||||
#
|
||||
## @method void setServerSignature(string sign)
|
||||
# modifies web server signature
|
||||
# @param $sign String to add to server signature
|
||||
sub setServerSignature {
|
||||
}
|
||||
|
||||
## @method void thread_share(string $variable)
|
||||
# share or not the variable (if authorized by specific module)
|
||||
|
|
|
@ -3,10 +3,10 @@ package Lemonldap::NG::Handler::API::PSGI::Server;
|
|||
use strict;
|
||||
our $VERSION = '1.9.0';
|
||||
|
||||
use base Lemonldap::NG::Handler::API::PSGI;
|
||||
use base 'Lemonldap::NG::Handler::API::PSGI';
|
||||
|
||||
sub uri {
|
||||
return $Lemonldap::NG::Handler::API::PSGI::$request->original_uri;
|
||||
return $Lemonldap::NG::Handler::API::PSGI::request->original_uri;
|
||||
}
|
||||
|
||||
1;
|
||||
|
|
|
@ -69,7 +69,7 @@ sub updateStatus {
|
|||
# Used to reject non authorized requests.
|
||||
# Inform the status processus and call logForbidden().
|
||||
# @param $uri URI
|
||||
# @return Apache2::Const::REDIRECT or Apache2::Const::FORBIDDEN
|
||||
# @return Apache2::Const::FORBIDDEN
|
||||
sub forbidden {
|
||||
my $class = shift;
|
||||
my $uri = Lemonldap::NG::Handler::API->unparsed_uri;
|
||||
|
@ -134,18 +134,35 @@ sub encodeUrl {
|
|||
# @return Apache2::Const::REDIRECT
|
||||
sub goToPortal {
|
||||
my ( $class, $url, $arg ) = @_;
|
||||
Lemonldap::NG::Handler::Main::Logger->lmLog(
|
||||
"Redirect "
|
||||
. Lemonldap::NG::Handler::API->remote_ip
|
||||
. " to portal (url was $url)",
|
||||
'debug'
|
||||
);
|
||||
my ( $ret, $msg );
|
||||
my $urlc_init = $class->encodeUrl($url);
|
||||
Lemonldap::NG::Handler::API->set_header_out(
|
||||
'Location' => &{ $tsv->{portal} }()
|
||||
. "?url=$urlc_init"
|
||||
. ( $arg ? "&$arg" : "" ) );
|
||||
return REDIRECT;
|
||||
if ( !$tsv->{noAjaxHook}
|
||||
and Lemonldap::NG::Handler::API->header_in('Accept') =~
|
||||
m|application/json| )
|
||||
{
|
||||
$msg =
|
||||
"Ajax request, send 401 instead of 302 "
|
||||
. Lemonldap::NG::Handler::API->remote_ip
|
||||
. " to portal (url was $url)";
|
||||
Lemonldap::NG::Handler::API->set_header_out(
|
||||
'WWW-Authenticate' => &{ $tsv->{portal} }()
|
||||
. "?url=$urlc_init"
|
||||
. ( $arg ? "&$arg" : "" ) );
|
||||
$ret = HTTP_UNAUTHORIZED;
|
||||
}
|
||||
else {
|
||||
$msg =
|
||||
"Redirect "
|
||||
. Lemonldap::NG::Handler::API->remote_ip
|
||||
. " to portal (url was $url)";
|
||||
Lemonldap::NG::Handler::API->set_header_out(
|
||||
'Location' => &{ $tsv->{portal} }()
|
||||
. "?url=$urlc_init"
|
||||
. ( $arg ? "&$arg" : "" ) );
|
||||
$ret = REDIRECT;
|
||||
}
|
||||
Lemonldap::NG::Handler::Main::Logger->lmLog( $msg, 'debug' );
|
||||
return $ret;
|
||||
}
|
||||
|
||||
## @rmethod protected $ fetchId()
|
||||
|
|
|
@ -74,29 +74,29 @@ sub _authAndTrace {
|
|||
# is not really HTTP compliant but nothing in this
|
||||
# protocol can do this. Our javascripts understand that
|
||||
# they have to prompt user with the URL
|
||||
elsif (
|
||||
$req->accept =~ m|application/json|
|
||||
or ( $req->contentType
|
||||
and $req->contentType =~ m|application/json| )
|
||||
)
|
||||
{
|
||||
$self->lmLog( 'Ajax request detected', 'debug' );
|
||||
if ( $res == 302 or $res == 303 ) {
|
||||
$self->lmLog( 'Rewrite redirection to 401 response', 'debug' );
|
||||
return [
|
||||
401, [ 'WWW-Authenticate' => $req->{respHeaders}->{Location} ], ['']
|
||||
];
|
||||
}
|
||||
else {
|
||||
$self->lmLog(
|
||||
"Lemonldap::NG::Handler::SharedConf::run() returns $res",
|
||||
'debug' );
|
||||
return [
|
||||
$res, [ 'Content-Type', 'application/json' ],
|
||||
[qq({"error":"$res"})]
|
||||
];
|
||||
}
|
||||
}
|
||||
#elsif (
|
||||
# $req->accept =~ m|application/json|
|
||||
# or ( $req->contentType
|
||||
# and $req->contentType =~ m|application/json| )
|
||||
# )
|
||||
#{
|
||||
# $self->lmLog( 'Ajax request detected', 'debug' );
|
||||
# if ( $res == 302 or $res == 303 ) {
|
||||
# $self->lmLog( 'Rewrite redirection to 401 response', 'debug' );
|
||||
# return [
|
||||
# 401, [ 'WWW-Authenticate' => $req->{respHeaders}->{Location} ], ['']
|
||||
# ];
|
||||
# }
|
||||
# else {
|
||||
# $self->lmLog(
|
||||
# "Lemonldap::NG::Handler::SharedConf::run() returns $res",
|
||||
# 'debug' );
|
||||
# return [
|
||||
# $res, [ 'Content-Type', 'application/json' ],
|
||||
# [qq({"error":"$res"})]
|
||||
# ];
|
||||
# }
|
||||
#}
|
||||
|
||||
# Non Ajax requests may be redirected to portal
|
||||
else {
|
||||
|
|
|
@ -15,7 +15,8 @@ sub _run {
|
|||
return sub {
|
||||
my $req = $_[0];
|
||||
$self->lmLog( 'New request', 'debug' );
|
||||
my $res = $self->_authAndTrace($req);
|
||||
my $res = $self->_authAndTrace(
|
||||
Lemonldap::NG::Common::PSGI::Request->new( $_[0] ) );
|
||||
|
||||
# TODO: transform headers in $res->[1]
|
||||
return $res;
|
||||
|
|
|
@ -111,7 +111,7 @@ sub defaultValuesInit {
|
|||
cda cookieExpiration cookieName
|
||||
customFunctions httpOnly securedCookie
|
||||
timeoutActivity useRedirectOnError useRedirectOnForbidden
|
||||
useSafeJail whatToTrace
|
||||
useSafeJail noAjaxHook whatToTrace
|
||||
)
|
||||
);
|
||||
|
||||
|
|
|
@ -35,6 +35,9 @@ sub init {
|
|||
foreach ( keys %$localconf );
|
||||
}
|
||||
|
||||
# Manager needs to keep new Ajax behaviour
|
||||
$args->{noAjaxHook} = 0;
|
||||
|
||||
return 0 unless ( $self->Lemonldap::NG::Handler::PSGI::Router::init($args) );
|
||||
|
||||
# TODO: manage errors
|
||||
|
|
|
@ -186,7 +186,7 @@ qr/^(?:(?:\-+\s*BEGIN\s+(?:PUBLIC\s+KEY|CERTIFICATE)\s*\-+\r?\n)?[a-zA-Z0-9\/\+\
|
|||
'test' => sub {
|
||||
my $test =
|
||||
grep( { $_ eq $_[0]; }
|
||||
map( { $$_{'k'}; } @{ $_[2]{'select'}; } ) );
|
||||
map( { $_->{'k'}; } @{ $_[2]{'select'}; } ) );
|
||||
return $test
|
||||
? 1
|
||||
: ( 0, "Invalid value '$_[0]' for this select" );
|
||||
|
@ -1011,7 +1011,7 @@ qr/^(?:(?:(?:(?:[a-zA-Z0-9][-a-zA-Z0-9]*)?[a-zA-Z0-9])[.])*(?:[a-zA-Z][-a-zA-Z0-
|
|||
'default' => 'ldap://localhost',
|
||||
'test' => sub {
|
||||
my $l = shift();
|
||||
my (@s) = split( /[\s,]+/, $l, 0 );
|
||||
my @s = split( /[\s,]+/, $l, 0 );
|
||||
foreach my $s (@s) {
|
||||
return 0, qq[Bad ldap uri "$s"]
|
||||
unless $s =~
|
||||
|
@ -1146,6 +1146,10 @@ qr/^(?:(?:(?:(?:[a-zA-Z0-9][-a-zA-Z0-9]*)?[a-zA-Z0-9])[.])*(?:[a-zA-Z][-a-zA-Z0-
|
|||
'default' => '; ',
|
||||
'type' => 'authParamsText'
|
||||
},
|
||||
'noAjaxHook' => {
|
||||
'default' => 0,
|
||||
'type' => 'bool'
|
||||
},
|
||||
'notification' => {
|
||||
'default' => 0,
|
||||
'type' => 'bool'
|
||||
|
|
|
@ -239,6 +239,11 @@ sub attributes {
|
|||
type => 'bool',
|
||||
documentation => 'Maintenance mode for all virtual hosts',
|
||||
},
|
||||
noAjaxHook => {
|
||||
default => 0,
|
||||
type => 'bool',
|
||||
documentation => 'Avoid replacing 302 by 401 for Ajax responses',
|
||||
},
|
||||
portal => {
|
||||
type => 'url',
|
||||
default => 'http://auth.example.com/',
|
||||
|
|
|
@ -607,7 +607,8 @@ sub tree {
|
|||
'port',
|
||||
'useRedirectOnForbidden',
|
||||
'useRedirectOnError',
|
||||
'maintenance'
|
||||
'maintenance',
|
||||
'noAjaxHook'
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
|
@ -325,6 +325,7 @@
|
|||
"newRSAKey": "New keys",
|
||||
"newRule": "New rule",
|
||||
"next": "Next",
|
||||
"noAjaxHook": "Keep redirections for Ajax",
|
||||
"noDatas": "No datas to display",
|
||||
"notABoolean": "Not a boolean",
|
||||
"notAnInteger": "Not an integer",
|
||||
|
|
|
@ -325,6 +325,7 @@
|
|||
"newRSAKey": "Nouvelles clefs",
|
||||
"newRule": "Nouvelle règle",
|
||||
"next": "Suivante",
|
||||
"noAjaxHook": "Conserver les redirections pour Ajax",
|
||||
"noDatas": "Aucune donnée à afficher",
|
||||
"notABoolean": "Pas un booléen",
|
||||
"notAnInteger": "Pas un nombre entier",
|
||||
|
|
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue
Block a user