From 107e7e25fd078040b9dfc8748b9c9c890bedc551 Mon Sep 17 00:00:00 2001
From: "renater.salaun" <renater.salaun@047e039d-479c-447e-8a29-aa6bf4a09bab>
Date: Tue, 16 Dec 2014 08:49:39 +0000
Subject: [PATCH] Add code to store SP informations in DB Then ensuring token
 creation request deals a known contact for that SP

git-svn-id: https://svn.geant.net/GEANT/edugain_testidp_account_manager/trunk@76 047e039d-479c-447e-8a29-aa6bf4a09bab
---
 bin/account-manager-client.pl            | 45 ++++++++++++++-
 bin/account-manager-web.pl               | 70 ++++++++++++++++++++++++
 conf/create-manager-db.sql               |  6 +-
 lib/IdPAccountManager/ServiceProvider.pm | 34 +++++++++++-
 templates/web/select_sp.tt2.html         | 22 ++------
 5 files changed, 154 insertions(+), 23 deletions(-)

diff --git a/bin/account-manager-client.pl b/bin/account-manager-client.pl
index cca7229..483e8d0 100755
--- a/bin/account-manager-client.pl
+++ b/bin/account-manager-client.pl
@@ -19,7 +19,7 @@ use IdPAccountManager::AuthenticationToken;
 my %options;
 unless (&GetOptions(\%options, 'help', 'add_test_account', 'account_profile=s', 'sp_entityid=s', 'list_test_accounts', 'parse_federation_metadata',
                     'list_service_providers','list_authentication_tokens', 'get_authentication_token', 'add_authentication_token','email_address=s',
-                    'token=s','send_notice','filter_expired','delete')) {
+                    'token=s','send_notice','filter_expired','delete','add_service_provider','contacts=s','displayname=s')) {
     die "Unknown options.";
 }
 
@@ -107,7 +107,42 @@ if ($options{'add_test_account'}) {
     printf "Hashref representing the metadata:\n";
     &IdPAccountManager::Tools::dump_var($federation_metadata->{'federation_metadata_as_hashref'}, 0, \*STDOUT);
     
-}elsif ($options{'list_service_providers'}) {
+}elsif ($options{'add_service_provider'}) {
+    
+    unless ($options{'sp_entityid'}) {
+        die "Missing sp_entityid option";
+    }
+
+    unless ($options{'contacts'}) {
+        die "Missing contacts option";
+    }
+    
+    ## Check if entry already exists in DB first
+    my $service_provider = new IdPAccountManager::ServiceProvider(entityid => $options{'sp_entityid'});
+    if ($service_provider->load(speculative => 1)) {
+        printf "Entry for %s already in DB; update it with new data\n", $options{'sp_entityid'};
+        
+        $service_provider->contacts($options{'contacts'});
+        $service_provider->displayname($options{'displayname'}) if ($options{'displayname'});
+    }else {
+    
+        $service_provider = new IdPAccountManager::ServiceProvider(entityid => $options{'sp_entityid'},
+                                                              contacts => $options{'contacts'},
+                                                              displayname => $options{'displayname'});
+        unless (defined $service_provider) {
+             IdPAccountManager::Tools::do_log('error',"Failed to create service provider");
+             exit -1;
+        }
+    }
+    
+    unless ($service_provider->save()) {
+        IdPAccountManager::Tools::do_log('error',"Failed to create service provider");
+        exit -1;
+    }
+    
+    printf "Service Provider created:\n";
+    
+  }elsif ($options{'list_service_providers'}) {
     
     my %args;    
     
@@ -277,10 +312,14 @@ Get informations on a token.
 
 Adds a new test account.
 
-=item C<account-manager-client.pl --send_notice ----email_address=john@my.fqdn>
+=item C<account-manager-client.pl --send_notice --email_address=john@my.fqdn>
 
 Sends a mail notice to the specified email address.
 
+=item C<account-manager-client.pl --add_service_provider --sp_entityid=='https://test.federation.renater.fr/test/ressource --displayname='Test SP' --contacts=email1@dom,email2@dom>
+
+Adds a new Service provider
+
 =back
 
 =head1 AUTHOR
diff --git a/bin/account-manager-web.pl b/bin/account-manager-web.pl
index e3e0b16..1fe3951 100755
--- a/bin/account-manager-web.pl
+++ b/bin/account-manager-web.pl
@@ -280,8 +280,62 @@ sub req_select_sp {
 	&IdPAccountManager::Tools::do_log('error', "Failed to parse federation metadata : $!");
 	return undef;
    }
+    
+    ## Create a serviceprovider object to store major parameters for this SP in DB
+    my $service_provider = new IdPAccountManager::ServiceProvider(entityid => $self->{'param_in'}{'sp_entityid'});
+    
+    ## Prepare data
+    #open TMP, ">/tmp/account_manager_metadata.dump"; &IdPAccountManager::Tools::dump_var($federation_metadata->{'federation_metadata_as_hashref'}[0], 0, \*TMP); close TMP;
+    my $sp_metadata_as_hashref = $federation_metadata->{'federation_metadata_as_hashref'}[0];
+    my @contacts;
+    if (defined $sp_metadata_as_hashref->{'contacts'}) {
+        foreach my $contact (@{$sp_metadata_as_hashref->{'contacts'}}) {
+            my $email = $contact->{'EmailAddress'};
+            $email =~ s/^(mailto:)//; ## Remove 'mailto:' prefixes if any
+            push @contacts, $email;
+        }
+    }
+    my $display_name;
+    if (defined $sp_metadata_as_hashref->{'display_name'}) {
+        ## Use English version of displayName if available
+        if ($sp_metadata_as_hashref->{'display_name'}{'en'}) {
+           $display_name = $sp_metadata_as_hashref->{'display_name'}{'en'};
+        ## Else any language
+        }else {
+            foreach my $lang (keys %{$sp_metadata_as_hashref->{'display_name'}}) {
+                #&IdPAccountManager::Tools::do_log('TRACE', "Display name(%s): %s", $lang, $sp_metadata_as_hashref->{'display_name'}{$lang});
+                $display_name = $sp_metadata_as_hashref->{'display_name'}{$lang};
+                last;
+            }
+        }
+    }
+
+    ## Try loading DB object first
+    if ($service_provider->load(speculative => 1)) {
+        $service_provider->contacts(join(',', @contacts));
+        $service_provider->displayname($display_name);
+                                    
+    }else {
+    
+        $service_provider = new IdPAccountManager::ServiceProvider(entityid => $self->{'param_in'}{'sp_entityid'},
+                                                                contacts => join(',', @contacts),
+                                                                displayname => $display_name);
+        unless (defined $service_provider) {
+            push @{$self->{'param_out'}{'errors'}}, "internal";
+            &IdPAccountManager::Tools::do_log('error', "Failed to create serviceprovider object");
+            return undef;
+        }
+    }
+    
+    unless ($service_provider->save()) {
+        push @{$self->{'param_out'}{'errors'}}, "internal";
+        &IdPAccountManager::Tools::do_log('error', "Failed to save serviceprovider object");
+        return undef;
+    }
+
 
    $self->{'param_out'}{'sp_metadata_as_hashref'} = $federation_metadata->{'federation_metadata_as_hashref'}[0];
+   $self->{'param_out'}{'serviceprovider'} = $service_provider;
 
     
     return 1;
@@ -305,6 +359,22 @@ sub req_generate_token {
 	return undef;
     }
 
+    ## Create a serviceprovider object to load parameters for this SP from DB
+    my $service_provider = new IdPAccountManager::ServiceProvider(entityid => $self->{'param_in'}{'sp_entityid'});
+    # Try loading DB object first
+    unless ($service_provider->load(speculative => 1)) {
+        push @{$self->{'param_out'}{'errors'}}, "internal";
+	&IdPAccountManager::Tools::do_log('error', "Failed to load SP with entityid '%s'", $self->{'param_in'}{'sp_entityid'});
+	return undef;
+    }
+    
+    ## Check that email_address is a known contact for this SP
+    unless ($service_provider->is_contact($self->{'param_in'}{'email_address'})) {
+        push @{$self->{'param_out'}{'errors'}}, "internal";
+	&IdPAccountManager::Tools::do_log('error', "Requested a token for %s for an unautorized address '%s'", $self->{'param_in'}{'sp_entityid'}, $self->{'param_in'}{'email_address'});
+	return undef;        
+    }
+    
     my $authentication_token = new IdPAccountManager::AuthenticationToken();
     unless (defined $authentication_token) {
  	push @{$self->{'param_out'}{'errors'}}, "internal";
diff --git a/conf/create-manager-db.sql b/conf/create-manager-db.sql
index f6d69be..a93c0a8 100644
--- a/conf/create-manager-db.sql
+++ b/conf/create-manager-db.sql
@@ -21,8 +21,10 @@ CREATE TABLE `serviceproviders` (
   `id` bigint(20) NOT NULL AUTO_INCREMENT,
   `entityid` varchar(200) NOT NULL,
   `displayname` varchar(500) DEFAULT NULL,
-  PRIMARY KEY (`id`)
-) ENGINE=MyISAM  DEFAULT CHARSET=utf8;
+  `contacts` varchar(2000) DEFAULT NULL,
+  PRIMARY KEY (`id`),
+  UNIQUE KEY `entityid` (`entityid`)
+) ENGINE=MyISAM  DEFAULT CHARSET=utf8 AUTO_INCREMENT=4 ;
 
 CREATE TABLE `testaccounts` (
   `id` bigint(20) NOT NULL AUTO_INCREMENT,
diff --git a/lib/IdPAccountManager/ServiceProvider.pm b/lib/IdPAccountManager/ServiceProvider.pm
index d744746..c038874 100644
--- a/lib/IdPAccountManager/ServiceProvider.pm
+++ b/lib/IdPAccountManager/ServiceProvider.pm
@@ -27,11 +27,40 @@ sub print {
     my $fd = shift || \*STDOUT;
     
     printf $fd "ServiceProvider ID=%s; entityid=%s; displayname=%s; contacts=%s\n",
-            $self->get('id'), $self->get('entityid'), $self->get('displayname'), $self->get('contacts');
+            $self->id, $self->entityid, $self->displayname, $self->contacts;
 
     return 1.
 }
 
+## list contacts for this SP, including those listed in conf.dev_sp_contact
+sub list_contacts_as_array {
+    my $self = shift;
+    
+    my @contact_list;
+    
+    foreach my $contact_email (split /,/, $self->contacts()) {
+        push @contact_list, $contact_email;
+    }
+    
+   foreach my $contact_email (split /,/, $Conf::global{'dev_sp_contact'}) {
+        push @contact_list, $contact_email;
+    } 
+    
+    return @contact_list;
+}
+
+## Check if email address is a known contact (or conf.dev_sp_contact)
+sub is_contact {
+    my $self = shift;
+    my $email = shift;
+    
+    foreach my $known_contact ($self->list_contacts_as_array()) {
+        return 1 if (lc($email) eq lc($known_contact));
+    }
+    
+    return 0;
+}
+
 ## list all test accounts
 ## Class method
 sub list_service_providers {
@@ -40,7 +69,8 @@ sub list_service_providers {
     my $persistent_accounts= IdPAccountManager::Data::Serviceprovider::Manager->get_serviceproviders(%args);
     my $service_providers;
     foreach my $persistent_sp (@{$persistent_accounts}) {
-        my $service_provider = new IdPAccountManager::ServiceProvider($persistent_sp);
+        my $service_provider = new IdPAccountManager::ServiceProvider(entityid => $persistent_sp->entityid());
+        $service_provider->load();
         push @$service_providers, $service_provider;
     }
     
diff --git a/templates/web/select_sp.tt2.html b/templates/web/select_sp.tt2.html
index 4631668..0d17803 100644
--- a/templates/web/select_sp.tt2.html
+++ b/templates/web/select_sp.tt2.html
@@ -1,6 +1,6 @@
 <h3>Send email challenge</h3>
-[% IF sp_metadata_as_hashref.display_name && sp_metadata_as_hashref.display_name.en %]
-[% SET sp_display_name = sp_metadata_as_hashref.display_name.en %]
+[% IF serviceprovider.displayname %]
+[% SET sp_display_name = serviceprovider.displayname %]
 [% ELSE %]
 [% SET sp_display_name = sp_metadata_as_hashref.entityid %]
 [% END %]
@@ -8,24 +8,15 @@
 Before you can create test accounts at this Identity Provider, we need to ensure you are a legitimate administrator of "[% sp_display_name %]".
 </div>
 
-<fieldset>
+<fieldset class="scrollable">
 [% IF  sp_metadata_as_hashref.contacts.defined %]
     <legend>Select your email address</legend>
    <label for="sp_entityid">The email addresses below have been extracted from your SP SAML metadata.<br/>Please select the email address where an email challenge
    can be sent to validate your identity</label>
 
 
-[% FOREACH contact IN sp_metadata_as_hashref.contacts -%]
- [% matches = contact.EmailAddress.match('^(mailto:)?(.*)$') %]
- [% contacts.${matches.1} = 1 %]
-[% END %]
-
-[% FOREACH email IN conf.dev_sp_contact.split(',') %]
-[% contacts.${email} = 1 %]
-[% END %]
-
 <div class="radio_inline">
-[% FOREACH email IN contacts.keys.sort %]
+[% FOREACH email IN serviceprovider.list_contacts_as_array.sort %]
 <input name="email_address" value="[% email %]" type="radio" class="required"/><label for="email_address">[% email %]</label><br/>
 
 <input type="hidden" name="sp_entityid" value="[% sp_metadata_as_hashref.entityid %]" id="sp_entityid"/>
@@ -34,9 +25,8 @@ Before you can create test accounts at this Identity Provider, we need to ensure
 </div>
 
 [% ELSE %]
-<div class="alert-box warning radius">No ContactPerson elements could be found in your SP SAML metadata. Therefore we are unable to provide test accounts for your SP. Please contact your local federation
+No ContactPerson elements could be found in your SP SAML metadata. Therefore we are unable to provide test accounts for your SP. Please contact your local federation
 administrator to add ContactPerson information to the SAML metadata.
-</div>
 [% END %]
 
 </fieldset>
@@ -48,4 +38,4 @@ administrator to add ContactPerson information to the SAML metadata.
           input.val([input.attr('value')]);
        });
     });
-</script>
+</script>
\ No newline at end of file
-- 
GitLab