UNPKG

@sisu-llc/pki-suit

Version:

Attivio SUIT, the Search UI Toolkit, is a library for creating search clients for searching the Attivio platform.

455 lines (405 loc) 15.5 kB
var _class, _temp; function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } import md5 from 'crypto-js/md5'; import StringUtils from './StringUtils'; import FetchUtils from './FetchUtils'; var AuthUtils = (_temp = _class = function () { function AuthUtils() { _classCallCheck(this, AuthUtils); } /** * Called by the application to pass in configuration to the * library's utility and API classes. */ AuthUtils.configure = function configure(users, config) { var configError = AuthUtils.validateConfiguration(config); if (configError) { throw configError; } if (config.ALL.authType === 'XML') { // Only validate users if the auth type is XML var usersError = AuthUtils.validateUsers(users); if (usersError) { throw usersError; } } AuthUtils.users = users; AuthUtils.config = config; }; /** * Logs the currently logged-in user out. */ AuthUtils.logout = function logout(callback) { // Tell the server to delete the SessionId cookie document.cookie = 'SessionId=; Path=' + AuthUtils.config.basename + '; Expires=Thu, 01 Jan 1970 00:00:01 GMT;'; document.cookie = 'JSESSIONID=; Path=' + AuthUtils.config.basename + '; Expires=Thu, 01 Jan 1970 00:00:01 GMT;'; // And remove the user we added to session storage sessionStorage.removeItem(AuthUtils.USER_KEY); if (AuthUtils.config.ALL.authType === 'SAML') { // For SAML auth, call the special URL from Spring/SAML to tell the IdP we’re logging out fetch(AuthUtils.config.ALL.baseUri + '/saml/logout', { method: 'GET' }).then(function () { // And then call the callback callback(); }).catch(function () { // Always do the callback even if we got an error fetching callback(); }); } else if (AuthUtils.config.ALL.authType === 'NONE') { // And tell the server to log us out fetch(AuthUtils.config.ALL.baseUri + '/', { method: 'POST' }).then(function () { // And then call the callback callback(); }).catch(function () { // Always do the callback even if we got an error fetching callback(); }); } else { // Just XML authentication, removing saved user (above) is good enough. // Still need to call the callback, though callback(); } }; /** * Imeplementation of the obfuscation algorithm from Jetty. */ AuthUtils.obfuscate = function obfuscate(orig) { var buf = []; var bytes = orig.split('').map(function (c) { return c.charCodeAt(0); }); bytes.forEach(function (b1, i) { var b2 = bytes[orig.length - (i + 1)]; var i1 = 127 + b1 + b2; var i2 = 127 + b1 - b2; var i0 = i1 * 256 + i2; var newChar = i0.toString(36); switch (newChar.length) { case 1: buf.push('000' + newChar); break; case 2: buf.push('00' + newChar); break; case 3: buf.push('0' + newChar); break; default: buf.push(newChar); break; } }); return buf.join(''); }; /** * Validate a password against a hashed one. */ AuthUtils.passwordMatches = function passwordMatches(comp, compTo) { if (compTo.startsWith('OBF:')) { var remainder = compTo.substring(4); var obfuscatedComp = AuthUtils.obfuscate(comp); return obfuscatedComp === remainder; } else if (compTo.startsWith('MD5:')) { var _remainder = compTo.substring(4); var md5Comp = md5(comp).toString(); return md5Comp === _remainder; } return comp === compTo; }; /** * Find the user info for a given user name. * This is only applicable in the case of XML authentication. */ AuthUtils.findUser = function findUser(username) { if (this.config.ALL.authType === 'XML') { if (Array.isArray(AuthUtils.users.principals.user)) { return AuthUtils.users.principals.user.find(function (testUser) { return testUser.$.id === username; }); } // This will happen if there's only use user... if (AuthUtils.users.principals.user.$.id === username) { return AuthUtils.users.principals.user; } } return null; }; /** * Attempt to log the specified user in. If an error * occurs logging in, then it is returned. Otherwise * this returns null. The log in is valid for the timeout * set in the authentication configuration. */ AuthUtils.login = function login(username, password) { if (!AuthUtils.config || !AuthUtils.config.ALL) { return null; } if (AuthUtils.config.ALL.authType === 'NONE') { return null; } if (AuthUtils.config.ALL.authType === 'XML') { var userObject = AuthUtils.findUser(username); if (userObject) { if (AuthUtils.passwordMatches(password, userObject.$.password)) { userObject.timeout = new Date().getTime() + AuthUtils.TIMEOUT; sessionStorage.setItem(AuthUtils.USER_KEY, JSON.stringify(userObject)); return null; } } return new Error('Invalid log-in credentials.'); } return null; }; /** * Save the currently logged-in user's info into session storage for easy access. */ AuthUtils.saveLoggedInUser = function saveLoggedInUser(userInfo) { if (userInfo) { var userInfoCopy = JSON.parse(JSON.stringify(userInfo)); userInfoCopy.timeout = new Date().getTime() + AuthUtils.TIMEOUT; sessionStorage.setItem(AuthUtils.USER_KEY, JSON.stringify(userInfoCopy)); } else { sessionStorage.removeItem(AuthUtils.USER_KEY); } }; /** * Check whether the user has a particular permission. * TO BE IMPLEMENTED */ AuthUtils.hasPermission = function hasPermission() { if (AuthUtils.config && AuthUtils.config.ALL && AuthUtils.config.ALL.authType === 'NONE') { return true; } return false; }; /** * Check whether there is a user currently logged in. */ AuthUtils.isLoggedIn = function isLoggedIn(permission) { if (!AuthUtils.config || !AuthUtils.config.ALL) { return false; } if (AuthUtils.config.ALL.authType === 'NONE') { return true; } var user = AuthUtils.getSavedUser(); if (user) { if (permission) { return AuthUtils.hasPermission(); } return true; } return false; }; /** * Get the full info object for a logged-in user we already know about. * If no user is logged in or if the logged-in user's login has expired, * then this method returns null. */ AuthUtils.getSavedUser = function getSavedUser() { var userObjectJson = sessionStorage.getItem(AuthUtils.USER_KEY); if (userObjectJson) { var userObject = JSON.parse(userObjectJson); if (userObject && userObject.timeout && userObject.timeout > new Date().getTime()) { return userObject; } } return null; }; /** * Get the full info object for the logged-in user and call the passed-in * callback function with this info. If no user is logged in, the callback * is passed null. * * @param callback a function which takes the user info as a parameter */ AuthUtils.getLoggedInUserInfo = function getLoggedInUserInfo(callback) { var userObject = AuthUtils.getSavedUser(); if (userObject && userObject.timeout && userObject.timeout > new Date().getTime()) { callback(userObject); } else if (AuthUtils.config.ALL.authType === 'SAML' || AuthUtils.config.ALL.authType === 'NONE') { // If the authentication is done on the front-end, we shouldn't // ever get here because if there's no saved user, then // no one is logged in yet... var fetchResponseCallback = function fetchResponseCallback(userInfo, error) { if (userInfo) { AuthUtils.saveLoggedInUser(userInfo); } if (error) { console.log('Got an error retrieving the current user\u2019s details.', error); } callback(userInfo); }; FetchUtils.fetch(AuthUtils.config.ALL.baseUri + '/rest/serverDetailsApi/user', null, fetchResponseCallback, 'GET', 'Got an error retrieving the current user\u2019s details.'); } else { // If we're doing our own authentication, and nobody is logged in, pass null to the callback callback(null); } }; AuthUtils.getLoggedInUserId = function getLoggedInUserId() { var userInfo = AuthUtils.getSavedUser(); if (userInfo) { if (userInfo.$ && userInfo.$.id) { // Special case for XML-based user authentication return userInfo.$.id; } if (userInfo.userId) { return userInfo.userId; } } return ''; }; /** * Get the user name to display given the user info passed in. */ AuthUtils.getUserName = function getUserName(userInfo) { if (userInfo) { if (userInfo.$) { // Special case for XML-based user authentication if (userInfo.$.name && userInfo.$.name.length > 0) { return userInfo.$.name; } return userInfo.$.id; } if (userInfo.fullName) { return userInfo.fullName; } if (userInfo.firstName && userInfo.lastName) { return userInfo.firstName + ' ' + userInfo.lastName; } if (userInfo.firstName) { return userInfo.firstName; } if (userInfo.lastName) { return userInfo.lastName; } if (userInfo.userId) { return userInfo.userId; } } return ''; }; /** * Validate the users object to make sure it won't cause us any * grief. Return null if it's good, or an error messager otherwise. * This should only be called if auth type is 'XML' */ AuthUtils.validateUsers = function validateUsers(users) { if (!users) { return 'The users.xml file was not properly loaded.'; } if (!users.principals) { return 'The users.xml file is invalid; it must contain an outer <principals> element.'; } if (!users.principals.user) { return 'The users.xml file is invalid; it must contain at least one <user> definition.'; } if (Array.isArray(users.principals.user)) { for (var i = 0; i < users.principals.user.length; i += 1) { if (!users.principals.user[i].$ || !StringUtils.notEmpty(users.principals.user[i].$.id)) { return 'The users.xml file is invalid; the user at position ' + i + ' is missing an "id" attribute.'; } } } else if (!users.principals.user.$ || !StringUtils.notEmpty(users.principals.user.$.id)) { return 'The users.xml file is invalid; the user is missing an "id" attribute.'; } return null; }; /** * Validate the configuration object to make sure it won't cause us any * grief. Return null if it's good, or an error messager otherwise. */ AuthUtils.validateConfiguration = function validateConfiguration(config) { if (!config) { return 'The configuration object must be specified.'; } if (!config.ALL) { return 'The configuration object is missing the \'ALL\' value.'; } if (config.ALL.baseUri === null || typeof config.ALL.baseUri === 'undefined') { // Note that baseUri can be the empty string, as in the case of running inside a node return 'The configuration object is missing the \'ALL.baseUri\' value.'; } if (!StringUtils.notEmpty(config.ALL.basename)) { return 'The configuration object is missing the \'ALL.basename\' value.'; } if (!StringUtils.notEmpty(config.ALL.authType)) { return 'The configuration object is missing the \'ALL.authType\' value.'; } if (config.ALL.authType !== 'XML' && config.ALL.authType !== 'SAML' && config.ALL.authType !== 'NONE') { return 'The configuration object has an invalid value for \'ALL.authType\': it must be \'XML,\' \'SAML,\' or \'NONE\' but it is \'' + config.ALL.authType + '.\''; // eslint-disable-line max-len } if (!StringUtils.notEmpty(config.ALL.defaultRealm)) { return 'The configuration object is missing the \'ALL.defaultRealm\' value.'; } if (!config.ALL.entityFields) { return 'The configuration object is missing the \'ALL.entityFields\' value.'; } if (!(config.ALL.entityFields instanceof Map)) { return 'The configuration object\'s \'ALL.entityFields\' value should be a Map.'; } if (!config.ALL.entityColors) { return 'The configuration object is missing the \'ALL.entityColors\' value.'; } if (!(config.ALL.entityColors instanceof Map)) { return 'The configuration object\'s \'ALL.entityColors\' value should be a Map.'; } if (!config.ALL.fields) { return 'The configuration object is missing the \'ALL.fields\' value.'; } if (!Array.isArray(config.ALL.fields)) { return 'The configuration object\'s \'ALL.fields\' value should be an array with at least one value.'; } if (config.ALL.fields.length < 1) { return 'The configuration object\'s \'ALL.fields\' value should be an array with at least one value.'; } if (!StringUtils.notEmpty(config.ALL.title)) { return 'The configuration object is missing the \'ALL.title\' value.'; } if (!StringUtils.notEmpty(config.ALL.uri)) { return 'The configuration object is missing the \'ALL.uri\' value.'; } if (!StringUtils.notEmpty(config.ALL.table)) { return 'The configuration object is missing the \'ALL.table\' value.'; } if (!StringUtils.notEmpty(config.ALL.latitude)) { return 'The configuration object is missing the \'ALL.latitude\' value.'; } if (!StringUtils.notEmpty(config.ALL.longitude)) { return 'The configuration object is missing the \'ALL.longitude\' value.'; } if (!StringUtils.notEmpty(config.ALL.mimetype)) { return 'The configuration object is missing the \'ALL.mimetype\' value.'; } if (!StringUtils.notEmpty(config.ALL.sourcePath)) { return 'The configuration object is missing the \'ALL.sourcePath\' value.'; } if (!StringUtils.notEmpty(config.ALL.previewImageUri)) { return 'The configuration object is missing the \'ALL.previewImageUri\' value.'; } if (!StringUtils.notEmpty(config.ALL.thumbnailImageUri)) { return 'The configuration object is missing the \'ALL.thumbnailImageUri\' value.'; } if (!StringUtils.notEmpty(config.ALL.moreLikeThisQuery)) { return 'The configuration object is missing the \'ALL.moreLikeThisQuery\' value.'; } if (!StringUtils.notEmpty(config.ALL.teaser)) { return 'The configuration object is missing the \'ALL.teaser\' value.'; } if (!StringUtils.notEmpty(config.ALL.text)) { return 'The configuration object is missing the \'ALL.text\' value.'; } return null; }; AuthUtils.getEntityColors = function getEntityColors() { if (this.config && this.config.ALL && this.config.ALL.entityColors) { return this.config.ALL.entityColors; } // If it's not configured, return an empty map. return new Map(); }; AuthUtils.getConfig = function getConfig() { return this.config; }; return AuthUtils; }(), _class.USER_KEY = 'suit-user', _class.TIMEOUT = 30 * 60 * 1000, _temp); export { AuthUtils as default };