LP#1817645: configurable HTTP API for patron auth/retrieval
[working/Evergreen.git] / Open-ILS / src / sql / Pg / 150.remoteauth.sql
1 BEGIN;
2
3 CREATE TABLE config.remoteauth_profile (
4     name TEXT PRIMARY KEY,
5     description TEXT,
6     context_org INT NOT NULL REFERENCES actor.org_unit(id) ON UPDATE CASCADE ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED,
7     enabled BOOLEAN NOT NULL DEFAULT FALSE,
8     perm INT NOT NULL REFERENCES permission.perm_list(id) ON UPDATE CASCADE ON DELETE RESTRICT DEFERRABLE INITIALLY DEFERRED,
9     restrict_to_org BOOLEAN NOT NULL DEFAULT TRUE,
10     allow_inactive BOOL NOT NULL DEFAULT FALSE,
11     allow_expired BOOL NOT NULL DEFAULT FALSE,
12     block_list TEXT
13 );
14
15 CREATE OR REPLACE FUNCTION actor.permit_remoteauth (profile_name TEXT, userid BIGINT) RETURNS TEXT AS $func$
16 DECLARE
17     usr               actor.usr%ROWTYPE;
18     profile           config.remoteauth_profile%ROWTYPE;
19     perm              TEXT;
20     context_org_list  INT[];
21     home_prox         INT;
22     block             TEXT;
23     penalty_count     INT;
24 BEGIN
25
26     SELECT INTO usr * FROM actor.usr WHERE id = userid AND NOT deleted;
27     IF usr IS NULL THEN
28         RETURN 'not_found';
29     END IF;
30
31     IF usr.barred IS TRUE THEN
32         RETURN 'blocked';
33     END IF;
34
35     SELECT INTO profile * FROM config.remoteauth_profile WHERE name = profile_name;
36     SELECT INTO context_org_list ARRAY_AGG(id) FROM actor.org_unit_full_path( profile.context_org );
37
38     -- user's home library must be within the context org
39     IF profile.restrict_to_org IS TRUE AND usr.home_ou NOT IN (SELECT * FROM UNNEST(context_org_list)) THEN
40         RETURN 'not_found';
41     END IF;
42
43     SELECT INTO perm code FROM permission.perm_list WHERE id = profile.perm;
44     IF permission.usr_has_perm(usr.id, perm, profile.context_org) IS FALSE THEN
45         RETURN 'not_found';
46     END IF;
47     
48     IF usr.expire_date < NOW() AND profile.allow_expired IS FALSE THEN
49         RETURN 'expired';
50     END IF;
51
52     IF usr.active IS FALSE AND profile.allow_inactive IS FALSE THEN
53         RETURN 'blocked';
54     END IF;
55
56     -- Proximity of user's home_ou to context_org to see if penalties should be ignored.
57     SELECT INTO home_prox prox FROM actor.org_unit_proximity WHERE from_org = usr.home_ou AND to_org = profile.context_org;
58
59     -- Loop through the block list to see if the user has any matching penalties.
60     IF profile.block_list IS NOT NULL THEN
61         FOR block IN SELECT UNNEST(STRING_TO_ARRAY(profile.block_list, '|')) LOOP
62             SELECT INTO penalty_count COUNT(DISTINCT csp.*)
63                 FROM  actor.usr_standing_penalty usp
64                         JOIN config.standing_penalty csp ON (csp.id = usp.standing_penalty)
65                 WHERE usp.usr = usr.id
66                         AND usp.org_unit IN ( SELECT * FROM UNNEST(context_org_list) )
67                         AND ( usp.stop_date IS NULL or usp.stop_date > NOW() )
68                         AND ( csp.ignore_proximity IS NULL OR csp.ignore_proximity < home_prox )
69                         AND csp.block_list ~ block;
70             IF penalty_count > 0 THEN
71                 -- User has penalties that match this block, so auth is not permitted.
72                 -- Don't bother testing the rest of the block list.
73                 RETURN 'blocked';
74             END IF;
75         END LOOP;
76     END IF;
77
78     -- User has passed all tests.
79     RETURN 'success';
80
81 END;
82 $func$ LANGUAGE plpgsql;
83
84 COMMIT;
85