Set application name when connecting to database

The services that connect directly to the PostgreSQL database (and Clark Kent) now look for an application_name parameter as part of the database login credentials specified in opensrf.xml. If present, the value is used to set the application name Pg connection value; this in turn shows up in the Postgres pg_stat_activity table and Pg’s logs.

Credit card receipts and privacy

To improve privacy and security, Evergreen now stores less data about credit card transactions. The following fields are no longer stored:

  • cc_type
  • cc_first_name
  • cc_last_name
  • expire_month
  • expire_year


All existing data within these fields will be deleted during the upgrade. Reports using this data will no longer function.

Additionally, a tool has been added to Evergreen for clearing the last 4 digits of the credit payment from the database after payments reach a certain age.

Print/email templates

The stock print and email payment templates have been modified to no longer use these fields, but only when the existing templates matched the stock templates. If local changes have been applied, it will be necessary to modify local templates to avoid referencing these fields which no longer exist.

Any templates whose hook is "money.format.payment_receipt.print" or "" may need modification. In stock Evergreen, these are templates:

  1. "" (stock id 29)
  2. "money.payment_receipt.print" (stock id 30)

Example diff:

-  [% CASE "credit_card_payment" %]credit card (
-      [%- SET cc_chunks = mp.credit_card_payment.cc_number.replace(' ','').chunk(4); -%]
-      [%- cc_chunks.slice(0, -1+cc_chunks.max).join.replace('\S','X') -%]
-      [% cc_chunks.last -%]
-      exp [% mp.credit_card_payment.expire_month %]/[% mp.credit_card_payment.expire_year -%]
-  )
+  [% CASE "credit_card_payment" %]credit card
+  [%- IF mp.credit_card_payment.cc_number %] ([% mp.credit_card_payment.cc_number %])[% END %]

Clearing the last 4 of the CC number

To activate automatic CC number clearing, add the following to opensrf’s crontab. Change timing to suit.

5  4  * * *   . ~/.bashrc && $EG_BIN_DIR/clear_cc_number.srfsh

The default retention age is 1 year, but this can be changed by modifying clear_cc_number.srfsh (typically found in /openils/bin/). Replace "1 year" with the age of your choice.

Configure multiple telephony servers via action/trigger

If you are using the AstCall action/trigger reactor to generate callfiles to send to an Asterisk server, until now the only place to specify the relevant configuration was in opensrf.xml. However, this restricted an Evergreen consortium to using only one Asterisk instance.

Now, the telephony parameters can also be specified as A/T event parameters, allowing per-library configuration.

Table 15.1. Telephony parameters


Example value






["Zap/1", "Zap/2", "IAX/"]










["MaxRetries: 3", "RetryTime: 60", "WaitTime: 30", "Archive: 1", "Extension: 10"]

Juvenile-to-adult batch script honors library setting

The batch juv_to_adult.srfsh script that, when set up as a cronjob, is responsible for toggling a patron from juvenile to adult now honors the age value set in the library setting named "Juvenile Age Threshold" (global.juvenile_age_threshold). When no library setting value is present at a given patron’s home library, the value passed in to the script will be used as a default.

New reporting source for hold/copy ratios

A new reporting source is added, "Hold/Copy Ratio per Bib and Pickup Library (and Descendants)", that, for each bib that has a hold request on it or any of its components, calculates the following:

  • active holds at each OU (including the OU’s descendants)
  • holdable copies at each OU (and its descendants)
  • the ratio of the above two counts
  • counts and ratio across the entire consortium

This source differs from the "Hold/Copy Ratio per Bib and Pickup Library" source by including all descendants of the organization unit one is filtering on.

One use case is allowing a multi-branch system within an Evergreen consortium that doesn’t do full resource sharing to readily calculate whether additional copies should be purchased for that system.

New patron action/trigger notice

A new action/trigger event definition ("New User Created Welcome Notice") has been added that will allow you to send a notice after a new patron has been created, based on the actor.usr create-date field.

This notice can be used for various tasks.

  • Sending a welcome email to new patrons to market library services.
  • Confirm that a new patron email address is correct.
  • Generate postal notices to send a welcome packet to new patrons.

Enable this event in the staff client at AdminLocal AdministrationNotifications / Action Triggers.

Improved password management and authentication

Evergreen user passwords are now stored with additional layers of encryption and may only be accessed directly by the database, not the application layer.

All API changes are backwards compatible with existing 3rd-party clients.

Migrating passwords

Passwords are migrated for each user automatically the first time a user logs in under the new setup. However, it is also possible to force password migration for a given user via a database function:

-- actor.migrate_passwd() will only migrate un-migrated
-- accounts, but it's faster to avoid any re-migration attempts.
SELECT actor.migrate_passwd(
FROM actor.usr au
    LEFT JOIN actor.passwd pw ON (pw.usr =

Using this, admins could perform manual batch updates to force all users to use the new, more secure passwords, regardless of when or whether a patron logs back into the system.

Beware that doing this for all users in a large database will take some time and should probably be performed in batches.

Changing Encryption Work Factor

Roughly speaking, the work factor determines the amount of time/effort required to crack passwords. The higher the value, the more secure the password. Higher values also mean that it takes longer for password verification (e.g. during login) to work.

At time of release, Evergreen uses a work factor value of 10. The value is set in the database table/column actor.passwd_type.iter_count (hash iteration count). When this value is modified, any passwords created or modified after the change will use the new work factor. Other passwords will continue using the work factor in place when they were created/modified, until they are changed once again.

Beware that raising the work factor can have a significant impact on login speeds. A work factor of 10 requires ~0.1 seconds to verify a password. A work factor of 15 takes almost 2 full seconds! Also beware that once a password is encoded with a higher work factor, it cannot be lowered again through any automatic means. The owner of the password would have to log in and modify the password after the work factor is re-lowered.

Because of this, it’s recommended that admins thoroughly test work factor modifications before deploying to production.

To check encryption timing:

-- enable psql timing
evergreen=# \timing

-- encode password "HELLOWORLD" with a work factor of 10.
evergreen=# select crypt('HELLOWORLD', gen_salt('bf', 10));
(1 row)

Time: 95.082 ms


To support the new storage mechanism, a new Evergreen service has been added called open-ils.auth_internal. This service runs on the private OpenSRF/XMPP domain and is used to store authenticated user data in the authentication cache.

This is a required service and changes to opensrf.xml (typically /openils/conf/opensrf.xml) are needed to run the new service.

Modifying opensrf.xml

  • A new <open-ils.auth_internal> app stanza is added to define the new service
  • Cache timeout settings are moved from the app stanza for open-ils.auth into open-ils.auth_internal
  • open-ils.auth_internal is added to the set of running services for the domain.

Example diff:

diff --git a/Open-ILS/examples/opensrf.xml.example b/Open-ILS/examples/opensrf.xml.example
index 3b47481..59f737a 100644
--- a/Open-ILS/examples/opensrf.xml.example
+++ b/Open-ILS/examples/opensrf.xml.example
@@ -424,6 +424,29 @@ vim:et:ts=4:sw=4:
                     <!-- defined app-specific settings here -->
+                    <auth_limits>
+                        <seed>30</seed> <!-- amount of time a seed request is valid for -->
+                        <block_time>90</block_time> <!-- amount of time since last auth or seed request to save failure counts -->
+                        <block_count>10</block_count> <!-- number of failures before blocking access -->
+                    </auth_limits>
+                </app_settings>
+            </open-ils.auth>
+            <!-- Internal authentication server -->
+            <open-ils.auth_internal>
+                <keepalive>5</keepalive>
+                <stateless>1</stateless>
+                <language>c</language>
+                <implementation></implementation>
+                <unix_config>
+                    <max_requests>1000</max_requests>
+                    <min_children>1</min_children>
+                    <max_children>15</max_children>
+                    <min_spare_children>1</min_spare_children>
+                    <max_spare_children>5</max_spare_children>
+                </unix_config>
+                <app_settings>
+                    <!-- defined app-specific settings here -->
                         <!-- default login timeouts based on login type -->
@@ -431,13 +454,10 @@ vim:et:ts=4:sw=4:
                         <persist>2 weeks</persist>
-                    <auth_limits>
-                        <seed>30</seed> <!-- amount of time a seed request is valid for -->
-                        <block_time>90</block_time> <!-- amount of time since last auth or seed request to save failure counts -->
-                        <block_count>10</block_count> <!-- number of failures before blocking access -->
-                    </auth_limits>
-            </open-ils.auth>
+            </open-ils.auth_internal>

             <!-- Authentication proxy server -->
@@ -1177,6 +1197,7 @@ vim:et:ts=4:sw=4:
+                <appname>open-ils.auth_internal</appname>

Sortable HTML reports

HTML reports can now be sorted by clicking on the header for a given column. Clicking on the header toggles between sorting the column in ascending and descending order. Note that sorting is available only when there are at most 10,000 rows of output.