From 17be15e88a4eade673ffb4e200940409a73cb3c6 Mon Sep 17 00:00:00 2001 From: Gallavardin Antoine Date: Mon, 28 Jun 2021 21:45:11 +0200 Subject: [PATCH] improve Metadata script import --- lemonldap-ng-common/scripts/importMetadata | 376 ++++++++++++++------- 1 file changed, 249 insertions(+), 127 deletions(-) mode change 100755 => 100644 lemonldap-ng-common/scripts/importMetadata diff --git a/lemonldap-ng-common/scripts/importMetadata b/lemonldap-ng-common/scripts/importMetadata old mode 100755 new mode 100644 index 1a2d8ca31..d645be247 --- a/lemonldap-ng-common/scripts/importMetadata +++ b/lemonldap-ng-common/scripts/importMetadata @@ -6,6 +6,19 @@ use Lemonldap::NG::Common::Conf; use LWP::UserAgent; use MIME::Base64; use XML::LibXML; +use Data::Dumper qw(Dumper); + + +sub toEntityIDkey { + my ($prefix, $entityID) = @_; + + my $entityIDKey = $entityID; + $entityIDKey =~ s/^https?:\/\///; + $entityIDKey =~ s/[^a-zA-Z0-9]/-/g; + $entityIDKey =~ s/-+$//g; + return($prefix . $entityIDKey); +} + #============================================================================== # Get command line options @@ -16,7 +29,8 @@ my $result = GetOptions( 'certificate|c=s', 'verbose|v', 'help|h', 'spconfprefix|s=s', 'idpconfprefix|i=s', 'warning|w', - 'remove|r' + 'remove|r', 'nagios|n', + 'blocklistsp|bs=s', 'blocklistidp|bi=s', 'dryrun|d' ); #============================================================================== @@ -27,15 +41,18 @@ if ( $opts{help} or !$opts{metadata} ) { "\nScript to import SAML metadata bundle file into LL::NG configuration\n\n"; print STDERR "Usage: $0 -m \n\n"; print STDERR "Options:\n"; - print STDERR -"\t-c (--certificate): URL of certificate, to check metadata document signature\n"; - print STDERR - "\t-i (--idpconfprefix): Prefix used to set IDP configuration key\n"; + print STDERR "\t-c (--certificate): URL of certificate, to check metadata document signature\n"; + print STDERR "\t-i (--idpconfprefix): Prefix used to set IDP configuration key\n"; print STDERR "\t-h (--help): print this message\n"; print STDERR "\t-m (--metadata): URL of metadata document\n"; - print STDERR - "\t-s (--spconfprefix): Prefix used to set SP configuration key\n"; + print STDERR "\t-s (--spconfprefix): Prefix used to set SP configuration key\n"; print STDERR "\t-w (--warning): print debug messages\n"; + print STDERR "\t-bs (--blocklistsp): list of SP entityID to avoid to modify/import\n"; + print STDERR "\t-bi (--blocklistip): list of IdP entityID to avoid to modify/import\n"; + print STDERR "\t-n (--nagios) : output only metrics nagios compatible\n"; + print STDERR "\t-d (--dryrun): do nothing\n"; + print STDERR "\t-v (--verbose): display all actions\n"; + print STDERR "\t-r (--remove): remove entityID inside LemonLDAP if was remove inside remote metadata\n"; exit 1; } @@ -43,11 +60,15 @@ if ( $opts{help} or !$opts{metadata} ) { # Default values #============================================================================== + + + my $spConfKeyPrefix = $opts{spconfprefix} || "sp-"; my $idpConfKeyPrefix = $opts{idpconfprefix} || "idp-"; # Set here attributes that are declared for your SP in the federation # They will be set as exported attributes for all IDP +# my $exportedAttributes = { 'cn' => '0;cn', 'eduPersonPrincipalName' => '0;eduPersonAffiliation', @@ -101,16 +122,46 @@ my $idpCounter = { 'updated' => 0, 'created' => 0, 'rejected' => 0, - 'removed' => 0 + 'removed' => 0, + 'ignored' => 0 }; my $spCounter = { 'found' => 0, 'updated' => 0, 'created' => 0, 'rejected' => 0, - 'removed' => 0 + 'removed' => 0, + 'ignored' => 0, }; + + +############# Block List manipulation + +my $blocklistsp = $opts{blocklistsp} || ""; +my $blocklistidp = $opts{blocklistidp} || ""; + +# BlockList initialisation +my @spBlocklist = (); +my @spBlocklistKey = (); +if ( $blocklistsp ) { + @spBlocklist = split(/,/,$opts{blocklistsp}); +} + +my @idpBlocklist = (); +my @idpBlocklistKey = (); +if ( $blocklistidp ) { + @idpBlocklist = split(/,/,$opts{blocklistidp}) +} + +foreach my $s (@spBlocklist) { + push(@spBlocklistKey,toEntityIDkey($spConfKeyPrefix, $s)); +} + +foreach my $s (@idpBlocklist) { + push(@idpBlocklistKey,toEntityIDkey($idpConfKeyPrefix, $s)); +} + #============================================================================== # Main #============================================================================== @@ -232,52 +283,57 @@ foreach my $partner_metadata = $partner->toString; $partner_metadata =~ s/\n//g; - # Check if entityID already in configuration - if ( defined $idpList->{$entityID} ) { + # test if IDP entityID is inside the block list - # Update metadata - $lastConf->{samlIDPMetaDataXML}->{ $idpList->{$entityID} } - ->{samlIDPMetaDataXML} = $partner_metadata; + if ( $entityID ~~ @idpBlocklist){ + if ( $opts{verbose} ) { + print "IDP $entityID won't be update/added \n"; + } + $idpCounter->{ignored}++; + }else{ + # Check if entityID already in configuration + if ( defined $idpList->{$entityID} ) { + + # Update metadata + $lastConf->{samlIDPMetaDataXML}->{ $idpList->{$entityID} } + ->{samlIDPMetaDataXML} = $partner_metadata; + + # Update attributes + $lastConf->{samlIDPMetaDataExportedAttributes} + ->{ $idpList->{$entityID} } = $exportedAttributes; - # Update attributes - $lastConf->{samlIDPMetaDataExportedAttributes} - ->{ $idpList->{$entityID} } = $exportedAttributes; + # Update options + $lastConf->{samlIDPMetaDataOptions}->{ $idpList->{$entityID} } + = $idpOptions; + + if ( $opts{verbose} ) { + print "Update IDP $entityID in configuration\n"; + } + $idpCounter->{updated}++; + } + else { + # Create a new partner + my $confKey = toEntityIDkey($idpConfKeyPrefix, $entityID); - # Update options - $lastConf->{samlIDPMetaDataOptions}->{ $idpList->{$entityID} } - = $idpOptions; + # Metadata + $lastConf->{samlIDPMetaDataXML}->{$confKey} + ->{samlIDPMetaDataXML} = $partner_metadata; - if ( $opts{verbose} ) { - print "Update IDP $entityID in configuration\n"; - } - $idpCounter->{updated}++; + # Attributes + $lastConf->{samlIDPMetaDataExportedAttributes}->{$confKey} = + $exportedAttributes; + + # Options + $lastConf->{samlIDPMetaDataOptions}->{$confKey} = $idpOptions; + + if ( $opts{verbose} ) { + print + "Declare new IDP $entityID (configuration key $confKey)\n"; + } + $idpCounter->{created}++; + } } - else { - # Create a new partner - my $entityIDKey = $entityID; - $entityIDKey =~ s/^https?:\/\///; - $entityIDKey =~ s/[^a-zA-Z0-9]/-/g; - $entityIDKey =~ s/-+$//g; - my $confKey = $idpConfKeyPrefix . $entityIDKey; - - # Metadata - $lastConf->{samlIDPMetaDataXML}->{$confKey} - ->{samlIDPMetaDataXML} = $partner_metadata; - - # Attributes - $lastConf->{samlIDPMetaDataExportedAttributes}->{$confKey} = - $exportedAttributes; - - # Options - $lastConf->{samlIDPMetaDataOptions}->{$confKey} = $idpOptions; - - if ( $opts{verbose} ) { - print -"Declare new IDP $entityID (configuration key $confKey)\n"; - } - $idpCounter->{created}++; - } - + } else { print STDERR @@ -346,50 +402,67 @@ foreach my $partner_metadata = $partner->toString; $partner_metadata =~ s/\n//g; - # Check if entityID already in configuration - if ( defined $spList->{$entityID} ) { - # Update metadata - $lastConf->{samlSPMetaDataXML}->{ $spList->{$entityID} } - ->{samlSPMetaDataXML} = $partner_metadata; - - # Update attributes - $lastConf->{samlSPMetaDataExportedAttributes} - ->{ $spList->{$entityID} } = $requestedAttributes; - - # Update options - $lastConf->{samlSPMetaDataOptions}->{ $spList->{$entityID} } = - $spOptions; + # test if IDP entityID is inside the block list + if ( $entityID ~~ @spBlocklist){ if ( $opts{verbose} ) { - print "Update SP $entityID in configuration\n"; - } - $spCounter->{updated}++; - } - else { - # Create a new partner - my $entityIDKey = $entityID; - $entityIDKey =~ s/^https?:\/\///; - $entityIDKey =~ s/[^a-zA-Z0-9]/-/g; - $entityIDKey =~ s/-+$//g; - my $confKey = $spConfKeyPrefix . $entityIDKey; + print "SP $entityID won't be update/added \n"; + } + $spCounter->{ignored}++; + }else{ + # Check if entityID already in configuration + if ( defined $spList->{$entityID} ) { + # Update metadata + $lastConf->{samlSPMetaDataXML}->{ $spList->{$entityID} } + ->{samlSPMetaDataXML} = $partner_metadata; - # Metadata - $lastConf->{samlSPMetaDataXML}->{$confKey}->{samlSPMetaDataXML} - = $partner_metadata; + # Update attributes + $lastConf->{samlSPMetaDataExportedAttributes} + ->{ $spList->{$entityID} } = $requestedAttributes; - # Attributes - $lastConf->{samlSPMetaDataExportedAttributes}->{$confKey} = - $requestedAttributes; + # Update options +# $lastConf->{samlSPMetaDataOptions}->{ $spList->{$entityID} } = +# $spOptions; +# FIX AGA + $lastConf->{samlSPMetaDataOptions}->{ $spList->{$entityID} } = + { %{$spOptions } }; - # Options - $lastConf->{samlSPMetaDataOptions}->{$confKey} = $spOptions; + if ( $opts{verbose} ) { + print "Update SP $entityID in configuration\n"; + } + $spCounter->{updated}++; + } + else { + # Create a new partner + my $confKey = toEntityIDkey($spConfKeyPrefix, $entityID); + + # Metadata + $lastConf->{samlSPMetaDataXML}->{$confKey}->{samlSPMetaDataXML} + = $partner_metadata; + + # Attributes + $lastConf->{samlSPMetaDataExportedAttributes}->{$confKey} = + $requestedAttributes; + + # Options + # $lastConf->{samlSPMetaDataOptions}->{$confKey} = $spOptions; + +# FIX AGA + $lastConf->{samlSPMetaDataOptions}->{$confKey} = { %{$spOptions } }; + + if ( $opts{verbose} ) { + print + "Declare new SP $entityID (configuration key $confKey)\n"; + } + $spCounter->{created}++; + } + # handle eduPersonTargetedID + if ( $requestedAttributes->{eduPersonTargetedID} ) { + delete $requestedAttributes->{eduPersonTargetedID}; + $lastConf->{samlSPMetaDataOptions}->{ $spList->{$entityID} }->{samlSPMetaDataOptionsNameIDFormat} = 'persistent'; + } - if ( $opts{verbose} ) { - print - "Declare new SP $entityID (configuration key $confKey)\n"; - } - $spCounter->{created}++; } } @@ -408,59 +481,108 @@ foreach if ( $opts{remove} ) { foreach ( keys %$idpList ) { my $idpConfKey = $idpList->{$_}; - unless ( defined $mdIdpList->{$_} ) { - delete $lastConf->{samlIDPMetaDataXML}->{$idpConfKey}; - delete $lastConf->{samlIDPMetaDataExportedAttributes} - ->{$idpConfKey}; - delete $lastConf->{samlIDPMetaDataOptions}->{$idpConfKey}; - $idpCounter->{removed}++; + if ( $idpConfKey ~~ @idpBlocklistKey){ if ( $opts{verbose} ) { - print "Remove IDP $idpConfKey\n"; + print "IDP $idpConfKey won't be deleted \n"; + } + }else{ + unless ( defined $mdIdpList->{$_} ) { + delete $lastConf->{samlIDPMetaDataXML}->{$idpConfKey}; + delete $lastConf->{samlIDPMetaDataExportedAttributes} + ->{$idpConfKey}; + delete $lastConf->{samlIDPMetaDataOptions}->{$idpConfKey}; + $idpCounter->{removed}++; + if ( $opts{verbose} ) { + print "Remove IDP $idpConfKey\n"; + } } } } foreach ( keys %$spList ) { my $spConfKey = $spList->{$_}; - unless ( defined $mdSpList->{$_} ) { - delete $lastConf->{samlSPMetaDataXML}->{$spConfKey}; - delete $lastConf->{samlSPMetaDataExportedAttributes}->{$spConfKey}; - delete $lastConf->{samlSPMetaDataOptions}->{$spConfKey}; - $spCounter->{removed}++; + if ( $spConfKey ~~ @spBlocklistKey){ if ( $opts{verbose} ) { - print "Remove SP $spConfKey\n"; + print "SP $spConfKey won't be deleted \n"; + } + }else{ + unless ( defined $mdSpList->{$_} ) { + delete $lastConf->{samlSPMetaDataXML}->{$spConfKey}; + delete $lastConf->{samlSPMetaDataExportedAttributes}->{$spConfKey}; + delete $lastConf->{samlSPMetaDataOptions}->{$spConfKey}; + $spCounter->{removed}++; + if ( $opts{verbose} ) { + print "Remove SP $spConfKey\n"; + } } } } } -# Register configuration -my $numConf = $conf->saveConf( $lastConf, ( cfgNumFixed => 1 ) ); +my $numConf = "DRY-RUN"; +my $exitCode = 0; -unless ($numConf) { - print "[ERROR] Unable to save configuration\n"; - exit 1; +if ( ! $opts{dryrun} ) { + # Register configuration + if ( $opts{verbose} ) { + print "[INFO] run mod EntityID will be inserted\n"; + } + $numConf = $conf->saveConf( $lastConf, ( cfgNumFixed => 1 ) ); + if ( $opts{verbose} ) { + print "[OK] Configuration $numConf saved\n"; + $exitCode = 0; + } + unless ($numConf) { + print "[ERROR] Unable to save configuration\n"; + $exitCode = 1; + } +}else{ + if ( $opts{verbose} ) { + print "[INFO] Dry-run mod no EntityID inserted\n"; + } } -print "[IDP]\tFound: " - . $idpCounter->{found} - . "\tUpdated: " - . $idpCounter->{updated} - . "\tCreated: " - . $idpCounter->{created} - . "\tRemoved: " - . $idpCounter->{removed} - . "\tRejected: " - . $idpCounter->{rejected} . "\n"; -print "[SP]\tFound: " - . $spCounter->{found} - . "\tUpdated: " - . $spCounter->{updated} - . "\tCreated: " - . $spCounter->{created} - . "\tRemoved: " - . $spCounter->{removed} - . "\tRejected: " - . $spCounter->{rejected} . "\n"; -print "[OK] Configuration $numConf saved\n"; -exit 0; + +if ( $opts{nagios} ) { + print "Metadata loaded inside Conf: [".$numConf."]|idp_found=".$idpCounter->{found} + .", idp_updated=".$idpCounter->{updated} + .", idp_created=".$idpCounter->{created} + .", idp_removed=".$idpCounter->{removed} + .", idp_rejected=".$idpCounter->{rejected} + .", idp_ignored=".$idpCounter->{ignored} + .", sp_found=".$spCounter->{found} + .", sp_updated=".$spCounter->{updated} + .", sp_created=".$spCounter->{created} + .", sp_removed=".$spCounter->{removed} + .", sp_rejected=".$spCounter->{rejected} + .", sp_ignored=".$spCounter->{ignored}."\n"; + }else{ + print "[IDP]\tFound: " + . $idpCounter->{found} + . "\tUpdated: " + . $idpCounter->{updated} + . "\tCreated: " + . $idpCounter->{created} + . "\tRemoved: " + . $idpCounter->{removed} + . "\tRejected: " + . $idpCounter->{rejected} + . "\tIgnored: " + . $idpCounter->{ignored} . "\n"; + print "[SP]\tFound: " + . $spCounter->{found} + . "\tUpdated: " + . $spCounter->{updated} + . "\tCreated: " + . $spCounter->{created} + . "\tRemoved: " + . $spCounter->{removed} + . "\tRejected: " + . $spCounter->{rejected} + . "\tIgnored: " + . $spCounter->{ignored} . "\n"; +} + + +exit $exitCode; +