[open-ils-commits] [GIT] Evergreen ILS branch master updated. a8076f5eefa9eec90a423ab85665659eb78a2e36

Evergreen Git git at git.evergreen-ils.org
Fri Mar 9 21:59:32 EST 2012


This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "Evergreen ILS".

The branch, master has been updated
       via  a8076f5eefa9eec90a423ab85665659eb78a2e36 (commit)
       via  3bfb4a67e3492ed75f40136d4b62d1b5d73d0f65 (commit)
       via  185a7b030f0298eaeff105253d00de733fc1b0f6 (commit)
       via  c26d0e54383b03739f3acd1c017a8c04af70d744 (commit)
       via  c308a805063f0071255733943be4d66035d0b97d (commit)
       via  3fbee8dd29dea23d8428d0ea3081ac2210b6d20c (commit)
       via  785c0ae815b547ad36b0876707ad8b95ea5eebce (commit)
      from  f99e8feb43bf0df1f100016aa01f57fcbabd0bed (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit a8076f5eefa9eec90a423ab85665659eb78a2e36
Author: Dan Wells <dbw2 at calvin.edu>
Date:   Fri Mar 9 21:34:43 2012 -0500

    Trivial redundant line removal
    
    Trivial change to remove duplicate setting of 'password' member
    left over from auth-proxy branch merge.
    
    Signed-off-by: Dan Wells <dbw2 at calvin.edu>

diff --git a/Open-ILS/web/opac/common/js/opac_utils.js b/Open-ILS/web/opac/common/js/opac_utils.js
index 801360d..aae4746 100644
--- a/Open-ILS/web/opac/common/js/opac_utils.js
+++ b/Open-ILS/web/opac/common/js/opac_utils.js
@@ -724,7 +724,6 @@ function doLogin(suppressEvents) {
 	var passwd = G.ui.login.password.value;
 
 	var args = {
-		password : hex_md5(seed + hex_md5(passwd)), 
 		type		: "opac", 
 		org		: getOrigLocation(),
 		agent : 'opac'

commit 3bfb4a67e3492ed75f40136d4b62d1b5d73d0f65
Author: Dan Scott <dscott at laurentian.ca>
Date:   Thu Mar 8 13:36:04 2012 -0500

    Add id_attr LDAP attribute to opensrf.xml.example
    
    Also add a Release Notes entry for the authentication proxy service.
    
    Signed-off-by: Dan Scott <dscott at laurentian.ca>
    Signed-off-by: Dan Wells <dbw2 at calvin.edu>

diff --git a/Open-ILS/examples/opensrf.xml.example b/Open-ILS/examples/opensrf.xml.example
index 82c55e7..ea6f18b 100644
--- a/Open-ILS/examples/opensrf.xml.example
+++ b/Open-ILS/examples/opensrf.xml.example
@@ -393,6 +393,7 @@ vim:et:ts=4:sw=4:
                             <hostname>name.domain.com</hostname>
                             <basedn>ou=people,dc=domain,dc=com</basedn>
                             <authid>cn=username,ou=specials,dc=domain,dc=com</authid>
+                            <id_attr>uid</id_attr>
                             <password>my_ldap_password_for_authid_user</password>
                             <login_types>
                                 <type>staff</type>
diff --git a/docs/RELEASE_NOTES_2_2.txt b/docs/RELEASE_NOTES_2_2.txt
index 036eef9..ecd0808 100644
--- a/docs/RELEASE_NOTES_2_2.txt
+++ b/docs/RELEASE_NOTES_2_2.txt
@@ -98,6 +98,27 @@ may be particularly useful for libraries that have defined one set of copy
 locations at the consortial level and want to enable quick keyboard navigation
 to copy locations by typing just the first letters of the copy location.
 
+Authentication proxy
+~~~~~~~~~~~~~~~~~~~~
+To support integration of Evergreen with organizational authentication systems,
+and to reduce the proliferation of user names and passwords, Evergreen offers 
+a new service called `open-ils.auth_proxy`. If you enable the service,
+`open-ils.auth_proxy` supports different authentication mechanisms
+that implement the `authenticate` method. You can define a chain of these
+authentication mechanisms to be tried in order within the `<authenticators>`
+element of the `opensrf.xml` configuration file, with the option of falling
+back to the `native` mode that uses Evergreen's internal method of password
+authentication.
+
+This service only provides authentication; there is no support for automatic
+provisioning of accounts. To authenticate against any authentication system,
+the user account must first be defined within the Evergreen system, and
+authentication will be based on the user name as it exists in Evergreen.
+
+A sample authentication mechanism for LDAP is provided in
+`Open-ILS::Application::AuthProxy::LDAP_AUTH`, and corresponding sample
+attributes can be found in `opensrf.xml.example`.
+
 Reports
 ~~~~~~~
 

commit 185a7b030f0298eaeff105253d00de733fc1b0f6
Author: Dan Scott <dscott at laurentian.ca>
Date:   Thu Feb 9 22:24:03 2012 -0500

    Add basic unit tests for AuthProxy + associated fixes
    
    The basic "will it load?" unit tests for AuthProxy* turned up a few
    requirements:
    
    1. Add install of Net::LDAP to Makefile.install
    2. Initialize the OpenSRF cache after bootstrapping
    
    Signed-off-by: Dan Scott <dscott at laurentian.ca>
    Signed-off-by: Dan Wells <dbw2 at calvin.edu>

diff --git a/Open-ILS/src/extras/Makefile.install b/Open-ILS/src/extras/Makefile.install
index 6c7abe7..6905c70 100644
--- a/Open-ILS/src/extras/Makefile.install
+++ b/Open-ILS/src/extras/Makefile.install
@@ -93,6 +93,7 @@ DEBS =  \
 	liblog-log4perl-perl\
 	libmarc-record-perl\
 	libncurses5-dev\
+	libnet-ldap-perl \
 	libnet-server-perl\
 	libnet-ssh2-perl\
 	libnspr4-dev\
@@ -188,6 +189,7 @@ FEDORA_RPMS = \
 	perl-Email-Simple \
 	perl-GDGraph3d \
 	perl-JSON-XS \
+	perl-LDAP \
 	perl-Locale-Codes \
 	perl-Net-IP \
 	perl-Net-SSH2 \
diff --git a/Open-ILS/src/perlmods/lib/OpenILS/Application/AuthProxy.pm b/Open-ILS/src/perlmods/lib/OpenILS/Application/AuthProxy.pm
index 86ab610..be1d05b 100644
--- a/Open-ILS/src/perlmods/lib/OpenILS/Application/AuthProxy.pm
+++ b/Open-ILS/src/perlmods/lib/OpenILS/Application/AuthProxy.pm
@@ -46,13 +46,14 @@ my $U = 'OpenILS::Application::AppUtils';
 my @authenticators;
 my %authenticators_by_name;
 my $enabled = 'false';
-my $cache = OpenSRF::Utils::Cache->new();
+my $cache;
 my $seed_timeout;
 my $block_timeout;
 my $block_count;
 
 sub initialize {
     my $conf = OpenSRF::Utils::SettingsClient->new;
+    $cache = OpenSRF::Utils::Cache->new();
 
     my @pfx = ( "apps", "open-ils.auth", "app_settings", "auth_limits" );
 
diff --git a/Open-ILS/src/perlmods/t/20-OpenILS-Application-AuthProxy.t b/Open-ILS/src/perlmods/t/20-OpenILS-Application-AuthProxy.t
new file mode 100644
index 0000000..ece37e7
--- /dev/null
+++ b/Open-ILS/src/perlmods/t/20-OpenILS-Application-AuthProxy.t
@@ -0,0 +1,10 @@
+#!perl -T
+
+use Test::More tests => 3;
+
+BEGIN {
+	use_ok( 'OpenILS::Application::AuthProxy' );
+}
+
+use_ok( 'OpenILS::Application::AuthProxy::AuthBase');
+use_ok( 'OpenILS::Application::AuthProxy::LDAP_Auth');

commit c26d0e54383b03739f3acd1c017a8c04af70d744
Author: Dan Scott <dscott at laurentian.ca>
Date:   Thu Feb 9 21:55:51 2012 -0500

    Sync AuthProxy config values with opensrf.xml.example
    
    The open-ils.auth/app_settings/auth_limits section of
    opensrf.xml.example offers different settings than O:A:AuthProxy looks
    up, which would typically lead to the default fallbacks. Also,
    O:A:AuthProxy appears to mistakenly use seed_timeout instead of
    block_timeout.
    
    Signed-off-by: Dan Scott <dscott at laurentian.ca>
    Signed-off-by: Dan Wells <dbw2 at calvin.edu>

diff --git a/Open-ILS/src/perlmods/lib/OpenILS/Application/AuthProxy.pm b/Open-ILS/src/perlmods/lib/OpenILS/Application/AuthProxy.pm
index 9f1ce8c..86ab610 100644
--- a/Open-ILS/src/perlmods/lib/OpenILS/Application/AuthProxy.pm
+++ b/Open-ILS/src/perlmods/lib/OpenILS/Application/AuthProxy.pm
@@ -57,9 +57,9 @@ sub initialize {
     my @pfx = ( "apps", "open-ils.auth", "app_settings", "auth_limits" );
 
     # read in (or set defaults) for brute force blocking settings
-    $seed_timeout = $conf->config_value( @pfx, "seed_timeout" );
+    $seed_timeout = $conf->config_value( @pfx, "seed" );
     $seed_timeout = 30 if (!$seed_timeout or $seed_timeout < 0);
-    $block_timeout = $conf->config_value( @pfx, "seed_timeout" );
+    $block_timeout = $conf->config_value( @pfx, "block_time" );
     $block_timeout = $seed_timeout * 3 if (!$block_timeout or $block_timeout < 0);
     $block_count = $conf->config_value( @pfx, "block_count" );
     $block_count = 10 if (!$block_count or $block_count < 0);

commit c308a805063f0071255733943be4d66035d0b97d
Author: Dan Scott <dscott at laurentian.ca>
Date:   Thu Feb 9 21:42:25 2012 -0500

    Whitespace fixup
    
    Fix the vim "noet" directive to avoid inadvertent introduction of tabs.
    
    Wrap a comment over multiple lines instead of creating a super-long
    line.
    
    Use one statement per line.
    
    Signed-off-by: Dan Scott <dscott at laurentian.ca>
    Signed-off-by: Dan Wells <dbw2 at calvin.edu>

diff --git a/Open-ILS/xul/staff_client/chrome/content/auth/session.js b/Open-ILS/xul/staff_client/chrome/content/auth/session.js
index 4b560b0..31843ee 100644
--- a/Open-ILS/xul/staff_client/chrome/content/auth/session.js
+++ b/Open-ILS/xul/staff_client/chrome/content/auth/session.js
@@ -1,5 +1,5 @@
 dump('entering auth/session.js\n');
-// vim:sw=4:ts=4:noet:
+// vim:sw=4:ts=4:et:
 
 if (typeof auth == 'undefined') auth = {};
 auth.session = function (view,login_type) {
@@ -43,8 +43,17 @@ auth.session.prototype = {
             }
 
             if (init || auth_proxy_enabled) {
-                if (xulG._data) { delete xulG._data; } // quick kludge; we were re-using a poisoned OpenILS.data (from ws_info.xul?) where js2JSON (and maybe other stuff) does not exist
-                JSAN.use('OpenILS.data'); var data = new OpenILS.data(); data.stash_retrieve();
+                if (xulG._data) {
+                    /* quick kludge; we were re-using a poisoned OpenILS.data
+                     * (from ws_info.xul?) where js2JSON (and maybe other
+                     * stuff) does not exist
+                     */
+                    delete xulG._data;
+                }
+
+                JSAN.use('OpenILS.data');
+                var data = new OpenILS.data();
+                data.stash_retrieve();
 
                 var params = { 
                     'username' : this.view.name_prompt.value,

commit 3fbee8dd29dea23d8428d0ea3081ac2210b6d20c
Author: Dan Wells <dbw2 at calvin.edu>
Date:   Mon Jan 16 15:13:43 2012 -0500

    Tie AuthProxy.pm to brute-force prevention setup
    
    Attempts to authenticate using either normal auth or
    AuthProxy.pm will now reference the same counter for
    the purposes of preventing brute-force password attacks.
    
    Signed-off-by: Dan Wells <dbw2 at calvin.edu>
    Signed-off-by: Dan Scott <dscott at laurentian.ca>

diff --git a/Open-ILS/src/perlmods/lib/OpenILS/Application/AuthProxy.pm b/Open-ILS/src/perlmods/lib/OpenILS/Application/AuthProxy.pm
index c165462..9f1ce8c 100644
--- a/Open-ILS/src/perlmods/lib/OpenILS/Application/AuthProxy.pm
+++ b/Open-ILS/src/perlmods/lib/OpenILS/Application/AuthProxy.pm
@@ -30,6 +30,7 @@ use strict;
 use warnings;
 use OpenILS::Application;
 use base qw/OpenILS::Application/;
+use OpenSRF::Utils::Cache;
 use OpenSRF::Utils::Logger qw(:logger);
 use OpenSRF::Utils::SettingsClient;
 use OpenILS::Application::AppUtils;
@@ -45,10 +46,25 @@ my $U = 'OpenILS::Application::AppUtils';
 my @authenticators;
 my %authenticators_by_name;
 my $enabled = 'false';
+my $cache = OpenSRF::Utils::Cache->new();
+my $seed_timeout;
+my $block_timeout;
+my $block_count;
 
 sub initialize {
     my $conf = OpenSRF::Utils::SettingsClient->new;
-    my @pfx = ( "apps", "open-ils.auth_proxy", "app_settings" );
+
+    my @pfx = ( "apps", "open-ils.auth", "app_settings", "auth_limits" );
+
+    # read in (or set defaults) for brute force blocking settings
+    $seed_timeout = $conf->config_value( @pfx, "seed_timeout" );
+    $seed_timeout = 30 if (!$seed_timeout or $seed_timeout < 0);
+    $block_timeout = $conf->config_value( @pfx, "seed_timeout" );
+    $block_timeout = $seed_timeout * 3 if (!$block_timeout or $block_timeout < 0);
+    $block_count = $conf->config_value( @pfx, "block_count" );
+    $block_count = 10 if (!$block_count or $block_count < 0);
+
+    @pfx = ( "apps", "open-ils.auth_proxy", "app_settings" );
 
     $enabled = $conf->config_value( @pfx, 'enabled' );
 
@@ -157,6 +173,19 @@ sub login {
     return OpenILS::Event->new( 'LOGIN_FAILED' )
       unless (&enabled() and ($args->{'username'} or $args->{'barcode'}));
 
+    # check for possibility of brute-force attack
+    my $fail_count;
+    # since barcode logins are for 'native' only, we will rely on the blocking
+    # code built-in to 'native' for those logins
+    if ($args->{'username'}) {
+        $fail_count = $cache->get_cache('oils_auth_' . $args->{'username'} . '_count') || 0;
+        if ($fail_count >= $block_count) {
+            $logger->debug("AuthProxy found too many recent failures for '" . $args->{'username'} . "' : $fail_count, forcing failure state.");
+            $cache->put_cache('oils_auth_' . $args->{'username'} . '_count', ++$fail_count, $block_timeout);
+            return OpenILS::Event->new( 'LOGIN_FAILED' );
+        }
+    }
+
     my @error_events;
     my $authenticated = 0;
     my $auths;
@@ -198,6 +227,10 @@ sub login {
     }
 
     # if we got this far, we failed
+    # increment the brute force counter if 'native' didn't already
+    if ($args->{'username'} and !exists $authenticators_by_name{'native'}) {
+        $cache->put_cache('oils_auth_' . $args->{'username'} . '_count', ++$fail_count, $block_timeout);
+    }
     # TODO: send back some form of collected error events
     return OpenILS::Event->new( 'LOGIN_FAILED' );
 }

commit 785c0ae815b547ad36b0876707ad8b95ea5eebce
Author: Dan Wells <dbw2 at calvin.edu>
Date:   Thu Nov 3 14:17:24 2011 -0400

    Initial external authentication support via proxy
    
    This is the initial commit to support an authentication proxy module
    to facilitate external authentication.  It is a work in progress.
    
    What is does so far:
      - Optionally redirects all JSOPAC login requests over SSL by building
        on the 'forceLoginSSL' configuration bool (you MUST enable this
        option for proper use of the auth proxy)
      - Provides a basic plug-in framework for external authentication
        implementations, including configuration options for segregating
        authenticators based on login type or org_unit
      - Allows for multiple cascading authentication tests, including
        simultaneous support for external and internal (EG 'native')
        authentication
      - Provides a 'master switch' to easily revert to using the native EG
        authentication routines only
      - Includes an example LDAP plug-in which supports bind-style auth
        checks
    
    Biggest outstanding known needs:
      - TTOPAC integration, including SSL redirection
      - Tying of login attempts to current brute-force prevention setup
      - Treatment of end-user 'change password' interfaces
      - Support TT/Conifer style authentication prompt
    
    Missing but desirable feature:
      - Allow for manual selection of authenticator by end-user, including
        localization support
    
    Signed-off-by: Dan Wells <dbw2 at calvin.edu>
    Signed-off-by: Dan Scott <dscott at laurentian.ca>

diff --git a/Open-ILS/examples/opensrf.xml.example b/Open-ILS/examples/opensrf.xml.example
index 325b4c2..82c55e7 100644
--- a/Open-ILS/examples/opensrf.xml.example
+++ b/Open-ILS/examples/opensrf.xml.example
@@ -190,6 +190,7 @@ vim:et:ts=4:sw=4:
                 <service>open-ils.circ</service>
                 <service>open-ils.actor</service>
                 <service>open-ils.auth</service>
+                <service>open-ils.auth_proxy</service>
                 <service>open-ils.collections</service>
                 <service>open-ils.justintime</service>
             </allowed_services>
@@ -361,6 +362,57 @@ vim:et:ts=4:sw=4:
                 </app_settings>
             </open-ils.auth>
 
+            <!-- Authentication proxy server -->
+            <open-ils.auth_proxy>
+                <keepalive>5</keepalive>
+                <stateless>1</stateless>
+                <language>perl</language>
+                <implementation>OpenILS::Application::AuthProxy</implementation>
+                <max_requests>93</max_requests>
+
+                <unix_config>
+                    <max_requests>1000</max_requests>
+                    <unix_log>open-ils.auth-proxy_unix.log</unix_log>
+                    <unix_sock>open-ils.auth-proxy_unix.sock</unix_sock>
+                    <unix_pid>open-ils.auth-proxy_unix.pid</unix_pid>
+                    <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>
+                    <!-- 'enabled' is the master switch; set to 'true' to enable proxied logins -->
+                    <enabled>false</enabled>
+                    <authenticators>
+                        <!-- the following is a sample configuration for the LDAP_Auth module; please adjust as needed -->
+                        <!--
+                        <authenticator>
+                            <name>ldap</name>
+                            <module>OpenILS::Application::AuthProxy::LDAP_Auth</module>
+                            <hostname>name.domain.com</hostname>
+                            <basedn>ou=people,dc=domain,dc=com</basedn>
+                            <authid>cn=username,ou=specials,dc=domain,dc=com</authid>
+                            <password>my_ldap_password_for_authid_user</password>
+                            <login_types>
+                                <type>staff</type>
+                                <type>opac</type>
+                            </login_types>
+                            <org_units>
+                                <unit>103</unit>
+                                <unit>104</unit>
+                            </org_units>
+                        </authenticator>
+                        -->
+                        <!-- 'native' is a proxied version of Evergreen's standard authentication -->
+                        <authenticator>
+                            <name>native</name>
+                            <!-- you can add 'login_types' and 'org_units' limits to this authenticator as well, if needed -->
+                        </authenticator>
+                    </authenticators>
+                </app_settings>
+            </open-ils.auth_proxy>
+
             <!-- Generic search server -->
             <open-ils.search>
                 <keepalive>5</keepalive>
@@ -1146,6 +1198,7 @@ vim:et:ts=4:sw=4:
                 <appname>open-ils.circ</appname> 
                 <appname>open-ils.actor</appname> 
                 <appname>open-ils.auth</appname> 
+                <appname>open-ils.auth_proxy</appname> 
                 <appname>open-ils.storage</appname>  
                 <appname>open-ils.penalty</appname>  
                 <appname>open-ils.justintime</appname>  
diff --git a/Open-ILS/examples/opensrf_core.xml.example b/Open-ILS/examples/opensrf_core.xml.example
index cebffee..440bd8b 100644
--- a/Open-ILS/examples/opensrf_core.xml.example
+++ b/Open-ILS/examples/opensrf_core.xml.example
@@ -22,6 +22,7 @@ Example OpenSRF bootstrap configuration file for Evergreen
           <service>open-ils.actor</service>
           <service>open-ils.acq</service>
           <service>open-ils.auth</service>
+          <service>open-ils.auth_proxy</service>
           <service>open-ils.booking</service>
           <service>open-ils.cat</service>
           <service>open-ils.circ</service>
@@ -89,6 +90,7 @@ Example OpenSRF bootstrap configuration file for Evergreen
       <service>open-ils.circ</service>
       <service>open-ils.actor</service>
       <service>open-ils.auth</service>
+      <service>open-ils.auth_proxy</service>
       <service>open-ils.collections</service>
       <service>open-ils.reporter</service>
     </services>
diff --git a/Open-ILS/src/perlmods/lib/OpenILS/Application/AuthProxy.pm b/Open-ILS/src/perlmods/lib/OpenILS/Application/AuthProxy.pm
new file mode 100644
index 0000000..c165462
--- /dev/null
+++ b/Open-ILS/src/perlmods/lib/OpenILS/Application/AuthProxy.pm
@@ -0,0 +1,292 @@
+#!/usr/bin/perl
+
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+
+=head1 NAME
+
+OpenILS::Application::AuthProxy - Negotiator for proxy-style authentication
+
+=head1 AUTHOR
+
+Dan Wells, dbw2 at calvin.edu
+
+=cut
+
+package OpenILS::Application::AuthProxy;
+
+use strict;
+use warnings;
+use OpenILS::Application;
+use base qw/OpenILS::Application/;
+use OpenSRF::Utils::Logger qw(:logger);
+use OpenSRF::Utils::SettingsClient;
+use OpenILS::Application::AppUtils;
+use OpenILS::Utils::Fieldmapper;
+use OpenILS::Event;
+use UNIVERSAL::require;
+use Digest::MD5 qw/md5_hex/;
+my $U = 'OpenILS::Application::AppUtils';
+
+# NOTE: code assumes throughout that '0' is never a valid username, barcode,
+# or password; some logic will need to be tweaked to support it if needed.
+
+my @authenticators;
+my %authenticators_by_name;
+my $enabled = 'false';
+
+sub initialize {
+    my $conf = OpenSRF::Utils::SettingsClient->new;
+    my @pfx = ( "apps", "open-ils.auth_proxy", "app_settings" );
+
+    $enabled = $conf->config_value( @pfx, 'enabled' );
+
+    my $auth_configs = $conf->config_value( @pfx, 'authenticators', 'authenticator' );
+    $auth_configs = [$auth_configs] if ref($auth_configs) eq 'HASH';
+
+    if ( !@$auth_configs ) {
+        $logger->error("AuthProxy: authenticators list not found!");
+    } else {
+        foreach my $auth_config (@$auth_configs) {
+            my $auth_handler;
+            if ($auth_config->{'name'} eq 'native') {
+                $auth_handler = 'OpenILS::Application::AuthProxy::Native';
+            } else {
+                $auth_handler = $auth_config->{module};
+                next unless $auth_handler;
+
+                $logger->debug("Attempting to load AuthProxy handler: $auth_handler");
+                $auth_handler->use;
+                if($@) {
+                    $logger->error("Unable to load AuthProxy handler [$auth_handler]: $@");
+                    next;
+                }
+            }
+
+            &_make_option_array($auth_config, 'login_types', 'type');
+            &_make_option_array($auth_config, 'org_units', 'unit');
+
+            my $authenticator = $auth_handler->new($auth_config);
+            push @authenticators, $authenticator;
+            $authenticators_by_name{$authenticator->name} = $authenticator;
+            $logger->debug("Successfully loaded AuthProxy handler: $auth_handler");
+        }
+        $logger->debug("AuthProxy: authenticators loaded");
+    }
+}
+
+# helper function to simplify the config structure
+sub _make_option_array {
+    my ($auth_config, $container_name, $node_name) = @_;
+
+    if (exists $auth_config->{$container_name}
+        and ref $auth_config->{$container_name} eq 'HASH') {
+        my $nodes = $auth_config->{$container_name}{$node_name};
+        if ($nodes) {
+            if (ref $nodes ne 'ARRAY') {
+                $auth_config->{$container_name} = [$nodes];
+            } else {
+                $auth_config->{$container_name} = $nodes;
+            }
+        } else {
+            delete $auth_config->{$container_name};
+        }
+    } else {
+        delete $auth_config->{$container_name};
+    }
+}
+
+
+
+__PACKAGE__->register_method(
+    method    => "enabled",
+    api_name  => "open-ils.auth_proxy.enabled",
+    api_level => 1,
+    stream    => 1,
+    argc      => 0,
+    signature => {
+        desc => q/Check if AuthProxy is enabled/,
+        return => {
+            desc => "True if enabled, false if not",
+            type => "bool"
+        }
+    }
+);
+sub enabled {
+    return (!$enabled or $enabled eq 'false') ? 0 : 1;
+}
+
+__PACKAGE__->register_method(
+    method    => "login",
+    api_name  => "open-ils.auth_proxy.login",
+    api_level => 1,
+    stream    => 1,
+    argc      => 1,
+    signature => {
+        desc => q/Basic single-factor login method/,
+        params => [
+            {name=> "args", desc => q/A hash of arguments.  Valid keys and their meanings:
+    username := Username to authenticate.
+    barcode  := Barcode of user to authenticate (currently supported by 'native' only!)
+    password := Password for verifying the user.
+    type     := Type of login being attempted (Staff Client, OPAC, etc.).
+    org      := Org unit id
+/,
+                type => "hash"}
+        ],
+        return => {
+            desc => "Authentication seed or failure event",
+            type => "mixed"
+        }
+    }
+);
+sub login {
+    my ( $self, $conn, $args ) = @_;
+
+    return OpenILS::Event->new( 'LOGIN_FAILED' )
+      unless (&enabled() and ($args->{'username'} or $args->{'barcode'}));
+
+    my @error_events;
+    my $authenticated = 0;
+    my $auths;
+
+    # if they specify an authenticator by name, only try that one
+    if ($args->{'name'}) {
+        $auths = [$authenticators_by_name{$args->{'name'}}];
+    } else {
+        $auths = \@authenticators;
+    }
+
+    foreach my $authenticator (@$auths) {
+        # skip authenticators specified for a different login type
+        # or org unit id
+        if ($authenticator->login_types and $args->{'type'}) {
+            next unless grep(/^(all|$args->{'type'})$/, @{$authenticator->{'login_types'}});
+        }
+        if ($authenticator->org_units and $args->{'org'}) {
+            next unless grep(/^(all|$args->{'org'})$/, @{$authenticator->{'org_units'}});
+        }
+
+        my $event;
+        # treat native specially
+        if ($authenticator->name eq 'native') {
+            $event = &_do_login($args);
+        } else {
+            $event = $authenticator->authenticate($args);
+        }
+        my $code = $U->event_code($event);
+        if ($code) {
+            push @error_events, $event;
+        } elsif (defined $code) { # code is '0', i.e. SUCCESS
+            if (exists $event->{'payload'}) { # we have a complete native login
+                return $event;
+            } else { # do a 'forced' login
+                return &_do_login($args, 1);
+            }
+        }
+    }
+
+    # if we got this far, we failed
+    # TODO: send back some form of collected error events
+    return OpenILS::Event->new( 'LOGIN_FAILED' );
+}
+
+sub _do_login {
+    my $args = shift;
+    my $authenticated = shift;
+
+    my $seeder = $args->{'username'} ? $args->{'username'} : $args->{'barcode'};
+    my $seed =
+      OpenSRF::AppSession->create("open-ils.auth")
+      ->request( 'open-ils.auth.authenticate.init', $seeder )->gather(1);
+
+    return OpenILS::Event->new( 'LOGIN_FAILED' )
+      unless $seed;
+
+    my $real_password = $args->{'password'};
+    # if we have already authenticated, look up the password needed to finish
+    if ($authenticated) {
+        # barcode-based login is supported only for 'native' logins
+        return OpenILS::Event->new( 'LOGIN_FAILED' ) if !$args->{'username'};
+        my $user = $U->cstorereq(
+            "open-ils.cstore.direct.actor.user.search.atomic",
+            { usrname => $args->{'username'} }
+        );
+        $args->{'password'} = md5_hex( $seed . $user->[0]->passwd );
+    } else {
+        $args->{'password'} = md5_hex( $seed . md5_hex($real_password) );
+    }
+    my $response = OpenSRF::AppSession->create("open-ils.auth")->request(
+        'open-ils.auth.authenticate.complete',
+        $args
+    )->gather(1);
+    $args->{'password'} = $real_password;
+
+    return OpenILS::Event->new( 'LOGIN_FAILED' )
+      unless $response;
+
+    return $response;
+}
+
+__PACKAGE__->register_method(
+    method    => "authenticators",
+    api_name  => "open-ils.auth_proxy.authenticators",
+    api_level => 1,
+    stream    => 1,
+    argc      => 1,
+    signature => {
+        desc => q/Get a list of viable authenticators/,
+        params => [
+            {name=> "args", desc => q/A hash of arguments.  Valid keys and their meanings:
+    type     := Type of login being attempted (Staff Client, OPAC, etc.).
+    org      := Org unit id
+/,
+                type => "hash"}
+        ],
+        return => {
+            desc => "List of viable authenticators",
+            type => "array"
+        }
+    }
+);
+sub authenticators {
+    my ( $self, $conn, $args ) = @_;
+
+    my @viable_auths;
+
+    foreach my $authenticator (@authenticators) {
+        # skip authenticators specified for a different login type
+        # or org unit id
+        if ($authenticator->login_types and $args->{'type'}) {
+            next unless grep(/^(all|$args->{'type'})$/, @{$authenticator->login_types});
+        }
+        if ($authenticator->org_units and $args->{'org'}) {
+            next unless grep(/^(all|$args->{'org'})$/, @{$authenticator->org_units});
+        }
+
+        push @viable_auths, $authenticator->name;
+    }
+
+    return \@viable_auths;
+}
+
+
+# --------------------------------------------------------------------------
+# Stub package for 'native' authenticator
+# --------------------------------------------------------------------------
+package OpenILS::Application::AuthProxy::Native;
+use strict; use warnings;
+use base 'OpenILS::Application::AuthProxy::AuthBase';
+
+1;
diff --git a/Open-ILS/src/perlmods/lib/OpenILS/Application/AuthProxy/AuthBase.pm b/Open-ILS/src/perlmods/lib/OpenILS/Application/AuthProxy/AuthBase.pm
new file mode 100644
index 0000000..338a7eb
--- /dev/null
+++ b/Open-ILS/src/perlmods/lib/OpenILS/Application/AuthProxy/AuthBase.pm
@@ -0,0 +1,48 @@
+package OpenILS::Application::AuthProxy::AuthBase;
+use strict;
+use warnings;
+use vars '$AUTOLOAD';
+use OpenSRF::Utils::Logger qw(:logger);
+
+sub new {
+    my( $class, $args ) = @_;
+    $class = ref $class || $class;
+    return bless($args, $class);
+}
+
+# --------------------------------------------------------------------------
+# Add automatic getter/setter methods
+# --------------------------------------------------------------------------
+my @AUTOLOAD_FIELDS = qw/
+    name
+    org_units
+    login_types
+/;
+sub AUTOLOAD {
+    my $self = shift;
+    my $type = ref($self) or die "$self is not an object";
+    my $data = shift;
+    my $name = $AUTOLOAD;
+    $name =~ s/.*://o;
+
+    # return immediately if called as the DESTROY method
+    return if $name eq 'DESTROY';
+
+    unless (grep { $_ eq $name } @AUTOLOAD_FIELDS) {
+        $logger->error("$type: invalid autoload field: $name");
+        die "$type: invalid autoload field: $name\n"
+    }
+
+    {
+        no strict 'refs';
+        *{"${type}::${name}"} = sub {
+            my $s = shift;
+            my $v = shift;
+            $s->{$name} = $v if defined $v;
+            return $s->{$name};
+        }
+    }
+    return $self->$name($data);
+}
+
+1;
diff --git a/Open-ILS/src/perlmods/lib/OpenILS/Application/AuthProxy/LDAP_Auth.pm b/Open-ILS/src/perlmods/lib/OpenILS/Application/AuthProxy/LDAP_Auth.pm
new file mode 100644
index 0000000..0a4a0b0
--- /dev/null
+++ b/Open-ILS/src/perlmods/lib/OpenILS/Application/AuthProxy/LDAP_Auth.pm
@@ -0,0 +1,77 @@
+package OpenILS::Application::AuthProxy::LDAP_Auth;
+use strict;
+use warnings;
+use base 'OpenILS::Application::AuthProxy::AuthBase';
+use OpenILS::Event;
+use Net::LDAP;
+use OpenSRF::Utils::SettingsClient;
+use OpenSRF::Utils::Logger qw(:logger);
+
+# default config var (override in configuration xml)
+my $id_attr = 'uid';
+
+sub authenticate {
+    my ( $self, $args ) = @_;
+    my $username = $args->{'username'};
+    my $password = $args->{'password'};
+
+    if (!$username) {
+        $logger->debug("User login failed: No username provided");
+        return OpenILS::Event->new( 'LOGIN_FAILED' );
+    }
+    if (!$password) {
+        $logger->debug("User login failed: No password provided");
+        return OpenILS::Event->new( 'LOGIN_FAILED' );
+    }
+
+    my $hostname_is_ldap = 0;
+    my $reached_ldap     = 0;
+    my $user_in_ldap     = 0;
+    my $login_succeeded  = 0;
+
+    my $hostname    = $self->{'hostname'};
+    my $basedn      = $self->{'basedn'};
+    my $authid      = $self->{'authid'};
+    my $authid_pass = $self->{'password'};
+    $id_attr        = $self->{'id_attr'} || $id_attr;
+
+    my $ldap;
+    if ( $ldap = Net::LDAP->new($hostname) ) {
+        $hostname_is_ldap = 1;
+        if ( $ldap->bind( $authid, password => $authid_pass )->code == 0 ) {
+            $reached_ldap = 1;
+            # verify username
+            if ( $ldap
+                ->search( base => $basedn, filter => "($id_attr=$username)" )
+                ->count != 0 ) {
+                $user_in_ldap = 1;
+
+                # verify password (bind check)
+                my $binddn = "$id_attr=$username,$basedn";
+                if ( $ldap->bind( $binddn, password => $password )
+                    ->code == 0 ) {
+                    $login_succeeded = 1;
+                }
+            }
+        }
+    }
+
+    if ( $login_succeeded ) {
+        return OpenILS::Event->new('SUCCESS');
+    } elsif ( !$hostname_is_ldap ) {
+        # TODO: custom failure events?
+        $logger->debug("User login failed: Incorrect LDAP hostname");
+        return OpenILS::Event->new( 'LOGIN_FAILED' );
+    } elsif ( !$reached_ldap ) {
+        $logger->debug("User login failed: The LDAP server is misconfigured or unavailable");
+        return OpenILS::Event->new( 'LOGIN_FAILED' );
+    } elsif ( !$user_in_ldap ) {
+        $logger->debug("User login failed: Username $username not in LDAP");
+        return OpenILS::Event->new( 'LOGIN_FAILED' );
+    } else {
+        $logger->debug("User login failed: Incorrect LDAP password");
+        return OpenILS::Event->new( 'LOGIN_FAILED' );
+    }
+}
+
+1;
diff --git a/Open-ILS/web/opac/common/js/config.js b/Open-ILS/web/opac/common/js/config.js
index 6c87b73..c70bbae 100644
--- a/Open-ILS/web/opac/common/js/config.js
+++ b/Open-ILS/web/opac/common/js/config.js
@@ -391,6 +391,8 @@ var FETCH_BIB_IDS_BY_BARCODE = 'open-ils.search:open-ils.search.multi_home.bib_i
 var FETCH_ORG_SETTING = 'open-ils.actor:open-ils.actor.ou_setting.ancestor_default';
 var TEST_PEER_BIBS				= 'open-ils.search:open-ils.search.peer_bibs.test';
 var FETCH_PEER_BIBS				= 'open-ils.search:open-ils.search.peer_bibs';
+var AUTH_PROXY_ENABLED			= 'open-ils.auth_proxy:open-ils.auth_proxy.enabled';
+var AUTH_PROXY_LOGIN			= 'open-ils.auth_proxy:open-ils.auth_proxy.login';
 
 /* ---------------------------------------------------------------------------- */
 
diff --git a/Open-ILS/web/opac/common/js/init.js b/Open-ILS/web/opac/common/js/init.js
index 9ad1ed8..b25b994 100644
--- a/Open-ILS/web/opac/common/js/init.js
+++ b/Open-ILS/web/opac/common/js/init.js
@@ -44,7 +44,20 @@ function init() {
 		}
 	}
 
-	runEvt("common", "run");
+	// show_login trumps normal page running
+	if(location.href.match(/&show_login=1/)) {
+		function reload() {
+			var src = location.href.replace(/&show_login=1/, '');
+			// forceLoginSSL setting (indicated by show_login)
+			// assumes we are not SSL on normal pages
+			src = src.replace(/https:/, 'http:');
+			goTo(src);
+		}
+		attachEvt("common", "loginCanceled", reload);
+		initLogin();
+	} else {
+		runEvt("common", "run");
+	}
 	//checkUserSkin();
 
 	var loc = findOrgLasso(getLasso());
diff --git a/Open-ILS/web/opac/common/js/opac_utils.js b/Open-ILS/web/opac/common/js/opac_utils.js
index bf1f3d6..801360d 100644
--- a/Open-ILS/web/opac/common/js/opac_utils.js
+++ b/Open-ILS/web/opac/common/js/opac_utils.js
@@ -712,17 +712,16 @@ function doLogin(suppressEvents) {
 
 	abortAllRequests();
 
-	var uname = G.ui.login.username.value;
-	var passwd = G.ui.login.password.value;	
-
-	var init_request = new Request( LOGIN_INIT, uname );
-   init_request.send(true);
-   var seed = init_request.result();
+	var auth_proxy_enabled = false;
+	var auth_proxy_enabled_request = new Request( AUTH_PROXY_ENABLED );
+	auth_proxy_enabled_request.request.alertEvent = false;
+	auth_proxy_enabled_request.send(true);
+	if (auth_proxy_enabled_request.result() == 1) {
+		auth_proxy_enabled = true;
+	}
 
-   if( ! seed || seed == '0') {
-      alert( "Error Communicating with Authentication Server" );
-      return null;
-   }
+	var uname = G.ui.login.username.value;
+	var passwd = G.ui.login.password.value;
 
 	var args = {
 		password : hex_md5(seed + hex_md5(passwd)), 
@@ -731,13 +730,29 @@ function doLogin(suppressEvents) {
 		agent : 'opac'
 	};
 
-    r = fetchOrgSettingDefault(globalOrgTree.id(), 'opac.barcode_regex');
-    if(r) REGEX_BARCODE = new RegExp(r);
-    
-    if( uname.match(REGEX_BARCODE) ) args.barcode = uname;
+	r = fetchOrgSettingDefault(globalOrgTree.id(), 'opac.barcode_regex');
+	if(r) REGEX_BARCODE = new RegExp(r);
+
+	if( uname.match(REGEX_BARCODE) ) args.barcode = uname;
 	else args.username = uname;
 
-   var auth_request = new Request( LOGIN_COMPLETE, args );
+	var auth_request;
+	if (!auth_proxy_enabled) {
+		var init_request = new Request( LOGIN_INIT, uname );
+		init_request.send(true);
+		var seed = init_request.result();
+
+		if( ! seed || seed == '0') {
+			alert( "Error Communicating with Authentication Server" );
+			return null;
+		}
+
+		args.password = hex_md5(seed + hex_md5(passwd));
+		auth_request = new Request( LOGIN_COMPLETE, args );
+	} else {
+		args.password = passwd;
+		auth_request = new Request( AUTH_PROXY_LOGIN, args );
+	}
 
 	auth_request.request.alertEvent = false;
    auth_request.send(true);
diff --git a/Open-ILS/web/opac/common/js/utils.js b/Open-ILS/web/opac/common/js/utils.js
index aeae80d..444d9cf 100644
--- a/Open-ILS/web/opac/common/js/utils.js
+++ b/Open-ILS/web/opac/common/js/utils.js
@@ -70,8 +70,16 @@ function userPressedEnter(evt) {
    return false;
 }   
 
-
+/* Using setTimeout in the following function means that goTo is threaded,
+   and multiple calls to it will be processed indeterminately.  Since goTo
+   should effectively end the page, we will only honor the first call. */
+var goToHasRun = false;
 function goTo(url) {
+	if (goToHasRun) {
+		return false;
+	}
+
+	goToHasRun = true;
 	/* setTimeout because ie sux */
 	setTimeout( function(){ location.href = url; }, 0 );
 }
diff --git a/Open-ILS/web/opac/skin/default/js/rdetail.js b/Open-ILS/web/opac/skin/default/js/rdetail.js
index ee77624..c4f1616 100644
--- a/Open-ILS/web/opac/skin/default/js/rdetail.js
+++ b/Open-ILS/web/opac/skin/default/js/rdetail.js
@@ -46,7 +46,7 @@ var rdetailEnd = null;
 var mfhdDetails = [];
 var orgHiding = false;
 
-if(location.href.match(/&place_hold=1/)) {
+if(location.href.match(/&place_hold=1/) || location.href.match(/&show_login=1/)) {
     // prevent load flicker between canvases
     hideMe(dojo.byId('canvas_main'));
 }
diff --git a/Open-ILS/web/opac/skin/default/js/sidebar.js b/Open-ILS/web/opac/skin/default/js/sidebar.js
index 638fc79..02d18ac 100644
--- a/Open-ILS/web/opac/skin/default/js/sidebar.js
+++ b/Open-ILS/web/opac/skin/default/js/sidebar.js
@@ -83,11 +83,13 @@ function loginDance() {
 }
 
 function loggedInOK() {
-	showCanvas();
-	G.ui.sidebar.username_dest.appendChild(text(G.user.usrname()));
-	unHideMe(G.ui.sidebar.logoutbox);
-	unHideMe(G.ui.sidebar.logged_in_as);
-	hideMe(G.ui.sidebar.loginbox);
+	if (!location.href.match(/&show_login=1/)) {
+		showCanvas();
+		G.ui.sidebar.username_dest.appendChild(text(G.user.usrname()));
+		unHideMe(G.ui.sidebar.logoutbox);
+		unHideMe(G.ui.sidebar.logged_in_as);
+		hideMe(G.ui.sidebar.loginbox);
+	}
 	runEvt( 'common', 'loggedIn');
 	
 	var org = G.user.prefs[PREF_DEF_LOCATION];
@@ -98,6 +100,11 @@ function loggedInOK() {
 		depth = findOrgDepth(org);
 
 	runEvt( "common", "locationChanged", org, depth);
+	if (location.href.match(/&show_login=1/)) {
+		// this redirect should only happen if the runEvt above didn't already
+		// trigger one
+		goTo(location.href.replace(/&show_login=1/, ''));
+	}
 }
 
 
@@ -157,6 +164,16 @@ function strongPassword(pass, alrt) {
 }
 
 function initLogin() {
+    var src = location.href;
+    if(forceLoginSSL && src.match(/^http:/)) {
+        src = src.replace(/^http:/, 'https:');
+        if(!src.match(/&show_login=1/)) {
+            src += '&show_login=1';
+        }
+        goTo(src);
+        return false;
+    }
+
     swapCanvas(G.ui.login.box);
     try{G.ui.login.username.focus();} catch(e) {}
 
diff --git a/Open-ILS/xul/staff_client/chrome/content/auth/session.js b/Open-ILS/xul/staff_client/chrome/content/auth/session.js
index c4f0ae8..4b560b0 100644
--- a/Open-ILS/xul/staff_client/chrome/content/auth/session.js
+++ b/Open-ILS/xul/staff_client/chrome/content/auth/session.js
@@ -18,25 +18,36 @@ auth.session.prototype = {
 
         var obj = this;
 
+        /* This request is done manually in a try block to allow it to fail
+         * silently if auth_proxy is not even running.  TODO: Move this check
+         * to a module which should be always running, perhaps 'auth'.
+         */
+        var auth_proxy_enabled = false;
         try {
-            var init = this.network.request(
-                api.AUTH_INIT.app,
-                api.AUTH_INIT.method,
-                [ this.view.name_prompt.value ]
-            );
+            var request = new RemoteRequest( api.AUTH_PROXY_ENABLED.app, api.AUTH_PROXY_ENABLED.method );
+            request.send(true);
+            request.setSecure(true);
+            if (request.getResultObject() == 1) {
+                auth_proxy_enabled = true;
+            }
+        } catch(E) {
+        }
+
+        try {
+            if (!auth_proxy_enabled) {
+                var init = this.network.request(
+                    api.AUTH_INIT.app,
+                    api.AUTH_INIT.method,
+                    [ this.view.name_prompt.value ]
+                );
+            }
 
-            if (init) {
+            if (init || auth_proxy_enabled) {
                 if (xulG._data) { delete xulG._data; } // quick kludge; we were re-using a poisoned OpenILS.data (from ws_info.xul?) where js2JSON (and maybe other stuff) does not exist
                 JSAN.use('OpenILS.data'); var data = new OpenILS.data(); data.stash_retrieve();
 
                 var params = { 
                     'username' : this.view.name_prompt.value,
-                    'password' : hex_md5(
-                        init +
-                        hex_md5(
-                            this.view.password_prompt.value
-                        )
-                    ),
                     'type' : 'temp',
                     'agent' : 'staffclient'
                 };
@@ -47,7 +58,19 @@ auth.session.prototype = {
                     data.ws_name = params.workstation; data.stash('ws_name');
                 }
 
-                var robj = this.network.simple_request( 'AUTH_COMPLETE', [ params ]);
+                var robj;
+                if (init) {
+                    params['password'] = hex_md5(
+                        init +
+                        hex_md5(
+                            this.view.password_prompt.value
+                        )
+                    );
+                    robj = this.network.simple_request( 'AUTH_COMPLETE', [ params ]);
+                } else if (auth_proxy_enabled) { // safety double-check
+                    params['password'] = this.view.password_prompt.value;
+                    robj = this.network.simple_request( 'AUTH_PROXY_LOGIN', [ params ] );
+                }
 
                 switch (Number(robj.ilsevent)) {
                     case 0:
diff --git a/Open-ILS/xul/staff_client/chrome/content/main/constants.js b/Open-ILS/xul/staff_client/chrome/content/main/constants.js
index 4120b6f..eea83a4 100644
--- a/Open-ILS/xul/staff_client/chrome/content/main/constants.js
+++ b/Open-ILS/xul/staff_client/chrome/content/main/constants.js
@@ -64,6 +64,8 @@ var api = {
     'AUTH_INIT' : { 'app' : 'open-ils.auth', 'method' : 'open-ils.auth.authenticate.init' },
     'AUTH_COMPLETE' : { 'app' : 'open-ils.auth', 'method' : 'open-ils.auth.authenticate.complete' },
     'AUTH_DELETE' : { 'app' : 'open-ils.auth', 'method' : 'open-ils.auth.session.delete' },
+    'AUTH_PROXY_ENABLED' : { 'app' : 'open-ils.auth_proxy', 'method' : 'open-ils.auth_proxy.enabled' },
+    'AUTH_PROXY_LOGIN' : { 'app' : 'open-ils.auth_proxy', 'method' : 'open-ils.auth_proxy.login' },
     'AUTH_WORKSTATION' : { 'app' : 'open-ils.actor', 'method' : 'open-ils.actor.workstation.register' },
     'AUTH_VERIFY_CREDENTIALS' : { 'app' : 'open-ils.actor', 'method' : 'open-ils.actor.verify_user_password' },
     'AUTOGENERATE_BARCODES' : { 'app' : 'open-ils.cat', 'method' : 'open-ils.cat.item.barcode.autogen' },

-----------------------------------------------------------------------

Summary of changes:
 Open-ILS/examples/opensrf.xml.example              |   54 ++++
 Open-ILS/examples/opensrf_core.xml.example         |    2 +
 Open-ILS/src/extras/Makefile.install               |    2 +
 .../perlmods/lib/OpenILS/Application/AuthProxy.pm  |  326 ++++++++++++++++++++
 .../lib/OpenILS/Application/AuthProxy/AuthBase.pm  |   48 +++
 .../lib/OpenILS/Application/AuthProxy/LDAP_Auth.pm |   77 +++++
 .../perlmods/t/20-OpenILS-Application-AuthProxy.t  |   10 +
 Open-ILS/web/opac/common/js/config.js              |    2 +
 Open-ILS/web/opac/common/js/init.js                |   15 +-
 Open-ILS/web/opac/common/js/opac_utils.js          |   46 ++-
 Open-ILS/web/opac/common/js/utils.js               |   10 +-
 Open-ILS/web/opac/skin/default/js/rdetail.js       |    2 +-
 Open-ILS/web/opac/skin/default/js/sidebar.js       |   27 ++-
 .../staff_client/chrome/content/auth/session.js    |   64 +++-
 .../staff_client/chrome/content/main/constants.js  |    2 +
 docs/RELEASE_NOTES_2_2.txt                         |   21 ++
 16 files changed, 668 insertions(+), 40 deletions(-)
 create mode 100644 Open-ILS/src/perlmods/lib/OpenILS/Application/AuthProxy.pm
 create mode 100644 Open-ILS/src/perlmods/lib/OpenILS/Application/AuthProxy/AuthBase.pm
 create mode 100644 Open-ILS/src/perlmods/lib/OpenILS/Application/AuthProxy/LDAP_Auth.pm
 create mode 100644 Open-ILS/src/perlmods/t/20-OpenILS-Application-AuthProxy.t


hooks/post-receive
-- 
Evergreen ILS


More information about the open-ils-commits mailing list