Support using a callback in auth.js config file

This commit is contained in:
Zaid Abdulla committed 2017-02-12 02:34:55 -08:00
1 parent 340016813c
commit 8e34c6a2f6
1 file changed
+66 -53
+66 -53
View File
@@ -49,6 +49,7 @@ util = require 'util'
URL = require 'url' URL = require 'url'
auth = require './auth' auth = require './auth'
udpConReq = (address, un, key, callback) -> udpConReq = (address, un, key, callback) ->
[host, port] = address.split(':', 2) [host, port] = address.split(':', 2)
@@ -71,8 +72,9 @@ udpConReq = (address, un, key, callback) ->
) )
connectionRequest = (deviceId, callback) -> httpConReq = (url, username, password, timeout, callback) ->
# ensure socket is reused in case of digest authentication options = URL.parse(url)
# Ensure socket is reused in case of digest authentication
agent = new http.Agent({maxSockets : 1}) agent = new http.Agent({maxSockets : 1})
statusToError = (statusCode) -> statusToError = (statusCode) ->
@@ -86,34 +88,54 @@ connectionRequest = (deviceId, callback) ->
else else
new Error("Unexpected response code from device: #{statusCode}") new Error("Unexpected response code from device: #{statusCode}")
conReq = (url, authString, callback) -> request = http.get(options, (res) ->
options = URL.parse(url) if res.statusCode == 401 and res.headers['www-authenticate']?
options.agent = agent authHeader = auth.parseAuthHeader(res.headers['www-authenticate'])
if authHeader.method is 'Basic'
options.headers = {'Authorization' : auth.basic(username, password)}
else if authHeader.method is 'Digest'
options.headers = {
'Authorization' : auth.digest(username, password, options.path, 'GET', null, authHeader)
}
if authString request = http.get(options, (res) ->
options.headers = {'Authorization' : authString} if res.statusCode == 0
# Workaround for some devices unexpectedly closing the connection
request = http.get(options, (res) -> request = http.get(options, (res) ->
if res.statusCode == 401 and res.headers['www-authenticate']? callback(statusToError(res.statusCode))
authHeader = auth.parseAuthHeader(res.headers['www-authenticate']) res.resume()
callback(res.statusCode, authHeader) ).on('error', (err) ->
# don't need body, go ahead and emit events to free up the socket for possible reuse request.abort()
res.resume() callback(statusToError(0))
) ).on('socket', (socket) ->
socket.setTimeout(timeout)
request.on('error', (err) -> socket.on('timeout', () -> request.abort())
# error event when request is aborted )
request.abort() else
callback(0) callback(statusToError(res.statusCode))
) res.resume()
).on('error', (err) ->
request.on('socket', (socket) ->
socket.setTimeout(2000)
socket.on('timeout', () ->
request.abort() request.abort()
callback(statusToError(0))
).on('socket', (socket) ->
socket.setTimeout(timeout)
socket.on('timeout', () -> request.abort())
) )
) else
callback(statusToError(res.statusCode))
# No listener for data so emit resume
res.resume()
).on('error', (err) ->
request.abort()
callback(statusToError(0))
).on('socket', (socket) ->
socket.setTimeout(timeout)
socket.on('timeout', () -> request.abort())
)
connectionRequest = (deviceId, callback) ->
proj = { proj = {
'Device.ManagementServer.ConnectionRequestURL._value' : 1, 'Device.ManagementServer.ConnectionRequestURL._value' : 1,
'Device.ManagementServer.UDPConnectionRequestAddress._value' : 1, 'Device.ManagementServer.UDPConnectionRequestAddress._value' : 1,
@@ -126,9 +148,7 @@ connectionRequest = (deviceId, callback) ->
} }
db.devicesCollection.findOne({_id : deviceId}, proj, (err, device)-> db.devicesCollection.findOne({_id : deviceId}, proj, (err, device)->
if err return callback(err) if err
callback(err)
return
if device.Device? # TR-181 data model if device.Device? # TR-181 data model
connectionRequestUrl = device.Device.ManagementServer.ConnectionRequestURL._value connectionRequestUrl = device.Device.ManagementServer.ConnectionRequestURL._value
@@ -141,33 +161,26 @@ connectionRequest = (deviceId, callback) ->
username = device.InternetGatewayDevice.ManagementServer.ConnectionRequestUsername?._value username = device.InternetGatewayDevice.ManagementServer.ConnectionRequestUsername?._value
password = device.InternetGatewayDevice.ManagementServer.ConnectionRequestPassword?._value password = device.InternetGatewayDevice.ManagementServer.ConnectionRequestPassword?._value
if not (username and password) and config.auth?.connectionRequest conReq = () ->
[username, password] = config.auth.connectionRequest(deviceId) if udpConnectionRequestAddress
udpConReq(udpConnectionRequestAddress, username, password, (err) -> throw err if err)
if udpConnectionRequestAddress httpConReq(connectionRequestUrl, username, password, 2000, (err) ->
udpConReq(udpConnectionRequestAddress, username, password, (err) -> throw err if err) if udpConnectionRequestAddress
return callback()
callback(err)
)
# for testing if config.auth?.connectionRequest?
#connectionRequestUrl = connectionRequestUrl.replace(/^(http:\/\/)([0-9\.]+)(\:[0-9]+\/[a-zA-Z0-9]+\/?$)/, '$110.1.1.254$3') # Callback is optional for backward compatibility
conReq(connectionRequestUrl, null, (statusCode, authHeader) -> if config.auth.connectionRequest.length > 4
if statusCode == 401 return config.auth.connectionRequest(deviceId, connectionRequestUrl, username, password, (u, p) ->
if authHeader.method is 'Basic' username = u
authString = auth.basic(username, password) password = p
else if authHeader.method is 'Digest' conReq()
uri = URL.parse(connectionRequestUrl)
authString = auth.digest(username, password, uri.path, 'GET', null, authHeader)
conReq(connectionRequestUrl, authString, (statusCode, authHeader) ->
if statusCode == 0
# Workaround for some devices unexpectedly closing the connection
return conReq(connectionRequestUrl, authString, (statusCode) -> callback(statusToError(statusCode)))
callback(statusToError(statusCode))
) )
else if udpConnectionRequestAddress [username, password] = config.auth.connectionRequest(deviceId, connectionRequestUrl, username, password)
return callback() conReq()
else
callback(statusToError(statusCode))
)
) )