]> git.evergreen-ils.org Git - working/Evergreen.git/blob - Open-ILS/web/js/ui/default/staff/services/auth.js
a677ff4bf20e45bc3afec159a853b2ef15487a2b
[working/Evergreen.git] / Open-ILS / web / js / ui / default / staff / services / auth.js
1 /* Core Sevice - egAuth
2  *
3  * Manages login and auth session retrieval.
4  */
5
6 angular.module('egCoreMod')
7
8 .factory('egAuth', 
9        ['$q','$timeout','$rootScope','egNet','egHatch', 
10 function($q , $timeout , $rootScope , egNet , egHatch) {
11
12     var service = {
13         // the currently active user (au) object
14         user : function() {
15             return this._user;
16         },
17
18         // the currently active auth token string
19         token : function() {
20             return egHatch.getLoginSessionItem('eg.auth.token');
21         },
22
23         // authtime in seconds
24         authtime : function() {
25             return egHatch.getLoginSessionItem('eg.auth.time');
26         },
27
28         // the currently active workstation name
29         // For ws_ou or wsid(), see egAuth.user().ws_ou(), etc.
30         workstation : function() {
31             return this.ws;
32         }
33     };
34
35     /* Returns a promise, which is resolved if valid
36      * authtoken is found, otherwise rejected */
37     service.testAuthToken = function() {
38         var deferred = $q.defer();
39         var token = service.token();
40
41         if (token) {
42
43             egNet.request(
44                 'open-ils.auth',
45                 'open-ils.auth.session.retrieve', token)
46
47             .then(function(user) {
48                 if (user && user.classname) {
49                     // authtoken test succeeded
50                     service._user = user;
51                     service.poll();
52                    
53                     if (user.wsid()) {
54                         // user previously logged in with a workstation. 
55                         // Find the workstation name from the list 
56                         // of configured workstations
57                         egHatch.getItem('eg.workstation.all')
58                         .then(function(all) { 
59                             if (all) {
60                                 var ws = all.filter(
61                                     function(w) {return w.id == user.wsid()})[0];
62                                 if (ws) service.ws = ws.name;
63                             }
64                             deferred.resolve(); // found WS
65                         });
66                     } else {
67                         deferred.resolve(); // no WS
68                     }
69                 } else {
70                     // authtoken test failed
71                     egHatch.clearLoginSessionItems();
72                     deferred.reject(); 
73                 }
74             });
75
76         } else {
77             // no authtoken to test
78             deferred.reject();
79         }
80
81         return deferred.promise;
82     };
83
84     /**
85      * Returns a promise, which is resolved on successful 
86      * login and rejected on failed login.
87      */
88     service.login = function(args) {
89         var deferred = $q.defer();
90
91         // Clear old LoginSession keys that were left in localStorage
92         // when the previous user closed the browser without logging
93         // out.  Under normal circumstance, LoginSession data would
94         // have been cleared by now, either during logout or cookie
95         // expiration.  But, if for some reason the user manually
96         // removed the auth token cookie w/o closing the browser
97         // (say, for testing), then this serves double duty to ensure
98         // LoginSession data cannot persist across logins.
99         egHatch.clearLoginSessionItems();
100
101         egNet.request(
102             'open-ils.auth',
103             'open-ils.auth.authenticate.init', args.username).then(
104             function(seed) {
105                 args.password = hex_md5(seed + hex_md5(args.password))
106                 egNet.request(
107                     'open-ils.auth',
108                     'open-ils.auth.authenticate.complete', args).then(
109                     function(evt) {
110                         if (evt.textcode == 'SUCCESS') {
111                             service.ws = args.workstation; 
112                             service.poll();
113                             egHatch.setLoginSessionItem(
114                                 'eg.auth.token', evt.payload.authtoken);
115                             egHatch.setLoginSessionItem(
116                                 'eg.auth.time', evt.payload.authtime);
117                             deferred.resolve();
118                         } else {
119                             // note: the likely outcome here is a NO_SESION
120                             // server event, which results in broadcasting an 
121                             // egInvalidAuth by egNet. 
122                             console.error('login failed ' + js2JSON(evt));
123                             deferred.reject();
124                         }
125                     }
126                 )
127             }
128         );
129
130         return deferred.promise;
131     };
132
133     /**
134      * Force-check the validity of the authtoken on occasion. 
135      * This allows us to redirect an idle staff client back to the login
136      * page after the session times out.  Otherwise, the UI would stay
137      * open with potentially sensitive data visible.
138      * TODO: What is the practical difference (for a browser) between 
139      * checking auth validity and the ui.general.idle_timeout setting?
140      * Does that setting serve a purpose in a browser environment?
141      */
142     service.poll = function() {
143         if (!service.authtime()) return;
144
145         $timeout(
146             function() {
147                 if (!service.authtime()) return;
148                 egNet.request(                                                     
149                     'open-ils.auth',                                               
150                     'open-ils.auth.session.retrieve', service.token())   
151                 .then(function(user) {
152                     if (user && user.classname) { // all good
153                         service.poll();
154                     } else {
155                         $rootScope.$broadcast('egAuthExpired') 
156                     }
157                 })
158             },
159             // add a 5 second delay to give the token plenty of time
160             // to expire on the server.
161             service.authtime() * 1000 + 5000
162         );
163     }
164
165     service.logout = function() {
166         if (service.token()) {
167             egNet.request(
168                 'open-ils.auth', 
169                 'open-ils.auth.session.delete', 
170                 service.token()); // fire and forget
171             egHatch.clearLoginSessionItems();
172         }
173         service._user = null;
174     };
175
176     return service;
177 }])
178
179
180 /**
181  * Service for testing user permissions.
182  * Note: this cannot live within egAuth, because it creates a circular
183  * dependency of egOrg -> egEnv -> egAuth -> egOrg
184  */
185 .factory('egPerm', 
186        ['$q','egNet','egAuth','egOrg',
187 function($q , egNet , egAuth , egOrg) {
188     var service = {};
189
190     /*
191      * Returns the full list of org unit objects at which the currently
192      * logged in user has the selected permissions.
193      * @permList - list or string.  If a list, the response object is a
194      * hash of perm => orgList maps.  If a string, the response is the
195      * org list for the requested perm.
196      */
197     service.hasPermAt = function(permList, asId) {
198         var deferred = $q.defer();
199         var isArray = true;
200         if (!angular.isArray(permList)) {
201             isArray = false;
202             permList = [permList];
203         }
204         // as called, this method will return the top-most org unit of the
205         // sub-tree at which this user has the selected permission.
206         // From there, flesh the descendant orgs locally.
207         egNet.request(
208             'open-ils.actor',
209             'open-ils.actor.user.has_work_perm_at.batch',
210             egAuth.token(), permList
211         ).then(function(resp) {
212             var answer = {};
213             angular.forEach(permList, function(perm) {
214                 var all = [];
215                 angular.forEach(resp[perm], function(oneOrg) {
216                     all = all.concat(egOrg.descendants(oneOrg, asId));
217                 });
218                 answer[perm] = all;
219             });
220             if (!isArray) answer = answer[permList[0]];
221             deferred.resolve(answer);
222         });
223        return deferred.promise;
224     };
225
226
227     /**
228      * Returns a hash of perm => hasPermBool for each requested permission.
229      * If the authenticated user has no workstation, no checks are made
230      * and all permissions return false.
231      */
232     service.hasPermHere = function(permList) {
233         var response = {};
234
235         var isArray = true;
236         if (!angular.isArray(permList)) {
237             isArray = false;
238             permList = [permList];
239         }
240
241         // no workstation, all are false
242         if (egAuth.user().wsid() === null) {
243             console.warn("egPerm.hasPermHere() called with no workstation");
244             if (isArray) {
245                 response = permList.map(function(perm) {
246                     return response[perm] = false;
247                 });
248             } else {
249                 response = false;
250             }
251             return $q.when(response);
252         }
253
254         ws_ou = Number(egAuth.user().ws_ou()); // from string
255
256         return service.hasPermAt(permList, true)
257         .then(function(orgMap) {
258             angular.forEach(orgMap, function(orgIds, perm) {
259                 // each permission is mapped to a flat list of org unit ids,
260                 // including descendants.  See if our workstation org unit
261                 // is in the list.
262                 response[perm] = orgIds.indexOf(ws_ou) > -1;
263             });
264             if (!isArray) response = response[permList[0]];
265             return response;
266         });
267     }
268
269     return service;
270 }])
271
272