Advertisement
Guest User

Untitled

a guest
Mar 20th, 2019
127
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 4.82 KB | None | 0 0
  1. 'use strict'
  2.  
  3. var caseless = require('caseless')
  4. var uuid = require('uuid')
  5. var helpers = require('./helpers')
  6.  
  7. var md5 = helpers.md5
  8. var toBase64 = helpers.toBase64
  9.  
  10. function Auth (request) {
  11. // define all public properties here
  12. this.request = request
  13. this.hasAuth = false
  14. this.sentAuth = false
  15. this.bearerToken = null
  16. this.user = null
  17. this.pass = null
  18. }
  19.  
  20. Auth.prototype.basic = function (user, pass, sendImmediately) {
  21. var self = this
  22. if (typeof user !== 'string' || (pass !== undefined && typeof pass !== 'string')) {
  23. self.request.emit('error', new Error('auth() received invalid user or password'))
  24. }
  25. self.user = user
  26. self.pass = pass
  27. self.hasAuth = true
  28. var header = user + ':' + (pass || '')
  29. if (sendImmediately || typeof sendImmediately === 'undefined') {
  30. var authHeader = 'Basic ' + toBase64(header)
  31. self.sentAuth = true
  32. return authHeader
  33. }
  34. }
  35.  
  36. Auth.prototype.bearer = function (bearer, sendImmediately) {
  37. var self = this
  38. self.bearerToken = bearer
  39. self.hasAuth = true
  40. if (sendImmediately || typeof sendImmediately === 'undefined') {
  41. if (typeof bearer === 'function') {
  42. bearer = bearer()
  43. }
  44. var authHeader = 'Bearer ' + (bearer || '')
  45. self.sentAuth = true
  46. return authHeader
  47. }
  48. }
  49.  
  50. Auth.prototype.digest = function (method, path, authHeader) {
  51. // TODO: More complete implementation of RFC 2617.
  52. // - handle challenge.domain
  53. // - support qop="auth-int" only
  54. // - handle Authentication-Info (not necessarily?)
  55. // - check challenge.stale (not necessarily?)
  56. // - increase nc (not necessarily?)
  57. // For reference:
  58. // http://tools.ietf.org/html/rfc2617#section-3
  59. // https://github.com/bagder/curl/blob/master/lib/http_digest.c
  60.  
  61. var self = this
  62.  
  63. var challenge = {}
  64. var re = /([a-z0-9_-]+)=(?:"([^"]+)"|([a-z0-9_-]+))/gi
  65. for (;;) {
  66. var match = re.exec(authHeader)
  67. if (!match) {
  68. break
  69. }
  70. challenge[match[1]] = match[2] || match[3]
  71. }
  72.  
  73. /**
  74. * RFC 2617: handle both MD5 and MD5-sess algorithms.
  75. *
  76. * If the algorithm directive's value is "MD5" or unspecified, then HA1 is
  77. * HA1=MD5(username:realm:password)
  78. * If the algorithm directive's value is "MD5-sess", then HA1 is
  79. * HA1=MD5(MD5(username:realm:password):nonce:cnonce)
  80. */
  81. var ha1Compute = function (algorithm, user, realm, pass, nonce, cnonce) {
  82. var ha1 = md5(user + ':' + realm + ':' + pass)
  83. if (algorithm && algorithm.toLowerCase() === 'md5-sess') {
  84. return md5(ha1 + ':' + nonce + ':' + cnonce)
  85. } else {
  86. return ha1
  87. }
  88. }
  89.  
  90. var qop = /(^|,)\s*auth\s*($|,)/.test(challenge.qop) && 'auth'
  91. var nc = qop && '00000001'
  92. var cnonce = qop && uuid().replace(/-/g, '')
  93. var ha1 = ha1Compute(challenge.algorithm, self.user, challenge.realm, self.pass, challenge.nonce, cnonce)
  94. var ha2 = md5(method + ':' + path)
  95. var digestResponse = qop
  96. ? md5(ha1 + ':' + challenge.nonce + ':' + nc + ':' + cnonce + ':' + qop + ':' + ha2)
  97. : md5(ha1 + ':' + challenge.nonce + ':' + ha2)
  98. var authValues = {
  99. username: self.user,
  100. realm: challenge.realm,
  101. nonce: challenge.nonce,
  102. uri: path,
  103. qop: qop,
  104. response: digestResponse,
  105. nc: nc,
  106. cnonce: cnonce,
  107. algorithm: challenge.algorithm,
  108. opaque: challenge.opaque
  109. }
  110.  
  111. authHeader = []
  112. for (var k in authValues) {
  113. if (authValues[k]) {
  114. if (k === 'qop' || k === 'nc' || k === 'algorithm') {
  115. authHeader.push(k + '=' + authValues[k])
  116. } else {
  117. authHeader.push(k + '="' + authValues[k] + '"')
  118. }
  119. }
  120. }
  121. authHeader = 'Digest ' + authHeader.join(', ')
  122. self.sentAuth = true
  123. return authHeader
  124. }
  125.  
  126. Auth.prototype.onRequest = function (user, pass, sendImmediately, bearer) {
  127. var self = this
  128. var request = self.request
  129.  
  130. var authHeader
  131. if (bearer === undefined && user === undefined) {
  132. self.request.emit('error', new Error('no auth mechanism defined'))
  133. } else if (bearer !== undefined) {
  134. authHeader = self.bearer(bearer, sendImmediately)
  135. } else {
  136. authHeader = self.basic(user, pass, sendImmediately)
  137. }
  138. if (authHeader) {
  139. request.setHeader('authorization', authHeader)
  140. }
  141. }
  142.  
  143. Auth.prototype.onResponse = function (response) {
  144. var self = this
  145. var request = self.request
  146.  
  147. if (!self.hasAuth || self.sentAuth) { return null }
  148.  
  149. var c = caseless(response.headers)
  150.  
  151. var authHeader = c.get('www-authenticate')
  152. var authVerb = authHeader && authHeader.split(' ')[0].toLowerCase()
  153. request.debug('reauth', authVerb)
  154.  
  155. switch (authVerb) {
  156. case 'basic':
  157. return self.basic(self.user, self.pass, true)
  158.  
  159. case 'bearer':
  160. return self.bearer(self.bearerToken, true)
  161.  
  162. case 'digest':
  163. return self.digest(request.method, request.path, authHeader)
  164. }
  165. }
  166.  
  167. exports.Auth = Auth
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement