From d76a8a00220a966ac153981a052d9646c88df5ba Mon Sep 17 00:00:00 2001 From: GitHub -- tdilauro Date: Mon, 8 Jul 2024 17:54:52 -0400 Subject: [PATCH] SIP2 patron location restriction. --- src/palace/manager/api/sip/__init__.py | 37 ++++++++++++++++++++++++-- src/palace/manager/api/sip/client.py | 5 ++++ 2 files changed, 40 insertions(+), 2 deletions(-) diff --git a/src/palace/manager/api/sip/__init__.py b/src/palace/manager/api/sip/__init__.py index 6d6fae399d..d76445e728 100644 --- a/src/palace/manager/api/sip/__init__.py +++ b/src/palace/manager/api/sip/__init__.py @@ -13,7 +13,10 @@ BasicAuthProviderLibrarySettings, BasicAuthProviderSettings, ) -from palace.manager.api.problem_details import INVALID_CREDENTIALS +from palace.manager.api.problem_details import ( + INVALID_CREDENTIALS, + PATRON_OF_ANOTHER_LIBRARY, +) from palace.manager.api.sip.client import Sip2Encoding, SIPClient from palace.manager.api.sip.dialect import Dialect as Sip2Dialect from palace.manager.integration.settings import ( @@ -24,7 +27,7 @@ from palace.manager.service.analytics.analytics import Analytics from palace.manager.sqlalchemy.model.patron import Patron from palace.manager.util import MoneyUtility -from palace.manager.util.problem_detail import ProblemDetail +from palace.manager.util.problem_detail import ProblemDetail, ProblemDetailException class SIP2Settings(BasicAuthProviderSettings): @@ -192,6 +195,19 @@ class SIP2LibrarySettings(BasicAuthProviderLibrarySettings): description="A specific identifier for the library or branch, if used in patron authentication", ), ) + # Used with SIP2, when it is available in the patron information response. + patron_location_restriction: str | None = FormField( + None, + form=ConfigurationFormItem( + label="Patron Location Restriction", + description=( + "A code for the library or branch which, when specified, " + "must exactly match the permanent location for the patron." + "
If an ILS does not include a location for patrons, specifying" + "a value here will always result in authentication failure." + ), + ), + ) class SIP2AuthenticationProvider( @@ -241,6 +257,7 @@ def __init__( self.ssl_verification = settings.ssl_verification self.dialect = settings.ils self.institution_id = library_settings.institution_id + self.patron_location_restriction = library_settings.patron_location_restriction self._client = client # Check if patrons should be blocked based on SIP status @@ -332,8 +349,24 @@ def remote_authenticate( # passing it on. password = None info = self.patron_information(username, password) + self._enforce_patron_location_restriction(info) return self.info_to_patrondata(info) + def _enforce_patron_location_restriction( + self, info: dict[str, Any] | ProblemDetail + ) -> None: + """Raise an exception if patron location does not match the restriction. + + If a location restriction is specified for the library against which the + patron is attempting to authenticate, then the authentication will fail unless + the location associated with the patron exactly matches that of the library. + """ + if ( + self.patron_location_restriction is not None + and info.get("permanent_location") != self.patron_location_restriction + ): + raise ProblemDetailException(PATRON_OF_ANOTHER_LIBRARY) + def _run_self_tests(self, _db): def makeConnection(sip): sip.connect() diff --git a/src/palace/manager/api/sip/client.py b/src/palace/manager/api/sip/client.py index 1449d772c0..57d67137a2 100644 --- a/src/palace/manager/api/sip/client.py +++ b/src/palace/manager/api/sip/client.py @@ -186,6 +186,10 @@ def _add(cls, internal_name, *args, **kwargs): named._add("screen_message", "AF", allow_multiple=True) named._add("print_line", "AG") +# This is a standard field for items, but Evergreen allows it to +# be returned in a Patron Information response (64) message. +named._add("permanent_location", "AQ") + # SIP extensions defined by Georgia Public Library Service's SIP # server, used by Evergreen and Koha. named._add("sipserver_patron_expiration", "PA") @@ -712,6 +716,7 @@ def patron_information_parser(self, data): named.screen_message, named.print_line, # Add common extension fields. + named.permanent_location, named.sipserver_patron_expiration, named.polaris_patron_expiration, named.sipserver_patron_class,