Replace request management in handler (#1044)
Note: this is a big change, more tests needed
This commit is contained in:
parent
cc1fc22dcb
commit
2e59ea441a
|
@ -29,11 +29,14 @@ sub new {
|
|||
$self->env->{PATH_INFO} =~ s|^$tmp|/|;
|
||||
$self->{uri} = uri_unescape( $self->env->{REQUEST_URI} );
|
||||
$self->{uri} =~ s|//+|/|g;
|
||||
$self->{datas} = {};
|
||||
$self->{error} = 0;
|
||||
$self->{respHeaders} = [];
|
||||
return $self;
|
||||
return bless( $self, $_[0] );
|
||||
}
|
||||
|
||||
sub datas { $_[0]->{datas} }
|
||||
|
||||
sub uri { $_[0]->{uri} }
|
||||
|
||||
sub userData {
|
||||
|
|
|
@ -9,6 +9,7 @@ lib/Lemonldap/NG/Handler/ApacheMP2/CDA.pm
|
|||
lib/Lemonldap/NG/Handler/ApacheMP2/DevOps.pm
|
||||
lib/Lemonldap/NG/Handler/ApacheMP2/Main.pm
|
||||
lib/Lemonldap/NG/Handler/ApacheMP2/Menu.pm
|
||||
lib/Lemonldap/NG/Handler/ApacheMP2/Request.pm
|
||||
lib/Lemonldap/NG/Handler/ApacheMP2/SecureToken.pm
|
||||
lib/Lemonldap/NG/Handler/ApacheMP2/ServiceToken.pm
|
||||
lib/Lemonldap/NG/Handler/ApacheMP2/ZimbraPreAuth.pm
|
||||
|
@ -48,7 +49,6 @@ META.yml
|
|||
README
|
||||
t/01-Lemonldap-NG-Handler-Main.t
|
||||
t/05-Lemonldap-NG-Handler-Reload.t
|
||||
t/10-Lemonldap-NG-Handler-SharedConf.t
|
||||
t/12-Lemonldap-NG-Handler-Jail.t
|
||||
t/13-Lemonldap-NG-Handler-Fake-Safe.t
|
||||
t/50-Lemonldap-NG-Handler-SecureToken.t
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
package Lemonldap::NG::Handler::ApacheMP2;
|
||||
|
||||
use strict;
|
||||
use Lemonldap::NG::Handler::ApacheMP2::Request;
|
||||
|
||||
use Lemonldap::NG::Handler::ApacheMP2::Main;
|
||||
|
||||
|
@ -13,30 +14,31 @@ our $VERSION = '2.0.0';
|
|||
|
||||
sub handler {
|
||||
shift if ($#_);
|
||||
my ($res) = getClass(@_)->run(@_);
|
||||
return $res;
|
||||
return launch( 'run', @_ );
|
||||
}
|
||||
|
||||
sub logout {
|
||||
shift if ($#_);
|
||||
return getClass(@_)->unlog(@_);
|
||||
return launch( 'unlog', @_ );
|
||||
}
|
||||
|
||||
sub status {
|
||||
shift if ($#_);
|
||||
return getClass(@_)->getStatus(@_);
|
||||
return launch( 'getStatus', @_ );
|
||||
}
|
||||
|
||||
# Internal method to get class to load
|
||||
sub getClass {
|
||||
my $type = Lemonldap::NG::Handler::ApacheMP2::Main->checkType(@_);
|
||||
sub launch {
|
||||
my ( $sub, $r ) = @_;
|
||||
my $req = Lemonldap::NG::Handler::Apache2::Request->new($r);
|
||||
my $type = Lemonldap::NG::Handler::ApacheMP2::Main->checkType($req);
|
||||
if ( my $t = $_[0]->dir_config('VHOSTTYPE') ) {
|
||||
$type = $t;
|
||||
}
|
||||
my $class = "Lemonldap::NG::Handler::ApacheMP2::$type";
|
||||
eval "require $class";
|
||||
die $@ if ($@);
|
||||
return $class;
|
||||
return $class->$sub($req);
|
||||
}
|
||||
|
||||
1;
|
||||
|
|
|
@ -43,33 +43,6 @@ our $request; # Apache2::RequestRec object for current request
|
|||
|
||||
#*run = \&Lemonldap::NG::Handler::Main::run;
|
||||
|
||||
## @rmethod protected int redirectFilter(string url, Apache2::Filter f)
|
||||
# Launch the current HTTP request then redirects the user to $url.
|
||||
# Used by logout_app and logout_app_sso targets
|
||||
# @param $url URL to redirect the user
|
||||
# @param $f Current Apache2::Filter object
|
||||
# @return Constant $class->OK
|
||||
sub redirectFilter {
|
||||
my $class = shift;
|
||||
my $url = shift;
|
||||
my $f = shift;
|
||||
unless ( $f->ctx ) {
|
||||
|
||||
# Here, we can use Apache2 functions instead of set_header_out
|
||||
# since this function is used only with Apache2.
|
||||
$f->r->status( $class->REDIRECT );
|
||||
$f->r->status_line("303 See Other");
|
||||
$f->r->headers_out->unset('Location');
|
||||
$f->r->err_headers_out->set( 'Location' => $url );
|
||||
$f->ctx(1);
|
||||
}
|
||||
while ( $f->read( my $buffer, 1024 ) ) {
|
||||
}
|
||||
$class->updateStatus( $f->r, '$class->REDIRECT',
|
||||
$class->datas->{ $class->tsv->{whatToTrace} }, 'filter' );
|
||||
return $class->OK;
|
||||
}
|
||||
|
||||
__PACKAGE__->init();
|
||||
|
||||
# INTERNAL METHODS
|
||||
|
@ -99,36 +72,21 @@ sub setServerSignature {
|
|||
};
|
||||
}
|
||||
|
||||
sub newRequest {
|
||||
my ( $class, $r ) = @_;
|
||||
$request = $r;
|
||||
}
|
||||
|
||||
## @method void set_user(string user)
|
||||
# sets remote_user
|
||||
# @param user string username
|
||||
sub set_user {
|
||||
my ( $class, $user ) = @_;
|
||||
$request->user($user);
|
||||
}
|
||||
|
||||
## @method string header_in(string header)
|
||||
# returns request header value
|
||||
# @param header string request header
|
||||
# @return request header value
|
||||
sub header_in {
|
||||
my ( $class, $header ) = @_;
|
||||
$header ||= $class; # to use header_in as a method or as a function
|
||||
return $request->headers_in->{$header};
|
||||
my ( $class, $request, $user ) = @_;
|
||||
$request->env->{'psgi.r'}->user($user);
|
||||
}
|
||||
|
||||
## @method void set_header_in(hash headers)
|
||||
# sets or modifies request headers
|
||||
# @param headers hash containing header names => header value
|
||||
sub set_header_in {
|
||||
my ( $class, %headers ) = @_;
|
||||
my ( $class, $request, %headers ) = @_;
|
||||
while ( my ( $h, $v ) = each %headers ) {
|
||||
$request->headers_in->set( $h => $v );
|
||||
$request->env->{'psgi.r'}->headers_in->set( $h => $v );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -138,11 +96,11 @@ sub set_header_in {
|
|||
# header 'Auth-User' is removed, 'Auth_User' be removed also
|
||||
# @param headers array with header names to remove
|
||||
sub unset_header_in {
|
||||
my ( $class, @headers ) = @_;
|
||||
my ( $class, $request, @headers ) = @_;
|
||||
foreach my $h1 (@headers) {
|
||||
$h1 = lc $h1;
|
||||
$h1 =~ s/-/_/g;
|
||||
$request->headers_in->do(
|
||||
$request->env->{'psgi.r'}->headers_in->do(
|
||||
sub {
|
||||
my $h = shift;
|
||||
my $h2 = lc $h;
|
||||
|
@ -158,120 +116,65 @@ sub unset_header_in {
|
|||
# sets response headers
|
||||
# @param headers hash containing header names => header value
|
||||
sub set_header_out {
|
||||
my ( $class, %headers ) = @_;
|
||||
my ( $class, $request, %headers ) = @_;
|
||||
while ( my ( $h, $v ) = each %headers ) {
|
||||
$request->err_headers_out->set( $h => $v );
|
||||
$request->env->{'psgi.r'}->err_headers_out->set( $h => $v );
|
||||
}
|
||||
}
|
||||
|
||||
## @method string hostname()
|
||||
# returns host, as set by full URI or Host header
|
||||
# @return host string Host value
|
||||
sub hostname {
|
||||
my $class = shift;
|
||||
return $request->hostname;
|
||||
}
|
||||
|
||||
## @method string remote_ip
|
||||
# returns client IP address
|
||||
# @return IP_Addr string client IP
|
||||
sub remote_ip {
|
||||
my $class = shift;
|
||||
my $remote_ip = (
|
||||
$request->connection->can('remote_ip')
|
||||
? $request->connection->remote_ip
|
||||
: $request->connection->client_ip
|
||||
);
|
||||
return $remote_ip;
|
||||
}
|
||||
|
||||
## @method boolean is_initial_req
|
||||
# returns true unless the current request is a subrequest
|
||||
# @return is_initial_req boolean
|
||||
sub is_initial_req {
|
||||
my $class = shift;
|
||||
return $request->is_initial_req;
|
||||
}
|
||||
|
||||
## @method string args(string args)
|
||||
# gets the query string
|
||||
# @return args string Query string
|
||||
sub args {
|
||||
my $class = shift;
|
||||
return $request->args();
|
||||
}
|
||||
|
||||
## @method string uri
|
||||
# returns the path portion of the URI, normalized, i.e. :
|
||||
# * URL decoded (characters encoded as %XX are decoded,
|
||||
# except ? in order not to merge path and query string)
|
||||
# * references to relative path components "." and ".." are resolved
|
||||
# * two or more adjacent slashes are merged into a single slash
|
||||
# @return path portion of the URI, normalized
|
||||
sub uri {
|
||||
my $class = shift;
|
||||
my $uri = $request->uri;
|
||||
$uri =~ s#//+#/#g;
|
||||
$uri =~ s#\?#%3F#g;
|
||||
return $uri;
|
||||
}
|
||||
|
||||
## @method string uri_with_args
|
||||
# returns the URI, with arguments and with path portion normalized
|
||||
# @return URI with normalized path portion
|
||||
sub uri_with_args {
|
||||
my $class = shift;
|
||||
return uri . ( $request->args ? "?" . $request->args : "" );
|
||||
}
|
||||
|
||||
## @method string unparsed_uri
|
||||
# returns the full original request URI, with arguments
|
||||
# @return full original request URI, with arguments
|
||||
sub unparsed_uri {
|
||||
my $class = shift;
|
||||
return $request->unparsed_uri;
|
||||
}
|
||||
|
||||
## @method string get_server_port
|
||||
# returns the port the server is receiving the current request on
|
||||
# @return port string server port
|
||||
sub get_server_port {
|
||||
my $class = shift;
|
||||
return $request->get_server_port;
|
||||
}
|
||||
|
||||
## @method string method
|
||||
# returns the port the server is receiving the current request on
|
||||
# @return port string server port
|
||||
sub method {
|
||||
my $class = shift;
|
||||
return $request->method;
|
||||
}
|
||||
|
||||
## Return environment variables as hash
|
||||
sub env {
|
||||
return \%ENV;
|
||||
return $_[1]->env->{'psgi.r'}->is_initial_req;
|
||||
}
|
||||
|
||||
## @method void print(string data)
|
||||
# write data in HTTP response body
|
||||
# @param data Text to add in response body
|
||||
sub print {
|
||||
my ( $class, $data ) = @_;
|
||||
$request->print($data);
|
||||
my ( $class, $request, $data ) = @_;
|
||||
$request->env->{'psgi.r'}->print($data);
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
__END__
|
||||
|
||||
## @rmethod protected int redirectFilter(string url, Apache2::Filter f)
|
||||
# Launch the current HTTP request then redirects the user to $url.
|
||||
# Used by logout_app and logout_app_sso targets
|
||||
# @param $url URL to redirect the user
|
||||
# @param $f Current Apache2::Filter object
|
||||
# @return Constant $class->OK
|
||||
sub redirectFilter {
|
||||
my $class = shift;
|
||||
my $url = shift;
|
||||
my $f = shift;
|
||||
unless ( $f->ctx ) {
|
||||
|
||||
# Here, we can use Apache2 functions instead of set_header_out
|
||||
# since this function is used only with Apache2.
|
||||
$f->r->status( $class->REDIRECT );
|
||||
$f->r->status_line("303 See Other");
|
||||
$f->r->headers_out->unset('Location');
|
||||
$f->r->err_headers_out->set( 'Location' => $url );
|
||||
$f->ctx(1);
|
||||
}
|
||||
while ( $f->read( my $buffer, 1024 ) ) {
|
||||
}
|
||||
$class->updateStatus( $f->r, '$class->REDIRECT',
|
||||
$class->datas->{ $class->tsv->{whatToTrace} }, 'filter' );
|
||||
return $class->OK;
|
||||
}
|
||||
|
||||
## @method void addToHtmlHead(string data)
|
||||
# add data at end of html head
|
||||
# @param data Text to add in html head
|
||||
sub addToHtmlHead {
|
||||
use APR::Bucket ();
|
||||
use APR::Brigade ();
|
||||
my ( $class, $data ) = @_;
|
||||
my ( $class, $request, $data ) = @_;
|
||||
$request->add_output_filter(
|
||||
sub {
|
||||
my $f = shift;
|
||||
|
@ -322,7 +225,7 @@ sub flatten_bb {
|
|||
# add or modify parameters in POST request body
|
||||
# @param $params hashref containing name => value
|
||||
sub setPostParams {
|
||||
my ( $class, $params ) = @_;
|
||||
my ( $class, $request, $params ) = @_;
|
||||
$request->add_input_filter(
|
||||
sub {
|
||||
my $f = shift;
|
||||
|
|
|
@ -0,0 +1,49 @@
|
|||
package Lemonldap::NG::Handler::ApacheMP2::Request;
|
||||
|
||||
use strict;
|
||||
use base 'Plack::Request';
|
||||
use Plack::Util;
|
||||
use URI;
|
||||
use URI::Escape;
|
||||
|
||||
# Build Plack::Request (inspired from Plack::Handler::Apache2)
|
||||
sub new {
|
||||
my ( $class, $r ) = @_;
|
||||
|
||||
# Apache populates ENV:
|
||||
$r->subprocess_env;
|
||||
my $env = {
|
||||
%ENV,
|
||||
'psgi.version' => [ 1, 1 ],
|
||||
'psgi.url_scheme' => ( $ENV{HTTPS} || 'off' ) =~ /^(?:on|1)$/i
|
||||
? 'https'
|
||||
: 'http',
|
||||
'psgi.input' => $r,
|
||||
'psgi.errors' => *STDERR,
|
||||
'psgi.multithread' => Plack::Util::FALSE,
|
||||
'psgi.multiprocess' => Plack::Util::TRUE,
|
||||
'psgi.run_once' => Plack::Util::FALSE,
|
||||
'psgi.streaming' => Plack::Util::TRUE,
|
||||
'psgi.nonblocking' => Plack::Util::FALSE,
|
||||
'psgix.harakiri' => Plack::Util::TRUE,
|
||||
'psgix.cleanup' => Plack::Util::TRUE,
|
||||
'psgix.cleanup.handlers' => [],
|
||||
'psqi.r' => $r,
|
||||
};
|
||||
if ( defined( my $HTTP_AUTHORIZATION = $r->headers_in->{Authorization} ) ) {
|
||||
$env->{HTTP_AUTHORIZATION} = $HTTP_AUTHORIZATION;
|
||||
}
|
||||
my $uri = URI->new( "http://" . $r->hostname . $r->{env}->{REQUEST_URI} );
|
||||
$env->{PATH_INFO} = uri_unescape( $uri->path );
|
||||
|
||||
my $self = Plack::Request->new($env);
|
||||
bless $self, $class;
|
||||
return $self;
|
||||
}
|
||||
|
||||
sub datas {
|
||||
my($self) = @_;
|
||||
return $self->{datas} ||= {};
|
||||
}
|
||||
|
||||
1;
|
|
@ -24,8 +24,8 @@ our @EXPORT_OK = @EXPORT;
|
|||
# using indefinitely a session id disclosed accidentally or maliciously.
|
||||
# @return session id
|
||||
sub fetchId {
|
||||
my $class = shift;
|
||||
if ( my $creds = $class->header_in('Authorization') ) {
|
||||
my ( $class, $req ) = @_;
|
||||
if ( my $creds = $req->env->{'HTTP_AUTHORIZATION'} ) {
|
||||
$creds =~ s/^Basic\s+//;
|
||||
my @date = localtime;
|
||||
my $day = $date[5] * 366 + $date[7];
|
||||
|
@ -41,17 +41,19 @@ sub fetchId {
|
|||
# and if needed, ask portal to create it through a SOAP request
|
||||
# @return true if the session was found, false else
|
||||
sub retrieveSession {
|
||||
my ( $class, $id ) = @_;
|
||||
my ( $class, $req, $id ) = @_;
|
||||
|
||||
# First check if session already exists
|
||||
if ( my $res = $class->Lemonldap::NG::Handler::Main::retrieveSession($id) )
|
||||
if ( my $res =
|
||||
$class->Lemonldap::NG::Handler::Main::retrieveSession( $req, $id ) )
|
||||
{
|
||||
return $res;
|
||||
}
|
||||
|
||||
# Then ask portal to create it
|
||||
if ( $class->createSession($id) ) {
|
||||
return $class->Lemonldap::NG::Handler::Main::retrieveSession($id);
|
||||
if ( $class->createSession( $req, $id ) ) {
|
||||
return $class->Lemonldap::NG::Handler::Main::retrieveSession( $req,
|
||||
$id );
|
||||
}
|
||||
else {
|
||||
return 0;
|
||||
|
@ -62,12 +64,12 @@ sub retrieveSession {
|
|||
# Ask portal to create it through a SOAP request
|
||||
# @return true if the session is created, else false
|
||||
sub createSession {
|
||||
my ( $class, $id ) = @_;
|
||||
my ( $class, $req, $id ) = @_;
|
||||
|
||||
# Add client IP as X-Forwarded-For IP in SOAP request
|
||||
my $xheader = $class->header_in('X-Forwarded-For');
|
||||
my $xheader = $req->env->{'HTTP_X_FORWARDED_FOR'};
|
||||
$xheader .= ", " if ($xheader);
|
||||
$xheader .= $class->remote_ip;
|
||||
$xheader .= $req->{env}->{REMOTE_ADDR};
|
||||
|
||||
#my $soapHeaders = HTTP::Headers->new( "X-Forwarded-For" => $xheader );
|
||||
## TODO: use adminSession or sessions
|
||||
|
@ -76,7 +78,7 @@ sub createSession {
|
|||
# default_headers => $soapHeaders
|
||||
#)->uri('urn:Lemonldap/NG/Common/PSGI/SOAPService');
|
||||
|
||||
my $creds = $class->header_in('Authorization');
|
||||
my $creds = $req->env->{'HTTP_AUTHORIZATION'};
|
||||
$creds =~ s/^Basic\s+//;
|
||||
my ( $user, $pwd ) = ( decode_base64($creds) =~ /^(.*?):(.*)$/ );
|
||||
$class->logger->debug("AuthBasic authentication for user: $user");
|
||||
|
@ -84,18 +86,18 @@ sub createSession {
|
|||
#my $soapRequest = $soapClient->getCookies( $user, $pwd, $id );
|
||||
my $url = $class->tsv->{portal}->() . "/sessions/global/$id?auth";
|
||||
$url =~ s#//sessions/#/sessions/#g;
|
||||
my $req = HTTP::Request->new( POST => $url );
|
||||
$req->header( 'X-Forwarded-For' => $xheader );
|
||||
$req->header( 'Content-Type' => 'application/x-www-form-urlencoded' );
|
||||
$req->header( Accept => 'application/json' );
|
||||
$req->content(
|
||||
my $get = HTTP::Request->new( POST => $url );
|
||||
$get->header( 'X-Forwarded-For' => $xheader );
|
||||
$get->header( 'Content-Type' => 'application/x-www-form-urlencoded' );
|
||||
$get->header( Accept => 'application/json' );
|
||||
$get->content(
|
||||
build_urlencoded(
|
||||
user => $user,
|
||||
password => $pwd,
|
||||
secret => $class->tsv->{cipher}->encrypt(time)
|
||||
)
|
||||
);
|
||||
my $resp = $class->ua->request($req);
|
||||
my $resp = $class->ua->request($get);
|
||||
|
||||
if ( $resp->is_success ) {
|
||||
$class->userLogger->notice("Good REST authentication for $user");
|
||||
|
@ -130,9 +132,9 @@ sub createSession {
|
|||
## @rmethod protected void hideCookie()
|
||||
# Hide user credentials to the protected application
|
||||
sub hideCookie {
|
||||
my $class = shift;
|
||||
my ( $class, $req ) = @_;
|
||||
$class->logger->debug("removing Authorization header");
|
||||
$class->unset_header_in('Authorization');
|
||||
$class->unset_header_in( $req, 'Authorization' );
|
||||
}
|
||||
|
||||
## @rmethod protected int goToPortal(string url, string arg)
|
||||
|
@ -142,12 +144,13 @@ sub hideCookie {
|
|||
# @param $arg optionnal GET parameters
|
||||
# @return Apache2::Const::REDIRECT or Apache2::Const::AUTH_REQUIRED
|
||||
sub goToPortal {
|
||||
my ( $class, $url, $arg ) = @_;
|
||||
my ( $class, $req, $url, $arg ) = @_;
|
||||
if ($arg) {
|
||||
return $class->Lemonldap::NG::Handler::Main::goToPortal( $url, $arg );
|
||||
return $class->Lemonldap::NG::Handler::Main::goToPortal( $req, $url,
|
||||
$arg );
|
||||
}
|
||||
else {
|
||||
$class->set_header_out(
|
||||
$class->set_header_out( $req,
|
||||
'WWW-Authenticate' => 'Basic realm="LemonLDAP::NG"' );
|
||||
return $class->AUTH_REQUIRED;
|
||||
}
|
||||
|
|
|
@ -6,11 +6,12 @@ our $VERSION = '2.0.0';
|
|||
|
||||
sub run {
|
||||
my ( $class, $req, $rule, $protection ) = @_;
|
||||
my $uri = $class->unparsed_uri;
|
||||
my $uri = $req->{env}->{REQUEST_URI};
|
||||
my $cn = $class->tsv->{cookieName};
|
||||
my ( $id, $session );
|
||||
if ( $uri =~ s/[\?&;]${cn}cda=(\w+)$//oi ) {
|
||||
if ( $id = $class->fetchId and $session = $class->retrieveSession($id) )
|
||||
if ( $id = $class->fetchId($req)
|
||||
and $session = $class->retrieveSession( $req, $id ) )
|
||||
{
|
||||
$class->logger->info(
|
||||
'CDA asked for an already available session, skipping');
|
||||
|
@ -19,19 +20,20 @@ sub run {
|
|||
my $cdaid = $1;
|
||||
$class->logger->debug("CDA request with id $cdaid");
|
||||
|
||||
my $cdaInfos = $class->getCDAInfos($cdaid);
|
||||
my $cdaInfos = $class->getCDAInfos( $req, $cdaid );
|
||||
unless ( $cdaInfos->{cookie_value} and $cdaInfos->{cookie_name} ) {
|
||||
$class->logger->error("CDA request for id $cdaid is not valid");
|
||||
return $class->FORBIDDEN;
|
||||
}
|
||||
|
||||
my $redirectUrl = $class->_buildUrl($uri);
|
||||
my $redirectUrl = $class->_buildUrl( $req, $uri );
|
||||
my $redirectHttps = ( $redirectUrl =~ m/^https/ );
|
||||
$class->set_header_out(
|
||||
$req,
|
||||
'Location' => $redirectUrl,
|
||||
'Set-Cookie' => $cdaInfos->{cookie_name} . "=" . 'c:'
|
||||
. $class->tsv->{cipher}->encrypt(
|
||||
$cdaInfos->{cookie_value} . ' ' . $class->resolveAlias
|
||||
$cdaInfos->{cookie_value} . ' ' . $class->resolveAlias($req)
|
||||
)
|
||||
. "; path=/"
|
||||
. ( $redirectHttps ? "; secure" : "" )
|
||||
|
@ -53,7 +55,7 @@ sub run {
|
|||
# Tries to retrieve the CDA session, get infos and delete session
|
||||
# @return CDA session infos
|
||||
sub getCDAInfos {
|
||||
my ( $class, $id ) = @_;
|
||||
my ( $class, $req, $id ) = @_;
|
||||
my $infos = {};
|
||||
|
||||
# Get the session
|
||||
|
|
|
@ -16,33 +16,36 @@ sub ua {
|
|||
}
|
||||
|
||||
sub grant {
|
||||
my ( $class, $session, $uri, $cond, $vhost ) = @_;
|
||||
$vhost ||= $class->resolveAlias;
|
||||
my ( $class, $req, $session, $uri, $cond, $vhost ) = @_;
|
||||
$vhost ||= $class->resolveAlias($req);
|
||||
$class->tsv->{lastVhostUpdate} //= {};
|
||||
unless ( $class->tsv->{defaultCondition}->{$vhost}
|
||||
and ( time() - $class->tsv->{lastVhostUpdate}->{$vhost} < 600 ) )
|
||||
{
|
||||
$class->loadVhostConfig($vhost);
|
||||
$class->loadVhostConfig( $req, $vhost );
|
||||
}
|
||||
return $class->Lemonldap::NG::Handler::Main::grant( $session, $uri, $cond,
|
||||
$vhost );
|
||||
return $class->Lemonldap::NG::Handler::Main::grant( $req, $session, $uri,
|
||||
$cond, $vhost );
|
||||
}
|
||||
|
||||
sub loadVhostConfig {
|
||||
my ( $class, $vhost ) = @_;
|
||||
my ( $class, $req, $vhost ) = @_;
|
||||
my $json;
|
||||
if ( $class->tsv->{useSafeJail} ) {
|
||||
my $base = $class->localConfig->{loopBackUrl}
|
||||
|| "http://127.0.0.1:" . $class->get_server_port;
|
||||
my $req = HTTP::Request->new( GET => "$base/rules.json" );
|
||||
$req->header( Host => $vhost );
|
||||
my $resp = $class->ua->request($req);
|
||||
|| "http://127.0.0.1:" . $req->{env}->{SERVER_PORT};
|
||||
my $get = HTTP::Request->new( GET => "$base/rules.json" );
|
||||
$get->header( Host => $vhost );
|
||||
my $resp = $class->ua->request($get);
|
||||
if ( $resp->is_success ) {
|
||||
eval { $json = from_json( $resp->content ) };
|
||||
if ($@) {
|
||||
$class->logger->error(
|
||||
"Bad rules.json for $vhost, skipping ($@)");
|
||||
}
|
||||
else {
|
||||
$class->logger->info("Compiling rules.json for $vhost");
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
|
|
@ -33,13 +33,13 @@ BEGIN {
|
|||
sub run {
|
||||
my $class = shift;
|
||||
my $r = $_[0];
|
||||
my $ret = $class->SUPER::run();
|
||||
my $ret = $class->SUPER::run($r);
|
||||
|
||||
# Continue only if user is authorized
|
||||
return $ret unless ( $ret == $class->OK );
|
||||
|
||||
# Get current URI
|
||||
my $uri = Lemonldap::NG::Handler::API->uri_with_args($r);
|
||||
my $uri = $r->{env}->{REQUEST_URI};
|
||||
|
||||
# Catch Secure Token parameters
|
||||
my $localConfig = $class->localConfig;
|
||||
|
@ -101,7 +101,7 @@ sub run {
|
|||
return $class->_returnError( $r, $secureTokenAllowOnError ) unless $key;
|
||||
|
||||
# Header location
|
||||
$class->set_header_in( $secureTokenHeader => $key );
|
||||
$class->set_header_in( $r, $secureTokenHeader => $key );
|
||||
|
||||
# Remove token
|
||||
eval 'use Apache2::Filter' unless ( $INC{"Apache2/Filter.pm"} );
|
||||
|
|
|
@ -5,9 +5,9 @@ use strict;
|
|||
our $VERSION = '2.0.0';
|
||||
|
||||
sub fetchId {
|
||||
my ($class) = @_;
|
||||
my $token = $class->header_in('X-Llng-Token');
|
||||
return $class->Lemonldap::NG::Handler::Main::fetchId() unless ($token);
|
||||
my ( $class, $req ) = @_;
|
||||
my $token = $req->{env}->{HTTP_X_LLNG_TOKEN};
|
||||
return $class->Lemonldap::NG::Handler::Main::fetchId($req) unless ($token);
|
||||
$class->logger->debug('Found token header');
|
||||
my $s = $class->tsv->{cipher}->decrypt($token);
|
||||
my ( $t, $_session_id, @vhosts ) = split /:/, $s;
|
||||
|
@ -19,7 +19,7 @@ sub fetchId {
|
|||
$class->userLogger->warn('Expired token');
|
||||
return 0;
|
||||
}
|
||||
my $vh = $class->resolveAlias;
|
||||
my $vh = $class->resolveAlias($req);
|
||||
unless ( grep { $_ eq $vh } @vhosts ) {
|
||||
$class->userLogger->error(
|
||||
"$vh not authorizated in token (" . join( ', ', @vhosts ) . ')' );
|
||||
|
|
|
@ -22,7 +22,7 @@ sub run {
|
|||
return $ret unless ( $ret == $class->OK );
|
||||
|
||||
# Get current URI
|
||||
my $uri = $class->uri_with_args($req);
|
||||
my $uri = $req->{env}->{REQUEST_URI};
|
||||
|
||||
# Get Zimbra parameters
|
||||
my $localConfig = $class->localConfig;
|
||||
|
@ -52,7 +52,7 @@ sub run {
|
|||
|
||||
# Build URL
|
||||
my $zimbra_url =
|
||||
$class->_buildZimbraPreAuthUrl( $zimbraPreAuthKey, $zimbraUrl,
|
||||
$class->_buildZimbraPreAuthUrl( $req, $zimbraPreAuthKey, $zimbraUrl,
|
||||
$class->datas->{$zimbraAccountKey},
|
||||
$zimbraBy, $timeout );
|
||||
|
||||
|
@ -72,7 +72,7 @@ sub run {
|
|||
# @param timeout Timout
|
||||
# @return Zimbra PreAuth URL
|
||||
sub _buildZimbraPreAuthUrl {
|
||||
my ( $class, $key, $url, $account, $by, $timeout ) = @_;
|
||||
my ( $class, $req, $key, $url, $account, $by, $timeout ) = @_;
|
||||
|
||||
# Expiration time is calculated with _utime and timeout
|
||||
my $expires =
|
||||
|
|
|
@ -4,7 +4,6 @@ use strict;
|
|||
|
||||
use Safe;
|
||||
use Lemonldap::NG::Common::Safelib; #link protected safe Safe object
|
||||
use constant SAFEWRAP => ( Safe->can("wrap_code_ref") ? 1 : 0 );
|
||||
use Mouse;
|
||||
|
||||
has customFunctions => ( is => 'rw', isa => 'Maybe[Str]' );
|
||||
|
@ -66,16 +65,10 @@ sub build_jail {
|
|||
$self->jail->share_from( 'Lemonldap::NG::Common::Safelib',
|
||||
$Lemonldap::NG::Common::Safelib::functions );
|
||||
|
||||
$self->jail->share_from(
|
||||
$api,
|
||||
[
|
||||
qw( &hostname &remote_ip &uri &uri_with_args
|
||||
&unparsed_uri &args &method &header_in &env )
|
||||
]
|
||||
);
|
||||
$self->jail->share_from( __PACKAGE__, [ @t, '&encrypt', '&token' ] );
|
||||
$self->jail->share_from( 'MIME::Base64', ['&encode_base64'] );
|
||||
$self->jail->share_from( 'Lemonldap::NG::Handler::Main', ['$_v'] );
|
||||
|
||||
#$self->jail->share_from( 'Lemonldap::NG::Handler::Main', ['$_v'] );
|
||||
|
||||
# Initialize cryptographic functions to be able to use them in jail.
|
||||
eval { token('a') };
|
||||
|
@ -142,7 +135,7 @@ sub share_from {
|
|||
}
|
||||
|
||||
## @imethod protected jail_reval()
|
||||
# Build and return restricted eval command with SAFEWRAP, if activated
|
||||
# Build and return restricted eval command
|
||||
# @return evaluation of $reval or $reval2
|
||||
sub jail_reval {
|
||||
my ( $self, $reval ) = @_;
|
||||
|
@ -151,14 +144,7 @@ sub jail_reval {
|
|||
# the "no safe wrap" reval
|
||||
|
||||
my $res;
|
||||
eval {
|
||||
$res = (
|
||||
SAFEWRAP
|
||||
and $self->useSafeJail
|
||||
? $self->jail->wrap_code_ref( $self->jail->reval($reval) )
|
||||
: $self->jail->reval($reval)
|
||||
);
|
||||
};
|
||||
eval { $res = ( $self->jail->reval($reval) ) };
|
||||
if ($@) {
|
||||
$self->error($@);
|
||||
return undef;
|
||||
|
|
|
@ -462,12 +462,11 @@ sub conditionSub {
|
|||
eval 'use Apache2::Filter' unless ( $INC{"Apache2/Filter.pm"} );
|
||||
return (
|
||||
sub {
|
||||
$Lemonldap::NG::Handler::ApacheMP2::Main::request
|
||||
->add_output_filter(
|
||||
$_[0]->add_output_filter(
|
||||
sub {
|
||||
return $class->redirectFilter( $u, @_ );
|
||||
}
|
||||
);
|
||||
);
|
||||
1;
|
||||
},
|
||||
0
|
||||
|
@ -481,8 +480,7 @@ sub conditionSub {
|
|||
|
||||
#TODO: check this
|
||||
$class->localUnlog;
|
||||
$Lemonldap::NG::Handler::ApacheMP2::Main::request
|
||||
->add_output_filter(
|
||||
$_[0]->add_output_filter(
|
||||
sub {
|
||||
my $r = $_[0]->r;
|
||||
return $class->redirectFilter(
|
||||
|
@ -492,7 +490,7 @@ sub conditionSub {
|
|||
@_
|
||||
);
|
||||
}
|
||||
);
|
||||
);
|
||||
1;
|
||||
},
|
||||
0
|
||||
|
@ -535,12 +533,12 @@ sub substitute {
|
|||
|
||||
# substitute special vars, just for retro-compatibility
|
||||
$expr =~ s/\$date\b/&date/sg;
|
||||
$expr =~ s/\$vhost\b/&hostname/sg;
|
||||
$expr =~ s/\$ip\b/&remote_ip/sg;
|
||||
$expr =~ s/\$vhost\b/\$ENV{HTTP_HOST}/sg;
|
||||
$expr =~ s/\$ip\b/\$ENV{REMOTE_ADDR}/sg;
|
||||
|
||||
# substitute vars with session datas, excepts special vars $_ and $\d+
|
||||
$expr =~ s/\$(?!ENV)(_*[a-zA-Z]\w*)/\$session->{$1}/sg;
|
||||
$expr =~ s/\$ENV\{/&env()->\{/g;
|
||||
$expr =~ s/\$(?!ENV)(_*[a-zA-Z]\w*)/\$s->{$1}/sg;
|
||||
$expr =~ s/\$ENV\{/\$r->{env}->\{/g;
|
||||
|
||||
return $expr;
|
||||
}
|
||||
|
@ -548,7 +546,7 @@ sub substitute {
|
|||
sub buildSub {
|
||||
my ( $class, $val ) = @_;
|
||||
my $res =
|
||||
$class->tsv->{jail}->jail_reval("sub{my \$session=\$_[0];return($val)}");
|
||||
$class->tsv->{jail}->jail_reval("sub{my (\$r,\$s)=\@_;return($val)}");
|
||||
unless ($res) {
|
||||
$class->logger->error( $class->tsv->{jail}->error );
|
||||
}
|
||||
|
|
|
@ -23,37 +23,35 @@ sub handler {
|
|||
sub logout {
|
||||
my $class;
|
||||
$class = $#_ ? shift : __PACKAGE__;
|
||||
$class->newRequest( $_[0] );
|
||||
return $class->unlog();
|
||||
return $class->unlog(@_);
|
||||
}
|
||||
|
||||
sub status {
|
||||
my $class;
|
||||
$class = $#_ ? shift : __PACKAGE__;
|
||||
$class->newRequest( $_[0] );
|
||||
return $class->getStatus();
|
||||
return $class->getStatus(@_);
|
||||
}
|
||||
|
||||
# Public methods
|
||||
|
||||
# Return Handler::Lib::Status output
|
||||
sub getStatus {
|
||||
my ($class) = @_;
|
||||
my ( $class, $req ) = @_;
|
||||
$class->logger->debug("Request for status");
|
||||
my $statusPipe = $class->tsv->{statusPipe};
|
||||
my $statusOut = $class->tsv->{statusOut};
|
||||
return $class->abort("$class: status page can not be displayed")
|
||||
return $class->abort( $req, "$class: status page can not be displayed" )
|
||||
unless ( $statusPipe and $statusOut );
|
||||
print $statusPipe "STATUS"
|
||||
. ( $class->args ? " " . $class->args : '' ) . "\n";
|
||||
print $statusPipe "STATUS" . ( $req->{env}->{QUERY_STRING} || '' ) . "\n";
|
||||
my $buf;
|
||||
|
||||
while (<$statusOut>) {
|
||||
last if (/^END$/);
|
||||
$buf .= $_;
|
||||
}
|
||||
$class->set_header_out( ( "Content-Type" => "text/html; charset=UTF-8" ) );
|
||||
$class->print($buf);
|
||||
$class->set_header_out( $req,
|
||||
"Content-Type" => "text/html; charset=UTF-8" );
|
||||
$class->print( $req, $buf );
|
||||
return $class->OK;
|
||||
}
|
||||
|
||||
|
@ -62,12 +60,11 @@ sub getStatus {
|
|||
sub checkType {
|
||||
my ( $class, $req ) = @_;
|
||||
|
||||
$class->newRequest($req);
|
||||
if ( time() - $class->lastCheck > $class->checkTime ) {
|
||||
die("$class: No configuration found")
|
||||
unless ( $class->checkConf );
|
||||
}
|
||||
my $vhost = $class->resolveAlias;
|
||||
my $vhost = $class->resolveAlias($req);
|
||||
return ( defined $class->tsv->{type}->{$vhost} )
|
||||
? $class->tsv->{type}->{$vhost}
|
||||
: 'Main';
|
||||
|
@ -84,14 +81,14 @@ sub run {
|
|||
my ( $class, $req, $rule, $protection ) = @_;
|
||||
my ( $id, $session );
|
||||
|
||||
return $class->DECLINED unless ( $class->is_initial_req );
|
||||
return $class->DECLINED unless ( $class->is_initial_req($req) );
|
||||
|
||||
# Direct return if maintenance mode is active
|
||||
if ( $class->checkMaintenanceMode ) {
|
||||
if ( $class->checkMaintenanceMode($req) ) {
|
||||
|
||||
if ( $class->tsv->{useRedirectOnError} ) {
|
||||
$class->logger->debug("Go to portal with maintenance error code");
|
||||
return $class->goToError( '/', $class->MAINTENANCE );
|
||||
return $class->goToError( $req, '/', $class->MAINTENANCE );
|
||||
}
|
||||
else {
|
||||
$class->logger->debug("Return maintenance error code");
|
||||
|
@ -100,25 +97,25 @@ sub run {
|
|||
}
|
||||
|
||||
# Cross domain authentication
|
||||
my $uri = $class->unparsed_uri;
|
||||
my $uri = $req->{env}->{REQUEST_URI};
|
||||
|
||||
$uri = $class->uri_with_args;
|
||||
$uri = $req->{env}->{REQUEST_URI};
|
||||
my ($cond);
|
||||
( $cond, $protection ) = $class->conditionSub($rule) if ($rule);
|
||||
$protection = $class->isUnprotected($uri) || 0
|
||||
$protection = $class->isUnprotected( $req, $uri ) || 0
|
||||
unless ( defined $protection );
|
||||
|
||||
if ( $protection == $class->SKIP ) {
|
||||
$class->logger->debug("Access control skipped");
|
||||
$class->updateStatus('SKIP');
|
||||
$class->hideCookie;
|
||||
$class->cleanHeaders;
|
||||
$class->updateStatus( $req, 'SKIP' );
|
||||
$class->hideCookie($req);
|
||||
$class->cleanHeaders($req);
|
||||
return $class->OK;
|
||||
}
|
||||
|
||||
# Try to recover cookie and user session
|
||||
if ( $id = $class->fetchId
|
||||
and $session = $class->retrieveSession($id) )
|
||||
if ( $id = $class->fetchId($req)
|
||||
and $session = $class->retrieveSession( $req, $id ) )
|
||||
{
|
||||
|
||||
# AUTHENTICATION done
|
||||
|
@ -127,24 +124,25 @@ sub run {
|
|||
my $kc = keys %{$session}; # in order to detect new local macro
|
||||
|
||||
# ACCOUNTING (1. Inform web server)
|
||||
$class->set_user( $session->{ $class->tsv->{whatToTrace} } );
|
||||
$class->set_user( $req, $session->{ $class->tsv->{whatToTrace} } );
|
||||
|
||||
# AUTHORIZATION
|
||||
return ( $class->forbidden($session), $session )
|
||||
unless ( $class->grant( $session, $uri, $cond ) );
|
||||
$class->updateStatus( 'OK', $session->{ $class->tsv->{whatToTrace} } );
|
||||
return ( $class->forbidden( $req, $session ), $session )
|
||||
unless ( $class->grant( $req, $session, $uri, $cond ) );
|
||||
$class->updateStatus( $req, 'OK',
|
||||
$session->{ $class->tsv->{whatToTrace} } );
|
||||
|
||||
# ACCOUNTING (2. Inform remote application)
|
||||
$class->sendHeaders($session);
|
||||
$class->sendHeaders( $req, $session );
|
||||
|
||||
# Store local macros
|
||||
if ( keys %$session > $kc ) {
|
||||
$class->logger->debug("Update local cache");
|
||||
$class->session->update( $session, { updateCache => 2 } );
|
||||
$req->datas->{session}->update( $session, { updateCache => 2 } );
|
||||
}
|
||||
|
||||
# Hide Lemonldap::NG cookie
|
||||
$class->hideCookie;
|
||||
$class->hideCookie($req);
|
||||
|
||||
# Log access granted
|
||||
$class->logger->debug( "User "
|
||||
|
@ -152,8 +150,8 @@ sub run {
|
|||
. " was granted to access to $uri" );
|
||||
|
||||
# Catch POST rules
|
||||
$class->postOutputFilter( $session, $uri );
|
||||
$class->postInputFilter( $session, $uri );
|
||||
$class->postOutputFilter( $req, $session, $uri );
|
||||
$class->postInputFilter( $req, $session, $uri );
|
||||
|
||||
return ( $class->OK, $session );
|
||||
}
|
||||
|
@ -162,9 +160,9 @@ sub run {
|
|||
|
||||
# Ignore unprotected URIs
|
||||
$class->logger->debug("No valid session but unprotected access");
|
||||
$class->updateStatus('UNPROTECT');
|
||||
$class->hideCookie;
|
||||
$class->cleanHeaders;
|
||||
$class->updateStatus( $req, 'UNPROTECT' );
|
||||
$class->hideCookie($req);
|
||||
$class->cleanHeaders($req);
|
||||
return $class->OK;
|
||||
}
|
||||
|
||||
|
@ -175,8 +173,8 @@ sub run {
|
|||
unless ($id);
|
||||
|
||||
# if the cookie was fetched, a log is sent by retrieveSession()
|
||||
$class->updateStatus( $id ? 'EXPIRED' : 'REDIRECT' );
|
||||
return $class->goToPortal( $class->unparsed_uri );
|
||||
$class->updateStatus( $req, $id ? 'EXPIRED' : 'REDIRECT' );
|
||||
return $class->goToPortal( $req, $req->{env}->{REQUEST_URI} );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -184,10 +182,10 @@ sub run {
|
|||
# Call localUnlog() then goToPortal() to unlog the current user.
|
||||
# @return Constant value returned by goToPortal()
|
||||
sub unlog {
|
||||
my $class = shift;
|
||||
$class->localUnlog(@_);
|
||||
$class->updateStatus('LOGOUT');
|
||||
return $class->goToPortal( '/', 'logout=1' );
|
||||
my ( $class, $req ) = @_;
|
||||
$class->localUnlog( $req, @_ );
|
||||
$class->updateStatus( $req, 'LOGOUT' );
|
||||
return $class->goToPortal( $req, '/', 'logout=1' );
|
||||
}
|
||||
|
||||
# INTERNAL METHODS
|
||||
|
@ -198,12 +196,14 @@ sub unlog {
|
|||
# @param optional user string Username to log, if undefined defaults to remote IP
|
||||
# @param optional url string URL to log, if undefined defaults to request URI
|
||||
sub updateStatus {
|
||||
my ( $class, $action, $user, $url ) = @_;
|
||||
my ( $class, $req, $action, $user, $url ) = @_;
|
||||
my $statusPipe = $class->tsv->{statusPipe} or return;
|
||||
$user ||= $class->remote_ip;
|
||||
$url ||= $class->uri_with_args;
|
||||
$user ||= $req->{env}->{REMOTE_ADDR};
|
||||
$url ||= $req->{env}->{REQUEST_URI};
|
||||
eval {
|
||||
print $statusPipe "$user => " . $class->hostname . "$url $action\n";
|
||||
print $statusPipe "$user => "
|
||||
. $req->{env}->{HTTP_HOST}
|
||||
. "$url $action\n";
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -220,8 +220,8 @@ sub lmLog {
|
|||
# Check if we are in maintenance mode
|
||||
# @return true if maintenance mode
|
||||
sub checkMaintenanceMode {
|
||||
my $class = shift;
|
||||
my $vhost = $class->resolveAlias;
|
||||
my ( $class, $req ) = @_;
|
||||
my $vhost = $class->resolveAlias($req);
|
||||
my $_maintenance =
|
||||
( defined $class->tsv->{maintenance}->{$vhost} )
|
||||
? $class->tsv->{maintenance}->{$vhost}
|
||||
|
@ -240,10 +240,10 @@ sub checkMaintenanceMode {
|
|||
# @param $cond optional Function granting access
|
||||
# @return True if the user is granted to access to the current URL
|
||||
sub grant {
|
||||
my ( $class, $session, $uri, $cond, $vhost ) = @_;
|
||||
return $cond->($session) if ($cond);
|
||||
my ( $class, $req, $session, $uri, $cond, $vhost ) = @_;
|
||||
return $cond->( $req, $session ) if ($cond);
|
||||
|
||||
$vhost ||= $class->resolveAlias;
|
||||
$vhost ||= $class->resolveAlias($req);
|
||||
if ( my $level = $class->tsv->{authnLevel}->{$vhost} ) {
|
||||
if ( $session->{authenticationLevel} < $level ) {
|
||||
$session->{_upgrade} = 1;
|
||||
|
@ -260,7 +260,8 @@ sub grant {
|
|||
$class->logger->debug( 'Regexp "'
|
||||
. $class->tsv->{locationConditionText}->{$vhost}->[$i]
|
||||
. '" match' );
|
||||
return $class->tsv->{locationCondition}->{$vhost}->[$i]->($session);
|
||||
return $class->tsv->{locationCondition}->{$vhost}->[$i]
|
||||
->( $req, $session );
|
||||
}
|
||||
}
|
||||
unless ( $class->tsv->{defaultCondition}->{$vhost} ) {
|
||||
|
@ -270,7 +271,7 @@ sub grant {
|
|||
return 0;
|
||||
}
|
||||
$class->logger->debug("$vhost: Apply default rule");
|
||||
return $class->tsv->{defaultCondition}->{$vhost}->($session);
|
||||
return $class->tsv->{defaultCondition}->{$vhost}->( $req, $session );
|
||||
}
|
||||
|
||||
## @rmethod protected int forbidden(string uri)
|
||||
|
@ -279,33 +280,33 @@ sub grant {
|
|||
# @param $uri URI
|
||||
# @return Constant $class->FORBIDDEN
|
||||
sub forbidden {
|
||||
my ( $class, $session, $vhost ) = @_;
|
||||
my $uri = $class->unparsed_uri;
|
||||
$vhost ||= $class->resolveAlias;
|
||||
my ( $class, $req, $session, $vhost ) = @_;
|
||||
my $uri = $req->{env}->{REQUEST_URI};
|
||||
$vhost ||= $class->resolveAlias($req);
|
||||
|
||||
if ( $session->{_logout} ) {
|
||||
$class->updateStatus( 'LOGOUT',
|
||||
$class->updateStatus( $req, 'LOGOUT',
|
||||
$session->{ $class->tsv->{whatToTrace} } );
|
||||
my $u = $session->{_logout};
|
||||
$class->localUnlog;
|
||||
return $class->goToPortal( $u, 'logout=1' );
|
||||
$class->localUnlog($req);
|
||||
return $class->goToPortal( $req, $u, 'logout=1' );
|
||||
}
|
||||
|
||||
if ( $session->{_upgrade} ) {
|
||||
return $class->goToPortal( $class->unparsed_uri, undef,
|
||||
'/upgradesession' );
|
||||
return $class->goToPortal( $req, $uri, undef, '/upgradesession' );
|
||||
}
|
||||
|
||||
# Log forbidding
|
||||
$class->userLogger->notice( "User "
|
||||
. $session->{ $class->tsv->{whatToTrace} }
|
||||
. " was forbidden to access to $vhost$uri" );
|
||||
$class->updateStatus( 'REJECT', $session->{ $class->tsv->{whatToTrace} } );
|
||||
$class->updateStatus( $req, 'REJECT',
|
||||
$session->{ $class->tsv->{whatToTrace} } );
|
||||
|
||||
# Redirect or Forbidden?
|
||||
if ( $class->tsv->{useRedirectOnForbidden} ) {
|
||||
$class->logger->debug("Use redirect for forbidden access");
|
||||
return $class->goToError( $uri, 403 );
|
||||
return $class->goToError( $req, $uri, 403 );
|
||||
}
|
||||
else {
|
||||
$class->logger->debug("Return forbidden access");
|
||||
|
@ -316,16 +317,16 @@ sub forbidden {
|
|||
## @rmethod protected void hideCookie()
|
||||
# Hide Lemonldap::NG cookie to the protected application.
|
||||
sub hideCookie {
|
||||
my $class = shift;
|
||||
my ( $class, $req ) = @_;
|
||||
$class->logger->debug("removing cookie");
|
||||
my $cookie = $class->header_in('Cookie');
|
||||
my $cookie = $req->env->{HTTP_COOKIE};
|
||||
my $cn = $class->tsv->{cookieName};
|
||||
$cookie =~ s/$cn(http)?=[^,;]*[,;\s]*//og;
|
||||
if ($cookie) {
|
||||
$class->set_header_in( 'Cookie' => $cookie );
|
||||
$class->set_header_in( $req, 'Cookie' => $cookie );
|
||||
}
|
||||
else {
|
||||
$class->unset_header_in('Cookie');
|
||||
$class->unset_header_in( $req, 'Cookie' );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -333,8 +334,8 @@ sub hideCookie {
|
|||
# Encode URl in the format used by Lemonldap::NG::Portal for redirections.
|
||||
# @return Base64 encoded string
|
||||
sub encodeUrl {
|
||||
my ( $class, $url ) = @_;
|
||||
$url = $class->_buildUrl($url) if ( $url !~ m#^https?://# );
|
||||
my ( $class, $req, $url ) = @_;
|
||||
$url = $class->_buildUrl( $req, $url ) if ( $url !~ m#^https?://# );
|
||||
return encode_base64( $url, '' );
|
||||
}
|
||||
|
||||
|
@ -344,24 +345,26 @@ sub encodeUrl {
|
|||
# @param $arg optionnal GET parameters
|
||||
# @return Constant $class->REDIRECT
|
||||
sub goToPortal {
|
||||
my ( $class, $url, $arg, $path ) = @_;
|
||||
my ( $class, $req, $url, $arg, $path ) = @_;
|
||||
$path ||= '';
|
||||
my ( $ret, $msg );
|
||||
my $urlc_init = $class->encodeUrl($url);
|
||||
my $urlc_init = $class->encodeUrl( $req, $url );
|
||||
$class->logger->debug(
|
||||
"Redirect " . $class->remote_ip . " to portal (url was $url)" );
|
||||
$class->set_header_out( 'Location' => $class->tsv->{portal}->()
|
||||
"Redirect $req->{env}->{REMOTE_ADDR} to portal (url was $url)");
|
||||
$class->set_header_out( $req,
|
||||
'Location' => $class->tsv->{portal}->()
|
||||
. "$path?url=$urlc_init"
|
||||
. ( $arg ? "&$arg" : "" ) );
|
||||
return $class->REDIRECT;
|
||||
}
|
||||
|
||||
sub goToError {
|
||||
my ( $class, $url, $code ) = @_;
|
||||
my $urlc_init = $class->encodeUrl($url);
|
||||
my ( $class, $req, $url, $code ) = @_;
|
||||
my $urlc_init = $class->encodeUrl( $req, $url );
|
||||
$class->logger->debug(
|
||||
"Redirect " . $class->remote_ip . " to lmError (url was $url)" );
|
||||
$class->set_header_out( 'Location' => $class->tsv->{portal}->()
|
||||
"Redirect $req->{env}->{REMOTE_ADDR} to lmError (url was $url)");
|
||||
$class->set_header_out( $req,
|
||||
'Location' => $class->tsv->{portal}->()
|
||||
. "/lmerror/$code"
|
||||
. "?url=$urlc_init" );
|
||||
return $class->REDIRECT;
|
||||
|
@ -371,9 +374,9 @@ sub goToError {
|
|||
# Get user cookies and search for Lemonldap::NG cookie.
|
||||
# @return Value of the cookie if found, 0 else
|
||||
sub fetchId {
|
||||
my $class = shift;
|
||||
my $t = $class->header_in('Cookie') or return 0;
|
||||
my $vhost = $class->resolveAlias;
|
||||
my ( $class, $req ) = @_;
|
||||
my $t = $req->{env}->{HTTP_COOKIE} or return 0;
|
||||
my $vhost = $class->resolveAlias($req);
|
||||
my $lookForHttpCookie = (
|
||||
$class->tsv->{securedCookie} =~ /^(2|3)$/
|
||||
and !( defined( $class->tsv->{https}->{$vhost} ) )
|
||||
|
@ -404,7 +407,7 @@ sub fetchId {
|
|||
# Tries to retrieve the session whose index is id
|
||||
# @return true if the session was found, false else
|
||||
sub retrieveSession {
|
||||
my ( $class, $id ) = @_;
|
||||
my ( $class, $req, $id ) = @_;
|
||||
my $now = time();
|
||||
|
||||
# 1. Search if the user was the same as previous (very efficient in
|
||||
|
@ -418,7 +421,7 @@ sub retrieveSession {
|
|||
}
|
||||
|
||||
# 2. Get the session from cache or backend
|
||||
my $session = $class->session(
|
||||
my $session = $req->datas->{session} = (
|
||||
Lemonldap::NG::Common::Session->new(
|
||||
{
|
||||
storageModule => $class->tsv->{sessionStorageModule},
|
||||
|
@ -460,11 +463,11 @@ sub retrieveSession {
|
|||
$class->tsv->{timeoutActivityInterval} )
|
||||
)
|
||||
{
|
||||
$class->session->update( { '_lastSeen' => $now } );
|
||||
$req->datas->{session}->update( { '_lastSeen' => $now } );
|
||||
|
||||
if ( $session->error ) {
|
||||
$class->logger->error("Cannot update session $id");
|
||||
$class->logger->error( $class->session->error );
|
||||
$class->logger->error( $req->datas->{session}->error );
|
||||
}
|
||||
else {
|
||||
$class->logger->debug("Update _lastSeen with $now");
|
||||
|
@ -487,8 +490,8 @@ sub retrieveSession {
|
|||
# @param $s path
|
||||
# @return URL
|
||||
sub _buildUrl {
|
||||
my ( $class, $s ) = @_;
|
||||
my $vhost = $class->hostname;
|
||||
my ( $class, $req, $s ) = @_;
|
||||
my $vhost = $req->{env}->{HTTP_HOST};
|
||||
my $_https = (
|
||||
defined( $class->tsv->{https}->{$vhost} )
|
||||
? $class->tsv->{https}->{$vhost}
|
||||
|
@ -497,7 +500,7 @@ sub _buildUrl {
|
|||
my $portString =
|
||||
$class->tsv->{port}->{$vhost}
|
||||
|| $class->tsv->{port}->{_}
|
||||
|| $class->get_server_port;
|
||||
|| $req->{env}->{SERVER_PORT};
|
||||
$portString = (
|
||||
( $_https && $portString == 443 )
|
||||
or ( !$_https && $portString == 80 )
|
||||
|
@ -513,8 +516,8 @@ sub _buildUrl {
|
|||
# $class->UNPROTECT if it is unprotected by "unprotect",
|
||||
# SKIP if is is unprotected by "skip"
|
||||
sub isUnprotected {
|
||||
my ( $class, $uri ) = @_;
|
||||
my $vhost = $class->resolveAlias;
|
||||
my ( $class, $req, $uri ) = @_;
|
||||
my $vhost = $class->resolveAlias($req);
|
||||
for (
|
||||
my $i = 0 ;
|
||||
$i < ( $class->tsv->{locationCount}->{$vhost} || 0 ) ;
|
||||
|
@ -531,12 +534,12 @@ sub isUnprotected {
|
|||
## @rmethod void sendHeaders()
|
||||
# Launch function compiled by forgeHeadersInit() for the current virtual host
|
||||
sub sendHeaders {
|
||||
my ( $class, $session ) = @_;
|
||||
my $vhost = $class->resolveAlias;
|
||||
my ( $class, $req, $session ) = @_;
|
||||
my $vhost = $class->resolveAlias($req);
|
||||
if ( defined $class->tsv->{forgeHeaders}->{$vhost} ) {
|
||||
|
||||
# Log headers in debug mode
|
||||
my %headers = $class->tsv->{forgeHeaders}->{$vhost}->($session);
|
||||
my %headers = $class->tsv->{forgeHeaders}->{$vhost}->( $req, $session );
|
||||
foreach my $h ( sort keys %headers ) {
|
||||
if ( defined( my $v = $headers{$h} ) ) {
|
||||
$class->logger->debug("Send header $h with value $v");
|
||||
|
@ -545,25 +548,26 @@ sub sendHeaders {
|
|||
$class->logger->debug("Send header $h with empty value");
|
||||
}
|
||||
}
|
||||
$class->set_header_in(%headers);
|
||||
$class->set_header_in( $req, %headers );
|
||||
}
|
||||
}
|
||||
|
||||
## @rmethod void cleanHeaders()
|
||||
# Unset HTTP headers, when sendHeaders is skipped
|
||||
sub cleanHeaders {
|
||||
my $class = shift;
|
||||
my $vhost = $class->resolveAlias;
|
||||
my ( $class, $req ) = @_;
|
||||
my $vhost = $class->resolveAlias($req);
|
||||
if ( defined( $class->tsv->{headerList}->{$vhost} ) ) {
|
||||
$class->unset_header_in( @{ $class->tsv->{headerList}->{$vhost} } );
|
||||
$class->unset_header_in( $req,
|
||||
@{ $class->tsv->{headerList}->{$vhost} } );
|
||||
}
|
||||
}
|
||||
|
||||
## @rmethod string resolveAlias
|
||||
# returns vhost whose current hostname is an alias
|
||||
sub resolveAlias {
|
||||
my $class = shift;
|
||||
my $vhost = $class->hostname;
|
||||
my ( $class, $req ) = @_;
|
||||
my $vhost = $req->{env}->{HTTP_HOST};
|
||||
return $class->tsv->{vhostAlias}->{$vhost} || $vhost;
|
||||
}
|
||||
|
||||
|
@ -575,18 +579,18 @@ sub resolveAlias {
|
|||
# @param $msg Message to log
|
||||
# @return Constant ($class->REDIRECT, $class->SERVER_ERROR)
|
||||
sub abort {
|
||||
my ( $class, $msg ) = @_;
|
||||
my ( $class, $req, $msg ) = @_;
|
||||
|
||||
# If abort is called without a valid request, fall to die
|
||||
eval {
|
||||
my $uri = $class->unparsed_uri;
|
||||
my $uri = $req->{env}->{REQUEST_URI};
|
||||
|
||||
$class->logger->error($msg);
|
||||
|
||||
# Redirect or die
|
||||
if ( $class->tsv->{useRedirectOnError} ) {
|
||||
$class->logger->debug("Use redirect for error");
|
||||
return $class->goToError( $uri, 500 );
|
||||
return $class->goToError( $req, $uri, 500 );
|
||||
}
|
||||
else {
|
||||
return $class->SERVER_ERROR;
|
||||
|
@ -598,9 +602,9 @@ sub abort {
|
|||
## @rmethod protected void localUnlog()
|
||||
# Delete current user from local cache entry.
|
||||
sub localUnlog {
|
||||
my ( $class, $id ) = @_;
|
||||
my ( $class, $req, $id ) = @_;
|
||||
$class->logger->debug('Local handler logout');
|
||||
if ( $id //= $class->fetchId ) {
|
||||
if ( $id //= $class->fetchId($req) ) {
|
||||
|
||||
# Delete thread datas
|
||||
if ( $class->datas->{_session_id}
|
||||
|
@ -608,6 +612,7 @@ sub localUnlog {
|
|||
{
|
||||
$class->datas( {} );
|
||||
}
|
||||
delete $req->datas->{session};
|
||||
|
||||
# Delete local cache
|
||||
if ( $class->tsv->{refLocalStorage}
|
||||
|
@ -622,18 +627,18 @@ sub localUnlog {
|
|||
# Add a javascript to html page in order to fill html form with fake data
|
||||
# @param uri URI to catch
|
||||
sub postOutputFilter {
|
||||
my ( $class, $session, $uri ) = @_;
|
||||
my $vhost = $class->resolveAlias;
|
||||
my ( $class, $req, $session, $uri ) = @_;
|
||||
my $vhost = $class->resolveAlias($req);
|
||||
|
||||
if ( defined( $class->tsv->{outputPostData}->{$vhost}->{$uri} ) ) {
|
||||
$class->logger->debug("Filling a html form with fake data");
|
||||
|
||||
$class->unset_header_in("Accept-Encoding");
|
||||
$class->unset_header_in( $req, "Accept-Encoding" );
|
||||
my %postdata =
|
||||
$class->tsv->{outputPostData}->{$vhost}->{$uri}->($session);
|
||||
$class->tsv->{outputPostData}->{$vhost}->{$uri}->( $req, $session );
|
||||
my $formParams = $class->tsv->{postFormParams}->{$vhost}->{$uri};
|
||||
my $js = $class->postJavascript( \%postdata, $formParams );
|
||||
$class->addToHtmlHead($js);
|
||||
my $js = $class->postJavascript( $req, \%postdata, $formParams );
|
||||
$class->addToHtmlHead( $req, $js );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -641,17 +646,18 @@ sub postOutputFilter {
|
|||
# Replace request body with form datas defined in configuration
|
||||
# @param uri URI to catch
|
||||
sub postInputFilter {
|
||||
my ( $class, $session, $uri ) = @_;
|
||||
my $vhost = $class->resolveAlias;
|
||||
my ( $class, $req, $session, $uri ) = @_;
|
||||
my $vhost = $class->resolveAlias($req);
|
||||
|
||||
if ( defined( $class->tsv->{inputPostData}->{$vhost}->{$uri} ) ) {
|
||||
$class->logger->debug("Replacing fake data with real form data");
|
||||
|
||||
my %data = $class->tsv->{inputPostData}->{$vhost}->{$uri}->($session);
|
||||
my %data =
|
||||
$class->tsv->{inputPostData}->{$vhost}->{$uri}->( $req, $session );
|
||||
foreach ( keys %data ) {
|
||||
$data{$_} = uri_escape( $data{$_} );
|
||||
}
|
||||
$class->setPostParams( \%data );
|
||||
$class->setPostParams( $req, \%data );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -659,7 +665,7 @@ sub postInputFilter {
|
|||
# build a javascript to fill a html form with fake data
|
||||
# @param data hashref containing input => value
|
||||
sub postJavascript {
|
||||
my ( $class, $data, $formParams ) = @_;
|
||||
my ( $class, $req, $data, $formParams ) = @_;
|
||||
|
||||
my $form = $formParams->{formSelector} || "form";
|
||||
|
||||
|
|
|
@ -24,7 +24,7 @@ BEGIN {
|
|||
};
|
||||
|
||||
# Current sessions properties
|
||||
our $_v = { session => {}, datas => {}, datasUpdate => {}, };
|
||||
our $_v = { datas => {}, datasUpdate => {}, };
|
||||
|
||||
# Thread shared accessors
|
||||
foreach ( keys %$_tshv ) {
|
||||
|
|
|
@ -19,14 +19,6 @@ use constant AUTH_REQUIRED => 401;
|
|||
use constant MAINTENANCE => 503;
|
||||
use constant defaultLogger => 'Lemonldap::NG::Common::Logger::Std';
|
||||
|
||||
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)
|
||||
# @param $variable the name of the variable to share
|
||||
|
@ -35,40 +27,27 @@ sub thread_share {
|
|||
# nothing to do in PSGI
|
||||
}
|
||||
|
||||
## @method void newRequest($r)
|
||||
# Store request in global $request variable
|
||||
#
|
||||
#@param $r Lemonldap::NG::Common::PSGI::Request
|
||||
sub newRequest {
|
||||
my ( $class, $r ) = @_;
|
||||
$request = $r;
|
||||
## @method void setServerSignature(string sign)
|
||||
# modifies web server signature
|
||||
# @param $sign String to add to server signature
|
||||
sub setServerSignature {
|
||||
}
|
||||
|
||||
## @method void set_user(string user)
|
||||
# sets remote_user in response headers
|
||||
# @param user string username
|
||||
sub set_user {
|
||||
my ( $class, $user ) = @_;
|
||||
push @{ $request->{respHeaders} }, 'Lm-Remote-User' => $user;
|
||||
}
|
||||
|
||||
## @method string header_in(string header)
|
||||
# returns request header value
|
||||
# @param header string request header
|
||||
# @return request header value
|
||||
sub header_in {
|
||||
my ( $class, $header ) = @_;
|
||||
$header ||= $class; # to use header_in as a method or as a function
|
||||
return $request->{env}->{ cgiName($header) };
|
||||
my ( $class, $req, $user ) = @_;
|
||||
push @{ $req->{respHeaders} }, 'Lm-Remote-User' => $user;
|
||||
}
|
||||
|
||||
## @method void set_header_in(hash headers)
|
||||
# sets or modifies request headers
|
||||
# @param headers hash containing header names => header value
|
||||
sub set_header_in {
|
||||
my ( $class, %headers ) = @_;
|
||||
my ( $class, $req, %headers ) = @_;
|
||||
while ( my ( $h, $v ) = each %headers ) {
|
||||
$request->{env}->{ cgiName($h) } = $v;
|
||||
$req->{env}->{ cgiName($h) } = $v;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -76,9 +55,9 @@ sub set_header_in {
|
|||
# removes request headers
|
||||
# @param headers array with header names to remove
|
||||
sub unset_header_in {
|
||||
my ( $class, @headers ) = @_;
|
||||
my ( $class, $req, @headers ) = @_;
|
||||
foreach my $h (@headers) {
|
||||
delete $request->{env}->{ cgiName($h) };
|
||||
delete $req->{env}->{ cgiName($h) };
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -86,28 +65,12 @@ sub unset_header_in {
|
|||
# sets response headers
|
||||
# @param headers hash containing header names => header value
|
||||
sub set_header_out {
|
||||
my ( $class, %headers ) = @_;
|
||||
my ( $class, $req, %headers ) = @_;
|
||||
while ( my ( $h, $v ) = each %headers ) {
|
||||
push @{ $request->{respHeaders} }, $h => $v;
|
||||
push @{ $req->{respHeaders} }, $h => $v;
|
||||
}
|
||||
}
|
||||
|
||||
## @method string hostname
|
||||
# returns host, as set by full URI or Host header
|
||||
# @return host string Host value
|
||||
sub hostname {
|
||||
my $h = $request->{env}->{HTTP_HOST};
|
||||
$h =~ s/:\d+//;
|
||||
return $h;
|
||||
}
|
||||
|
||||
## @method string remote_ip
|
||||
# returns client IP address
|
||||
# @return IP_Addr string client IP
|
||||
sub remote_ip {
|
||||
return $request->{env}->{REMOTE_ADDR};
|
||||
}
|
||||
|
||||
## @method boolean is_initial_req
|
||||
# always returns true
|
||||
# @return is_initial_req boolean
|
||||
|
@ -115,69 +78,12 @@ sub is_initial_req {
|
|||
return 1;
|
||||
}
|
||||
|
||||
## @method string args(string args)
|
||||
# gets the query string
|
||||
# @return args string Query string
|
||||
sub args {
|
||||
return $request->{env}->{QUERY_STRING};
|
||||
}
|
||||
|
||||
## @method string uri
|
||||
# returns the path portion of the URI, normalized, i.e. :
|
||||
# * URL decoded (characters encoded as %XX are decoded,
|
||||
# except ? in order not to merge path and query string)
|
||||
# * references to relative path components "." and ".." are resolved
|
||||
# * two or more adjacent slashes are merged into a single slash
|
||||
# @return path portion of the URI, normalized
|
||||
sub uri {
|
||||
return $request->uri;
|
||||
}
|
||||
|
||||
## @method string uri_with_args
|
||||
# returns the URI, with arguments and with path portion normalized
|
||||
# @return URI with normalized path portion
|
||||
sub uri_with_args {
|
||||
return $request->{env}->{REQUEST_URI};
|
||||
}
|
||||
|
||||
## @method string unparsed_uri
|
||||
# returns the full original request URI, with arguments
|
||||
# @return full original request URI, with arguments
|
||||
sub unparsed_uri {
|
||||
return $request->{env}->{REQUEST_URI};
|
||||
}
|
||||
|
||||
## @method string get_server_port
|
||||
# returns the port the server is receiving the current request on
|
||||
# @return port string server port
|
||||
sub get_server_port {
|
||||
return $request->{env}->{SERVER_PORT};
|
||||
}
|
||||
|
||||
## @method string method
|
||||
# returns the request method
|
||||
# @return port string server port
|
||||
sub method {
|
||||
return $request->{env}->{REQUEST_METHOD};
|
||||
}
|
||||
|
||||
## Return FastCGI environment variables as hash
|
||||
sub env {
|
||||
return $request->{env};
|
||||
}
|
||||
|
||||
## @method void print(string data)
|
||||
# write data in HTTP response body
|
||||
# @param data Text to add in response body
|
||||
sub print {
|
||||
my ( $class, $data ) = @_;
|
||||
$request->{respBody} .= $data;
|
||||
}
|
||||
|
||||
sub cgiName {
|
||||
my $h = uc(shift);
|
||||
$h =~ s/-/_/g;
|
||||
return "HTTP_$h";
|
||||
my ( $class, $req, $data ) = @_;
|
||||
$req->{respBody} .= $data;
|
||||
}
|
||||
|
||||
sub addToHtmlHead {
|
||||
|
@ -188,6 +94,12 @@ sub addToHtmlHead {
|
|||
;
|
||||
}
|
||||
|
||||
sub cgiName {
|
||||
my $h = uc(shift);
|
||||
$h =~ s/-/_/g;
|
||||
return "HTTP_$h";
|
||||
}
|
||||
|
||||
*setPostParams = *addToHtmlHead;
|
||||
|
||||
1;
|
||||
|
|
|
@ -18,43 +18,29 @@ use constant defaultLogger => 'Lemonldap::NG::Common::Logger::Syslog';
|
|||
# sets or modifies request headers
|
||||
# @param headers hash containing header names => header value
|
||||
sub set_header_in {
|
||||
my ( $class, %headers ) = @_;
|
||||
my ( $class, $req, %headers ) = @_;
|
||||
for my $k ( keys %headers ) {
|
||||
$Lemonldap::NG::Handler::PSGI::Main::request->{ cgiName($k) } =
|
||||
$headers{$k};
|
||||
$req->{env}->{ cgiName($k) } = $headers{$k};
|
||||
}
|
||||
push @{ $Lemonldap::NG::Handler::PSGI::Main::request->{respHeaders} },
|
||||
%headers;
|
||||
push @{ $req->{respHeaders} }, %headers;
|
||||
}
|
||||
|
||||
sub unset_header_in {
|
||||
my ( $class, $header ) = @_;
|
||||
$Lemonldap::NG::Handler::PSGI::Main::request->{respHeaders} =
|
||||
[ grep { $_ ne $header }
|
||||
@{ $Lemonldap::NG::Handler::PSGI::Main::request->{respHeaders} } ];
|
||||
my ( $class, $req, $header ) = @_;
|
||||
$req->{respHeaders} = [ grep { $_ ne $header } @{ $req->{respHeaders} } ];
|
||||
$header =~ s/-/_/g;
|
||||
delete $Lemonldap::NG::Handler::PSGI::Main::request->{ cgiName($header) };
|
||||
delete $req->{env}->{$header};
|
||||
delete $req->{env}->{"HTTP_$header"};
|
||||
}
|
||||
|
||||
# Inheritence is broken in this case with Debian >= jessie
|
||||
*checkType = *Lemonldap::NG::Handler::PSGI::Main::checkType;
|
||||
*setServerSignature = *Lemonldap::NG::Handler::PSGI::Main::setServerSignature;
|
||||
*thread_share = *Lemonldap::NG::Handler::PSGI::Main::thread_share;
|
||||
*newRequest = *Lemonldap::NG::Handler::PSGI::Main::newRequest;
|
||||
*set_user = *Lemonldap::NG::Handler::PSGI::Main::set_user;
|
||||
*header_in = *Lemonldap::NG::Handler::PSGI::Main::header_in;
|
||||
*set_header_out = *Lemonldap::NG::Handler::PSGI::Main::set_header_out;
|
||||
*hostname = *Lemonldap::NG::Handler::PSGI::Main::hostname;
|
||||
*remote_ip = *Lemonldap::NG::Handler::PSGI::Main::remote_ip;
|
||||
*is_initial_req = *Lemonldap::NG::Handler::PSGI::Main::is_initial_req;
|
||||
*args = *Lemonldap::NG::Handler::PSGI::Main::args;
|
||||
*env = *Lemonldap::NG::Handler::PSGI::Main::env;
|
||||
*uri = *Lemonldap::NG::Handler::PSGI::Main::uri;
|
||||
*uri_with_args = *Lemonldap::NG::Handler::PSGI::Main::uri_with_args;
|
||||
*unparsed_uri = *Lemonldap::NG::Handler::PSGI::Main::unparsed_uri;
|
||||
*get_server_port = *Lemonldap::NG::Handler::PSGI::Main::get_server_port;
|
||||
*method = *Lemonldap::NG::Handler::PSGI::Main::method;
|
||||
*print = *Lemonldap::NG::Handler::PSGI::Main::print;
|
||||
*cgiName = *Lemonldap::NG::Handler::PSGI::Main::cgiName;
|
||||
*addToHtmlHead = *Lemonldap::NG::Handler::PSGI::Main::addToHtmlHead;
|
||||
*cgiName = *Lemonldap::NG::Handler::PSGI::Main::cgiName;
|
||||
1;
|
||||
|
|
|
@ -3,7 +3,7 @@ use strict;
|
|||
use warnings;
|
||||
require 't/test.pm';
|
||||
|
||||
use Test::More tests => 10;
|
||||
use Test::More tests => 4;
|
||||
BEGIN { use_ok('Lemonldap::NG::Handler::Main') }
|
||||
|
||||
# get a standard basic configuration in $args hashref
|
||||
|
@ -22,12 +22,13 @@ $ENV{SERVER_NAME} = "test1.example.com";
|
|||
#open STDERR, '>/dev/null';
|
||||
|
||||
my $conf = {
|
||||
'cfgNum' => 1,
|
||||
'logLevel' => 'error',
|
||||
'portal' => 'http://auth.example.com/',
|
||||
'globalStorage' => 'Apache::Session::File',
|
||||
'post' => {},
|
||||
'locationRules' => {
|
||||
cfgNum => 1,
|
||||
logLevel => 'error',
|
||||
portal => 'http://auth.example.com/',
|
||||
globalStorage => 'Apache::Session::File',
|
||||
post => {},
|
||||
key => 1,
|
||||
locationRules => {
|
||||
'test1.example.com' => {
|
||||
|
||||
# Basic rules
|
||||
|
@ -51,10 +52,3 @@ ok( !$@, 'init' );
|
|||
ok( $h->configReload($conf), 'Load conf' );
|
||||
|
||||
ok( $h->tsv->{portal}->() eq 'http://auth.example.com/', 'portal' );
|
||||
|
||||
ok( $h->grant( undef, '/s' ), 'basic rule "accept"' );
|
||||
ok( !$h->grant( undef, '/no' ), 'basic rule "deny"' );
|
||||
ok( $h->grant( undef, '/a/a' ), 'bad ordered rule 1/2' );
|
||||
ok( $h->grant( undef, '/a' ), 'bad ordered rule 2/2' );
|
||||
ok( !$h->grant( undef, '/b/a' ), 'good ordered rule 1/2' );
|
||||
ok( $h->grant( undef, '/b' ), 'good ordered rule 2/2' );
|
||||
|
|
|
@ -1,69 +0,0 @@
|
|||
# Before `make install' is performed this script should be runnable with
|
||||
# `make test'. After `make install' it should work as `perl Lemonldap-NG-Handler-SharedConf.t'
|
||||
|
||||
#########################
|
||||
|
||||
# change 'tests => 1' to 'tests => last_test_to_print';
|
||||
|
||||
use Test::More tests => 6;
|
||||
use Cwd 'abs_path';
|
||||
use File::Basename;
|
||||
use File::Temp;
|
||||
require 't/test.pm';
|
||||
|
||||
my $ini = File::Temp->new();
|
||||
my $dir = dirname( abs_path($0) );
|
||||
my $tmp = File::Temp::tempdir();
|
||||
|
||||
print $ini "[all]
|
||||
logger = Lemonldap::NG::Common::Logger::Std
|
||||
logLevel = error
|
||||
[configuration]
|
||||
type=File
|
||||
dirName=$dir
|
||||
localStorage=Cache::FileCache
|
||||
localStorageOptions={ \\
|
||||
'namespace' => 'lemonldap-ng-config',\\
|
||||
'default_expires_in' => 600, \\
|
||||
'directory_umask' => '007', \\
|
||||
'cache_root' => '$tmp', \\
|
||||
'cache_depth' => 0, \\
|
||||
}
|
||||
|
||||
";
|
||||
|
||||
$ini->flush();
|
||||
|
||||
use Env qw(LLNG_DEFAULTCONFFILE);
|
||||
$LLNG_DEFAULTCONFFILE = $ini->filename;
|
||||
|
||||
#open STDERR, '>/dev/null';
|
||||
|
||||
#########################
|
||||
|
||||
# Insert your test code below, the Test::More module is use()ed here so read
|
||||
# its man page ( perldoc Test::More ) for help writing this test script.
|
||||
|
||||
use_ok('Lemonldap::NG::Handler::Main');
|
||||
|
||||
my $ret;
|
||||
|
||||
our $apacheRequest;
|
||||
|
||||
my $h = 'Lemonldap::NG::Handler::Test';
|
||||
|
||||
ok( $h->init(), 'Initialize handler' );
|
||||
|
||||
ok( $h->checkType($apacheRequest) eq 'Main', 'Get Main type' );
|
||||
|
||||
ok( $ret = $h->run($apacheRequest),
|
||||
'run Handler with basic configuration and no cookie' );
|
||||
|
||||
ok( $ret = 302, 'Return code is 302' );
|
||||
|
||||
ok(
|
||||
$Lemonldap::NG::Handler::Test::header eq
|
||||
'Location:http://auth.example.com/?url=aHR0cDovL3Rlc3QxLmV4YW1wbGUuY29tLw==',
|
||||
'testing redirection URL from previous run'
|
||||
) or print STDERR "Got: $Lemonldap::NG::Handler::Test::header\n";
|
||||
|
|
@ -6,7 +6,7 @@
|
|||
# change 'tests => 1' to 'tests => last_test_to_print';
|
||||
|
||||
use strict;
|
||||
use Test::More tests => 12;
|
||||
use Test::More tests => 9;
|
||||
require 't/test.pm';
|
||||
BEGIN { use_ok('Lemonldap::NG::Handler::Main::Jail') }
|
||||
|
||||
|
@ -47,12 +47,3 @@ ok(
|
|||
ok( $res = &$code, "Function works" );
|
||||
ok( $res == 1, 'Get good result' );
|
||||
|
||||
$sub = "sub { return (hostname()) }";
|
||||
$code = $jail->jail_reval($sub);
|
||||
ok(
|
||||
( defined($code) and ref($code) eq 'CODE' ),
|
||||
'hostname api function is defined'
|
||||
);
|
||||
ok( $res = &$code, "Function works $res" );
|
||||
ok( $res eq 'test1.example.com', 'Get good result' );
|
||||
|
||||
|
|
|
@ -1417,7 +1417,7 @@ sub getIDP {
|
|||
foreach ( keys %{ $self->idpList } ) {
|
||||
my $idpConfKey = $self->idpList->{$_}->{confKey};
|
||||
my $cond = $self->idpRules->{$idpConfKey} or next;
|
||||
if ( $cond->( $req->sessionInfo ) ) {
|
||||
if ( $cond->( $req, $req->sessionInfo ) ) {
|
||||
$self->logger->debug(
|
||||
"IDP $idpConfKey resolution rule match");
|
||||
$idp = $_;
|
||||
|
|
|
@ -113,7 +113,11 @@ sub run {
|
|||
return PE_ERROR;
|
||||
}
|
||||
my ( $host, $uri ) = ( $1, $2 );
|
||||
if ( $self->p->HANDLER->grant( $req->sessionInfo, $1, undef, $2 ) )
|
||||
if (
|
||||
$self->p->HANDLER->grant(
|
||||
$req, $req->sessionInfo, $1, undef, $2
|
||||
)
|
||||
)
|
||||
{
|
||||
$self->logger->debug("CAS service $service access allowed");
|
||||
}
|
||||
|
|
|
@ -295,7 +295,7 @@ sub run {
|
|||
|
||||
# Check if this RP is authorizated
|
||||
if ( my $rule = $self->rpRules->{$rp} ) {
|
||||
unless ( $rule->( $req->sessionInfo ) ) {
|
||||
unless ( $rule->( $req, $req->sessionInfo ) ) {
|
||||
$self->userLogger->warn( 'User '
|
||||
. $req->sessionInfo->{ $self->conf->{whatToTrace} }
|
||||
. "was not authorizated to access to $rp" );
|
||||
|
|
|
@ -324,7 +324,7 @@ sub run {
|
|||
$req->env->{llng_saml_spconfkey} = $spConfKey;
|
||||
|
||||
if ( my $rule = $self->spRules->{$sp} ) {
|
||||
unless ( $rule->( $req->sessionInfo ) ) {
|
||||
unless ( $rule->( $req, $req->sessionInfo ) ) {
|
||||
$self->userLogger->warn( 'User '
|
||||
. $req->sessionInfo->{ $self->conf->{whatToTrace} }
|
||||
. "was not authorizated to access to $sp" );
|
||||
|
|
|
@ -90,7 +90,7 @@ sub getNotifBack {
|
|||
or return $self->sendError( $req, 'Unable to decrypt', 500 );
|
||||
|
||||
# Verify that session exists
|
||||
$req->userData( $self->p->HANDLER->retrieveSession($id) )
|
||||
$req->userData( $self->p->HANDLER->retrieveSession( $req, $id ) )
|
||||
or return $self->sendError( $req, 'Unknown session', 401 );
|
||||
|
||||
# Restore datas
|
||||
|
|
|
@ -102,7 +102,7 @@ sub checkForNotifications {
|
|||
next LOOP;
|
||||
}
|
||||
|
||||
unless ( $condition->( $req->sessionInfo ) ) {
|
||||
unless ( $condition->( $req, $req->sessionInfo ) ) {
|
||||
$self->logger->debug(
|
||||
'Notification condition not authorizated');
|
||||
|
||||
|
@ -152,7 +152,7 @@ sub getNotifBack {
|
|||
or return $self->sendError( $req, 'Unable to decrypt', 500 );
|
||||
|
||||
# Verify that session exists
|
||||
$req->userData( $self->p->HANDLER->retrieveSession($id) )
|
||||
$req->userData( $self->p->HANDLER->retrieveSession( $req, $id ) )
|
||||
or return $self->sendError( $req, 'Unknown session', 401 );
|
||||
|
||||
# Restore datas
|
||||
|
|
|
@ -43,8 +43,6 @@ has ua => (
|
|||
is => 'rw',
|
||||
lazy => 1,
|
||||
builder => sub {
|
||||
|
||||
# TODO : LWP options to use a proxy for example
|
||||
my $ua = Lemonldap::NG::Common::UserAgent->new( $_[0]->{conf} );
|
||||
$ua->env_proxy();
|
||||
return $ua;
|
||||
|
|
|
@ -377,7 +377,7 @@ sub getSkin {
|
|||
|
||||
# Load specific skin from skinRules
|
||||
foreach my $rule ( @{ $self->conf->{skinRules} } ) {
|
||||
if ( $rule->[1]->( $req->sessionInfo ) ) {
|
||||
if ( $rule->[1]->( $req, $req->sessionInfo ) ) {
|
||||
$skin = $rule->[0];
|
||||
$self->logger->debug("Skin $skin selected from skin rule");
|
||||
}
|
||||
|
|
|
@ -111,7 +111,7 @@ sub displayModules {
|
|||
foreach my $module ( @{ $self->menuModules } ) {
|
||||
$self->logger->debug("Check if $module->[0] has to be displayed");
|
||||
|
||||
if ( $module->[1]->() ) {
|
||||
if ( $module->[1]->( $req, $req->sessionInfo ) ) {
|
||||
my $moduleHash = { $module->[0] => 1 };
|
||||
if ( $module->[0] eq 'Appslist' ) {
|
||||
$moduleHash->{'APPSLIST_LOOP'} = $self->appslist($req);
|
||||
|
@ -465,8 +465,7 @@ sub _filterHash {
|
|||
delete $apphash->{$key}
|
||||
unless (
|
||||
$self->p->HANDLER->grant(
|
||||
$req->sessionInfo,
|
||||
$appuri, undef, $vhost
|
||||
$req, $req->sessionInfo, $appuri, undef, $vhost
|
||||
)
|
||||
);
|
||||
next;
|
||||
|
|
|
@ -344,7 +344,7 @@ sub setMacros {
|
|||
my ( $self, $req ) = @_;
|
||||
foreach ( sort keys %{ $self->_macros } ) {
|
||||
$req->{sessionInfo}->{$_} =
|
||||
$self->_macros->{$_}->( $req->sessionInfo );
|
||||
$self->_macros->{$_}->( $req, $req->sessionInfo );
|
||||
}
|
||||
PE_OK;
|
||||
}
|
||||
|
@ -383,7 +383,7 @@ sub setPersistentSessionInfo {
|
|||
sub setLocalGroups {
|
||||
my ( $self, $req ) = @_;
|
||||
foreach ( sort keys %{ $self->_groups } ) {
|
||||
if ( $self->_groups->{$_}->( $req->sessionInfo ) ) {
|
||||
if ( $self->_groups->{$_}->( $req, $req->sessionInfo ) ) {
|
||||
$req->{sessionInfo}->{groups} .=
|
||||
$self->conf->{multiValuesSeparator} . $_;
|
||||
$req->{sessionInfo}->{hGroups}->{$_}->{name} = $_;
|
||||
|
|
|
@ -17,9 +17,6 @@ has steps => ( is => 'rw' );
|
|||
# Authentication result
|
||||
has authResult => ( is => 'rw' );
|
||||
|
||||
# Datas shared between methods
|
||||
has datas => ( is => 'rw' );
|
||||
|
||||
# Session datas when created
|
||||
has id => ( is => 'rw' );
|
||||
has sessionInfo => ( is => 'rw' );
|
||||
|
|
|
@ -260,7 +260,7 @@ sub autoRedirect {
|
|||
|
||||
# Redirection should be made if urldc defined
|
||||
if ( $req->{urldc} ) {
|
||||
if ( $self->_jsRedirect->() ) {
|
||||
if ( $self->_jsRedirect->( $req, $req->sessionInfo ) ) {
|
||||
$req->error(PE_REDIRECT);
|
||||
$req->datas->{redirectFormMethod} = "get";
|
||||
}
|
||||
|
@ -490,7 +490,7 @@ sub _deleteSession {
|
|||
) unless ($preserveCookie);
|
||||
}
|
||||
|
||||
HANDLER->localUnlog( $session->id );
|
||||
HANDLER->localUnlog( $req, $session->id );
|
||||
$session->remove;
|
||||
|
||||
# Create an obsolete cookie to remove it
|
||||
|
|
|
@ -48,7 +48,7 @@ sub init {
|
|||
|
||||
sub _run {
|
||||
my ( $self, $req ) = @_;
|
||||
return PE_OK unless ( $self->rule->( $req->sessionInfo ) );
|
||||
return PE_OK unless ( $self->rule->( $req, $req->sessionInfo ) );
|
||||
$self->userLogger->info( 'Second factor required ('
|
||||
. $self->prefix
|
||||
. ') for '
|
||||
|
|
|
@ -41,7 +41,7 @@ sub grantSession {
|
|||
}
|
||||
foreach ( sort sortByComment keys %{ $self->rules } ) {
|
||||
$self->logger->debug("Grant session condition \"$_\"");
|
||||
unless ( $self->rules->{$_}->( $req->sessionInfo ) ) {
|
||||
unless ( $self->rules->{$_}->( $req, $req->sessionInfo ) ) {
|
||||
$req->userData( {} );
|
||||
$self->userLogger->error( 'User '
|
||||
. $req->user
|
||||
|
|
|
@ -316,7 +316,7 @@ sub mysession {
|
|||
|
||||
# Now check for authorization
|
||||
my $res =
|
||||
$self->p->HANDLER->grant( $req->userData, $uri, undef, $host );
|
||||
$self->p->HANDLER->grant( $req, $req->userData, $uri, undef, $host );
|
||||
$self->logger->debug(" Result is $res");
|
||||
return $self->p->sendJSONresponse( $req, { result => $res } );
|
||||
}
|
||||
|
|
|
@ -391,7 +391,8 @@ sub isAuthorizedURI {
|
|||
}
|
||||
|
||||
$req->{sessionInfo} = $session->data;
|
||||
my $r = $self->p->HANDLER->grant( $req, $uri, undef, $host );
|
||||
my $r =
|
||||
$self->p->HANDLER->grant( $req, $req->{sessionInfo}, $uri, undef, $host );
|
||||
|
||||
return $r;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user