From: Bill Erickson Date: Wed, 11 Mar 2020 21:15:45 +0000 (-0400) Subject: SIP2Mediator experiment WIP X-Git-Url: https://old-git.evergreen-ils.org/?a=commitdiff_plain;h=d86f6da6832f2286524846493fe1262e17f1fec4;p=working%2FEvergreen.git SIP2Mediator experiment WIP Signed-off-by: Bill Erickson --- diff --git a/Open-ILS/src/perlmods/lib/OpenILS/WWW/SIP2Mediator.pm b/Open-ILS/src/perlmods/lib/OpenILS/WWW/SIP2Mediator.pm index 87ba0e828e..f614505e94 100644 --- a/Open-ILS/src/perlmods/lib/OpenILS/WWW/SIP2Mediator.pm +++ b/Open-ILS/src/perlmods/lib/OpenILS/WWW/SIP2Mediator.pm @@ -20,31 +20,72 @@ use Apache2::RequestRec; use CGI; use DateTime; use DateTime::Format::ISO8601; -use OpenSRF::Utils::JSON; +use JSON::XS; use OpenSRF::Utils::Cache; use OpenSRF::System; -use OpenSRF::Utils::SettingsClient; use OpenILS::Utils::CStoreEditor q/:funcs/; use OpenSRF::Utils::Logger q/$logger/; use OpenILS::Application::AppUtils; use OpenILS::Utils::DateTime qw/:datetime/; my $U = 'OpenILS::Application::AppUtils'; - -# TODO: config file which maps SIP logins to ILS logins and -# applies various flags. - -my $bs_config; +my $cache; + +my $json = JSON::XS->new; +$json->ascii(1); +$json->allow_nonref(1); + +my $config = { # TODO: move to external config / database settings + options => { + # Allow 99 (sc status) message before successful 93 (login) message + allow_sc_status_before_login => 1 + }, + accounts => [{ + sip_username => 'sip', + sip_password => 'sip', + ils_username => 'admin', + ils_password => 'demo123', + ils_workstation => 'BR1-gamma' + }], + institutions => [{ + id => 'example', + supports => [ # Supported Messages (BX) + 'Y', # patron status request, + 'Y', # checkout, + 'Y', # checkin, + 'N', # block patron, + 'Y', # acs status, + 'N', # request sc/acs resend, + 'Y', # login, + 'Y', # patron information, + 'N', # end patron session, + 'Y', # fee paid, + 'Y', # item information, + 'N', # item status update, + 'N', # patron enable, + 'N', # hold, + 'Y', # renew, + 'N', # renew all, + ], + options => {} + }] +}; + +my $osrf_config; sub import { - $bs_config = shift; + $osrf_config = shift; + warn "OSRF CONFIG IS $osrf_config\n"; } my $init_complete = 0; -sub child_init { +sub init { + return if $init_complete; $init_complete = 1; - OpenSRF::System->bootstrap_client(config_file => $bs_config); + OpenSRF::System->bootstrap_client(config_file => $osrf_config); OpenILS::Utils::CStoreEditor->init; + $cache = OpenSRF::Utils::Cache->new; + return Apache2::Const::OK; } @@ -57,18 +98,18 @@ sub handler { my $r = shift; my $cgi = CGI->new; - child_init() unless $init_complete; + init(); - my $session = $cgi->param('session'); - my $message = OpenSRF::Utils::JSON->JSON2perl($cgi->param('message')); + my $seskey = $cgi->param('session'); + my $message = $json->decode($cgi->param('message')); my $msg_code = $message->{code}; my $response; if ($msg_code eq '93') { - $response = handle_login($session, $message); + $response = handle_login($seskey, $message); } elsif ($msg_code eq '99') { - $response = handle_sc_status($session, $message); + $response = handle_sc_status($seskey, $message); } unless ($response) { @@ -77,43 +118,120 @@ sub handler { } $r->content_type('application/json'); - $r->print(OpenSRF::Utils::JSON->perl2JSON($response)); + $r->print($json->encode($response)); return Apache2::Const::OK; } -sub handle_login { - my ($session, $message) = @_; +# Returns the value of the first occurrence of the requested field by SIP code. +sub get_field_value { + my ($message, $code) = @_; + for my $field (@{$message->{fields}}) { + my ($c, $v) = each(%$field); # one key/value pair per field + return $v if $c eq $code; + } - # TODO: login and cache the authtoken vis the $session + return undef; +} + +sub get_auth_account { + my ($seskey) = @_; + my $account = $cache->get_cache("sip2_$seskey"); + + if ($account) { + return $account->{authtoken}; + } else { + $logger->info("SIP2 no cached session for seskey=$seskey"); + return undef; + } +} + +# Logs in to Evergreen and caches the authtoken with the SIP account. +# Returns true on success, false on failure to authenticate. +sub set_auth_token { + my ($seskey, $account) = @_; + + my $auth = $U->simplereq( + 'open-ils.auth', + 'open-ils.auth.login', { + username => $account->{ils_username}, + password => $account->{ils_password}, + workstation => $account->{ils_workstation}, + type => 'staff' + }); + + if ($auth->{textcode} eq 'SUCCESS') { + $account->{authtoken} = $auth->{payload}->{authtoken}; + $cache->put_cache("sip2_$seskey", $account); + return 1; + + } else { + $logger->warn("SIP2 login failed for ils_username".$account->{ils_username}); + return 0; + } +} + +sub handle_login { + my ($seskey, $message) = @_; my $response = { code => '94', - fixed_fields => ['1'] + fixed_fields => ['0'] # default to login failed. }; + my $sip_username = get_field_value($message, 'CN'); + my $sip_password = get_field_value($message, 'CO'); + + my ($account) = grep { + $_->{sip_username} eq $sip_username && + $_->{sip_password} eq $sip_password + } @{$config->{accounts}}; + + if ($account) { + $response->{fixed_fields}->[0] = '1' + if set_auth_token($seskey, $account); + + } else { + $logger->info("SIP2 login failed for user=$sip_username") + } + return $response; } +# NOTE: response should be modified as message handlers are implemented. sub handle_sc_status { - my ($session, $message) = @_; + my ($seskey, $message) = @_; + + return undef unless ( + $config->{options}->{allow_sc_status_before_login} || + get_auth_account($seskey) + ); - # TODO: If we don't want to allow sc_status requests without - # authentication, check for the authtoken. + # The SC Status message does not include an institution, but expects + # one in return. Use the configuration for the first institution. + # Maybe the SIP server itself should track which institutoin its + # instance is configured to use. That may multiple servers could, + # one per institution. + my $instconf = $config->{institutions}->[0]; + my $instname = $instconf->{id}; my $response = { code => '98', fixed_fields => [ 'Y', # online_status - 'N', # checkin_ok - 'N', # checkout_ok - 'N', # acs_renewal_policy + 'Y', # checkin_ok + 'Y', # checkout_ok + 'Y', # acs_renewal_policy 'N', # status_update_ok 'N', # offline_ok '999', # timeout_period '999', # retries_allowed sipdate(), # transaction date '2.00' # protocol_version + ], + fields => [ + {AO => $instname}, + {BX => join('', @{$instconf->{supports}})} ] } }