From 6f6660583891a8986c0c376432b53780561c1e0d Mon Sep 17 00:00:00 2001 From: Tomas Cohen Arazi Date: Tue, 29 Jul 2025 18:20:06 -0300 Subject: [PATCH] Bug 40545: Add has_2fa_enabled and reset_2fa methods to Koha::Patron This adds two new methods to Koha::Patron for managing two-factor authentication: * has_2fa_enabled() - Returns 1 if patron has 2FA enabled, 0 otherwise * reset_2fa() - Clears secret and sets auth_method to 'password' The reset_2fa method includes audit logging when BorrowersLog is enabled and returns the patron object for method chaining. To test: 1. Apply patch 2. Run: $ ktd --shell k$ prove t/db_dependent/Koha/Patron.t => SUCCESS: Tests pass! 3. Sign off :-D --- Koha/Patron.pm | 41 ++++++++++++++++++++++++++ t/db_dependent/Koha/Patron.t | 57 +++++++++++++++++++++++++++++++++++- 2 files changed, 97 insertions(+), 1 deletion(-) diff --git a/Koha/Patron.pm b/Koha/Patron.pm index cfa570e0f00..d7dcb0de386 100644 --- a/Koha/Patron.pm +++ b/Koha/Patron.pm @@ -1139,6 +1139,47 @@ sub set_password { return $self; } +=head3 has_2fa_enabled + +my $has_2fa = $patron->has_2fa_enabled; + +Returns 1 if the patron has two-factor authentication enabled, 0 otherwise. + +=cut + +sub has_2fa_enabled { + my ($self) = @_; + + return ( defined $self->secret && $self->secret ne '' ) ? 1 : 0; +} + +=head3 reset_2fa + +$patron->reset_2fa; + +Resets the patron's two-factor authentication settings by clearing the secret +and setting the auth_method back to 'password'. + +Returns the patron object for method chaining. + +=cut + +sub reset_2fa { + my ($self) = @_; + + $self->set( + { + secret => undef, + auth_method => 'password', + } + )->store; + + logaction( "MEMBERS", "RESET 2FA", $self->borrowernumber, "" ) + if C4::Context->preference("BorrowersLog"); + + return $self; +} + =head3 renew_account my $new_expiry_date = $patron->renew_account diff --git a/t/db_dependent/Koha/Patron.t b/t/db_dependent/Koha/Patron.t index 7cba994728a..3700c707284 100755 --- a/t/db_dependent/Koha/Patron.t +++ b/t/db_dependent/Koha/Patron.t @@ -19,7 +19,7 @@ use Modern::Perl; -use Test::More tests => 42; +use Test::More tests => 44; use Test::NoWarnings; use Test::Exception; use Test::Warn; @@ -3118,3 +3118,58 @@ subtest 'is_anonymous' => sub { $schema->storage->txn_rollback; }; + +subtest 'has_2fa_enabled() tests' => sub { + plan tests => 3; + + $schema->storage->txn_begin; + + my $patron = $builder->build_object( { class => 'Koha::Patrons' } ); + + # Test patron without 2FA + is( $patron->has_2fa_enabled, 0, 'has_2fa_enabled returns 0 when no secret is set' ); + + # Test patron with empty secret + $patron->secret('')->store; + is( $patron->has_2fa_enabled, 0, 'has_2fa_enabled returns 0 when secret is empty string' ); + + # Test patron with 2FA enabled + $patron->secret('some_secret_value')->store; + is( $patron->has_2fa_enabled, 1, 'has_2fa_enabled returns 1 when secret is set' ); + + $schema->storage->txn_rollback; +}; + +subtest 'reset_2fa() tests' => sub { + plan tests => 6; + + $schema->storage->txn_begin; + + my $patron = $builder->build_object( { class => 'Koha::Patrons' } ); + + # Set up patron with 2FA enabled + $patron->set( + { + secret => 'test_secret_123', + auth_method => 'two-factor', + } + )->store; + + # Verify 2FA is enabled + is( $patron->has_2fa_enabled, 1, '2FA is enabled before reset' ); + is( $patron->auth_method, 'two-factor', 'auth_method is two-factor before reset' ); + + # Test reset_2fa method + my $result = $patron->reset_2fa; + + # Verify method returns patron object for chaining + isa_ok( $result, 'Koha::Patron', 'reset_2fa returns Koha::Patron object' ); + is( $result->borrowernumber, $patron->borrowernumber, 'returned object is the same patron' ); + + # Verify 2FA has been reset + $patron->discard_changes; + is( $patron->has_2fa_enabled, 0, '2FA is disabled after reset' ); + is( $patron->auth_method, 'password', 'auth_method is password after reset' ); + + $schema->storage->txn_rollback; +}; -- 2.50.1