From adfd86d7fe910cb098f32a9c50d891b6c01ed080 Mon Sep 17 00:00:00 2001 From: Maxime Besson Date: Tue, 19 Nov 2019 17:24:58 +0100 Subject: [PATCH] Add script to convert sessions between backends (#2014) --- Makefile | 1 + debian/liblemonldap-ng-common-perl.install | 2 + lemonldap-ng-common/MANIFEST | 1 + lemonldap-ng-common/Makefile.PL | 1 + lemonldap-ng-common/scripts/convertSessions | 250 ++++++++++++++++++++ rpm/lemonldap-ng.spec | 2 + 6 files changed, 257 insertions(+) create mode 100755 lemonldap-ng-common/scripts/convertSessions diff --git a/Makefile b/Makefile index 52d77ab1d..a1f673ee7 100644 --- a/Makefile +++ b/Makefile @@ -623,6 +623,7 @@ install_bin: install_conf_dir ${SRCPORTALDIR}/site/cron/purgeCentralCache \ ${SRCPORTALDIR}/scripts/llngDeleteSession \ ${SRCCOMMONDIR}/scripts/convertConfig \ + ${SRCCOMMONDIR}/scripts/convertSessions \ ${SRCCOMMONDIR}/scripts/lmMigrateConfFiles2ini \ ${SRCCOMMONDIR}/scripts/rotateOidcKeys \ ${SRCMANAGERDIR}/scripts/lmConfigEditor \ diff --git a/debian/liblemonldap-ng-common-perl.install b/debian/liblemonldap-ng-common-perl.install index 353de61df..c7cc2aa90 100644 --- a/debian/liblemonldap-ng-common-perl.install +++ b/debian/liblemonldap-ng-common-perl.install @@ -1,12 +1,14 @@ /etc/lemonldap-ng/lemonldap-ng.ini /etc/lemonldap-ng/for_etc_hosts /usr/share/man/man1/convertConfig.1p +/usr/share/man/man1/convertSessions.1p /usr/share/man/man1/lemonldap-ng-cli.1p /usr/share/man/man3/Lemonldap::NG::Common* /usr/share/perl5/auto/Lemonldap/NG/Common /usr/share/perl5/Lemonldap/NG/Common* /usr/share/lemonldap-ng/ressources /usr/share/lemonldap-ng/bin/convertConfig +/usr/share/lemonldap-ng/bin/convertSessions /usr/share/lemonldap-ng/bin/importMetadata /usr/share/lemonldap-ng/bin/lmMigrateConfFiles2ini /usr/share/lemonldap-ng/bin/rotateOidcKeys diff --git a/lemonldap-ng-common/MANIFEST b/lemonldap-ng-common/MANIFEST index 94f97455b..d7c3d045d 100644 --- a/lemonldap-ng-common/MANIFEST +++ b/lemonldap-ng-common/MANIFEST @@ -70,6 +70,7 @@ META.json META.yml README scripts/convertConfig +scripts/convertSessions scripts/importMetadata scripts/lemonldap-ng-cli scripts/lmMigrateConfFiles2ini diff --git a/lemonldap-ng-common/Makefile.PL b/lemonldap-ng-common/Makefile.PL index 86745216a..8124b7bf5 100644 --- a/lemonldap-ng-common/Makefile.PL +++ b/lemonldap-ng-common/Makefile.PL @@ -90,6 +90,7 @@ WriteMakefile( }, MAN1PODS => { 'scripts/convertConfig' => 'blib/man1/convertConfig.1p', + 'scripts/convertSessions' => 'blib/man1/convertSessions.1p', 'scripts/lemonldap-ng-cli' => 'blib/man1/lemonldap-ng-cli.1p', }, ); diff --git a/lemonldap-ng-common/scripts/convertSessions b/lemonldap-ng-common/scripts/convertSessions new file mode 100755 index 000000000..cb5c8bfd1 --- /dev/null +++ b/lemonldap-ng-common/scripts/convertSessions @@ -0,0 +1,250 @@ +#!/usr/bin/perl +#============================================================================= +# LemonLDAP::NG session conversion tool +# +# This script lets an administrator migrate existing sessions from one backend +# to another. It is mostly useful when run on persistant sessions, but it can be +# useful in some other cases too, such as OIDC Offline sessions +# +# This is part of LemonLDAP::NG product, released under GPL +#============================================================================= + +use Lemonldap::NG::Common::Apache::Session; +use Lemonldap::NG::Common::Session; +use Config::IniFiles; +use strict; +use Getopt::Std; +$Getopt::Std::STANDARD_HELP_VERSION = 1; + +our $VERSION = "2.0.6"; + +# Options +# -d: debug mode +# -c: configuration file +# -i: ignore errors +my $opts = {}; +getopts( 'dic:', $opts ); + +my $debug = $opts->{d}; +my $config_file = $opts->{c}; +my $ignore_errors = $opts->{i}; +my $nb_converted = 0; +my $nb_error = 0; + +sub HELP_MESSAGE { + my $OUT = shift; + print $OUT < '/var/lib/lemonldap-ng/sessions', \\ + 'LockDirectory' => '/var/lib/lemonldap-ng/sessions/lock', \\ +} +# Only convert some session types +# sessionKind = Persistent, SSO + +[sessions_to] +storageModule = Apache::Session::Browseable::Postgres +storageModuleOptions = { \\ + 'DataSource' => 'DBI:Pg:database=lemonldapdb;host=pg.example.com', \\ + 'UserName' => 'lemonldaplogin', \\ + 'Password' => 'lemonldappw', \\ + 'Commit' => 1, \\ + 'Index' => 'ipAddr _whatToTrace user', \\ + 'TableName' => 'sessions', \\ +} + +END_MESSAGE +} + +unless ($config_file) { + HELP_MESSAGE( \*STDERR ); + die "You must provide the -c option"; +} + +my $inicfg = + Config::IniFiles->new( -file => $config_file, -allowcontinue => 1 ); +my $cfg = {}; + +die "Could not read configuration file" unless $inicfg; + +for my $section (qw/sessions_from sessions_to/) { + die "Could not find section $section in configuration file $config_file" + unless $inicfg->SectionExists($section); + + # Load section parameters + my $r; + foreach ( $inicfg->Parameters($section) ) { + $r->{$_} = $inicfg->val( $section, $_ ); + + # Remove spaces before and after value (#1488) + $r->{$_} =~ s/^\s*(.+?)\s*/$1/; + if ( $r->{$_} =~ /^[{\[].*[}\]]$/ || $r->{$_} =~ /^sub\s*{.*}$/ ) { + eval "\$r->{$_} = $r->{$_}"; + if ($@) { + print $@; + return $r; + } + } + } + $cfg->{$section} = $r; +} + +my $backendFrom; +my $backendTo; +my @sessionKindOnly; +if ( $cfg->{sessions_from}->{sessionKind} ) { + @sessionKindOnly = split /\W+/, $cfg->{sessions_from}->{sessionKind}; +} + +if ( $cfg->{sessions_from}->{storageModule} ) { + $backendFrom = $cfg->{sessions_from}->{storageModuleOptions}; + $backendFrom->{backend} = $cfg->{sessions_from}->{storageModule}; +} +else { + die + "[sessions_from] configuration section does not declare a storageModule"; +} + +if ( $cfg->{sessions_to}->{storageModule} ) { + $backendTo = $cfg->{sessions_to}->{storageModuleOptions}; + $backendTo->{backend} = $cfg->{sessions_to}->{storageModule}; +} +else { + die "[sessions_to] configuration section does not declare a storageModule"; +} + +Lemonldap::NG::Common::Apache::Session->get_key_from_all_sessions( + $backendFrom, + sub { + my $entry = shift; + my $id = shift; + + print "Processing session $id\n" if $debug; + my $s = Lemonldap::NG::Common::Session->new( { + storageModule => $backendTo->{backend}, + storageModuleOptions => $backendTo, + id => $id, + info => $entry, + force => 1, + } + ); + + # If filtering sessionKind + if (@sessionKindOnly) { + + unless ( grep { $_ eq $entry->{_session_kind} } @sessionKindOnly ) { + return undef; + } + } + + if ( $s->error ) { + die "Error encountered on session $id" unless $ignore_errors; + $nb_error += 1; + print "Error converting session $id : " . $s->error . "\n"; + } + else { + print "Session $id successfully converted\n" if $debug; + $nb_converted += 1; + } + } +); + +print "$nb_converted sessions have been converted\n"; + +print "$nb_error errors encountered during conversion\n" if $nb_error; + +my $exit = $nb_error ? 1 : 0; +exit $exit; + +__END__ + +=head1 NAME + +=encoding utf8 + +convertSessions - A tool to convert Lemonldap::NG sessions between storage backends. + +=head1 SYNOPSIS + + convertSession [-di] -c parameters.ini + + +=head1 DESCRIPTION + +convertConfig is a command line tool to migrate all sessions stored +in a source backend (sessions_from), into a new backend (sessions_to). + +It requires a special configuration file in which you must list the source +and destination backend modules and parameters. + +Sessions will not be deleted from the source backend. Existing sessions in the +destination backend will be kept, unless they have the same session ID as a +session in the source backend. In that case, the source will overwrite the +destination. + + +=head1 CONFIGURATION FILE FORMAT + +The configuration file needs two sections to describe the source and destination backends + +Here is an example + + [sessions_from] + storageModule = Apache::Session::File + storageModuleOptions = { \ + 'Directory' => '/var/lib/lemonldap-ng/sessions', \ + 'LockDirectory' => '/var/lib/lemonldap-ng/sessions/lock', \ + } + # Only migrate some session types + # sessionKind = Persistent, SSO + + [sessions_to] + storageModule = Apache::Session::Browseable::Postgres + storageModuleOptions = { \ + 'DataSource' => 'DBI:Pg:database=lemonldapdb;host=pg.example.com', \ + 'UserName' => 'lemonldaplogin', \ + 'Password' => 'lemonldappw', \ + 'Commit' => 1, \ + 'Index' => 'ipAddr _whatToTrace user', \ + 'TableName' => 'sessions', \ + } + + +The C parameter may be used to filter only some session types. + +Thanks to this, you can use this script to migrate from one database holding +all your sessions to separate tables from each session type. + + +=head1 SEE ALSO + +L + +=head1 AUTHORS + +=over + +=item Maxime Besson, Emaxime.besson@worteks.comE + +=back + +=head1 BUG REPORT + +Use OW2 system to report bug or ask for features: +L + +=head1 DOWNLOAD + +Lemonldap::NG is available at +L + diff --git a/rpm/lemonldap-ng.spec b/rpm/lemonldap-ng.spec index 02d2e0765..ca8304217 100644 --- a/rpm/lemonldap-ng.spec +++ b/rpm/lemonldap-ng.spec @@ -561,10 +561,12 @@ fi %config(noreplace) %{apache_confdir}/z-lemonldap-ng-manager.conf %config(noreplace) %{apache_confdir}/z-lemonldap-ng-portal.conf %{_mandir}/man1/convertConfig* +%{_mandir}/man1/convertSessions* %dir %{_libexecdir}/%{name} %dir %{lm_sbindir} %dir %{lm_bindir} %{lm_bindir}/convertConfig +%{lm_bindir}/convertSessions %{lm_bindir}/importMetadata %{lm_bindir}/lmMigrateConfFiles2ini %{lm_bindir}/rotateOidcKeys