From fb714b39cc6165e28d3f5418d1a56d8c00cad5d3 Mon Sep 17 00:00:00 2001 From: Ere Maijala <ere.maijala@helsinki.fi> Date: Tue, 19 Aug 2014 15:30:36 -0400 Subject: [PATCH] Fixed Voyager authentication using non-latin characters in password. --- .../VuFind/src/VuFind/ILS/Driver/Voyager.php | 84 +++++++++++-------- 1 file changed, 51 insertions(+), 33 deletions(-) diff --git a/module/VuFind/src/VuFind/ILS/Driver/Voyager.php b/module/VuFind/src/VuFind/ILS/Driver/Voyager.php index ffd39a2d24c..16b8a8d60a0 100644 --- a/module/VuFind/src/VuFind/ILS/Driver/Voyager.php +++ b/module/VuFind/src/VuFind/ILS/Driver/Voyager.php @@ -1218,48 +1218,66 @@ class Voyager extends AbstractBase $login_field = isset($this->config['Catalog']['login_field']) ? $this->config['Catalog']['login_field'] : 'LAST_NAME'; $login_field = preg_replace('/[^\w]/', '', $login_field); - - $sql = "SELECT PATRON.PATRON_ID, PATRON.FIRST_NAME, PATRON.LAST_NAME " . - "FROM $this->dbName.PATRON, $this->dbName.PATRON_BARCODE " . - "WHERE PATRON.PATRON_ID = PATRON_BARCODE.PATRON_ID AND " . - "lower(PATRON_BARCODE.PATRON_BARCODE) = :barcode AND "; - if (isset($this->config['Catalog']['fallback_login_field'])) { - $fallback_login_field = preg_replace( + $fallback_login_field + = isset($this->config['Catalog']['fallback_login_field']) + ? preg_replace( '/[^\w]/', '', $this->config['Catalog']['fallback_login_field'] - ); - $sql .= "(lower(PATRON.{$login_field}) = :login OR " . - "(PATRON.{$login_field} IS NULL AND " . - "lower(PATRON.{$fallback_login_field}) = :login))"; - } else { - $sql .= "lower(PATRON.{$login_field}) = :login"; - } + ) : ''; + + // Turns out it's difficult and inefficient to handle the mismatching + // character sets of the Voyager database in the query (in theory something + // like + // "UPPER(UTL_I18N.RAW_TO_NCHAR(UTL_RAW.CAST_TO_RAW(field), 'WE8ISO8859P1'))" + // could be used, but it's SLOW and ugly). We'll rely on the fact that the + // barcode shouldn't contain any characters outside the basic latin + // characters and check login verification fields here. + + $sql = "SELECT PATRON.PATRON_ID, PATRON.FIRST_NAME, PATRON.LAST_NAME, " . + "PATRON.{$login_field} as LOGIN"; + if ($fallback_login_field) { + $sql .= ", PATRON.{$fallback_login_field} as FALLBACK_LOGIN"; + } + $sql .= " FROM $this->dbName.PATRON, $this->dbName.PATRON_BARCODE " . + "WHERE PATRON.PATRON_ID = PATRON_BARCODE.PATRON_ID AND " . + "lower(PATRON_BARCODE.PATRON_BARCODE) = :barcode"; try { - $bindLogin = strtolower(utf8_decode($login)); $bindBarcode = strtolower(utf8_decode($barcode)); + $compareLogin = mb_strtolower($login, 'UTF-8'); - $this->debugSQL(__FUNCTION__, $sql, array(':login' => $bindLogin)); + $this->debugSQL(__FUNCTION__, $sql, array(':barcode' => $bindBarcode)); $sqlStmt = $this->db->prepare($sql); - $sqlStmt->bindParam(':login', $bindLogin, PDO::PARAM_STR); $sqlStmt->bindParam(':barcode', $bindBarcode, PDO::PARAM_STR); $sqlStmt->execute(); - $row = $sqlStmt->fetch(PDO::FETCH_ASSOC); - if (isset($row['PATRON_ID']) && ($row['PATRON_ID'] != '')) { - return array( - 'id' => utf8_encode($row['PATRON_ID']), - 'firstname' => utf8_encode($row['FIRST_NAME']), - 'lastname' => utf8_encode($row['LAST_NAME']), - 'cat_username' => $barcode, - 'cat_password' => $login, - // There's supposed to be a getPatronEmailAddress stored - // procedure in Oracle, but I couldn't get it to work here; - // might be worth investigating further if needed later. - 'email' => null, - 'major' => null, - 'college' => null); - } else { - return null; + // For some reason barcode is not unique, so evaluate all resulting + // rows just to be safe + while ($row = $sqlStmt->fetch(PDO::FETCH_ASSOC)) { + $primary = !is_null($row['LOGIN']) + ? mb_strtolower(utf8_encode($row['LOGIN']), 'UTF-8') + : null; + $fallback = $fallback_login_field && is_null($row['LOGIN']) + ? mb_strtolower(utf8_encode($row['FALLBACK_LOGIN']), 'UTF-8') + : null; + + if ((!is_null($primary) && $primary == $compareLogin) + || ($fallback_login_field && is_null($primary) + && $fallback == $compareLogin) + ) { + return array( + 'id' => utf8_encode($row['PATRON_ID']), + 'firstname' => utf8_encode($row['FIRST_NAME']), + 'lastname' => utf8_encode($row['LAST_NAME']), + 'cat_username' => $barcode, + 'cat_password' => $login, + // There's supposed to be a getPatronEmailAddress stored + // procedure in Oracle, but I couldn't get it to work here; + // might be worth investigating further if needed later. + 'email' => null, + 'major' => null, + 'college' => null); + } } + return null; } catch (PDOException $e) { throw new ILSException($e->getMessage()); } -- GitLab