Commit 41943789 authored by Xavier Guimard's avatar Xavier Guimard

Prepare session explorer to examine persistent sessions

See #495
parent 8f5fcaf2
......@@ -33,20 +33,22 @@ Examples:
## Sessions
* Sessions list: `/sessions`
* Session: `/sessions/<hash>`
* **TODO**: Session key: `/sessions/<hash>/<key>`
* Delete session: `DELETE /sessions/<hash>`
Note that global can be replaced by persistent to list persistent sessions.
* Sessions list: `/sessions/global`
* Session: `/sessions/global/<hash>`
* **TODO**: Session key: `/sessions/global/<hash>/<key>`
* Delete session: `DELETE /sessions/global/<hash>`
* Filters:
* All connected users which username start by a letter:
`/sessions?_whatToTrace=<letter>*&groupBy=_whatToTrace`
* User's sessions: `/sessions?_whatToTrace=foo.bar`
* IP's sessions: `/sessions?ip=1.2.3.4`
* Double sessions by IP: `/sessions?doubleIP`
`/sessions/global?_whatToTrace=<letter>*&groupBy=_whatToTrace`
* User's sessions: `/sessions/global?_whatToTrace=foo.bar`
* IP's sessions: `/sessions/global?ip=1.2.3.4`
* Double sessions by IP: `/sessions/global?doubleIP`
* Group by:
* First letter of Connected users: `/sessions?groupBy=substr(_whatToTrace,1)`
* First letter of Connected users: `/sessions/global?groupBy=substr(_whatToTrace,1)`
* Order:
* Sessions sorted by user: `/sessions?orderBy=_whatToTrace`
* Sessions sorted by user: `/sessions/global?orderBy=_whatToTrace`
Note that sessions are grouped automaticaly.
......
......@@ -14,6 +14,8 @@ use feature 'state';
extends 'Lemonldap::NG::Manager::Lib';
has conf => ( is => 'rw', isa => 'HashRef', default => sub { {} } );
our $VERSION = '2.0.0';
#############################
......@@ -29,10 +31,13 @@ sub addRoutes {
$self->addRoute( 'sessions.html', undef, ['GET'] )
# READ
->addRoute( 'sessions', undef, ['GET'] )
->addRoute( sessions => { ':sessionType' => 'sessions' }, ['GET'] )
# DELETE
->addRoute( sessions => { ':sessionId' => 'delSession' }, ['DELETE'] );
->addRoute(
sessions => { ':sessionType' => { ':sessionId' => 'delSession' } },
['DELETE']
);
#TODO: transfer this in Manager.pm ?
if ( my $localConf = $self->confAcc->getLocalConf(SESSIONSEXPLORERSECTION) )
......@@ -40,6 +45,19 @@ sub addRoutes {
$self->{$_} = $localConf->{$_} foreach ( keys %$localConf );
}
my $conf = $self->confAcc->getConf();
foreach my $type (@sessionTypes) {
if ( my $tmp =
$self->{ $type . 'Storage' } || $conf->{ $type . 'Storage' } )
{
$self->{conf}->{$type}->{module} = $tmp;
$self->{conf}->{$type}->{options} =
$self->{ $type . 'StorageOptions' }
|| $conf->{ $type . 'StorageOptions' }
|| {};
}
}
$self->{ipField} ||= 'ipAddr';
$self->{multiValuesSeparator} ||= '; ';
$self->{hiddenAttributes} //= "_password";
......@@ -57,12 +75,18 @@ sub sessions {
return $self->session( $req, $session, $skey );
}
# Case 2: list of sessions
my $mod = $self->getMod($req)
or return $self->sendError( $req, undef, 400 );
my $params = $req->params();
delete $params->{sessionType};
my $res;
# Case 2: list of sessions
# 2.1 Get fields to require
my @fields = ( '_httpSessionType', $self->{ipField}, $tsv->{whatToTrace} );
my @fields =
( '_httpSessionType', $self->{ipField}, $tsv->{whatToTrace} );
if ( my $groupBy = $params->{groupBy} ) {
$groupBy = $1
if ( $groupBy =~ /^substr\((\w+)(?:,\d+(?:,\d+)?)?\)$/ );
......@@ -83,11 +107,13 @@ sub sessions {
# 2.2 Restrict query if possible: search for filters (any query arg that is
# not a keyword)
my $moduleOptions = $tsv->{sessionStorageOptions} || {};
$moduleOptions->{backend} = $tsv->{sessionStorageModule};
my $moduleOptions = $mod->{options};
$moduleOptions->{backend} = $mod->{module};
if (
my %filters = map {
/^(?:(?:group|order)By|doubleIp)$/ ? () : ( $_ => $params->{$_} );
/^(?:(?:group|order)By|doubleIp)$/
? ()
: ( $_ => $params->{$_} );
} keys %$params
)
{
......@@ -276,9 +302,11 @@ sub delSession {
my ( $self, $req ) = splice @_;
return $self->sendJSONresponse( $req, { result => 1 } )
if ( $self->{demoMode} );
my $mod = $self->getMod($req)
or return $self->sendError( $req, undef, 400 );
my $id = $req->params('sessionId')
or return $self->sendError( $req, 'sessionId is missing', 400 );
my $session = $self->getApacheSession($id);
my $session = $self->getApacheSession( $mod, $id );
$session->remove;
if ( $session->error ) {
return $self->sendError( $req, $session->error, 200 );
......@@ -289,10 +317,12 @@ sub delSession {
sub session {
my ( $self, $req, $id, $skey ) = splice @_;
my ( %h, $res );
my $mod = $self->getMod($req)
or return $self->sendError( $req, undef, 400 );
# Try to read session
# TODO: conf in PSGI
my $apacheSession = $self->getApacheSession($id)
my $apacheSession = $self->getApacheSession( $mod, $id )
or return $self->sendError( $req, undef, 400 );
my %session = %{ $apacheSession->data };
......@@ -315,11 +345,11 @@ sub session {
}
sub getApacheSession {
my ( $self, $id ) = splice @_;
my ( $self, $mod, $id ) = splice @_;
my $apacheSession = Lemonldap::NG::Common::Session->new(
{
storageModule => $tsv->{sessionStorageModule},
storageModuleOptions => $tsv->{sessionStorageOptions},
storageModule => $mod->{module},
storageModuleOptions => $mod->{options},
cacheModule => $tsv->{sessionCacheModule},
cacheModuleOptions => $tsv->{sessionCacheOptions},
id => $id,
......@@ -333,4 +363,18 @@ sub getApacheSession {
return $apacheSession;
}
sub getMod {
my ( $self, $req ) = @_;
my ( $s, $m );
unless ( $s = $req->params('sessionType') ) {
$self->error('Session type is required');
return ();
}
unless ( $m = $self->conf->{$s} ) {
$self->error('Unknown (or unconfigured) session type');
return ();
}
return $m;
}
1;
......@@ -115,7 +115,7 @@
$scope.deleteSession = function() {
$scope.waiting = true;
$http.delete(scriptname + "sessions/" + $scope.currentSession.id).success(function(data) {
$http.delete(scriptname + "sessions/global/" + $scope.currentSession.id).success(function(data) {
$scope.currentSession = null;
$scope.currentScope.remove();
$scope.waiting = false;
......@@ -259,7 +259,7 @@
$scope.currentScope = scope;
var sessionId = scope.$modelValue.session;
$http.get(scriptname + "sessions/" + sessionId).success(function(data) {
$http.get(scriptname + "sessions/global/" + sessionId).success(function(data) {
$scope.currentSession = transformSession(data);
});
}
......@@ -306,7 +306,7 @@
}
query = scheme[level]($scope.type, value, currentQuery);
$http.get(scriptname + "sessions?" + query).success(function(data) {
$http.get(scriptname + "sessions/global?" + query).success(function(data) {
if (data.result) {
data.values.forEach(function(n) {
autoId++;
......
......@@ -35,13 +35,13 @@ sub newSession {
my @ids;
$ids[0] = newSession( 'dwho', '127.10.0.1' );
$ids[1] = newSession( 'dwho2', '127.2.0.2' );
my $res = jsonResponse("/sessions/$ids[0]");
my $res = jsonResponse("/sessions/global/$ids[0]");
ok( ( $res->{uid} and $res->{uid} eq 'dwho' ), 'Uid found' );
ok( ( $res->{ipAddr} and $res->{ipAddr} eq '127.10.0.1' ), 'IP found' );
count(2);
# "All" query
$res = jsonResponse("/sessions/");
$res = jsonResponse("/sessions/global/");
ok( $res->{result} == 1, 'Result code = 1' );
ok( $res->{count} == 2, 'Found 2 sessions' );
ok( @{ $res->{values} } == 2, 'List 2 sessions' );
......@@ -51,7 +51,7 @@ ok( $res->{values}->[$_]->{session} =~ /^(?:$ids[0]|$ids[1])$/,
count(5);
# GroupBy query
$res = jsonResponse( '/sessions', 'groupBy=substr(uid,1)' );
$res = jsonResponse( '/sessions/global', 'groupBy=substr(uid,1)' );
ok( $res->{result} == 1, 'Result code = 1' );
ok( $res->{count} == 1, 'Found 1 entry' );
ok( $res->{values}->[0]->{value} && $res->{values}->[0]->{value} eq 'd',
......@@ -61,25 +61,25 @@ ok( $res->{values}->[0]->{count} == 2, 'Found 2 sessions starting with "d"' );
count(4);
$ids[2] = newSession( 'foo', '127.3.0.3' );
$res = jsonResponse( '/sessions', 'groupBy=substr(uid,1)' );
$res = jsonResponse( '/sessions/global', 'groupBy=substr(uid,1)' );
ok( $res->{count} == 2, 'Found 2 entries' );
count(1);
# Filtered queries
$res = jsonResponse( '/sessions', 'uid=d*' );
$res = jsonResponse( '/sessions/global', 'uid=d*' );
ok( $res->{count} == 2, 'Found 2 sessions' );
ok( $res->{values}->[$_]->{session} =~ /^(?:$ids[0]|$ids[1])$/,
'Good session id' )
foreach ( 0 .. 1 );
count(3);
$res = jsonResponse( '/sessions', 'uid=f*' );
$res = jsonResponse( '/sessions/global', 'uid=f*' );
ok( $res->{count} == 1, 'Found 1 sessions' );
ok( $res->{values}->[0]->{session} eq $ids[2], 'Good session id' );
count(2);
# DoubleIp
$ids[3] = newSession( 'foo', '127.3.0.4' );
$res = jsonResponse( '/sessions', 'doubleIp' );
$res = jsonResponse( '/sessions/global', 'doubleIp' );
ok( $res->{count} == 1, 'Found 1 user' );
ok( $res->{values}->[0]->{value} eq 'foo', 'User is foo' );
ok(
......@@ -89,7 +89,7 @@ ok(
count(4);
# New GroupBy query test with 4 sessions
$res = jsonResponse( '/sessions', 'groupBy=uid' );
$res = jsonResponse( '/sessions/global', 'groupBy=uid' );
ok(
(
$res->{values}->[0]->{value} eq 'dwho'
......@@ -114,7 +114,7 @@ ok(
count(3);
# Ordered queries
$res = jsonResponse( '/sessions', 'orderBy=uid' );
$res = jsonResponse( '/sessions/global', 'orderBy=uid' );
ok( $res->{values}->[0]->{uid} eq 'dwho', '1st user is dwho' );
ok( $res->{values}->[1]->{uid} eq 'dwho2', '2nd user is dwho2' );
ok( $res->{values}->[2]->{uid} eq 'foo', '3rd user is foo' );
......@@ -122,15 +122,15 @@ ok( $res->{values}->[3]->{uid} eq 'foo', '4rd user is foo' );
count(4);
# IPv4 networks
$res = jsonResponse( '/sessions', 'groupBy=net4(ipAddr,1)' );
$res = jsonResponse( '/sessions/global', 'groupBy=net4(ipAddr,1)' );
ok( $res->{count} == 1, 'One A subnet' );
ok( $res->{values}->[0]->{count} == 4, 'All sessions found' );
$res = jsonResponse( '/sessions', 'groupBy=net4(ipAddr,2)' );
$res = jsonResponse( '/sessions/global', 'groupBy=net4(ipAddr,2)' );
ok( $res->{count} == 3, 'Three B subnet' );
ok( $res->{values}->[2]->{count} == 2, 'All sessions found' );
count(4);
$res = jsonResponse( '/sessions', 'orderBy=net4(ipAddr)' );
$res = jsonResponse( '/sessions/global', 'orderBy=net4(ipAddr)' );
ok( $res->{count} == 4, '4 sessions ordered' );
ok( $res->{values}->[0]->{session} eq $ids[1], '1st is id[1]' );
ok( $res->{values}->[1]->{session} eq $ids[2], '2nd is id[2]' );
......@@ -143,7 +143,7 @@ count(5);
# Delete sessions
foreach (@ids) {
my $res;
ok( $res = del("/sessions/$_"), "Delete $_" );
ok( $res = del("/sessions/global/$_"), "Delete $_" );
ok( $res->[0] == 200, 'Result code is 200' );
ok( JSON::decode_json( $res->[2]->[0] )->{result} == 1,
'Body is JSON and result==1' );
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment