270 lines
7.1 KiB
Perl
Executable File
270 lines
7.1 KiB
Perl
Executable File
#!/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::Long;
|
|
use Pod::Usage;
|
|
|
|
our $VERSION = "2.0.6";
|
|
|
|
# Options
|
|
# -d: debug mode
|
|
# -c: configuration file
|
|
# -r: configuration file
|
|
# -i: ignore errors
|
|
|
|
my $debug;
|
|
my $config_file;
|
|
my $ignore_errors;
|
|
my %rename;
|
|
my $help;
|
|
my $nb_converted = 0;
|
|
my $nb_error = 0;
|
|
|
|
GetOptions(
|
|
'help|?' => \$help,
|
|
'debug|d' => \$debug,
|
|
'config|c=s' => \$config_file,
|
|
'ignore-errors|i' => \$ignore_errors,
|
|
'rename|r=s' => \%rename,
|
|
) or pod2usage(2);
|
|
pod2usage(
|
|
-exitval => 1,
|
|
-verbose => 99,
|
|
-sections => "SYNOPSIS|OPTIONS|CONFIGURATION FILE FORMAT"
|
|
) if $help;
|
|
|
|
unless ($config_file) {
|
|
pod2usage(
|
|
-exitval => 2,
|
|
-verbose => 99,
|
|
-message => "You must provide the -c option\n",
|
|
-sections => "SYNOPSIS|OPTIONS|CONFIGURATION FILE FORMAT"
|
|
);
|
|
}
|
|
|
|
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 ($@) {
|
|
die "Error evaluating $section/$_: $@";
|
|
}
|
|
}
|
|
}
|
|
$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;
|
|
|
|
# If filtering sessionKind
|
|
if (@sessionKindOnly) {
|
|
|
|
unless ( grep { $_ eq $entry->{_session_kind} } @sessionKindOnly ) {
|
|
print "Ignoring session $id with type "
|
|
. $entry->{_session_kind} . "\n"
|
|
if $debug;
|
|
return undef;
|
|
}
|
|
}
|
|
|
|
if (%rename) {
|
|
for my $oldkey ( keys %rename ) {
|
|
my $newkey = $rename{$oldkey};
|
|
if ( $newkey and $entry->{$oldkey} ) {
|
|
print "Renaming $oldkey to $newkey in session $id\n"
|
|
if $debug;
|
|
$entry->{$newkey} = delete $entry->{$oldkey};
|
|
}
|
|
}
|
|
}
|
|
|
|
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 ( $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] [-r oldkey=newkey ] -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 OPTIONS
|
|
|
|
=over
|
|
|
|
=item B<--config>,B<-c>
|
|
|
|
Specify configuration file
|
|
|
|
=item B<--debug>,B<-d>
|
|
|
|
Turns on debugging information
|
|
|
|
=item B<--ignore-errors>,B<-i>
|
|
|
|
Skip to the next session if converting a session fails
|
|
|
|
=item B<--rename oldkey=newkey>,B<-r oldkey=newkey>
|
|
|
|
Rename key names when migrating from one backend to the next.
|
|
|
|
This option can be specified multiple times
|
|
|
|
=back
|
|
|
|
=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<sessionKind> 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<http://lemonldap-ng.org/>
|
|
|
|
=head1 AUTHORS
|
|
|
|
=over
|
|
|
|
=item Maxime Besson, E<lt>maxime.besson@worteks.comE<gt>
|
|
|
|
=back
|
|
|
|
=head1 BUG REPORT
|
|
|
|
Use OW2 system to report bug or ask for features:
|
|
L<https://gitlab.ow2.org/lemonldap-ng/lemonldap-ng/issues>
|
|
|
|
=head1 DOWNLOAD
|
|
|
|
Lemonldap::NG is available at
|
|
L<http://forge.objectweb.org/project/showfiles.php?group_id=274>
|
|
|