Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enable password recovery when using ILS Authentication #3997

Open
wants to merge 20 commits into
base: dev
Choose a base branch
from

Conversation

oharacj
Copy link
Contributor

@oharacj oharacj commented Oct 8, 2024

Add handling to enable password recovery when using ILS Authentication method

…tion.

Updated based on the PHP 8.3 test failures.
…tion.

Updated based on the PHP 8.3 test failures. When I ran php cbf it made changes to the if statements that caused this failure.
Copy link
Member

@demiankatz demiankatz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, @oharacj! See below for a few initial thoughts and questions.

module/VuFind/src/VuFind/Auth/ILSAuthenticator.php Outdated Show resolved Hide resolved
module/VuFind/src/VuFind/Auth/ILSAuthenticator.php Outdated Show resolved Hide resolved
@@ -2079,9 +2125,12 @@ public function newPasswordAction()
}
// Update hash to prevent reusing hash
$this->getAuthManager()->updateUserVerifyHash($user);
// Login
if ($followUp = $this->followup()->retrieve('url')) {
$newUrl = strstr($followUp, 'Verify', true) . 'Home';
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure I understand the purpose of this; maybe a comment is in order.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

added a comment. Happy to answer any other questions about this or taking ANY suggestions. Image is before this code block.

image

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, that makes sense, though I'm not sure I understand exactly what $followUpUrl = strstr($followUp, 'Verify', true) . 'Home'; is trying to do. I wonder if it might be better to do something like $followUpUrl = str_contains($followUp, 'Verify') ? $this->url()->fromRoute('home') : $followUp; (so we're using the router instead of string manipulation to pick the destination URL... but maybe I'm misunderstanding which target route is actually desired).

Copy link
Contributor

@EreMaijala EreMaijala left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should work without an existing VuFind account. My proposal would be to add another ILS driver method for looking up the patron with email address and card number. Since we already have a local implementation that works across ILS systems, our experience is that this allows recovery with any ILS that can do the lookup and update the password. See https://github.com/NatLibFi/NDL-VuFind2/blob/dev/module/Finna/src/Finna/ILS/Driver/KohaRest.php#L747 for our implementation with Koha.

The recovery token data and any other information needed (e.g. target ILS for MultiILS) from the lookup method can be stored in access_token table with a random hash as the id. This hash should be included in the recovery link in the email along.

Since this functionality is somewhat different from internal password recovery, it might make sense to separate the implementation. That's why we chose locally to use different method names etc.

*
* @return bool
*/
public function supportsPasswordRecovery()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My initial work is only supposed to be for the ILS auth. MultiILS is something I'll look at in the future but I'm not sure it's part of the scope of this work. Is this piece a necessity? If so, I can start working on this and I'll resubmit when I have it done. I only have one ILS and I can't really test but I'm happy to look into it.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You could potentially use the Demo driver as a second ILS for testing purposes, if that helps! Let me know if you need more details/help to get that set up.

{
$driver = $this->getCatalog()->getDriver();
if (
method_exists($driver, 'changePassword')
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd suggest a new method for updating the password during recovery, since changePassword requires the patron from patronLogin method. Our custom code uses this:
https://github.com/NatLibFi/NDL-VuFind2/blob/dev/module/Finna/src/Finna/ILS/Driver/KohaRest.php#L792

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've updated the code to use a resetPassword method for this. I've added my resetPassword to the SierraRest Driver.

Updated comments, line endings, follow-up edits have been put in abstractbase, explained the redirect.
added trailing comma to return array
Object-Oriented Programming is a thing.
@oharacj
Copy link
Contributor Author

oharacj commented Oct 16, 2024

This should work without an existing VuFind account. My proposal would be to add another ILS driver method for looking up the patron with email address and card number. Since we already have a local implementation that works across ILS systems, our experience is that this allows recovery with any ILS that can do the lookup and update the password. See https://github.com/NatLibFi/NDL-VuFind2/blob/dev/module/Finna/src/Finna/ILS/Driver/KohaRest.php#L747 for our implementation with Koha.

I have an ILS method called getPatronFromUsername which provides this function exactly. It has been added to the SierraRest driver.

The recovery token data and any other information needed (e.g. target ILS for MultiILS) from the lookup method can be stored in access_token table with a random hash as the id. This hash should be included in the recovery link in the email along.

Since this functionality is somewhat different from internal password recovery, it might make sense to separate the implementation. That's why we chose locally to use different method names etc.

I am partially utilising the internal password recovery methods in order to keep from duplicating functionality

Copy link
Member

@demiankatz demiankatz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the progress, @oharacj -- see below for a few more tips, questions and ideas. :-)

@@ -59,6 +59,9 @@ use_prefixed_ids = false
; used (redirect_uri above is not set).
username_field = "code"
password_field = "pin"
; Some library systems use a four digit access pin. Others prefer to have alpha numeric
; passwords. set digits_only to true for pin functionality. Default is false (alpha-num).
digits_only = true
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are higher-level password rules defined in config.ini. I wonder if it would be beneficial to make this setting more parallel with those (especially if we could refactor code to make the password validation logic reusable -- I haven't inspected to see how feasible this is, but it seems likely to be an option).

Alternatively, if there are really only two different options in Sierra, maybe it would be more clear to call this setting four_digit_pin (to account for both the length restriction and the content restriction), or to have a setting like password_mode = pin|password (if we want to allow for more possibilities in the future than a binary setting can provide.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just checking to see if you have any thoughts on this point, since there hasn't been further discussion on it since October. (Also happy to hear @EreMaijala's thoughts, if any).

Copy link
Contributor

@EreMaijala EreMaijala Dec 16, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should use the same rules as when changing a password, i.e. the [changePassword] section in ILS driver's ini:

; Uncomment the following lines to enable password (PIN) change
;[changePassword]
; PIN change parameters. The default limits are taken from the interface documentation.
;minLength = 4
;maxLength = 4
; See the password_pattern/password_hint settings in the [Authentication] section
; of config.ini for notes on these settings. When set here, these will override the
; config.ini defaults when Sierra is used for authentication.
;pattern = "numeric"
;hint = "Your optional custom hint can go here."

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm still not sure how I've managed to miss this section of the ini so many times. I had to have looked over it hundreds of times without seeing that there was a [changePassword] section. I'll remove the custom stuff I did but I'll also have to make a change to the changePassword function in the SierraRest driver in order to remove the hard-coded digits only section of password change.

*
* @return bool
*/
public function supportsPasswordRecovery()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You could potentially use the Demo driver as a second ILS for testing purposes, if that helps! Let me know if you need more details/help to get that set up.

module/VuFind/src/VuFind/ILS/Driver/SierraRest.php Outdated Show resolved Hide resolved
@@ -309,11 +309,12 @@ public function getStoredCatalogCredentials()
* fails, clear the user's stored credentials so they can enter new, corrected
* ones.
*
* Returns associative array of patron data on success, false on failure.
* @param $user_name - the username/barcode for ILS password reset
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor points of style: I'd suggest $username or $userName instead of $user_name -- we rarely use snake_case in our code, so the other options would be more consistent. Also, you don't need the "-" separator in this comment.

@@ -2079,9 +2125,12 @@ public function newPasswordAction()
}
// Update hash to prevent reusing hash
$this->getAuthManager()->updateUserVerifyHash($user);
// Login
if ($followUp = $this->followup()->retrieve('url')) {
$newUrl = strstr($followUp, 'Verify', true) . 'Home';
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, that makes sense, though I'm not sure I understand exactly what $followUpUrl = strstr($followUp, 'Verify', true) . 'Home'; is trying to do. I wonder if it might be better to do something like $followUpUrl = str_contains($followUp, 'Verify') ? $this->url()->fromRoute('home') : $followUp; (so we're using the router instead of string manipulation to pick the destination URL... but maybe I'm misunderstanding which target route is actually desired).

Copy link
Member

@demiankatz demiankatz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the ongoing work, @oharacj -- I started my review this morning but ran into some questions that I think will be resolved by merging the dev branch into this PR, so I decided to stop until that's done to be sure I'm reviewing everything in an up-to-date and working state. Please let me know if you run into any trouble with this!

@@ -59,6 +59,9 @@ use_prefixed_ids = false
; used (redirect_uri above is not set).
username_field = "code"
password_field = "pin"
; Some library systems use a four digit access pin. Others prefer to have alpha numeric
; passwords. set digits_only to true for pin functionality. Default is false (alpha-num).
digits_only = true
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just checking to see if you have any thoughts on this point, since there hasn't been further discussion on it since October. (Also happy to hear @EreMaijala's thoughts, if any).

module/VuFind/src/VuFind/Auth/ILSAuthenticator.php Outdated Show resolved Hide resolved
@oharacj oharacj requested a review from demiankatz December 30, 2024 15:43
Copy link
Member

@demiankatz demiankatz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't have time for a full review yet, but I noticed one thing that looks like a problem and had a couple of very minor style suggestions that you can apply by just committing my suggestions from within the comments below. :-)

if (!empty($method)) {
$this->getAuthManager()->setAuthMethod($method);
}
} $this->getAuthManager()->setAuthMethod($method);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There seems to be a formatting problem here -- did this brace get moved up a line somehow?

Comment on lines +2101 to +2102
//This exists because the followupURL gets set to Verify which returns
//an error message due to trying to check the hash a second time
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor style suggestion -- add spaces after //:

Suggested change
//This exists because the followupURL gets set to Verify which returns
//an error message due to trying to check the hash a second time
// This exists because the followupURL gets set to Verify which returns
// an error message due to trying to check the hash a second time

Comment on lines +26 to +28
<?php if (!empty($this->target)): ?>
<input type="hidden" value="<?=$this->escapeHtmlAttr($this->target) ?>" name="target">
<?php endif; ?>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems to have some extra indentation:

Suggested change
<?php if (!empty($this->target)): ?>
<input type="hidden" value="<?=$this->escapeHtmlAttr($this->target) ?>" name="target">
<?php endif; ?>
<?php if (!empty($this->target)): ?>
<input type="hidden" value="<?=$this->escapeHtmlAttr($this->target) ?>" name="target">
<?php endif; ?>

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants