UNPKG

origintrail-node

Version:

OriginTrail Node - Decentralized Knowledge Graph Node Library

180 lines (149 loc) 5.01 kB
import ipLib from 'ip'; import jwtUtil from './util/jwt-util.js'; class AuthService { constructor(ctx) { this._authConfig = ctx.config.auth; this._repository = ctx.repositoryModuleManager; this._logger = ctx.logger; } /** * Authenticate users based on provided ip and token * @param ip * @param token * @returns {boolean} */ async authenticate(ip, token) { const isWhitelisted = this._isIpWhitelisted(ip); const isTokenValid = await this._isTokenValid(token); const tokenAuthEnabled = this._authConfig.tokenBasedAuthEnabled; const ipAuthEnabled = this._authConfig.ipBasedAuthEnabled; const requiresBoth = this._authConfig.bothIpAndTokenAuthRequired; let isAuthenticated = false; if (tokenAuthEnabled && ipAuthEnabled) { isAuthenticated = requiresBoth ? isWhitelisted && isTokenValid : isWhitelisted || isTokenValid; } else { isAuthenticated = isWhitelisted && isTokenValid; } if (!isAuthenticated) { this._logMessage('Received unauthenticated request.'); } return isAuthenticated; } /** * Checks whether user whose token is provided has abilities for system operation * @param token * @param systemOperation * @returns {Promise<boolean|*>} */ async isAuthorized(token, systemOperation) { if (!this._authConfig.tokenBasedAuthEnabled) { return true; } /* If IP is whitelisted and both IP and Token Auth is NOT required pass authorization check. Authentication middleware checks if IP is white listed before authorization middleware. */ if (!(await this._isTokenValid(token))) { if ( !this._authConfig.bothIpAndTokenAuthRequired && this._authConfig.ipBasedAuthEnabled ) { return true; } return false; } const tokenId = jwtUtil.getPayload(token).jti; const abilities = await this._repository.getTokenAbilities(tokenId); const isAuthorized = abilities.includes(systemOperation); const logMessage = isAuthorized ? `Token ${tokenId} is successfully authenticated and authorized.` : `Received unauthorized request.`; this._logMessage(logMessage); return isAuthorized; } /** * Determines whether operation is listed in config.auth.publicOperations * @param operationName * @returns {boolean} */ isPublicOperation(operationName) { if (!Array.isArray(this._authConfig.publicOperations)) { return false; } return this._authConfig.publicOperations.some( (publicOperation) => publicOperation === `V0/${operationName}` || publicOperation === operationName, ); } /** * Validates token structure and revoked status * If ot-node is configured not to do a token based auth, it will return true * @param token * @returns {boolean} * @private */ async _isTokenValid(token) { if (!this._authConfig.tokenBasedAuthEnabled) { return true; } if (!token) { return false; } if (!jwtUtil.validateJWT(token)) { return false; } const isRevoked = await this._isTokenRevoked(token); return isRevoked !== null && !isRevoked; } /** * Checks whether provided ip is whitelisted in config * Returns false if ip based auth is disabled * @param reqIp * @returns {boolean} * @private */ _isIpWhitelisted(reqIp) { if (!this._authConfig.ipBasedAuthEnabled) { return true; } for (const whitelistedIp of this._authConfig.ipWhitelist) { let isEqual = false; try { isEqual = ipLib.isEqual(reqIp, whitelistedIp); } catch (e) { // if ip is not valid IP isEqual should remain false } if (isEqual) { return true; } } return false; } /** * Checks whether provided token is revoked * Returns false if token based auth is disabled * @param token * @returns {Promise<boolean|*>|boolean} * @private */ _isTokenRevoked(token) { if (!this._authConfig.tokenBasedAuthEnabled) { return false; } const tokenId = jwtUtil.getPayload(token).jti; return this._repository.isTokenRevoked(tokenId); } /** * Logs message if loggingEnabled is set to true * @param message * @private */ _logMessage(message) { if (this._authConfig.loggingEnabled) { this._logger.info(`[AUTH] ${message}`); } } } export default AuthService;