From 785c0ae815b547ad36b0876707ad8b95ea5eebce Mon Sep 17 00:00:00 2001 From: Dan Wells Date: Thu, 3 Nov 2011 14:17:24 -0400 Subject: [PATCH] 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 Signed-off-by: Dan Scott --- Open-ILS/examples/opensrf.xml.example | 53 ++++ Open-ILS/examples/opensrf_core.xml.example | 2 + .../lib/OpenILS/Application/AuthProxy.pm | 292 ++++++++++++++++++ .../OpenILS/Application/AuthProxy/AuthBase.pm | 48 +++ .../Application/AuthProxy/LDAP_Auth.pm | 77 +++++ 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 | 45 ++- 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 +- .../chrome/content/auth/session.js | 49 ++- .../chrome/content/main/constants.js | 2 + 13 files changed, 588 insertions(+), 36 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 diff --git a/Open-ILS/examples/opensrf.xml.example b/Open-ILS/examples/opensrf.xml.example index 325b4c2c70..82c55e7bb4 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: open-ils.circ open-ils.actor open-ils.auth + open-ils.auth_proxy open-ils.collections open-ils.justintime @@ -361,6 +362,57 @@ vim:et:ts=4:sw=4: + + + 5 + 1 + perl + OpenILS::Application::AuthProxy + 93 + + + 1000 + open-ils.auth-proxy_unix.log + open-ils.auth-proxy_unix.sock + open-ils.auth-proxy_unix.pid + 1 + 15 + 1 + 5 + + + + + false + + + + + + native + + + + + + 5 @@ -1146,6 +1198,7 @@ vim:et:ts=4:sw=4: open-ils.circ open-ils.actor open-ils.auth + open-ils.auth_proxy open-ils.storage open-ils.penalty open-ils.justintime diff --git a/Open-ILS/examples/opensrf_core.xml.example b/Open-ILS/examples/opensrf_core.xml.example index cebffeee44..440bd8bc10 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 open-ils.actor open-ils.acq open-ils.auth + open-ils.auth_proxy open-ils.booking open-ils.cat open-ils.circ @@ -89,6 +90,7 @@ Example OpenSRF bootstrap configuration file for Evergreen open-ils.circ open-ils.actor open-ils.auth + open-ils.auth_proxy open-ils.collections open-ils.reporter 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 0000000000..c1654626a0 --- /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@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 0000000000..338a7eb57f --- /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 0000000000..0a4a0b0a3a --- /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 6c87b73467..c70bbae5bb 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 9ad1ed8301..b25b99486a 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 bf1f3d6cbf..801360daaf 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 aeae80decf..444d9cf88d 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 ee7762417b..c4f16163e2 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 638fc79230..02d18aca89 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 c4f0ae841d..4b560b05e4 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 4120b6feb9..eea83a4aa4 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' }, -- 2.43.2