diff --git a/e2e-tests/lemonldap-ng.ini b/e2e-tests/lemonldap-ng.ini index aa49c3de6..90c53abc7 100644 --- a/e2e-tests/lemonldap-ng.ini +++ b/e2e-tests/lemonldap-ng.ini @@ -13,7 +13,7 @@ dirName=__pwd__/e2e-tests/conf ; 'default_expires_in' => 600, \ ; 'directory_umask' => '007', \ ; 'cache_root' => '__pwd__/e2e-tests/conf', \ -; 'cache_depth' => 0, \ +; 'cache_depth' => 3, \ ;} [portal] diff --git a/lemonldap-ng-common/lemonldap-ng.ini b/lemonldap-ng-common/lemonldap-ng.ini index c3161ef61..23e018e06 100644 --- a/lemonldap-ng-common/lemonldap-ng.ini +++ b/lemonldap-ng-common/lemonldap-ng.ini @@ -159,7 +159,7 @@ dirName=/var/lib/lemonldap-ng/conf ; 'default_expires_in' => 600, \ ; 'directory_umask' => '007', \ ; 'cache_root' => '/tmp', \ -; 'cache_depth' => 0, \ +; 'cache_depth' => 3, \ ; } localStorage=Cache::FileCache localStorageOptions={ \ @@ -167,7 +167,7 @@ localStorageOptions={ \ 'default_expires_in' => 600, \ 'directory_umask' => '007', \ 'cache_root' => '/tmp', \ - 'cache_depth' => 0, \ + 'cache_depth' => 3, \ } [portal] diff --git a/lemonldap-ng-common/lib/Lemonldap/NG/Common/Apache/Session/REST.pm b/lemonldap-ng-common/lib/Lemonldap/NG/Common/Apache/Session/REST.pm index eb2d4d373..2d6d55996 100644 --- a/lemonldap-ng-common/lib/Lemonldap/NG/Common/Apache/Session/REST.pm +++ b/lemonldap-ng-common/lib/Lemonldap/NG/Common/Apache/Session/REST.pm @@ -227,9 +227,11 @@ sub save { Lemonldap::NG::Handler::Main->tsv->{cipher}->encrypt(time); }; print STDERR "$@\n" if ($@); - $req->content( to_json( $self->{data} ) ); + my $content = to_json( $self->{data} ); + $req->content($content); delete $self->{data}->{__secret}; - $req->header( 'Content-Type' => 'application/json' ); + $req->header( 'Content-Type' => 'application/json' ); + $req->header( 'Content-Length' => length($content) ); my $resp = $self->ua->request($req); if ( $resp->is_success ) { @@ -267,29 +269,62 @@ sub delete { return ( $resp->is_success ? 1 : 0 ); } +sub searchOn { + my ( $class, $args, $selectField, $value, @fields ) = @_; + return $class->_getAll( "all=1&search=$selectField,$value", + $args, ( @fields ? \@fields : () ) ); +} + ## @method get_key_from_all_sessions() # Not documented. sub get_key_from_all_sessions() { - die "Not implemented"; my ( $class, $args, $data ) = @_; + my $res = $class->_getAll( 'all=1', $args, $data ); + return unless $res; + + if ( ref($data) eq 'CODE' ) { + my $r; + foreach my $k ( keys %$res ) { + my $tmp = &$data( $res->{$k}, $k ); + $r->{$k} = $tmp if ( defined($tmp) ); + } + $res = $r; + } + return $res; +} + +sub _getAll { + my ( $class, $query, $args, $data ) = @_; my $self = bless {}, $class; - foreach (qw(baseUrl user password realm)) { + foreach (qw(baseUrl user password realm lwpOpts lwpSslOpts kind)) { $self->{$_} = $args->{$_}; } + $self->{data} = { data => ( ref($data) eq 'CODE' ? undef : $data ) }; die('baseUrl is required') unless ( $self->{baseUrl} ); - if ( ref($data) eq 'CODE' ) { + my $req = HTTP::Request->new( POST => $self->base . "?$query" ); + eval { + $self->{data}->{__secret} = + Lemonldap::NG::Handler::Main->tsv->{cipher}->encrypt(time); + }; + print STDERR "$@\n" if ($@); + my $content = to_json( $self->{data} ); + $req->content($content); + $req->header( 'Content-Length' => length($content) ); + delete $self->{data}->{__secret}; + $req->header( 'Content-Type' => 'application/json' ); + my $resp = $self->ua->request($req); - #my $r = $self->_soapCall( "get_key_from_all_sessions", $args ); - #my $res; - #if ($r) { - # foreach my $k ( keys %$r ) { - # my $tmp = &$data( $r->{$k}, $k ); - # $res->{$k} = $tmp if ( defined($tmp) ); - # } - #} + if ( $resp->is_success ) { + my $res; + eval { $res = from_json( $resp->content, { allow_nonref => 1 } ) }; + if ($@) { + die "Bad REST response: $@"; + } + return $res; } else { - #return $self->_soapCall( "get_key_from_all_sessions", $args, $data ); + print STDERR "REST server returns " . $resp->status_line . "\n"; + return; } } diff --git a/lemonldap-ng-handler/eg/scripts/purgeLocalCache b/lemonldap-ng-handler/eg/scripts/purgeLocalCache index 7929c7187..2e8022989 100755 --- a/lemonldap-ng-handler/eg/scripts/purgeLocalCache +++ b/lemonldap-ng-handler/eg/scripts/purgeLocalCache @@ -29,14 +29,6 @@ if ($localconf) { print "Configuration loaded\n" if $debug; -# Handler cache -if ( $conf->{localStorage} ) { - eval "require $conf->{localStorage}"; - $conf->{localStorageOptions}->{default_expires_in} ||= 600; - my $c = $conf->{localStorage}->new( $conf->{localStorageOptions} ); - $c->purge(); -} - # Session cache if ( $conf->{localSessionStorage} ) { eval "require $conf->{localSessionStorage}"; diff --git a/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Main/Run.pm b/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Main/Run.pm index cf9a42679..ef6d48364 100644 --- a/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Main/Run.pm +++ b/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Main/Run.pm @@ -237,7 +237,7 @@ sub do { [$s] ]; } - elsif ( $err > 0 and $err != PE_PASSWORD_OK ) { + elsif ( $err > 0 and $err != PE_PASSWORD_OK and $err != PE_LOGOUT_OK ) { return $self->sendJSONresponse( $req, { result => 0, error => $err }, diff --git a/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Plugins/RESTServer.pm b/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Plugins/RESTServer.pm index 970033b01..0fb072148 100644 --- a/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Plugins/RESTServer.pm +++ b/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Plugins/RESTServer.pm @@ -6,6 +6,8 @@ # * GET /sessions/// : get a session key value # * GET /sessions///[k1,k2] : get some session key value # * POST /sessions/ : create a session +# * POST /sessions/?all=1 : get all sessions (needs a token) +# * POST /sessions/?all=1&search=uid,dwho: search all sessions where uid=dwho (needs a token) # * PUT /sessions// : update some keys # * DELETE /sessions// : delete a session # @@ -203,7 +205,7 @@ sub newSession { if ( $t = $self->conf->{cipher}->decrypt($s) and $t <= time - and $t > time - 30 ) + and $t > time - 15 ) { $force = 1; } @@ -212,6 +214,29 @@ sub newSession { } } + if ( $req->param('all') and not $id ) { + return $self->p->sendError( $req, + 'Bad key, refuse to send all sessions', 400 ) + unless ($force); + my $data = $infos->{data}; + my $opts = $self->conf->{globalStorageOptions} || {}; + $opts->{backend} = $self->conf->{globalStorage}; + my $sessions; + if ( my $query = $req->param('search') ) { + my ( $field, @values ) = split /,/, $query; + $sessions = Lemonldap::NG::Common::Apache::Session->searchOn( + $opts, $field, + join( ',', @values ), + ( $data ? @$data : () ) + ); + } + else { + $sessions = + Lemonldap::NG::Common::Apache::Session + ->get_key_from_all_sessions( $opts, $data ); + } + return $self->p->sendJSONresponse( $req, $sessions ); + } my $session = $self->getApacheSession( $mod, $id, $infos, $force ); return $self->p->sendError( $req, 'Unable to create session', 500 ) unless ($session); diff --git a/lemonldap-ng-portal/t/34-Auth-Proxy-and-REST-Server.t b/lemonldap-ng-portal/t/34-Auth-Proxy-and-REST-Server.t index c461df62f..92ae87447 100644 --- a/lemonldap-ng-portal/t/34-Auth-Proxy-and-REST-Server.t +++ b/lemonldap-ng-portal/t/34-Auth-Proxy-and-REST-Server.t @@ -16,12 +16,11 @@ my %handlerOR = ( issuer => [], sp => [] ); LWP::Protocol::PSGI->register( sub { my $req = Plack::Request->new(@_); - ok( - $req->uri =~ m#http://auth.idp.com(.*)#, - ' @ REST request (' . $req->method . " $1)" - ); + ok( $req->uri =~ m#http://auth.idp.com([^\?]*?)(?:\?(.*))?$#, + ' @ REST request (' . $req->method . " $1)" ); count(1); - my $url = $1; + my $url = $1; + my $query = $2; my $res; my $s = $req->content; if ( $req->method =~ /^(post|put)$/i ) { @@ -31,6 +30,7 @@ LWP::Protocol::PSGI->register( $res = $issuer->$mth( $url, IO::String->new($s), + ( $query ? ( query => $query ) : () ), length => length($s), type => $req->header('Content-Type'), ), @@ -46,6 +46,7 @@ LWP::Protocol::PSGI->register( ok( $res = $issuer->$mth( $url, + ( $query ? ( query => $query ) : () ), accept => $req->header('Accept'), cookie => $req->header('Cookie') ), @@ -169,6 +170,76 @@ ok( $res = $issuer->_get("/sessions/global/$newId/cn"), 'Verify cn' ); ok( $res->[2]->[0] eq 'CN', ' CN is good' ); count(2); +use_ok('Lemonldap::NG::Common::Apache::Session::REST'); +ok( + $res = + Lemonldap::NG::Common::Apache::Session::REST->get_key_from_all_sessions( { + baseUrl => 'http://auth.idp.com/sessions/global/', + } + ), + 'Search all sessions' +); + +my ( $c1, $c2 ) = ( 0, 0 ); +if ( ok( ref($res) eq 'HASH', ' Result is an hash' ) ) { + my $tmp = 1; + foreach ( keys %$res ) { + $c1++; + unless ( $res->{$_}->{_session_id} ) { + $tmp = 0; + diag "Bad session:\n" . Dumper( $res->{$_} ); + } + } + ok( $c1, " Found $c1 sessions" ); + ok( $tmp, ' All sessions are valid' ); + count(2); +} +count(3); + +ok($res=Lemonldap::NG::Common::Apache::Session::REST->get_key_from_all_sessions( {baseUrl => 'http://auth.idp.com/sessions/global/'},sub{return 'a'}),'Search all sessions with a code'); + +if ( ok( ref($res) eq 'HASH', ' Result is an hash' ) ) { + my $tmp = 1; + my $c = 0; + foreach ( keys %$res ) { + $c++; + unless ( $res->{$_} eq 'a' ) { + $tmp = 0; + diag "Bad session:\n" . Dumper( $res->{$_} ); + } + } + ok( $c == $c1, " Found the same count") or explain($c,$c1); + ok( $tmp, ' All sessions are valid' ); + count(2); +} +count(2); + +ok( + $res = Lemonldap::NG::Common::Apache::Session::REST->searchOn( { + baseUrl => 'http://auth.idp.com/sessions/global/' + }, + 'uid', 'dwho' + ), + 'Search dwho sessions' +); +if ( ok( ref($res) eq 'HASH', ' Result is an hash' ) ) { + my $tmp = 1; + foreach ( keys %$res ) { + $c2++; + unless ( $res->{$_}->{_session_id} ) { + $tmp = 0; + diag "Bad session:\n" . Dumper( $res->{$_} ); + } + } + ok( $c2, " Found $c2 sessions" ); + ok( $tmp, ' All sessions are valid' ); + count(2); +} + +ok( $c2 < $c1, + 'searchOn() count is lower than get_key_from_all_sessions() count' ); +count(3); + # Del new session ok( $res = $issuer->app->( {