<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>
</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>
<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>
<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>
<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>
--- /dev/null
+#!/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;
--- /dev/null
+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;
--- /dev/null
+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;
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';
/* ---------------------------------------------------------------------------- */
}
}
- 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());
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)),
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);
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 );
}
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'));
}
}
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];
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/, ''));
+ }
}
}
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) {}
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'
};
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:
'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' },