UNPKG

@m92/express-utils

Version:

Utility Module for Express Framework

198 lines (156 loc) 6.01 kB
'use strict' import autoBind from 'auto-bind' import AUTHENTICATOR_ERRORS from '../constants/AUTHENTICATOR_ERRORS' export default class Authenticator { constructor (CONFIG, CONSTANTS, thisExpressUtils) { this.CONFIG = CONFIG this.CONSTANTS = CONSTANTS const { DISABLE_OAUTH, DISABLE_AAUTH } = CONFIG const { HttpClient, CustomError, reqHandler, ERROR_CLASSIFICATION, httpContext } = thisExpressUtils const { asyncWrapper } = reqHandler this.ERROR_CLASSIFICATION = ERROR_CLASSIFICATION this.HttpClient = HttpClient this.CustomError = CustomError this.httpContext = httpContext autoBind(this) const validateToken = ( (DISABLE_OAUTH && this._bypassMiddleware) || this._validateToken ) this.validateToken = asyncWrapper(validateToken) const validateApiKey = ( (DISABLE_AAUTH && this._bypassMiddleware) || this._validateApiKey ) this.validateApiKey = asyncWrapper(validateApiKey) } async _bypassMiddleware (request, response, next) { return process.nextTick(next) } async _validateToken (request, response, next) { // Check if 'byPassOAuth' Property has been Set by Another Middleware to Disable Auth const { byPassOAuth } = request if (byPassOAuth === true) { return process.nextTick(next) } const apiParams = this._buildOAuthParams(request) || {} await this._callOAuthApi(apiParams, request, response) next() } async _validateApiKey (request, response, next) { // Check if 'byPassAAuth' Property has been Set by Another Middleware to Disable Auth const { byPassAAuth } = request if (byPassAAuth === true) { return process.nextTick(next) } const apiParams = this._buildAAuthParams(request) || {} await this._callAAuthApi(apiParams, request, response) next() } // --------- Token Authentication -------------------------------------------- _buildOAuthParams (request) { const { CONFIG, CONSTANTS, CustomError } = this const token = this._extractRequestToken(request) if (!token) { throw new CustomError(undefined, AUTHENTICATOR_ERRORS.TOKEN_NOT_FOUND) } const { OAUTH_POOL_ID = '', OAUTH_ENDPOINT = '' } = CONFIG const { POOL_ID_REQUEST_KEY = '' } = CONSTANTS const url = OAUTH_ENDPOINT const poolId = OAUTH_POOL_ID || request[POOL_ID_REQUEST_KEY] const body = { poolId, token } const oauthParams = { url, body } return oauthParams } async _callOAuthApi (params, routerRequest, routerResponse) { const { url = '', headers = {}, body = {} } = params const options = { method: 'POST', url, headers, data: body } const httpClient = new this.HttpClient() const response = await httpClient.request(options) return this._setRouterRequestResponseForOAuth(routerRequest, routerResponse, response) } _extractRequestToken (request) { const { CONSTANTS } = this const { DEFAULT_AUTH, AUTH_HEADER, ACCESS_TOKEN_PROP } = CONSTANTS const token = (DEFAULT_AUTH && request[AUTH_HEADER.REQUEST_PROP]) || request[ACCESS_TOKEN_PROP] return token } _setRouterRequestResponseForOAuth (routerRequest, routerResponse, authResponse) { const { CONSTANTS, httpContext } = this const { DEFAULT_AUTH, AUTH_HEADER, ACCESS_TOKEN_PROP, CLAIMS_REQUEST_KEY, OAUTH_RESPONSE_PROP } = CONSTANTS const { data: oauthBody = {} } = authResponse const { statusCode, data: oauthData = {} } = oauthBody const { claims = {}, refreshedToken } = oauthData // '!statusCode' => response data is not of structure 'ResponseBody' if (!statusCode) { routerResponse[OAUTH_RESPONSE_PROP] = oauthData return } routerRequest[CLAIMS_REQUEST_KEY] = claims const refreshedTokenResponseProp = (DEFAULT_AUTH && AUTH_HEADER.REQUEST_PROP) || ACCESS_TOKEN_PROP routerResponse[refreshedTokenResponseProp] = refreshedToken httpContext.setResponseToken(refreshedToken) httpContext.setUser(claims) } // --------------------------------------------------------------------------- // --------- Token Authentication -------------------------------------------- _buildAAuthParams (request) { const { CONFIG, CONSTANTS, CustomError } = this const apiKey = this._extractApiKey(request) if (!apiKey) { throw new CustomError(undefined, AUTHENTICATOR_ERRORS.API_KEY_NOT_FOUND) } const { AAUTH_ENDPOINT, AAUTH_API_KEY } = CONFIG const { API_KEY_HEADER_KEY } = CONSTANTS const url = AAUTH_ENDPOINT const headers = { [API_KEY_HEADER_KEY]: AAUTH_API_KEY } const body = { apiKey } const aauthParams = { url, headers, body } return aauthParams } async _callAAuthApi (params, routerRequest, routerResponse) { const { url = '', headers = {}, body = {} } = params const options = { method: 'POST', url, headers, data: body } const httpClient = new this.HttpClient() const response = await httpClient.request(options) return this._setRouterRequestResponseForAAuth(routerRequest, routerResponse, response) } _extractApiKey (request) { const { CONSTANTS } = this const { API_KEY_REQUEST_KEY } = CONSTANTS const apiKey = request[API_KEY_REQUEST_KEY] return apiKey } _setRouterRequestResponseForAAuth (routerRequest, routerResponse, authResponse) { const { CONSTANTS, httpContext } = this const { AAUTH_RESPONSE_PROP, API_KEY_REQUEST_KEY } = CONSTANTS const { data: aauthBody = {} } = authResponse const { statusCode, data: aauthData = {} } = aauthBody // '!statusCode' => response data is not of structure 'ResponseBody' if (!statusCode) { routerResponse[AAUTH_RESPONSE_PROP] = aauthBody return } routerRequest[API_KEY_REQUEST_KEY] = aauthData httpContext.setApiUser(aauthData) } // --------------------------------------------------------------------------- }