1 /* Core Sevice - egAuth
3 * Manages login and auth session retrieval.
6 angular.module('egCoreMod')
9 ['$q','$timeout','$rootScope','$window','$location','egNet','egHatch',
10 function($q , $timeout , $rootScope , $window , $location , egNet , egHatch) {
13 // the currently active user (au) object
18 // the currently active auth token string
20 return egHatch.getLoginSessionItem('eg.auth.token');
23 // authtime in seconds
24 authtime : function() {
25 return egHatch.getLoginSessionItem('eg.auth.time');
28 // the currently active workstation name
29 // For ws_ou or wsid(), see egAuth.user().ws_ou(), etc.
30 workstation : function() {
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();
45 'open-ils.auth.session.retrieve', token)
47 .then(function(user) {
48 if (user && user.classname) {
49 // authtoken test succeeded
52 service.check_workstation(deferred);
55 // authtoken test failed
56 egHatch.clearLoginSessionItems();
62 // no authtoken to test
63 deferred.reject('No authtoken found');
66 return deferred.promise;
69 service.check_workstation = function(deferred) {
71 var user = service.user();
72 var ws_path = '/admin/workstation/workstations';
74 return egHatch.getItem('eg.workstation.all')
75 .then(function(workstations) {
76 if (!workstations) workstations = [];
78 // If the user is authenticated with a workstation, get the
79 // name from the locally registered version of the workstation.
83 var ws = workstations.filter(
84 function(w) {return w.id == user.wsid()})[0];
93 if ($location.path() == ws_path) {
94 // User is on the workstation admin page. No need
100 // At this point, the user is trying to access a page
101 // besides the workstation admin page without a valid
102 // registered workstation. Send them back to the
103 // workstation admin page.
105 // NOTE: egEnv also defines basePath, but we cannot import
106 // egEnv here becuase it creates a circular reference.
107 $window.location.href = '/eg/staff' + ws_path;
113 * Returns a promise, which is resolved on successful
114 * login and rejected on failed login.
116 service.login = function(args, ops) {
117 // avoid modifying the caller's data structure.
118 args = angular.copy(args);
120 if (!ops) { // only set on redo attempts.
121 ops = {deferred : $q.defer()};
123 // Clear old LoginSession keys that were left in localStorage
124 // when the previous user closed the browser without logging
125 // out. Under normal circumstance, LoginSession data would
126 // have been cleared by now, either during logout or cookie
127 // expiration. But, if for some reason the user manually
128 // removed the auth token cookie w/o closing the browser
129 // (say, for testing), then this serves double duty to ensure
130 // LoginSession data cannot persist across logins.
131 egHatch.clearLoginSessionItems();
134 service.login_api(args).then(function(evt) {
136 if (evt.textcode == 'SUCCESS') {
137 service.handle_login_ok(args, evt);
138 ops.deferred.resolve({
139 invalid_workstation : ops.invalid_workstation
142 } else if (evt.textcode == 'WORKSTATION_NOT_FOUND') {
143 ops.invalid_workstation = true;
144 delete args.workstation;
145 service.login(args, ops); // redo w/o workstation
148 // note: the likely outcome here is a NO_SESION
149 // server event, which results in broadcasting an
150 // egInvalidAuth by egNet.
151 console.error('login failed ' + js2JSON(evt));
152 ops.deferred.reject();
156 return ops.deferred.promise;
159 service.login_api = function(args) {
160 return egNet.request(
162 'open-ils.auth.authenticate.init', args.username)
163 .then(function(seed) {
164 // avoid clobbering the bare password in case
165 // we need it for a login redo attempt.
166 var login_args = angular.copy(args);
167 login_args.password = hex_md5(seed + hex_md5(args.password));
169 return egNet.request(
171 'open-ils.auth.authenticate.complete', login_args)
176 service.handle_login_ok = function(args, evt) {
177 service.ws = args.workstation;
178 egHatch.setLoginSessionItem('eg.auth.token', evt.payload.authtoken);
179 egHatch.setLoginSessionItem('eg.auth.time', evt.payload.authtime);
184 * Force-check the validity of the authtoken on occasion.
185 * This allows us to redirect an idle staff client back to the login
186 * page after the session times out. Otherwise, the UI would stay
187 * open with potentially sensitive data visible.
188 * TODO: What is the practical difference (for a browser) between
189 * checking auth validity and the ui.general.idle_timeout setting?
190 * Does that setting serve a purpose in a browser environment?
192 service.poll = function() {
193 if (!service.authtime()) return;
197 if (!service.authtime()) return;
200 'open-ils.auth.session.retrieve', service.token())
201 .then(function(user) {
202 if (user && user.classname) { // all good
205 $rootScope.$broadcast('egAuthExpired')
209 // add a 5 second delay to give the token plenty of time
210 // to expire on the server.
211 service.authtime() * 1000 + 5000
215 service.logout = function() {
216 if (service.token()) {
219 'open-ils.auth.session.delete',
220 service.token()); // fire and forget
221 egHatch.clearLoginSessionItems();
223 service._user = null;
231 * Service for testing user permissions.
232 * Note: this cannot live within egAuth, because it creates a circular
233 * dependency of egOrg -> egEnv -> egAuth -> egOrg
236 ['$q','egNet','egAuth','egOrg',
237 function($q , egNet , egAuth , egOrg) {
241 * Returns the full list of org unit objects at which the currently
242 * logged in user has the selected permissions.
243 * @permList - list or string. If a list, the response object is a
244 * hash of perm => orgList maps. If a string, the response is the
245 * org list for the requested perm.
247 service.hasPermAt = function(permList, asId) {
248 var deferred = $q.defer();
250 if (!angular.isArray(permList)) {
252 permList = [permList];
254 // as called, this method will return the top-most org unit of the
255 // sub-tree at which this user has the selected permission.
256 // From there, flesh the descendant orgs locally.
259 'open-ils.actor.user.has_work_perm_at.batch',
260 egAuth.token(), permList
261 ).then(function(resp) {
263 angular.forEach(permList, function(perm) {
265 angular.forEach(resp[perm], function(oneOrg) {
266 all = all.concat(egOrg.descendants(oneOrg, asId));
270 if (!isArray) answer = answer[permList[0]];
271 deferred.resolve(answer);
273 return deferred.promise;
278 * Returns a hash of perm => hasPermBool for each requested permission.
279 * If the authenticated user has no workstation, no checks are made
280 * and all permissions return false.
282 service.hasPermHere = function(permList) {
286 if (!angular.isArray(permList)) {
288 permList = [permList];
291 // no workstation, all are false
292 if (egAuth.user().wsid() === null) {
293 console.warn("egPerm.hasPermHere() called with no workstation");
295 response = permList.map(function(perm) {
296 return response[perm] = false;
301 return $q.when(response);
304 ws_ou = Number(egAuth.user().ws_ou()); // from string
306 return service.hasPermAt(permList, true)
307 .then(function(orgMap) {
308 angular.forEach(orgMap, function(orgIds, perm) {
309 // each permission is mapped to a flat list of org unit ids,
310 // including descendants. See if our workstation org unit
312 response[perm] = orgIds.indexOf(ws_ou) > -1;
314 if (!isArray) response = response[permList[0]];