react / wstein / node_modules / jest-cli / node_modules / jsdom / node_modules / request / lib / auth.js
81141 views'use strict'12var caseless = require('caseless')3, uuid = require('node-uuid')4, helpers = require('./helpers')56var md5 = helpers.md57, toBase64 = helpers.toBase648910function Auth (request) {11// define all public properties here12this.request = request13this.hasAuth = false14this.sentAuth = false15this.bearerToken = null16this.user = null17this.pass = null18}1920Auth.prototype.basic = function (user, pass, sendImmediately) {21var self = this22if (typeof user !== 'string' || (pass !== undefined && typeof pass !== 'string')) {23self.request.emit('error', new Error('auth() received invalid user or password'))24}25self.user = user26self.pass = pass27self.hasAuth = true28var header = user + ':' + (pass || '')29if (sendImmediately || typeof sendImmediately === 'undefined') {30var authHeader = 'Basic ' + toBase64(header)31self.sentAuth = true32return authHeader33}34}3536Auth.prototype.bearer = function (bearer, sendImmediately) {37var self = this38self.bearerToken = bearer39self.hasAuth = true40if (sendImmediately || typeof sendImmediately === 'undefined') {41if (typeof bearer === 'function') {42bearer = bearer()43}44var authHeader = 'Bearer ' + (bearer || '')45self.sentAuth = true46return authHeader47}48}4950Auth.prototype.digest = function (method, path, authHeader) {51// TODO: More complete implementation of RFC 2617.52// - check challenge.algorithm53// - support algorithm="MD5-sess"54// - handle challenge.domain55// - support qop="auth-int" only56// - handle Authentication-Info (not necessarily?)57// - check challenge.stale (not necessarily?)58// - increase nc (not necessarily?)59// For reference:60// http://tools.ietf.org/html/rfc2617#section-361// https://github.com/bagder/curl/blob/master/lib/http_digest.c6263var self = this6465var challenge = {}66var re = /([a-z0-9_-]+)=(?:"([^"]+)"|([a-z0-9_-]+))/gi67for (;;) {68var match = re.exec(authHeader)69if (!match) {70break71}72challenge[match[1]] = match[2] || match[3]73}7475var ha1 = md5(self.user + ':' + challenge.realm + ':' + self.pass)76var ha2 = md5(method + ':' + path)77var qop = /(^|,)\s*auth\s*($|,)/.test(challenge.qop) && 'auth'78var nc = qop && '00000001'79var cnonce = qop && uuid().replace(/-/g, '')80var digestResponse = qop81? md5(ha1 + ':' + challenge.nonce + ':' + nc + ':' + cnonce + ':' + qop + ':' + ha2)82: md5(ha1 + ':' + challenge.nonce + ':' + ha2)83var authValues = {84username: self.user,85realm: challenge.realm,86nonce: challenge.nonce,87uri: path,88qop: qop,89response: digestResponse,90nc: nc,91cnonce: cnonce,92algorithm: challenge.algorithm,93opaque: challenge.opaque94}9596authHeader = []97for (var k in authValues) {98if (authValues[k]) {99if (k === 'qop' || k === 'nc' || k === 'algorithm') {100authHeader.push(k + '=' + authValues[k])101} else {102authHeader.push(k + '="' + authValues[k] + '"')103}104}105}106authHeader = 'Digest ' + authHeader.join(', ')107self.sentAuth = true108return authHeader109}110111Auth.prototype.onRequest = function (user, pass, sendImmediately, bearer) {112var self = this113, request = self.request114115var authHeader116if (bearer === undefined && user === undefined) {117self.request.emit('error', new Error('no auth mechanism defined'))118} else if (bearer !== undefined) {119authHeader = self.bearer(bearer, sendImmediately)120} else {121authHeader = self.basic(user, pass, sendImmediately)122}123if (authHeader) {124request.setHeader('authorization', authHeader)125}126}127128Auth.prototype.onResponse = function (response) {129var self = this130, request = self.request131132if (!self.hasAuth || self.sentAuth) { return null }133134var c = caseless(response.headers)135136var authHeader = c.get('www-authenticate')137var authVerb = authHeader && authHeader.split(' ')[0].toLowerCase()138request.debug('reauth', authVerb)139140switch (authVerb) {141case 'basic':142return self.basic(self.user, self.pass, true)143144case 'bearer':145return self.bearer(self.bearerToken, true)146147case 'digest':148return self.digest(request.method, request.path, authHeader)149}150}151152exports.Auth = Auth153154155