From 0de7b5e81411b4c55e4027564506f2af7e379120 Mon Sep 17 00:00:00 2001 From: "renater.salaun" <renater.salaun@047e039d-479c-447e-8a29-aa6bf4a09bab> Date: Wed, 10 Sep 2014 07:47:22 +0000 Subject: [PATCH] Rewriting TestAccount.pm code to better articulate IdPAccountManager::Data::Testaccount objects with objects git-svn-id: https://svn.geant.net/GEANT/edugain_testidp_account_manager/trunk@6 047e039d-479c-447e-8a29-aa6bf4a09bab --- bin/account-manager-client.pl | 14 +- bin/expire-test-accounts.pl | 8 +- lib/IdPAccountManager/TestAccount.pm | 114 +++++++++----- lib/IdPAccountManager/Tools.pm | 145 ++++++++++++++++++ templates/accountProfiles/student1.tt2 | 10 +- .../accountProfiles/valid-accounts.php.tt2 | 2 +- 6 files changed, 241 insertions(+), 52 deletions(-) create mode 100644 lib/IdPAccountManager/Tools.pm diff --git a/bin/account-manager-client.pl b/bin/account-manager-client.pl index eee0ffc..845ea10 100755 --- a/bin/account-manager-client.pl +++ b/bin/account-manager-client.pl @@ -34,10 +34,16 @@ if ($options{'create_test_account'}) { my $test_account = new IdPAccountManager::TestAccount(account_profile => $options{'account_profile'}, sp_entityid => $options{'sp_entityid'}); unless (defined $test_account) { - die "Failed to create test account"; + IdPAccountManager::Tools::do_log('error',"Failed to create test account"); + exit -1; } - printf "Account created:\n\tuserid: user%d\n\tpassword: %s\n", $test_account->id, $test_account->user_password; + unless ($test_account->save()) { + IdPAccountManager::Tools::do_log('error',"Failed to create test account"); + exit -1; + } + + printf "Account created:\n\tuserid: user%d\n\tpassword: %s\n", $test_account->get('id'), $test_account->get('user_password'); }elsif ($options{'list_test_accounts'}) { @@ -54,8 +60,6 @@ if ($options{'create_test_account'}) { my $all = IdPAccountManager::TestAccount::list_test_accounts(%args); foreach my $test_account (@$all) { - printf "Account ID=%s; password=%s; sp_entityid=%s; account_profile=%s; creation_date=%s; expiration_date=%s\n", - $test_account->id, $test_account->user_password, $test_account->sp_entityid, $test_account->account_profile, - &POSIX::strftime('%Y:%m:%d', localtime($test_account->creation_date)), &POSIX::strftime('%Y:%m:%d', localtime($test_account->expiration_date)); + $test_account->print(); } } diff --git a/bin/expire-test-accounts.pl b/bin/expire-test-accounts.pl index 24ed1b7..070f7c7 100755 --- a/bin/expire-test-accounts.pl +++ b/bin/expire-test-accounts.pl @@ -26,9 +26,7 @@ if ($options {'list_only'}) { my $all = IdPAccountManager::TestAccount::list_test_accounts('query' => ['expiration_date' => {lt => time}]); foreach my $test_account (@$all) { - printf "Account ID=%s; password=%s; sp_entityid=%s; account_profile=%s; creation_date=%s; expiration_date=%s\n", - $test_account->id, $test_account->user_password, $test_account->sp_entityid, $test_account->account_profile, - &POSIX::strftime('%Y:%m:%d', localtime($test_account->creation_date)), &POSIX::strftime('%Y:%m:%d', localtime($test_account->expiration_date)); + $test_account->print(); } }else { @@ -37,9 +35,7 @@ if ($options {'list_only'}) { printf "Removing expired test accounts...\n"; foreach my $test_account (@$all) { - printf "\tAccount ID=%s; password=%s; sp_entityid=%s; account_profile=%s; creation_date=%s; expiration_date=%s\n", - $test_account->id, $test_account->user_password, $test_account->sp_entityid, $test_account->account_profile, - &POSIX::strftime('%Y:%m:%d', localtime($test_account->creation_date)), &POSIX::strftime('%Y:%m:%d', localtime($test_account->expiration_date)); + $test_account->print(); $test_account->delete || die; } printf "%d accounts removed\n", $#{$all}+1; diff --git a/lib/IdPAccountManager/TestAccount.pm b/lib/IdPAccountManager/TestAccount.pm index b55321b..da9ef0e 100644 --- a/lib/IdPAccountManager/TestAccount.pm +++ b/lib/IdPAccountManager/TestAccount.pm @@ -1,48 +1,87 @@ package IdPAccountManager::TestAccount; +use strict; + use IdPAccountManager::Data::Testaccount; use IdPAccountManager::Data::Testaccount::Manager; use IdPAccountManager::Tools; use IdPAccountManager::Conf; -use Moose; -use Moose::Util::TypeConstraints; - -subtype 'entityid', - as 'Str', - where { /^(urn:|http(s)?\:\/\/)/ }, - message { "$_ is not a valide entityid"}; - -has 'account_profile' => (is => 'rw', - isa => 'Str', - required => 1); -has 'sp_entityid' => (is => 'rw', - isa => 'entityid', - required => 1, - ); -has 'id' => (is => 'ro', - isa => 'Int', - required => 0, - ); -has 'user_password' => (is => 'ro', - isa => 'Str', - required => 0, - ); - -sub BUILD { +require Exporter; +my @ISA = qw(Exporter); +my @EXPORT = qw(); + +use Carp; + +INIT { + ## Set error mode to non fatal + IdPAccountManager::Data::Testaccount::Manager->error_mode('return'); + } + +sub new { + my ($pkg) = shift; + my %args = @_; + + my $self = {}; + + ## Bless Provider object + bless $self, $pkg; + + ## Object may be created either with a hashref as argument or an IdPAccountManager::Data::Testaccount object + ## Second case is usefull when fetching a set of IdPAccountManager::Data::Testaccount via IdPAccountManager::Data::Testaccount::Manager + if (ref($_[0]) eq 'IdPAccountManager::Data::Testaccount') { + $self->{'persistent'} = $_[0]; + }else { + $self->{'persistent'} = IdPAccountManager::Data::Testaccount->new(%args); + } + return $self; +} + +sub get { my $self = shift; - my $args = shift; + my $attribute_name = shift; - my $testaccount_db = IdPAccountManager::Data::Testaccount->new('account_profile' => $args->{'account_profile'}, - 'sp_entityid' => $args->{'sp_entityid'}, - 'user_password' => &IdPAccountManager::Tools::generate_password(), - 'creation_date' => time, - 'expiration_date' => time + ($IdPAccountManager::Conf::global{'accounts_validity_period'} * 3600 * 24)); - $testaccount_db->save(); + return $self->{'persistent'}->$attribute_name; +} + +sub save { + my $self = shift; + + ## If no id is defined, it is a new account + unless (defined $self->{'persistent'}->id) { + $self->{'persistent'}->creation_date(time); + $self->{'persistent'}->expiration_date(time + ($IdPAccountManager::Conf::global{'accounts_validity_period'} * 3600 * 24)); + $self->{'persistent'}->user_password(&IdPAccountManager::Tools::generate_password()); + } + + unless ($self->{'persistent'}->save()) { + IdPAccountManager::Tools::do_log('error', "Failed to save Test Account in DB"); + return undef; + } +} + +## Delete a test account +sub delete { + my $self = shift; - ## TODO : update IdP conf file; given the account profile + unless ($self->{'persistent'}->delete()) { + IdPAccountManager::Tools::do_log('error', "Failed to delete a test account in DB"); + return undef; + } +} + +## Print the content of a test account +sub print { + my $self = shift; + my $fd = shift || \*STDOUT; + + printf $fd "Account ID=%s; password=%s; sp_entityid=%s; account_profile=%s; creation_date=%s; expiration_date=%s\n", + $self->get('id'), $self->get('user_password'), $self->get('sp_entityid'), $self->get('account_profile'), + &POSIX::strftime('%Y:%m:%d', localtime($self->get('creation_date'))), &POSIX::strftime('%Y:%m:%d', localtime($self->get('expiration_date'))); + + return 1. } ## list all test accounts @@ -50,9 +89,14 @@ sub BUILD { sub list_test_accounts { my %args = @_; - my $all = IdPAccountManager::Data::Testaccount::Manager->get_testaccounts(%args); + my $persistent_accounts= IdPAccountManager::Data::Testaccount::Manager->get_testaccounts(%args); + my $accounts; + foreach my $persistent_account (@{$persistent_accounts}) { + my $account = new IdPAccountManager::TestAccount($persistent_account); + push @$accounts, $account; + } - return $all; + return $accounts; } #before 'new' => sub { print "about to call new\n"; }; diff --git a/lib/IdPAccountManager/Tools.pm b/lib/IdPAccountManager/Tools.pm new file mode 100644 index 0000000..e23e165 --- /dev/null +++ b/lib/IdPAccountManager/Tools.pm @@ -0,0 +1,145 @@ +package IdPAccountManager::Tools; + +use Template; + +my %log_levels = ('debug' => 0, 'info' => 1, 'trace' => 1, 'notice' => 2, 'error' => 3); + + +# This function generates a random password +sub generate_password{ + my $length_of_randomstring=10;# the length of + # the random string to generate + + # plusieurs tirages : + # 1-tirage des caractères obligatoires : les mettre dans un tableau + my @uppers=('A'..'N','P'..'Z'); + my @lowers=('a'..'k','m'..'z'); + my @punctuation=('%',';',':','!','?','&','$','*','(',')','{','}','[',']','<','>','.','=','-','#'); + my @numerics=('0'..'9'); + my @rndtab; + push(@rndtab,$uppers[rand @uppers]); + push(@rndtab,$lowers[rand @lowers]); + push(@rndtab,$punctuation[rand @punctuation]); + + ## Pas de caractères 8bit pour l'antispam + push(@rndtab,$numerics[rand @numerics]); + + # 2-tirage des caractères optionnels : les ajouter au tableau + my @chars=('a'..'k','m'..'z','A'..'N','P'..'Z','0'..'9','_','%',';',':','!','?','&','$','*','(',')','{','}','[',']','<','>','.','=','-','#'); + foreach (6..$length_of_randomstring) { + # rand @chars will generate a random + # number between 0 and scalar @chars + push(@rndtab,$chars[rand @chars]); + } + + # 3-ordonnancement de ceux-ci : les retirer aléatoirement du tableau en les concaténant dans une chaîne + my $rndstring=''; + my $cpt=1; + while($cpt<=$length_of_randomstring) { + my $indice = rand @rndtab; + $rndstring.=$rndtab[$indice]; + splice (@rndtab, $indice, 1); + $cpt+=1; + } + return $rndstring; +} + +## Updates simpleSamlPhp authsources.php configuration file +sub update_ssp_authsources { + + my $tt2 = Template->new({'INCLUDE_PATH' => $IdPAccountManager::Conf::global{'root_manager_dir'}.':'.$IdPAccountManager::Conf::global{'root_manager_dir'}.'/templates/accountProfiles'}); + my %args = ('accounts' => IdPAccountManager::TestAccount::list_test_accounts(), + 'conf' => \%IdPAccountManager::Conf::global); + + #chdir $IdPAccountManager::Conf::global{'root_manager_dir'}; + + my $template_file = 'templates/accountProfiles/valid-accounts.php.tt2'; + my $output_file = 'conf/valid-accounts.php'; + #printf "Trace : in=%s, out=%s\n", $template_file, $output_file; + unless ($tt2->process($template_file, \%args, $output_file)) { + IdPAccountManager::Tools::do_log('error', "Failed to update valid-accounts.php: %s", $tt2->error()); + return undef; + } + +} + +## Dump a variable's content +sub dump_var { + my ($var, $level, $fd) = @_; + + if (ref($var)) { + if (ref($var) eq 'ARRAY') { + foreach my $index (0..$#{$var}) { + print $fd "\t"x$level.$index."\n"; + &dump_var($var->[$index], $level+1, $fd); + } + }elsif (ref($var) eq 'HASH') { + foreach my $key (sort keys %{$var}) { + print $fd "\t"x$level.'_'.$key.'_'."\n"; + &dump_var($var->{$key}, $level+1, $fd); + } + }else { + if (defined $var) { + print $fd "\t"x$level."'$var'"."\n"; + }else { + print $fd "\t"x$level."UNDEF\n"; + } + } + }else { + if (defined $var) { + print $fd "\t"x$level."'$var'"."\n"; + }else { + print $fd "\t"x$level."UNDEF\n"; + } + } +} + +sub do_log { + my $level = shift; + my $message = shift; + + unless ($log_levels{$level} < $log_levels{$IdPAccountManager::Conf::global{'log_level'}}) { + + ## Determine calling function and parameters + ## If in 'err' level, build a stack trace + my $caller_string; + if ($level eq 'error'){ + my $go_back = 1; + my @calls; + while (my @call = caller($go_back)) { + unshift @calls, $call[3].'#'.$call[2]; + $go_back++; + } + + $caller_string = join(' > ',@calls); + }else { + my @call = caller(1); + + $caller_string = $call[3].'()'; + } + + $level = uc($level); + my $ip = $ENV{'REMOTE_HOST'}.'/'.$ENV{'REMOTE_ADDR'} || 'NOIP'; + my $date = POSIX::strftime ("%Y:%m:%d %H:%M:%S", localtime(time)); + my $user = lc($ENV{'mail'}) || 'NOEMAIL'; + open TMP, ">>".$IdPAccountManager::Conf::global{'log_file'}; printf TMP "$date - ($level) - $ip - $user - $caller_string $message\n", @_; close TMP; + } + return 1; +} + +1; # Magic true value required at end of module +__END__ + +=head1 NAME + +IdPAccountManager::Tools - Set of subroutines usefull for the Account manager + +=head1 SYNOPSIS + +=head1 DESCRIPTION + +=head1 SUBROUTINES/METHODS + +=head1 AUTHOR + +Olivier Salaün (olivier.salaun@renater.fr) diff --git a/templates/accountProfiles/student1.tt2 b/templates/accountProfiles/student1.tt2 index 64095dd..d4aba8c 100644 --- a/templates/accountProfiles/student1.tt2 +++ b/templates/accountProfiles/student1.tt2 @@ -1,13 +1,13 @@ -'user[% account.id %]:[% account.user_password %]' => array( - 'uid' => 'user[% account.id %]', +'user[% account.id %]:[% account.get('user_password') %]' => array( + 'uid' => 'user[% account.get('id') %]', 'eduPersonAffiliation' => array('member', 'student'), 'eduPersonScopedAffiliation' => array('member@[% conf.idp_scope %]', 'student@[% conf.idp_scope %]'), 'displayName' => 'John Kleinman', 'cn' => 'John Kleinman', 'mail' => 'john.kleinman@[% conf.idp_scope %]', - 'eduPersonPrincipalName' =>'[% account.id %]@[% conf.idp_scope %]', - 'eduPersonTargetedID' =>'[% conf.idp_entityid %]![% account.sp_entityid %]!X622UR2A7PG1uVhATobBOrMz+Ys=', + 'eduPersonPrincipalName' =>'[% account.get('id') %]@[% conf.idp_scope %]', + 'eduPersonTargetedID' =>'[% conf.idp_entityid %]![% account.get('sp_entityid') %]!X622UR2A7PG1uVhATobBOrMz+Ys=', 'schacHomeOrganization' => '[% conf.idp_scope %]', 'schacHomeOrganizationType' => 'urn:schac:homeOrganizationType:int:university', - 'associatedSP' => '[% account.sp_entityid %]', + 'associatedSP' => '[% account.get('sp_entityid') %]', ), diff --git a/templates/accountProfiles/valid-accounts.php.tt2 b/templates/accountProfiles/valid-accounts.php.tt2 index 2f6a363..ecb525f 100644 --- a/templates/accountProfiles/valid-accounts.php.tt2 +++ b/templates/accountProfiles/valid-accounts.php.tt2 @@ -4,6 +4,6 @@ $validTestAccounts = array ( 'exampleauth:UserPass', [% FOREACH account IN accounts %] - [% INCLUDE "${account.account_profile}.tt2" %] + [% INCLUDE "${account.get('account_profile')}.tt2" %] [% END %] ); -- GitLab