From d58fcee103431cd355b71828f6abca15205db268 Mon Sep 17 00:00:00 2001
From: Guillaume Rousse <guillaume.rousse@renater.fr>
Date: Fri, 3 Nov 2017 11:02:55 +0100
Subject: [PATCH] use a plain text file for configuration

---
 bin/account-manager-client.pl          |  41 +++++----
 bin/account-manager-web.pl             |  11 ++-
 conf/Conf.pm                           | 113 -------------------------
 conf/IdPAccountManager.conf            |  77 +++++++++++++++++
 lib/IdPAccountManager/Configuration.pm |  33 ++++++++
 lib/IdPAccountManager/WebRequest.pm    |  58 ++++++-------
 6 files changed, 170 insertions(+), 163 deletions(-)
 delete mode 100644 conf/Conf.pm
 create mode 100644 conf/IdPAccountManager.conf
 create mode 100644 lib/IdPAccountManager/Configuration.pm

diff --git a/bin/account-manager-client.pl b/bin/account-manager-client.pl
index 2ae8709..2be941c 100755
--- a/bin/account-manager-client.pl
+++ b/bin/account-manager-client.pl
@@ -25,6 +25,7 @@ use IdPAccountManager::Data::TestAccount::Manager;
 use IdPAccountManager::Data::ServiceProvider;
 use IdPAccountManager::Data::ServiceProvider::Manager;
 use IdPAccountManager::SAMLMetadata;
+use IdPAccountManager::Configuration;
 use IdPAccountManager::Logger;
 
 my %options;
@@ -50,12 +51,16 @@ pod2usage(
     -verbose => 0
 ) unless $action;
 
+my $configuration = IdPAccountManager::Configuration->new(
+    file => 'conf/IdPAccountManager.conf'
+);
+
 IdPAccountManager::DB->register_db(
-    driver          => $Conf::global{database_type},
-    database        => $Conf::global{database_name},
-    host            => $Conf::global{database_host},
-    password        => $Conf::global{database_password},
-    username        => $Conf::global{database_user}
+    driver   => $configuration->{database_type},
+    database => $configuration->{database_name},
+    host     => $configuration->{database_host},
+    password => $configuration->{database_password},
+    username => $configuration->{database_user}
 );
 
 my $db = IdPAccountManager::DB->new();
@@ -100,7 +105,7 @@ sub add_test_account {
 
     die "Failed to save test account\n"
         unless $test_account->save(
-            accounts_validity_period => $Conf::global{'accounts_validity_period'}
+            accounts_validity_period => $configuration->{'accounts_validity_period'}
         );
 
     printf "Account created:\n\tuserid: user%d\n\tpassword: %s\n",
@@ -142,8 +147,8 @@ sub list_test_accounts {
 
         die "failed to update simpleSAMLphp configuration file\n"
             unless IdPAccountManager::Tools::update_ssp_authsources(
-                $Conf::global{'root_manager_dir'},
-                \%Conf::global
+                $configuration->{'root_manager_dir'},
+                $configuration
             );
 
         printf "Update simpleSamlPhp configuration file...\n";
@@ -157,7 +162,7 @@ sub parse_federation_metadata {
     die "unable to load federation metadata\n"
         unless $federation_metadata->load(
             federation_metadata_file_path =>
-              $Conf::global{'federation_metadata_file_path'}
+              $configuration->{'federation_metadata_file_path'}
         );
 
     my %args;
@@ -169,7 +174,7 @@ sub parse_federation_metadata {
         unless $federation_metadata->parse(%args);
 
     printf "Document %s parsed\n",
-      $Conf::global{'federation_metadata_file_path'};
+      $configuration->{'federation_metadata_file_path'};
 
     ## List SAML entities
     printf "Hashref representing the metadata:\n";
@@ -249,7 +254,7 @@ sub list_authentication_tokens {
     }
     if ($options{'filter_expired'}) {
         push @{ $args{'query'} }, 'creation_date' =>
-          { lt => time - ($Conf::global{'tokens_validity_period'} * 3600) };
+          { lt => time - ($configuration->{'tokens_validity_period'} * 3600) };
     }
 
     my $tokens =
@@ -346,8 +351,8 @@ sub send_notice {
     ) unless $options{'email_address'};
 
     my $logger = IdPAccountManager::Logger->new(
-        file      => $Conf::global{'log_file'},
-        verbosity => $Conf::global{'log_level'}
+        file      => $configuration->{'log_file'},
+        verbosity => $configuration->{'log_level'}
     );
 
     die "Failed to send mail notice to $options{'email_address'}\n"
@@ -356,11 +361,11 @@ sub send_notice {
             'data'                => {},
             'to'                  => $options{'email_address'},
             'logger'              => $logger,
-            'conf'                => \%Conf::global,
-            'admin_email'         => $Conf::global{'admin_email'},
-            'dev_no_mail_outside' => $Conf::global{'dev_no_mail_outside'},
-            'dev_sp_contact'      => $Conf::global{'dev_sp_contact'},
-            'notice_from'         => $Conf::global{'notice_from'}
+            'conf'                => $configuration,
+            'admin_email'         => $configuration->{'admin_email'},
+            'dev_no_mail_outside' => $configuration->{'dev_no_mail_outside'},
+            'dev_sp_contact'      => $configuration->{'dev_sp_contact'},
+            'notice_from'         => $configuration->{'notice_from'}
         );
 
     printf "Mail notice sent to $options{'email_address'}\n";
diff --git a/bin/account-manager-web.pl b/bin/account-manager-web.pl
index 3729cf9..631c80a 100755
--- a/bin/account-manager-web.pl
+++ b/bin/account-manager-web.pl
@@ -18,9 +18,9 @@ use CGI::Util;
 use Template;
 use Template::Constants qw( :debug );
 
-use Conf;
 use IdPAccountManager::SAMLMetadata;
 
+use IdPAccountManager::Configuration;
 use IdPAccountManager::WebRequest;
 
 ## Defining parameters format
@@ -48,9 +48,14 @@ umask 0002;
 
 chdir $Conf::global{'root_manager_dir'};
 
+my $configuration = IdPAccountManager::Configuration->new(
+    file => 'conf/IdPAccountManager.conf'
+);
+
 my $request = new IdPAccountManager::WebRequest(
-    actions => \%actions,
-    format  => \%format
+    actions       => \%actions,
+    format        => \%format,
+    configuration => $configuration
 );
 
 if (defined $request) {
diff --git a/conf/Conf.pm b/conf/Conf.pm
deleted file mode 100644
index 18ae1e0..0000000
--- a/conf/Conf.pm
+++ /dev/null
@@ -1,113 +0,0 @@
-package Conf;
-
-our %global = (
-
-    ## Code version
-    'version' => 'open Beta 1',
-
-    ## Name of the application used in web pages, mail notices
-    'app_name' => 'eduGAIN Access Check',
-
-    ## URL of the application
-    'app_url' => 'https://my.fqdn/accountmanager',
-
-    ## Validity period of test accounts, in days
-    'accounts_validity_period' => 7,
-
-    ## Token validity period, in hours
-    'tokens_validity_period' => 2,
-
-    ## Scope used by the associated IdP
-    'idp_scope' => 'my.fqdn',
-
-    ## EntityID of the IdP
-    'idp_entityid' => 'https://my.fqdn/simplesaml/saml2/idp/metadata.php',
-
-    ## Name of the IdP
-    'idp_displayname' => 'eduGAIN Access Check',
-
-    ## Root simpleSamlPhp directory
-    'root_ssp_dir' => '/opt/testidp/simplesamlphp',
-
-    ## Root test account manager directory
-    'root_manager_dir' => '/opt/testidp/IdPAccountManager',
-
-    ## Database type refers to a Perl Database Driver name
-    ## However only a subset of existing DBDs are supported by Rose::DB::Object:
-    ## Pg, mysql, SQLite, Informix, Oracle (DBD names are case sensitives)
-    'database_type' => 'mysql',
-
-    ## Database hostname
-    'database_host' => 'localhost',
-
-    ## Database_name
-    'database_name' => 'idp_account_manager',
-
-    ## Database username
-    'database_user' => 'root',
-
-    ## Database user password
-    'database_password' => 'root',
-
-    ## Log file for the manager
-    'log_file' => '/opt/testidp/IdPAccountManager/log/manager.log',
-
-    ## Log level : debug, info, trace, notice, error
-    'log_level' => 'info',
-
-    ## email address to contact admins
-    'admin_email' => 'john@my.fqdn',
-
-    ## email address to ask for support
-    'support_email' => 'support@my.fqdn',
-
-    ## Development feature
-    ## Protection to prevent notifications during test dev phases
-    ## Notify only admin_email above
-    'dev_no_mail_outside' => 1,
-
-    ## Development feature
-    ## hard-coded list of contactPersons
-    ## these email addresses will be added to the list of contacts for any SP
-    'dev_sp_contact' => 'john@my.fqdn,sarah@my.fqdn',
-
-    ## From field use by the account manager
-    'notice_from' => 'edugain-access-check.fqdn',
-
-    ## federation metadata local copy path
-    'federation_metadata_file_path' =>
-      '/opt/testidp/IdPAccountManager/conf/edugain-md.xml',
-
-    ## Valid account profiles
-    'account_profiles' => [
-        'fullset1',       'limitedset1', 'generic1', 'student1',
-        'student2',       'teacher1',    'teacher2', 'alumni1',
-        'librarywalkin1', 'employee1',   'researcher1'
-    ],
-);
-
-1;    # Magic true value required at end of module
-__END__
-
-=head1 NAME
-
-Conf - Configuration of the Test Account manager
-
-=head1 SYNOPSIS
-
-use Conf;
-
-printf "Version: %s\n", $Conf::global{'version'};
-
-=head1 DESCRIPTION
-
-The Test Account manager instanciates test accounts associated to a SAML Identity Provider. This module is the main configuration file for the
-software.
-
-=head1 CONFIGURATION OPTIONS
-
-See the code for the list of supported configuration options
-
-=head1 AUTHOR
-
-Olivier Salaün (olivier.salaun@renater.fr)
diff --git a/conf/IdPAccountManager.conf b/conf/IdPAccountManager.conf
new file mode 100644
index 0000000..8ed6bb6
--- /dev/null
+++ b/conf/IdPAccountManager.conf
@@ -0,0 +1,77 @@
+# Code version
+version = open Beta 1
+
+# Name of the application used in web pages, mail notices
+app_name = eduGAIN Access Check
+
+# URL of the application
+app_url = https://my.fqdn/accountmanager
+
+# Validity period of test accounts, in days
+accounts_validity_period = 7
+
+# Token validity period, in hours
+tokens_validity_period = 2
+
+# Scope used by the associated IdP
+idp_scope = my.fqdn
+
+# EntityID of the IdP
+idp_entityid = https://my.fqdn/simplesaml/saml2/idp/metadata.php
+
+# Name of the IdP
+idp_displayname = eduGAIN Access Check
+
+# Root simpleSamlPhp directory
+root_ssp_dir = /opt/testidp/simplesamlphp
+
+# Root test account manager directory
+root_manager_dir = /opt/testidp/IdPAccountManager
+
+# Database type refers to a Perl Database Driver name
+# However only a subset of existing DBDs are supported by Rose::DB::Object:
+# Pg, mysql, SQLite, Informix, Oracle (DBD names are case sensitives)
+database_type = mysql
+
+# Database hostname
+database_host = localhost
+
+# Database_name
+database_name = idp_account_manager
+
+# Database username
+database_user = idpadmin
+
+# Database user password
+database_password = secret
+
+# Log file for the manager
+log_file = /opt/testidp/IdPAccountManager/log/manager.log
+
+# Log level : debug, info, trace, notice, error
+log_level = info
+
+# email address to contact admins
+admin_email = john@my.fqdn
+
+# email address to ask for support
+support_email = support@my.fqdn
+
+# Development feature
+# Protection to prevent notifications during test dev phases
+# Notify only admin_email above
+dev_no_mail_outside = 1
+
+# Development feature
+# hard-coded list of contactPersons
+# these email addresses will be added to the list of contacts for any SP
+dev_sp_contact = john@my.fqdn, sarah@my.fqdn
+
+# From field use by the account manager
+notice_from = edugain-access-check.fqdn
+
+# federation metadata local copy path
+federation_metadata_file_path = /opt/testidp/IdPAccountManager/conf/edugain-md.xml
+
+# Valid account profiles
+account_profiles = fullset1, limitedset1, generic1, student1, student2, teacher1, teacher2, alumni1, librarywalkin1, employee1, researcher1
diff --git a/lib/IdPAccountManager/Configuration.pm b/lib/IdPAccountManager/Configuration.pm
new file mode 100644
index 0000000..0e956b2
--- /dev/null
+++ b/lib/IdPAccountManager/Configuration.pm
@@ -0,0 +1,33 @@
+package IdPAccountManager::Configuration;
+
+use strict;
+use warnings;
+
+use English qw(-no_match_vars);
+
+sub new {
+    my ($pkg) = shift;
+    my %args = @_;
+
+    die "missing argument 'file'" unless $args{file};
+    die "non-existing file $args{file}" unless -f $args{file};
+    die "non-readable file $args{file}" unless -r $args{file};
+
+    my $self = {};
+    my $handle;
+    open($handle, '<', $args{file}) or die "Failed to open $args{file}: $ERRNO";
+
+    while (my $line = <$handle>) {
+        next unless $line =~ /^(\S+)\s*=\s*(.+)$/;
+        my $key = $1;
+        my $val = $2;
+        $self->{$1} = $2;
+    }
+    close $handle;
+
+    bless $self, $pkg;
+
+    return $self;
+}
+
+1;
diff --git a/lib/IdPAccountManager/WebRequest.pm b/lib/IdPAccountManager/WebRequest.pm
index e1c5bf1..943b9a4 100755
--- a/lib/IdPAccountManager/WebRequest.pm
+++ b/lib/IdPAccountManager/WebRequest.pm
@@ -8,20 +8,20 @@ use IdPAccountManager::Logger;
 use IdPAccountManager::Data::TestAccount;
 use IdPAccountManager::Data::AuthenticationToken;
 use IdPAccountManager::Data::ServiceProvider;
-use Conf;
 
 ## New web request
 sub new {
     my ($pkg, %args) = @_;
 
     my $self = {
-        format  => $args{format},
-        actions => $args{actions},
+        format        => $args{format},
+        actions       => $args{actions},
+        configuration => $args{configuration},
     };
 
     $self->{logger} = IdPAccountManager::Logger->new(
-        file      => $Conf::global{'log_file'},
-        verbosity => $Conf::global{'log_level'}
+        file      => $self->{configuration}->{'log_file'},
+        verbosity => $self->{configuration}->{'log_level'}
     );
     $self->{logger}->log(
         level   => LOG_INFO,
@@ -29,11 +29,11 @@ sub new {
     );
 
     IdPAccountManager::DB->register_db(
-        driver          => $Conf::global{database_type},
-        database        => $Conf::global{database_name},
-        host            => $Conf::global{database_host},
-        password        => $Conf::global{database_password},
-        username        => $Conf::global{database_user}
+        driver          => $self->{configuration}->{database_type},
+        database        => $self->{configuration}->{database_name},
+        host            => $self->{configuration}->{database_host},
+        password        => $self->{configuration}->{database_password},
+        username        => $self->{configuration}->{database_user}
     );
 
     $self->{db} = IdPAccountManager::DB->new();
@@ -56,7 +56,7 @@ sub new {
     $self->{'param_out'}{'url_cgi'} = $ENV{'SCRIPT_NAME'};
     $self->{'param_out'}{'env'}     = \%ENV;
     $self->{'param_out'}{'actions'} = $args{actions};
-    $self->{'param_out'}{'conf'}    = \%Conf::global;
+    $self->{'param_out'}{'conf'}    = $self->{configuration};
 
     ## Clean input vars
     foreach my $key (keys %{ $self->{'param_in'} }) {
@@ -169,8 +169,8 @@ sub respond {
                     'escape_quotes' =>
                       [ \&IdPAccountManager::Tools::escape_quotes, 0 ]
                 },
-                INCLUDE_PATH => $Conf::global{'root_manager_dir'} . ':'
-                  . $Conf::global{'root_manager_dir'}
+                INCLUDE_PATH => $self->{configuration}->{'root_manager_dir'} . ':'
+                  . $self->{configuration}->{'root_manager_dir'}
                   . '/templates/accountProfiles',
 
                 #DEBUG => 'all',
@@ -209,14 +209,14 @@ sub respond {
     if (@errors_admin) {
         $self->{'param_out'}{'subject'} = 'Error notification - web interface';
         IdPAccountManager::Tools::mail_notice(
-            'template'    => 'templates/mail/notification_generic_error.tt2.eml',
-            'data'        => $self->{'param_out'},
-            'logger'      => $self->{'logger'},
-            'conf'                => \%Conf::global,
-            'admin_email'         => $Conf::global{'admin_email'},
-            'dev_no_mail_outside' => $Conf::global{'dev_no_mail_outside'},
-            'dev_sp_contact'      => $Conf::global{'dev_sp_contact'},
-            'notice_from'         => $Conf::global{'notice_from'}
+            'template'            => 'templates/mail/notification_generic_error.tt2.eml',
+            'data'                => $self->{'param_out'},
+            'logger'              => $self->{'logger'},
+            'conf'                => $self->{configuration},
+            'admin_email'         => $self->{configuration}->{'admin_email'},
+            'dev_no_mail_outside' => $self->{configuration}->{'dev_no_mail_outside'},
+            'dev_sp_contact'      => $self->{configuration}->{'dev_sp_contact'},
+            'notice_from'         => $self->{configuration}->{'notice_from'}
         );
     }
 }
@@ -233,7 +233,7 @@ sub req_account_wizard {
     unless (
         $federation_metadata->load(
             federation_metadata_file_path =>
-              $Conf::global{'federation_metadata_file_path'}
+              $self->{configuration}->{'federation_metadata_file_path'}
         )
       )
     {
@@ -280,7 +280,7 @@ sub req_select_sp {
     unless (
         $federation_metadata->load(
             federation_metadata_file_path =>
-              $Conf::global{'federation_metadata_file_path'}
+              $self->{configuration}->{'federation_metadata_file_path'}
         )
       )
     {
@@ -310,7 +310,7 @@ sub req_select_sp {
     my $service_provider = IdPAccountManager::Data::ServiceProvider->new(
         db             => $self->{db},
         entityid       => $self->{'param_in'}{'sp_entityid'},
-        dev_sp_contact => $Conf::global{'dev_sp_contact'}
+        dev_sp_contact => $self->{configuration}->{'dev_sp_contact'}
     );
 
     ## Prepare data
@@ -353,7 +353,7 @@ sub req_select_sp {
             entityid       => $self->{'param_in'}{'sp_entityid'},
             contacts       => join(',', @contacts),
             displayname    => $display_name,
-            dev_sp_contact => $Conf::global{'dev_sp_contact'}
+            dev_sp_contact => $self->{configuration}->{'dev_sp_contact'}
         );
         unless (defined $service_provider) {
             push @{ $self->{'param_out'}{'errors'} }, "internal";
@@ -407,7 +407,7 @@ sub req_generate_token {
     my $service_provider = IdPAccountManager::Data::ServiceProvider->new(
         db             => $self->{db},
         entityid       => $self->{'param_in'}{'sp_entityid'},
-        dev_sp_contact => $Conf::global{'dev_sp_contact'}
+        dev_sp_contact => $self->{configuration}->{'dev_sp_contact'}
     );
 
     # Try loading DB object first
@@ -579,7 +579,7 @@ sub req_validate_token {
     ## create test accounts
     my @test_accounts;
 
-    foreach my $profile ($Conf::global{'account_profiles'}) {
+    foreach my $profile ($self->{configuration}->{'account_profiles'}) {
         my $test_account = IdPAccountManager::Data::TestAccount->new(
             db              => $self->{db},
             account_profile => $profile,
@@ -602,8 +602,8 @@ sub req_validate_token {
 
     ## Update simpleSAMLphp configuration to enable test accounts
     unless (IdPAccountManager::Tools::update_ssp_authsources(
-            $Conf::global{'root_manager_dir'},
-            \%Conf::global
+            $self->{configuration}->{'root_manager_dir'},
+            $self->{configuration}
         )) {
         push @{ $self->{'param_out'}{'errors'} }, "accounts_creation_failed";
         $self->{logger}->log(
-- 
GitLab