dynatrace-cordova-outsystems-plugin
Version:
This plugin gives you the ability to use the Dynatrace instrumentation in your hybrid application (Cordova, Ionic, ..). It uses the Mobile Agent, the JavaScript Agent and the Javascript Bridge. The Mobile Agent will give you all device specific values con
169 lines (146 loc) • 4.77 kB
JavaScript
var caseless = require('caseless')
, uuid = require('uuid')
, helpers = require('./helpers')
var md5 = helpers.md5
, toBase64 = helpers.toBase64
function Auth (request) {
// define all public properties here
this.request = request
this.hasAuth = false
this.sentAuth = false
this.bearerToken = null
this.user = null
this.pass = null
}
Auth.prototype.basic = function (user, pass, sendImmediately) {
var self = this
if (typeof user !== 'string' || (pass !== undefined && typeof pass !== 'string')) {
self.request.emit('error', new Error('auth() received invalid user or password'))
}
self.user = user
self.pass = pass
self.hasAuth = true
var header = user + ':' + (pass || '')
if (sendImmediately || typeof sendImmediately === 'undefined') {
var authHeader = 'Basic ' + toBase64(header)
self.sentAuth = true
return authHeader
}
}
Auth.prototype.bearer = function (bearer, sendImmediately) {
var self = this
self.bearerToken = bearer
self.hasAuth = true
if (sendImmediately || typeof sendImmediately === 'undefined') {
if (typeof bearer === 'function') {
bearer = bearer()
}
var authHeader = 'Bearer ' + (bearer || '')
self.sentAuth = true
return authHeader
}
}
Auth.prototype.digest = function (method, path, authHeader) {
// TODO: More complete implementation of RFC 2617.
// - handle challenge.domain
// - support qop="auth-int" only
// - handle Authentication-Info (not necessarily?)
// - check challenge.stale (not necessarily?)
// - increase nc (not necessarily?)
// For reference:
// http://tools.ietf.org/html/rfc2617#section-3
// https://github.com/bagder/curl/blob/master/lib/http_digest.c
var self = this
var challenge = {}
var re = /([a-z0-9_-]+)=(?:"([^"]+)"|([a-z0-9_-]+))/gi
for (;;) {
var match = re.exec(authHeader)
if (!match) {
break
}
challenge[match[1]] = match[2] || match[3]
}
/**
* RFC 2617: handle both MD5 and MD5-sess algorithms.
*
* If the algorithm directive's value is "MD5" or unspecified, then HA1 is
* HA1=MD5(username:realm:password)
* If the algorithm directive's value is "MD5-sess", then HA1 is
* HA1=MD5(MD5(username:realm:password):nonce:cnonce)
*/
var ha1Compute = function (algorithm, user, realm, pass, nonce, cnonce) {
var ha1 = md5(user + ':' + realm + ':' + pass)
if (algorithm && algorithm.toLowerCase() === 'md5-sess') {
return md5(ha1 + ':' + nonce + ':' + cnonce)
} else {
return ha1
}
}
var qop = /(^|,)\s*auth\s*($|,)/.test(challenge.qop) && 'auth'
var nc = qop && '00000001'
var cnonce = qop && uuid().replace(/-/g, '')
var ha1 = ha1Compute(challenge.algorithm, self.user, challenge.realm, self.pass, challenge.nonce, cnonce)
var ha2 = md5(method + ':' + path)
var digestResponse = qop
? md5(ha1 + ':' + challenge.nonce + ':' + nc + ':' + cnonce + ':' + qop + ':' + ha2)
: md5(ha1 + ':' + challenge.nonce + ':' + ha2)
var authValues = {
username: self.user,
realm: challenge.realm,
nonce: challenge.nonce,
uri: path,
qop: qop,
response: digestResponse,
nc: nc,
cnonce: cnonce,
algorithm: challenge.algorithm,
opaque: challenge.opaque
}
authHeader = []
for (var k in authValues) {
if (authValues[k]) {
if (k === 'qop' || k === 'nc' || k === 'algorithm') {
authHeader.push(k + '=' + authValues[k])
} else {
authHeader.push(k + '="' + authValues[k] + '"')
}
}
}
authHeader = 'Digest ' + authHeader.join(', ')
self.sentAuth = true
return authHeader
}
Auth.prototype.onRequest = function (user, pass, sendImmediately, bearer) {
var self = this
, request = self.request
var authHeader
if (bearer === undefined && user === undefined) {
self.request.emit('error', new Error('no auth mechanism defined'))
} else if (bearer !== undefined) {
authHeader = self.bearer(bearer, sendImmediately)
} else {
authHeader = self.basic(user, pass, sendImmediately)
}
if (authHeader) {
request.setHeader('authorization', authHeader)
}
}
Auth.prototype.onResponse = function (response) {
var self = this
, request = self.request
if (!self.hasAuth || self.sentAuth) { return null }
var c = caseless(response.headers)
var authHeader = c.get('www-authenticate')
var authVerb = authHeader && authHeader.split(' ')[0].toLowerCase()
request.debug('reauth', authVerb)
switch (authVerb) {
case 'basic':
return self.basic(self.user, self.pass, true)
case 'bearer':
return self.bearer(self.bearerToken, true)
case 'digest':
return self.digest(request.method, request.path, authHeader)
}
}
exports.Auth = Auth