From 0b2da4195eae7cdcec04008fbac6d10d4ff93b50 Mon Sep 17 00:00:00 2001
From: Zdenek Sustr <git@sustr.net>
Date: Tue, 18 Jul 2017 17:22:14 +0200
Subject: [PATCH 1/3] [process-voms*] Remove duplicate entries on input

- Actively check the setting of property voms.skip_ca_check,
- Remove duplicate user entries that only differ in CA
- Avoid attempting to create/handle duplicate VOMS accounts.
---
 slave/process-voms-dirac/changelog            |  8 +++
 .../lib/process-voms_dirac.pl                 | 49 +++++++++++++++++++
 slave/process-voms/changelog                  |  8 +++
 slave/process-voms/lib/process-voms.pl        | 49 +++++++++++++++++++
 4 files changed, 114 insertions(+)

diff --git a/slave/process-voms-dirac/changelog b/slave/process-voms-dirac/changelog
index 1acf5c2d..4ee3c859 100755
--- a/slave/process-voms-dirac/changelog
+++ b/slave/process-voms-dirac/changelog
@@ -1,3 +1,11 @@
+perun-slave-process-voms (1.0.1) stable; urgency=high
+
+  * Actively check the setting of property voms.skip_ca_check and remove
+    duplicate user entries that only differ in CA before attempting to
+    create/handle duplicate VOMS accounts.
+
+ -- Zdenek Sustr <sustr4@cesnet.cz>  Tue Jul 18 17:19:34 CEST 2017
+
 perun-slave-process-voms-dirac (1.0.0) stable; urgency=medium
 
   * New slave forked from process-voms, enhanced with "nickname" attribute handling
diff --git a/slave/process-voms-dirac/lib/process-voms_dirac.pl b/slave/process-voms-dirac/lib/process-voms_dirac.pl
index 788d0aaf..1dbe69ec 100755
--- a/slave/process-voms-dirac/lib/process-voms_dirac.pl
+++ b/slave/process-voms-dirac/lib/process-voms_dirac.pl
@@ -17,6 +17,8 @@ my $csv = Text::CSV->new({ sep_char => ',' });
 $attributeStatusFilePrefix = "/var/lib/perun/process-voms-dirac/process-voms-attributes-";
 my $attributeStatusDir = dirname($attributeStatusFilePrefix);
 make_path($attributeStatusDir) unless (-e $attributeStatusDir);
+my $etcDir = "/etc/voms-admin";
+my $etcPropertyFilename = "service.properties";
 
 ### serialize is used to turn an array of hash references into a manageable structure
 sub serialize {
@@ -110,6 +112,46 @@ sub knownCA {
 }
 
 
+### readProperties reads VO properties file into an array
+#	$path		Path to the file
+sub readProperties {
+	$path = shift;
+	my %properties;
+	if (open(INI, "$path")) {
+                syslog LOG_DEBUG, "Reading config file \"$path\".";
+                print STDERR "Reading config file \"$path\".\n";
+	        while (<INI>) {
+			chomp;
+			if (/^(\S*)\s*=\s*(\S*)(#.*)?$/) {
+				$properties{"$1"} = "$2";
+			}
+		}
+                close (INI);
+	}
+	else {
+                syslog LOG_WARN, "Could not open config file \"$path\". No way to read VO properties";
+                print STDERR "Could not open config file \"$path\". No way to read VO properties\n";
+	}
+	return %properties;
+}
+
+### uniqueDN checks if the user's DN already exists in a list of DNs seen
+#	$user_ref	User structure reference
+#	$seen_ref	List of DNs for comparison
+sub uniqueDN {
+	$seen_ref = $_[1];
+	$user_ref = $_[0];
+
+	if(grep {$_ eq "$user_ref->{'DN'}"} @$seen_ref) {
+		syslog LOG_ERR, "Duplicate user \"" . $user_ref->{'DN'} .
+			"\" dropped with CA \"" . $user_ref->{'CA'} . "\"";
+		print STDERR "Duplicate user \"" . $user_ref->{'DN'} .
+			"\" dropped with CA \"" . $user_ref->{'CA'} . "\"\n";
+		return 0;
+	}
+	return 1;
+}
+
 # This is the actual start.
 
 openlog($program, 'cons,pid', 'user');
@@ -120,6 +162,10 @@ my $retval = 0;
 foreach my $vo (@{$vos->{'vo'}}) { # Iterating through individual VOs in the XML
 	$name = $vo->{'name'};
 
+	my %properties = readProperties("$etcDir/$name/$etcPropertyFilename");
+	my $checkCA = $properties{"voms.skip_ca_check"} eq "True" ? 0 : 1;
+	syslog LOG_DEBUG, "voms.skip_ca_check: " . $properties{"voms.skip_ca_check"} . ", $checkCA\n";
+	print STDERR "voms.skip_ca_check: " . $properties{"voms.skip_ca_check"} . ", $checkCA\n";
 
 	#Collect lists from voms-admin
 	my @groups_current=`voms-admin --vo \Q${name}\E list-groups`;
@@ -195,9 +241,12 @@ foreach my $vo (@{$vos->{'vo'}}) { # Iterating through individual VOs in the XML
 	my @attributes_toBe;		# List of al users with attributes
 	my @groups_toBe = ( "/$name" );	# Desired list of groups
 	my @roles_toBe = ( "VO-Admin" );# Desired list of roles, plus the default VO-Admin role
+	my @DNs_Seen;			# DNs already included
 	foreach $user (@{$vo->{'users'}->{'user'}}) {
 		next unless knownCA(\@cas, $user->{'CA'});
 		my %theUser= ( 'CA' => "$user->{'CA'}",'DN' => "$user->{'DN'}", 'CN' => getCN($user->{'DN'}), 'email' => "$user->{'email'}" );
+		next unless ($checkCA || uniqueDN(\%theUser, \@DNs_Seen));
+		push(@DNs_Seen, $theUser{'DN'});
 		if($user->{'nickname'}) {
 			my %userAttributes = ( 'CA' => "$user->{'CA'}",'DN' => "$user->{'DN'}", 'name' => 'nickname', 'value' => "$user->{'nickname'}" );
 			push(@attributes_toBe, \%userAttributes);
diff --git a/slave/process-voms/changelog b/slave/process-voms/changelog
index 71e02eb4..32520b72 100755
--- a/slave/process-voms/changelog
+++ b/slave/process-voms/changelog
@@ -1,3 +1,11 @@
+perun-slave-process-voms (3.1.7) stable; urgency=high
+
+  * Actively check the setting of property voms.skip_ca_check and remove
+    duplicate user entries that only differ in CA before attempting to
+    create/handle duplicate VOMS accounts.
+
+ -- Zdenek Sustr <sustr4@cesnet.cz>  Tue Jul 18 17:19:34 CEST 2017
+
 perun-slave-process-voms (3.1.6) stable; urgency=high
 
   * fixing error output for list-roles and list-cas operations
diff --git a/slave/process-voms/lib/process-voms.pl b/slave/process-voms/lib/process-voms.pl
index c4b4b555..b056dc89 100755
--- a/slave/process-voms/lib/process-voms.pl
+++ b/slave/process-voms/lib/process-voms.pl
@@ -13,6 +13,9 @@ my $vos = XMLin( '-',
 	KeyAttr => [] );
 my $csv = Text::CSV->new({ sep_char => ',' });
 
+my $etcDir = "/etc/voms-admin";
+my $etcPropertyFilename = "service.properties";
+
 ### serialize is used to turn an array of hash references into a manageable structure
 sub serialize {
     JSON::XS->new->relaxed(0)->ascii(1)->canonical(1)->encode($_[0]);
@@ -101,6 +104,45 @@ sub knownCA {
 	}
 }
 
+### readProperties reads VO properties file into an array
+#      $path           Path to the file
+sub readProperties {
+       $path = shift;
+       my %properties;
+       if (open(INI, "$path")) {
+                syslog LOG_DEBUG, "Reading config file \"$path\".";
+                print STDERR "Reading config file \"$path\".\n";
+               while (<INI>) {
+                       chomp;
+                       if (/^(\S*)\s*=\s*(\S*)(#.*)?$/) {
+                               $properties{"$1"} = "$2";
+                       }
+               }
+                close (INI);
+       }
+       else {
+                syslog LOG_WARN, "Could not open config file \"$path\". No way to read VO properties";
+                print STDERR "Could not open config file \"$path\". No way to read VO properties\n";
+       }
+       return %properties;
+}
+
+### uniqueDN checks if the user's DN already exists in a list of DNs seen
+#      $user_ref       User structure reference
+#      $seen_ref       List of DNs for comparison
+sub uniqueDN {
+       $seen_ref = $_[1];
+       $user_ref = $_[0];
+
+       if(grep {$_ eq "$user_ref->{'DN'}"} @$seen_ref) {
+               syslog LOG_ERR, "Duplicate user \"" . $user_ref->{'DN'} .
+                       "\" dropped with CA \"" . $user_ref->{'CA'} . "\"";
+               print STDERR "Duplicate user \"" . $user_ref->{'DN'} .
+                       "\" dropped with CA \"" . $user_ref->{'CA'} . "\"\n";
+               return 0;
+       }
+       return 1;
+}
 
 # This is the actual start.
 
@@ -112,6 +154,10 @@ my $retval = 0;
 foreach my $vo (@{$vos->{'vo'}}) { # Iterating through individual VOs in the XML
 	$name = $vo->{'name'};
 
+	my %properties = readProperties("$etcDir/$name/$etcPropertyFilename");
+	my $checkCA = $properties{"voms.skip_ca_check"} eq "True" ? 0 : 1;
+	syslog LOG_DEBUG, "voms.skip_ca_check: " . $properties{"voms.skip_ca_check"} . ", $checkCA\n";
+	print STDERR "voms.skip_ca_check: " . $properties{"voms.skip_ca_check"} . ", $checkCA\n";
 
 	#Collect lists from voms-admin
 	my @groups_current=`voms-admin --vo \Q${name}\E list-groups`;
@@ -162,9 +208,12 @@ foreach my $vo (@{$vos->{'vo'}}) { # Iterating through individual VOs in the XML
 	my %groupMembers_toBe;		# Desired membership in groups (pure, disregarding roles)
 	my @groups_toBe = ( "/$name" );	# Desired list of groups
 	my @roles_toBe = ( "VO-Admin" );# Desired list of roles, plus the default VO-Admin role
+	my @DNs_Seen;                   # DNs already included
 	foreach $user (@{$vo->{'users'}->{'user'}}) {
 		next unless knownCA($user->{'CA'});
 		my %theUser= ( 'CA' => "$user->{'CA'}",'DN' => "$user->{'DN'}", 'CN' => getCN($user->{'DN'}), 'email' => "$user->{'email'}" );
+		next unless ($checkCA || uniqueDN(\%theUser, \@DNs_Seen));
+		push(@DNs_Seen, $theUser{'DN'});
 		push( @{$groupMembers_toBe{"/$name"}}, \%theUser ); #Add user to root group (make them a member)
 		foreach $group (@{$user->{'groups'}->{'group'}}){
 			push(@groups_toBe, "/$name/$group->{'name'}") unless grep{$_ eq "/$name/$group->{'name'}"} @groups_toBe;
-- 
GitLab


From 7350c34d6f11a5eea9c43b4aa6a8bf7f9e0fdf7e Mon Sep 17 00:00:00 2001
From: Zdenek Sustr <git@sustr.net>
Date: Wed, 19 Jul 2017 13:02:48 +0200
Subject: [PATCH 2/3] [process-voms*] Settling requirements form review

- Indentation by \t
- Simple comparison instead of ternary operator
---
 .../lib/process-voms_dirac.pl                 | 28 ++++++------
 slave/process-voms/lib/process-voms.pl        | 44 +++++++++----------
 2 files changed, 36 insertions(+), 36 deletions(-)

diff --git a/slave/process-voms-dirac/lib/process-voms_dirac.pl b/slave/process-voms-dirac/lib/process-voms_dirac.pl
index 2680587d..428bc4e3 100755
--- a/slave/process-voms-dirac/lib/process-voms_dirac.pl
+++ b/slave/process-voms-dirac/lib/process-voms_dirac.pl
@@ -47,9 +47,9 @@ sub getCN {
 #   is not called in some cases
 #       DN      DN to process
 sub normalizeEmail {
-        my $normalized = shift;
-        $normalized =~ s/\/(E|e|((E|e|)(mail|mailAddress|mailaddress|MAIL|MAILADDRESS)))=/\/Email=/;
-        return $normalized
+	my $normalized = shift;
+	$normalized =~ s/\/(E|e|((E|e|)(mail|mailAddress|mailaddress|MAIL|MAILADDRESS)))=/\/Email=/;
+	return $normalized
 }
 
 ### normalizeUID applies the same normalization replacement on user DNs as voms-admin itself
@@ -57,9 +57,9 @@ sub normalizeEmail {
 #   is not called in some cases
 #       DN      DN to process
 sub normalizeUID {
-        my $normalized = shift;
-        $normalized =~ s/\/(UserId|USERID|userId|userid|uid|Uid)=/\/UID=/;
-        return $normalized
+	my $normalized = shift;
+	$normalized =~ s/\/(UserId|USERID|userId|userid|uid|Uid)=/\/UID=/;
+	return $normalized
 }
 
 ### listToHashes accepts a three-column CSV and produces an array of hashes with the following structure:
@@ -138,19 +138,19 @@ sub readProperties {
 	$path = shift;
 	my %properties;
 	if (open(INI, "$path")) {
-                syslog LOG_DEBUG, "Reading config file \"$path\".";
-                print STDERR "Reading config file \"$path\".\n";
-	        while (<INI>) {
+		syslog LOG_DEBUG, "Reading config file \"$path\".";
+		print STDERR "Reading config file \"$path\".\n";
+		while (<INI>) {
 			chomp;
 			if (/^(\S*)\s*=\s*(\S*)(#.*)?$/) {
 				$properties{"$1"} = "$2";
 			}
 		}
-                close (INI);
+		close (INI);
 	}
 	else {
-                syslog LOG_WARN, "Could not open config file \"$path\". No way to read VO properties";
-                print STDERR "Could not open config file \"$path\". No way to read VO properties\n";
+		syslog LOG_WARN, "Could not open config file \"$path\". No way to read VO properties";
+		print STDERR "Could not open config file \"$path\". No way to read VO properties\n";
 	}
 	return %properties;
 }
@@ -183,7 +183,7 @@ foreach my $vo (@{$vos->{'vo'}}) { # Iterating through individual VOs in the XML
 	$name = $vo->{'name'};
 
 	my %properties = readProperties("$etcDir/$name/$etcPropertyFilename");
-	my $checkCA = $properties{"voms.skip_ca_check"} eq "True" ? 0 : 1;
+	my $checkCA = $properties{"voms.skip_ca_check"} ne "True";
 	syslog LOG_DEBUG, "voms.skip_ca_check: " . $properties{"voms.skip_ca_check"} . ", $checkCA\n";
 	print STDERR "voms.skip_ca_check: " . $properties{"voms.skip_ca_check"} . ", $checkCA\n";
 
@@ -237,7 +237,7 @@ foreach my $vo (@{$vos->{'vo'}}) { # Iterating through individual VOs in the XML
 		#Role Membership
 		foreach $role (@roles_current) {
 			$groupRoles_current{"$group"}{"$role"}=listToHashes(\@cas, `voms-admin --vo \Q${name}\E list-users-with-role \Q${group}\E \Q${role}\E`);
-	        }
+		}
 	}
 
 	$attributeStatusFile = $attributeStatusFilePrefix.$name.".xml";
diff --git a/slave/process-voms/lib/process-voms.pl b/slave/process-voms/lib/process-voms.pl
index 53d95a65..c8862b49 100755
--- a/slave/process-voms/lib/process-voms.pl
+++ b/slave/process-voms/lib/process-voms.pl
@@ -125,24 +125,24 @@ sub knownCA {
 }
 
 ### readProperties reads VO properties file into an array
-#      $path           Path to the file
+#      $path	   Path to the file
 sub readProperties {
        $path = shift;
        my %properties;
        if (open(INI, "$path")) {
-                syslog LOG_DEBUG, "Reading config file \"$path\".";
-                print STDERR "Reading config file \"$path\".\n";
-               while (<INI>) {
-                       chomp;
-                       if (/^(\S*)\s*=\s*(\S*)(#.*)?$/) {
-                               $properties{"$1"} = "$2";
-                       }
-               }
-                close (INI);
+		syslog LOG_DEBUG, "Reading config file \"$path\".";
+		print STDERR "Reading config file \"$path\".\n";
+	       while (<INI>) {
+		       chomp;
+		       if (/^(\S*)\s*=\s*(\S*)(#.*)?$/) {
+			       $properties{"$1"} = "$2";
+		       }
+	       }
+		close (INI);
        }
        else {
-                syslog LOG_WARN, "Could not open config file \"$path\". No way to read VO properties";
-                print STDERR "Could not open config file \"$path\". No way to read VO properties\n";
+		syslog LOG_WARN, "Could not open config file \"$path\". No way to read VO properties";
+		print STDERR "Could not open config file \"$path\". No way to read VO properties\n";
        }
        return %properties;
 }
@@ -155,11 +155,11 @@ sub uniqueDN {
        $user_ref = $_[0];
 
        if(grep {$_ eq "$user_ref->{'DN'}"} @$seen_ref) {
-               syslog LOG_ERR, "Duplicate user \"" . $user_ref->{'DN'} .
-                       "\" dropped with CA \"" . $user_ref->{'CA'} . "\"";
-               print STDERR "Duplicate user \"" . $user_ref->{'DN'} .
-                       "\" dropped with CA \"" . $user_ref->{'CA'} . "\"\n";
-               return 0;
+	       syslog LOG_ERR, "Duplicate user \"" . $user_ref->{'DN'} .
+		       "\" dropped with CA \"" . $user_ref->{'CA'} . "\"";
+	       print STDERR "Duplicate user \"" . $user_ref->{'DN'} .
+		       "\" dropped with CA \"" . $user_ref->{'CA'} . "\"\n";
+	       return 0;
        }
        return 1;
 }
@@ -175,7 +175,7 @@ foreach my $vo (@{$vos->{'vo'}}) { # Iterating through individual VOs in the XML
 	$name = $vo->{'name'};
 
 	my %properties = readProperties("$etcDir/$name/$etcPropertyFilename");
-	my $checkCA = $properties{"voms.skip_ca_check"} eq "True" ? 0 : 1;
+	my $checkCA = $properties{"voms.skip_ca_check"} ne "True";
 	syslog LOG_DEBUG, "voms.skip_ca_check: " . $properties{"voms.skip_ca_check"} . ", $checkCA\n";
 	print STDERR "voms.skip_ca_check: " . $properties{"voms.skip_ca_check"} . ", $checkCA\n";
 
@@ -219,7 +219,7 @@ foreach my $vo (@{$vos->{'vo'}}) { # Iterating through individual VOs in the XML
 		#Role Membership
 		foreach $role (@roles_current) {
 			$groupRoles_current{"$group"}{"$role"}=listToHashes(`voms-admin --vo \Q${name}\E list-users-with-role \Q${group}\E \Q${role}\E`);
-	        }
+		}
 	}
 
 
@@ -228,7 +228,7 @@ foreach my $vo (@{$vos->{'vo'}}) { # Iterating through individual VOs in the XML
 	my %groupMembers_toBe;		# Desired membership in groups (pure, disregarding roles)
 	my @groups_toBe = ( "/$name" );	# Desired list of groups
 	my @roles_toBe = ( "VO-Admin" );# Desired list of roles, plus the default VO-Admin role
-	my @DNs_Seen;                   # DNs already included
+	my @DNs_Seen;		   # DNs already included
 	foreach $user (@{$vo->{'users'}->{'user'}}) {
 		next unless knownCA($user->{'CA'});
 		my %theUser= ( 'CA' => "$user->{'CA'}",'DN' => normalizeUID(normalizeEmail($user->{'DN'})), 'CN' => getCN($user->{'DN'}), 'email' => "$user->{'email'}" );
@@ -261,7 +261,7 @@ foreach my $vo (@{$vos->{'vo'}}) { # Iterating through individual VOs in the XML
 	my %membersToAdd;
 	my %rolesToAssign;
 	my %rolesToDismiss;
-        foreach $group (@groups_toBe) {
+	foreach $group (@groups_toBe) {
 		@{$membersToRemove{"$group"}} = array_minus_deep(@{$groupMembers_current{"$group"}}, @{$groupMembers_toBe{"$group"}});
 		@{$membersToRemove{"$group"}} = array_minus_deep(@{$membersToRemove{"$group"}}, @{$membersToRemove{"/$name"}}) unless( "$group" eq "/$name" ); # No need to remove user from groups if they are going to be fully removed
 		@{$membersToAdd{"$group"}} = array_minus_deep(@{$groupMembers_toBe{"$group"}}, @{$groupMembers_current{"$group"}});
@@ -271,7 +271,7 @@ foreach my $vo (@{$vos->{'vo'}}) { # Iterating through individual VOs in the XML
 			@{$rolesToDismiss{"$group"}{"$role"}} = array_minus_deep(@{$rolesToDismiss{"$group"}{"$role"}}, @{$membersToRemove{"/$name"}}); # No need to revoke roles if the user is going to be fully removed
 			@{$rolesToDismiss{"$group"}{"$role"}} = array_minus_deep(@{$rolesToDismiss{"$group"}{"$role"}}, @{$membersToRemove{"$group"}}); # No need to revoke roles if the user is going to be removed from the group
 		}
-        }
+	}
 
 
 	# Effect changes
-- 
GitLab


From 4118f53466801d1e3f3441bb80163ba617c16df3 Mon Sep 17 00:00:00 2001
From: Zdenek Sustr <git@sustr.net>
Date: Wed, 23 Aug 2017 14:29:23 +0200
Subject: [PATCH 3/3] [process-voms] Resolving changelog conflicts

---
 slave/process-voms-dirac/changelog | 9 +++++++--
 slave/process-voms/changelog       | 9 +++++++--
 2 files changed, 14 insertions(+), 4 deletions(-)

diff --git a/slave/process-voms-dirac/changelog b/slave/process-voms-dirac/changelog
index 7e1cf4fb..d2205060 100755
--- a/slave/process-voms-dirac/changelog
+++ b/slave/process-voms-dirac/changelog
@@ -1,12 +1,17 @@
-perun-slave-process-voms-dirac (1.0.1) stable; urgency=high
+perun-slave-process-voms-dirac (1.0.2) stable; urgency=high
 
   * Actively check the setting of property voms.skip_ca_check and remove
     duplicate user entries that only differ in CA before attempting to
     create/handle duplicate VOMS accounts.
+
+ -- Zdenek Sustr <sustr4@cesnet.cz>  Tue Jul 18 17:19:34 CEST 2017
+
+perun-slave-process-voms-dirac (1.0.1) stable; urgency=high
+
   * working around inconsistent normalization of DNs in voms-admin
     by pre-normalizing perun exports using the same pattern
 
- -- Zdenek Sustr <sustr4@cesnet.cz>  Tue Jul 18 17:19:34 CEST 2017
+ -- Zdenek Sustr <sustr4@cesnet.cz>  Mon Jul 17 17:36:21 CEST 2017
 
 perun-slave-process-voms-dirac (1.0.0) stable; urgency=medium
 
diff --git a/slave/process-voms/changelog b/slave/process-voms/changelog
index c230acce..dc3d68be 100755
--- a/slave/process-voms/changelog
+++ b/slave/process-voms/changelog
@@ -1,12 +1,17 @@
-perun-slave-process-voms (3.1.7) stable; urgency=high
+perun-slave-process-voms (3.1.8) stable; urgency=high
 
   * Actively check the setting of property voms.skip_ca_check and remove
     duplicate user entries that only differ in CA before attempting to
     create/handle duplicate VOMS accounts.
+
+ -- Zdenek Sustr <sustr4@cesnet.cz>  Tue Jul 18 17:19:34 CEST 2017
+
+perun-slave-process-voms (3.1.7) stable; urgency=high
+
   * working around inconsistent normalization of DNs in voms-admin
     by pre-normalizing perun exports using the same pattern
 
- -- Zdenek Sustr <sustr4@cesnet.cz>  Tue Jul 18 17:19:34 CEST 2017
+ -- Zdenek Sustr <sustr4@cesnet.cz>  Mon Jul 17 17:36:21 CEST 2017
 
 perun-slave-process-voms (3.1.6) stable; urgency=high
 
-- 
GitLab