UNPKG

openhim-core

Version:

The OpenHIM core application that provides logging and routing of http requests

104 lines (88 loc) 3.42 kB
User = require('../model/users').User crypto = require 'crypto' logger = require 'winston' config = require "../config/config" config.api = config.get('api') config.auditing = config.get('auditing') atna = require 'atna-audit' auditing = require '../auditing' os = require 'os' himSourceID = config.auditing.auditEvents.auditSourceID # will NOT audit any successful logins on the following paths (specified as regex patterns) # only 'noisy' endpoints should be included, such as heartbeats or endpoints that get polled # # /transactions is treated as a special case - see below auditingExemptPaths = [ /\/tasks/ /\/events.*/ /\/metrics.*/ /\/mediators\/.*\/heartbeat/ /\/audits/ /\/logs/ ] isUndefOrEmpty = (string) -> return not string? or string is '' exports.authenticate = (next) -> header = this.request.header email = header['auth-username'] authTS = header['auth-ts'] authSalt = header['auth-salt'] authToken = header['auth-token'] auditAuthFailure = -> audit = atna.userLoginAudit atna.OUTCOME_SERIOUS_FAILURE, himSourceID, os.hostname(), email audit = atna.wrapInSyslog audit auditing.sendAuditEvent audit, -> logger.debug 'Processed internal audit' # if any of the required headers aren't present if isUndefOrEmpty(email) or isUndefOrEmpty(authTS) or isUndefOrEmpty(authSalt) or isUndefOrEmpty(authToken) logger.info "API request made by #{email} from #{this.request.host} is missing required API authentication headers, denying access" this.status = 401 auditAuthFailure() return # check if request is recent requestDate = new Date Date.parse authTS authWindowSeconds = config.api.authWindowSeconds ? 10 to = new Date() to.setSeconds(to.getSeconds() + authWindowSeconds) from = new Date() from.setSeconds(from.getSeconds() - authWindowSeconds) if requestDate < from or requestDate > to # request expired logger.info "API request made by #{email} from #{this.request.host} has expired, denying access" this.status = 401 auditAuthFailure() return user = yield User.findOne(email: email).exec() this.authenticated = user if not user # not authenticated - user not found logger.info "No user exists for #{email}, denying access to API, request originated from #{this.request.host}" this.status = 401 auditAuthFailure() return hash = crypto.createHash 'sha512' hash.update user.passwordHash hash.update authSalt hash.update authTS if authToken is hash.digest 'hex' # authenticated if this.path is '/transactions' if not this.query.filterRepresentation or this.query.filterRepresentation isnt 'full' # exempt from auditing success yield next return else for pathTest in auditingExemptPaths if pathTest.test this.path # exempt from auditing success yield next return # send audit audit = atna.userLoginAudit atna.OUTCOME_SUCCESS, himSourceID, os.hostname(), email, user.groups.join(','), user.groups.join(',') audit = atna.wrapInSyslog audit auditing.sendAuditEvent audit, -> logger.debug 'Processed internal audit' yield next else # not authenticated - token mismatch logger.info "API token did not match expected value, denying access to API, the request was made by #{email} from #{this.request.host}" this.status = 401 auditAuthFailure()