#!/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