From 5d8bbd194b57c9a2f9aa860899b5c0a767345ad3 Mon Sep 17 00:00:00 2001
From: Guillaume Rousse <guillaume.rousse@renater.fr>
Date: Fri, 24 Nov 2017 17:31:21 +0100
Subject: [PATCH] let the caller compute relevant data

---
 bin/account-manager.pl.in                    | 23 ++++++++++--------
 lib/IdPAccountManager/AuthenticationToken.pm | 24 -------------------
 lib/IdPAccountManager/Tools.pm               | 10 ++++++++
 lib/IdPAccountManager/WebRequest.pm          | 25 +++++++++++---------
 4 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/bin/account-manager.pl.in b/bin/account-manager.pl.in
index 4356bf1..3a1bd57 100755
--- a/bin/account-manager.pl.in
+++ b/bin/account-manager.pl.in
@@ -311,23 +311,26 @@ sub add_token {
         -verbose => 0
     ) unless $options{sp_entityid};
 
-    my $token = IdPAccountManager::AuthenticationToken->new(
+    # delete any previous token for the same email/service couple
+    my $old_token = IdPAccountManager::AuthenticationToken->new(
         db            => $db,
         email_address => $options{email_address},
         sp_entityid   => $options{sp_entityid}
     );
 
-    ## First remove token if on exist for this email+SP
-    if ($token->load(speculative => 1)) {
-        $token->delete() or die "failed to delete authentication token\n";
-
-        $token = IdPAccountManager::AuthenticationToken->new(
-            db            => $db,
-            email_address => $options{email_address},
-            sp_entityid   => $options{sp_entityid}
-        );
+    if ($old_token->load(speculative => 1)) {
+        $old_token->delete() or die "failed to delete authentication token\n";
     }
 
+    # compute a new token
+    my $token = IdPAccountManager::AuthenticationToken->new(
+        db            => $db,
+        email_address => $options{email_address},
+        sp_entityid   => $options{sp_entityid},
+        creation_date => DateTime->today(),
+        token         => IdPAccountManager::Tools::generate_token()
+    );
+
     $token->save() or die "failed to save authentication token\n";
 
     $token->print();
diff --git a/lib/IdPAccountManager/AuthenticationToken.pm b/lib/IdPAccountManager/AuthenticationToken.pm
index cbc3315..85292f6 100644
--- a/lib/IdPAccountManager/AuthenticationToken.pm
+++ b/lib/IdPAccountManager/AuthenticationToken.pm
@@ -5,9 +5,6 @@ use warnings;
 
 use base 'IdPAccountManager::DB::Object';
 
-use Digest::MD5;
-use DateTime;
-
 __PACKAGE__->meta->setup(
     table   => 'authenticationtokens',
 
@@ -38,25 +35,4 @@ sub print {
       $self->creation_date()->strftime('%Y:%m:%d');
 }
 
-sub save {
-    my ($self) = @_;
-
-    # If no ID is defined, it is a new account
-    if (! defined $self->id()) {
-        $self->creation_date(DateTime->today());
-        $self->token(_generate_token($self->email_address()));
-    }
-
-    $self->SUPER::save();
-}
-
-sub _generate_token {
-    my ($salt, $size) = @_;
-    $size = 20 unless $size;
-
-    # ID is based on time + PID
-    return substr(Digest::MD5::md5_hex(time . $$ . $salt), -1 * $size);
-}
-
 1;
-
diff --git a/lib/IdPAccountManager/Tools.pm b/lib/IdPAccountManager/Tools.pm
index 9587f6e..bf3c930 100644
--- a/lib/IdPAccountManager/Tools.pm
+++ b/lib/IdPAccountManager/Tools.pm
@@ -4,7 +4,9 @@ use strict;
 use warnings;
 
 use Digest::SHA;
+use Digest::MD5;
 use Encode;
+use English qw(-no_match_vars);
 use Template;
 
 # get SHA256 hash for a string
@@ -61,6 +63,14 @@ sub generate_password {
     return $rndstring;
 }
 
+# ID is based on time + PID
+sub generate_token {
+    my ($salt, $size) = @_;
+    $size = 20 unless $size;
+
+    return substr(Digest::MD5::md5_hex(time . $PID . $salt), -1 * $size);
+}
+
 ## Updates simpleSamlPhp authsources.php configuration file
 sub update_ssp_authsources {
     my ($templates_dir, $output, $accounts) = @_;
diff --git a/lib/IdPAccountManager/WebRequest.pm b/lib/IdPAccountManager/WebRequest.pm
index 7b40270..d6c384c 100644
--- a/lib/IdPAccountManager/WebRequest.pm
+++ b/lib/IdPAccountManager/WebRequest.pm
@@ -319,30 +319,33 @@ sub req_generate_token {
         return;
     }
 
-    my $token = IdPAccountManager::AuthenticationToken->new(
+    # delete any previous token for the same email/service couple
+    my $old_token = IdPAccountManager::AuthenticationToken->new(
         db            => $self->{db},
         email_address => $self->{in}->{email_address},
         sp_entityid   => $self->{in}->{sp_entityid}
     );
 
-    ## First remove token if one exist for this email+SP
-    if ($token->load(speculative => 1)) {
-        unless ($token->delete()) {
+    if ($old_token->load(speculative => 1)) {
+        unless ($old_token->delete()) {
             push @{ $self->{out}->{errors} }, "internal";
             $self->{logger}->errorf(
                 "Failed to delete previous authentication token with ID %s",
-                $token->id()
+                $old_token->id()
             );
             return;
         }
-
-        $token = IdPAccountManager::AuthenticationToken->new(
-            db            => $self->{db},
-            email_address => $self->{in}->{email_address},
-            sp_entityid   => $self->{in}->{sp_entityid}
-        );
     }
 
+    # compute a new token
+    my $token = IdPAccountManager::AuthenticationToken->new(
+        db            => $self->{db},
+        email_address => $self->{in}->{email_address},
+        sp_entityid   => $self->{in}->{sp_entityid},
+        creation_date => DateTime->today(),
+        token         => IdPAccountManager::Tools::generate_token()
+    );
+
     unless ($token->save()) {
         push @{ $self->{out}->{errors} }, "internal";
         $self->{logger}->error("Failed to save authentication token");
-- 
GitLab