From: Bill Erickson Date: Wed, 27 Feb 2013 18:08:07 +0000 (-0500) Subject: Z39.50 stored credentials X-Git-Url: https://old-git.evergreen-ils.org/?a=commitdiff_plain;h=19aa7ef17714cdf9c07b23ec90ac81c5ba6453d4;p=contrib%2FConifer.git Z39.50 stored credentials * New non-IDL-accessible DB table for storing credentials * API for applying credentials * Additions to the Z39.50 configuration UI for applying and clearing credentials. * At Z39.50 search time, if no creds are provided by the caller, but creds are configured in the database, creds from the DB are used to make the Z39 search call. * Release notes included Signed-off-by: Bill Erickson Signed-off-by: Mike Rylander --- diff --git a/Open-ILS/examples/opensrf_core.xml.example b/Open-ILS/examples/opensrf_core.xml.example index 39ddbf8c28..6e0d675f0d 100644 --- a/Open-ILS/examples/opensrf_core.xml.example +++ b/Open-ILS/examples/opensrf_core.xml.example @@ -187,6 +187,7 @@ Example OpenSRF bootstrap configuration file for Evergreen open-ils.cstore.direct.actor.user.create open-ils.cstore.direct.actor.user.update open-ils.cstore.direct.actor.user.delete + open-ils.search.z3950.apply_credentials diff --git a/Open-ILS/src/perlmods/lib/OpenILS/Application/Search/Z3950.pm b/Open-ILS/src/perlmods/lib/OpenILS/Application/Search/Z3950.pm index 978b106e4c..1f17a0ccc0 100644 --- a/Open-ILS/src/perlmods/lib/OpenILS/Application/Search/Z3950.pm +++ b/Open-ILS/src/perlmods/lib/OpenILS/Application/Search/Z3950.pm @@ -27,6 +27,44 @@ my $sclient; my %services; my $default_service; +__PACKAGE__->register_method( + method => 'apply_credentials', + api_name => 'open-ils.search.z3950.apply_credentials', + signature => { + desc => "Apply credentials for a Z39.50 server", + params => [ + {desc => 'Authtoken', type => 'string'}, + {desc => 'Z39.50 Source (server) name', type => 'string'}, + {desc => 'Context org unit', type => 'number'}, + {desc => 'Username', type => 'string'}, + {desc => 'Password', type => 'string'} + ], + return => { + desc => 'Event; SUCCESS on success, other event type on error' + } + } +); + +sub apply_credentials { + my ($self, $client, $auth, $source, $ctx_ou, $username, $password) = @_; + + my $e = new_editor(authtoken => $auth, xact => 1); + + return $e->die_event unless + $e->checkauth and + $e->allowed('ADMIN_Z3950_SOURCE', $ctx_ou); + + $e->json_query({from => [ + 'config.z3950_source_credentials_apply', + $source, $ctx_ou, $username, $password + ]}) or return $e->die_event; + + $e->commit; + + return OpenILS::Event->new('SUCCESS'); +} + + __PACKAGE__->register_method( method => 'do_class_search', @@ -314,14 +352,22 @@ sub do_search { my $limit = $$args{limit} || 10; my $offset = $$args{offset} || 0; - my $username = $$args{username} || ""; - my $password = $$args{password} || ""; + my $editor = new_editor(authtoken => $auth); + return $editor->event unless + $editor->checkauth and + $editor->allowed('REMOTE_Z3950_QUERY', $editor->requestor->ws_ou); + + my $creds = $editor->json_query({from => [ + 'config.z3950_source_credentials_lookup', + $$args{service}, $editor->requestor->ws_ou + ]})->[0] || {}; - my $tformat = $services{$args->{service}}->{transmission_format} || $output; + # use the caller-provided username/password if offered. + # otherwise, use the stored credentials. + my $username = $$args{username} || $creds->{username} || ""; + my $password = $$args{password} || $creds->{password} || ""; - my $editor = new_editor(authtoken => $auth); - return $editor->event unless $editor->checkauth; - return $editor->event unless $editor->allowed('REMOTE_Z3950_QUERY'); + my $tformat = $services{$args->{service}}->{transmission_format} || $output; $logger->info("z3950: connecting to server $host:$port:$db as $username"); diff --git a/Open-ILS/src/sql/Pg/002.schema.config.sql b/Open-ILS/src/sql/Pg/002.schema.config.sql index 38416d9d97..6f63a17723 100644 --- a/Open-ILS/src/sql/Pg/002.schema.config.sql +++ b/Open-ILS/src/sql/Pg/002.schema.config.sql @@ -514,6 +514,15 @@ CREATE TABLE config.z3950_attr ( CONSTRAINT z_code_format_once_per_source UNIQUE (code,format,source) ); +CREATE TABLE config.z3950_source_credentials ( + id SERIAL PRIMARY KEY, + owner INTEGER NOT NULL, -- REFERENCES actor.org_unit(id), + source TEXT NOT NULL REFERENCES config.z3950_source(name), + username TEXT, + password TEXT, + CONSTRAINT czsc_source_once_per_lib UNIQUE (source, owner) +); + CREATE TABLE config.i18n_locale ( code TEXT PRIMARY KEY, marc_code TEXT NOT NULL, -- should exist in config.coded_value_map WHERE ctype = 'item_lang' diff --git a/Open-ILS/src/sql/Pg/800.fkeys.sql b/Open-ILS/src/sql/Pg/800.fkeys.sql index 5314b0ee05..cf55a30e7c 100644 --- a/Open-ILS/src/sql/Pg/800.fkeys.sql +++ b/Open-ILS/src/sql/Pg/800.fkeys.sql @@ -132,6 +132,8 @@ CREATE INDEX by_heading ON authority.record_entry (authority.simple_normalize_he ALTER TABLE config.z3950_source ADD CONSTRAINT use_perm_fkey FOREIGN KEY (use_perm) REFERENCES permission.perm_list (id) ON UPDATE CASCADE ON DELETE RESTRICT DEFERRABLE INITIALLY DEFERRED; +ALTER TABLE config.z3950_source_credentials ADD CONSTRAINT z3950_source_creds_owner_fkey FOREIGN KEY (owner) REFERENCES actor.org_unit (id) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED; + ALTER TABLE config.org_unit_setting_type_log ADD CONSTRAINT config_org_unit_setting_type_log_fkey FOREIGN KEY (org) REFERENCES actor.org_unit (id) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED; ALTER TABLE config.filter_dialog_filter_set diff --git a/Open-ILS/src/sql/Pg/999.functions.global.sql b/Open-ILS/src/sql/Pg/999.functions.global.sql index 76592193c2..c3f1533369 100644 --- a/Open-ILS/src/sql/Pg/999.functions.global.sql +++ b/Open-ILS/src/sql/Pg/999.functions.global.sql @@ -2188,3 +2188,51 @@ return $retval; $BODY$ LANGUAGE plperlu IMMUTABLE STRICT COST 100; -- user activity functions -- + + +-- find the most relevant set of credentials for the Z source and org +CREATE OR REPLACE FUNCTION config.z3950_source_credentials_lookup + (source TEXT, owner INTEGER) + RETURNS config.z3950_source_credentials AS $$ + + SELECT creds.* + FROM config.z3950_source_credentials creds + JOIN actor.org_unit aou ON (aou.id = creds.owner) + JOIN actor.org_unit_type aout ON (aout.id = aou.ou_type) + WHERE creds.source = $1 AND creds.owner IN ( + SELECT id FROM actor.org_unit_ancestors($2) + ) + ORDER BY aout.depth DESC LIMIT 1; + +$$ LANGUAGE SQL STABLE; + +-- since we are not exposing config.z3950_source_credentials +-- via the IDL, providing a stored proc gives us a way to +-- set values in the table via cstore +CREATE OR REPLACE FUNCTION config.z3950_source_credentials_apply + (src TEXT, org INTEGER, uname TEXT, passwd TEXT) + RETURNS VOID AS $$ +BEGIN + PERFORM 1 FROM config.z3950_source_credentials + WHERE owner = org AND source = src; + + IF FOUND THEN + IF COALESCE(uname, '') = '' AND COALESCE(passwd, '') = '' THEN + DELETE FROM config.z3950_source_credentials + WHERE owner = org AND source = src; + ELSE + UPDATE config.z3950_source_credentials + SET username = uname, password = passwd + WHERE owner = org AND source = src; + END IF; + ELSE + IF COALESCE(uname, '') <> '' OR COALESCE(passwd, '') <> '' THEN + INSERT INTO config.z3950_source_credentials + (source, owner, username, password) + VALUES (src, org, uname, passwd); + END IF; + END IF; +END; +$$ LANGUAGE PLPGSQL; + + diff --git a/Open-ILS/src/sql/Pg/upgrade/XXXX.schema.z3950_credentials.sql b/Open-ILS/src/sql/Pg/upgrade/XXXX.schema.z3950_credentials.sql new file mode 100644 index 0000000000..ca6d3646e3 --- /dev/null +++ b/Open-ILS/src/sql/Pg/upgrade/XXXX.schema.z3950_credentials.sql @@ -0,0 +1,60 @@ + +BEGIN; + +CREATE TABLE config.z3950_source_credentials ( + id SERIAL PRIMARY KEY, + owner INTEGER NOT NULL REFERENCES actor.org_unit(id), + source TEXT NOT NULL REFERENCES config.z3950_source(name), + -- do some Z servers require a username but no password or vice versa? + username TEXT, + password TEXT, + CONSTRAINT czsc_source_once_per_lib UNIQUE (source, owner) +); + +-- find the most relevant set of credentials for the Z source and org +CREATE OR REPLACE FUNCTION config.z3950_source_credentials_lookup + (source TEXT, owner INTEGER) + RETURNS config.z3950_source_credentials AS $$ + + SELECT creds.* + FROM config.z3950_source_credentials creds + JOIN actor.org_unit aou ON (aou.id = creds.owner) + JOIN actor.org_unit_type aout ON (aout.id = aou.ou_type) + WHERE creds.source = $1 AND creds.owner IN ( + SELECT id FROM actor.org_unit_ancestors($2) + ) + ORDER BY aout.depth DESC LIMIT 1; + +$$ LANGUAGE SQL STABLE; + +-- since we are not exposing config.z3950_source_credentials +-- via the IDL, providing a stored proc gives us a way to +-- set values in the table via cstore +CREATE OR REPLACE FUNCTION config.z3950_source_credentials_apply + (src TEXT, org INTEGER, uname TEXT, passwd TEXT) + RETURNS VOID AS $$ +BEGIN + PERFORM 1 FROM config.z3950_source_credentials + WHERE owner = org AND source = src; + + IF FOUND THEN + IF COALESCE(uname, '') = '' AND COALESCE(passwd, '') = '' THEN + DELETE FROM config.z3950_source_credentials + WHERE owner = org AND source = src; + ELSE + UPDATE config.z3950_source_credentials + SET username = uname, password = passwd + WHERE owner = org AND source = src; + END IF; + ELSE + IF COALESCE(uname, '') <> '' OR COALESCE(passwd, '') <> '' THEN + INSERT INTO config.z3950_source_credentials + (source, owner, username, password) + VALUES (src, org, uname, passwd); + END IF; + END IF; +END; +$$ LANGUAGE PLPGSQL; + + +COMMIT; diff --git a/Open-ILS/src/templates/conify/global/config/z3950_source.tt2 b/Open-ILS/src/templates/conify/global/config/z3950_source.tt2 index abe02e4164..2589ca2c67 100644 --- a/Open-ILS/src/templates/conify/global/config/z3950_source.tt2 +++ b/Open-ILS/src/templates/conify/global/config/z3950_source.tt2 @@ -16,9 +16,32 @@
- +

+ +
+ [% l('Credentials for ') %] + + [% l('Username') %] + + [% l('Password') %] + + + +
+ +
' + val + ''; } diff --git a/docs/RELEASE_NOTES_NEXT/z39_source_credentials.txt b/docs/RELEASE_NOTES_NEXT/z39_source_credentials.txt new file mode 100644 index 0000000000..eb74bcc6f6 --- /dev/null +++ b/docs/RELEASE_NOTES_NEXT/z39_source_credentials.txt @@ -0,0 +1,13 @@ +Storing Z39.50 Server Credentials +================================= + +In the Z39.50 configuration interface, staff now have the option to apply +z39.50 login credentials to each Z39.50 server at different levels of the +org unit hierarchy (similar to org unit settings). When credentials are set +for a Z39 server, searches against the z39 server will used the stored +credentials, unless other credentials are provided by the caller, in which +case the caller credentials are used. + +For security purposes, passwords may not be retrieved or reported on by staff. +Staff can only apply new values for credentials or clear existing ones. +