# Plugin to enable "stay connected on this device" feature package Lemonldap::NG::Portal::Plugins::StayConnected; use 5.16.0; use strict; use Mouse; use Lemonldap::NG::Portal::Main::Constants qw( PE_OK PE_SENDRESPONSE ); our $VERSION = '2.1.0'; extends 'Lemonldap::NG::Portal::Main::Plugin'; # INTERFACE use constant endAuth => 'newDevice'; use constant beforeAuth => 'check'; use constant beforeLogout => 'logout'; # INITIALIZATION has ott => ( is => 'rw', lazy => 1, default => sub { my $ott = $_[0]->{p}->loadModule('Lemonldap::NG::Portal::Lib::OneTimeToken'); $ott->timeout( $_[0]->conf->{formTimeout} ); return $ott; } ); # Default timeout: 1 month has timeout => ( is => 'rw', lazy => 1, default => sub { $_[0]->{conf}->{stayConnectedTimeout} || 2678400; } ); sub init { my ($self) = @_; $self->addAuthRoute( registerbrowser => 'storeBrowser', ['POST'] ); return 1; } # RUNNING METHODS # Registration: detect if user wants to stay connected. Then ask for # fingerprint sub newDevice { my ( $self, $req ) = @_; if ( $req->param('stayconnected') ) { my $token = $self->ott->createToken( { name => $req->sessionInfo->{ $self->conf->{whatToTrace} } } ); $req->response( $self->p->sendHtml( $req, '../common/registerBrowser', params => { URL => $req->urldc, TOKEN => $token, ACTION => '/registerbrowser', } ) ); return PE_SENDRESPONSE; } return PE_OK; } # Store data in a long-time session sub storeBrowser { my ( $self, $req ) = @_; $req->urldc( $req->param('url') ); $req->mustRedirect(1); if ( my $token = $req->param('token') ) { if ( my $tmp = $self->ott->getToken($token) ) { my $uid = $req->userData->{ $self->conf->{whatToTrace} }; if ( $tmp->{name} eq $uid ) { if ( my $fg = $req->param('fg') ) { my $ps = Lemonldap::NG::Common::Session->new( storageModule => $self->conf->{globalStorage}, storageModuleOptions => $self->conf->{globalStorageOptions}, kind => "SSO", info => { _utime => time + $self->timeout, _session_uid => $uid, _connectedSince => time, dataKeep => $req->data->{dataToKeep}, fingerprint => $fg, }, ); # Cookie available 30 days $req->addCookie( $self->p->cookie( name => 'llngconnexion', value => $ps->id, max_age => 2592000, ) ); } else { $self->logger->warn("Browser hasn't return fingerprint"); } } else { $self->userLogger->error( "StayConnected: mismatch UID: $tmp->{name} / $uid"); } } else { $self->userLogger->error( "StayConnected called with an expired token"); } } else { $self->userLogger->error('StayConnected called without token'); } # Deliver cookie llngbrowser return $self->p->do( $req, [ sub { PE_OK } ] ); } # Check for: # - persistent connection cookie # - valid session # - uniq id is kept # Then delete authentication methods from "steps" array. sub check { my ( $self, $req ) = @_; if ( my $cid = $req->cookies->{llngconnexion} ) { my $ps = Lemonldap::NG::Common::Session->new( storageModule => $self->conf->{globalStorage}, storageModuleOptions => $self->conf->{globalStorageOptions}, kind => "SSO", id => $cid, ); if ( $ps and my $uid = $ps->data->{_session_uid} ) { $self->logger->debug('Persistent connection found'); if ( my $fg = $req->param('fg') and my $token = $req->param('token') ) { if ( my $prm = $self->ott->getToken($token) ) { $req->data->{dataKeep} = $ps->data->{dataKeep}; $self->logger->debug('Persistent connection found'); if ( $fg eq $ps->data->{fingerprint} ) { $req->user($uid); my @steps = grep { !ref $_ and $_ !~ /^(?:extractFormInfo|authenticate)$/ } @{ $req->steps }; $req->steps( \@steps ); $self->userLogger->notice( "$uid connected by StayConnected cookie"); return PE_OK; } else { $self->userLogger->warn("Fingerprint changed for $uid"); } } else { $self->userLogger->notice( "StayConnected: expired token for $uid"); } } else { my $token = $self->ott->createToken( $req->parameters ); $req->response( $self->p->sendHtml( $req, '../common/registerBrowser', params => { TOKEN => $token, ACTION => '#', } ) ); return PE_SENDRESPONSE; } } else { $self->userLogger->notice('Persistent connection expired'); } } return PE_OK; } sub logout { my ( $self, $req ) = @_; $req->addCookie( $self->p->cookie( name => 'llngconnexion', value => 0, expires => 'Wed, 21 Oct 2015 00:00:00 GMT' ) ); return PE_OK; } 1;