1

我正在尝试对服务器进行一些摘要授权,然后使用 nokogiri 解析生成的 HTML。我正在使用 net-http-digest_auth gem (https://github.com/drbrain/net-http-digest_auth) 进行 url 连接。一切都很好,直到我启动了 digest_auth 代码(第 20 行);它抛出一个“未知算法“MD5”错误'..

来自控制台的完整错误消息: ~/.rvm/gems/ruby-1.9.3-p194@rails32/gems/net-http-digest_auth-1.2.1/lib/net/http/digest_auth.rb:105:in 'auth_header': unknown algorithm ""MD5"" (Net::HTTP::DigestAuth::Error) from ./server_connection.rb:20:in '<main>'

第 20 行是 auth 行: auth = digest_auth.auth_header uri, res['www-authenticate'], 'GET'

这是我的完整代码(几乎完全逐字逐句地来自 github 链接上使用的示例代码):

#!/usr/bin/env ruby
require 'uri'
require 'net/http'
require 'net/http/digest_auth'

digest_auth = Net::HTTP::DigestAuth.new

uri = URI.parse 'http://url/controlpage?name=_internal_variables_&asList=1&useJS=True'
uri.user = 'username'
uri.password = 'password'

h = Net::HTTP.new uri.host, uri.port

req = Net::HTTP::Get.new uri.request_uri

res = h.request req

# res is a 401 response with a WWW-Authenticate header
auth = digest_auth.auth_header uri, res['www-authenticate'], 'GET'

# create a new request with the Authorization header
req = Net::HTTP::Get.new uri.request_uri
req.add_field 'Authorization', auth

# re-issue request with Authorization
res = h.request req

if res.code == "200"
  page = Nokogiri::HTML(res)
  isDaylight = page.css('.controlTitle:contains("isDaylight") ~ .controlValue');
  puts isDaylight.content
end

通过 Chrome 的开发工具更新了这个问题以包含请求标头:

GET /_getupdatedcontrols?name=_internal_variables_&asList=True&folderFilter=0&changeCount=479&serverState=idle HTTP/1.1
Host: url
Connection: keep-alive
Cache-Control: no-cache
Authorization: Digest username="username", realm="Indigo Control Server", nonce="71079e9f29f7210325ae451d0f423f07", uri="/_getupdatedcontrols?name=_internal_variables_&asList=True&folderFilter=0&changeCount=479&serverState=idle", algorithm=MD5, response="bc056cc472d35f7967973cb51c5b1a65", qop=auth, nc=00005649, cnonce="18dfcf3e4a7b809d"
X-Indigo-Web-Server-Version: 1
X-Prototype-Version: 1.6.0.3
X-Requested-With: XMLHttpRequest
Pragma: no-cache
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_4) AppleWebKit/536.11 (KHTML, like Gecko) Chrome/20.0.1132.17 Safari/536.11
Accept: text/javascript, text/html, application/xml, text/xml, */*
Referer: http://url/controlpage?name=_internal_variables_&asList=1&useJS=True
Accept-Encoding: gzip,deflate,sdch
Accept-Language: en-US,en;q=0.8
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3
4

2 回答 2

2

我最终使用httpclient gem来完成同样的事情。

完成我所追求的最终代码:

#!/usr/bin/env ruby
require 'httpclient'
require 'nokogiri'

c = HTTPClient.new
c.debug_dev = STDOUT

c.set_auth("http://domain.com", "username", "password")

doc = Nokogiri::HTML(c.get_content("http://domain.com"))
isDaylight = "";
doc.css('.controlTitle:contains("isDaylight") ~ .controlValue').each do |var|
  isDaylight = var.content
end

if (!isDaylight)
  system("curl -X PUT --digest -u username:password -d isOn=1 http://domain.com")
else
  system("curl -X PUT --digest -u username:password -d isOn=0 http://domain.com")
end

我希望这可以帮助其他可能正在使用家庭自动化服务器并需要轻松进行基于摘要的身份验证的人。

于 2012-05-28T17:48:09.223 回答
1

Seth,我在使用 ruby​​ 编写脚本时遇到了同样的问题。我是 ruby​​ 的新手,但经过一些谷歌搜索和一些 Charles Proxy 向我展示了发生了什么,我发现 HTTP 实现在 Auth 标头的 algorithm="MD5" 部分中包含引号是很常见的,这是不正确的根据规范(应该是算法=MD5,不带引号)。您从 Chrome devtools 更新的标头日志显示您的服务器响应符合规范,但 ruby​​ 库在解释该响应字符串时不是。这可以看出

您服务器的 401 响应包括:

注意 算法=MD5

Authorization: Digest username="username", realm="Indigo Control Server", nonce="71079e9f29f7210325ae451d0f423f07", uri="/_getupdatedcontrols?name=_internal_variables_&asList=True&folderFilter=0&changeCount=479&serverState=idle", algorithm=MD5, response="bc056cc472d35f7967973cb51c5b1a65", qop=auth, nc=00005649, cnonce="18dfcf3e4a7b809d"

但是使用这个 Ruby 库的初始请求的控制台输出显示:

注意 算法=\“MD5\”

<- "GET /some/request HTTP/1.1\r\nAccept: */*\r\nUser-Agent: Ruby\r\nConnection: close\r\nHost: 10.1.0.15\r\n\r\n"
-> "HTTP/1.1 401 Unauthorized\r\n"
-> "Content-Length: 530\r\n"
-> "Server: SomeServer/5.0\r\n"
-> "Allow: GET, HEAD, POST, PUT\r\n"
-> "Date: Sun, 27 Jan 2013 00:29:23 GMT\r\n"
-> "Content-Type: text/html;charset=utf-8\r\n"
-> "Www-Authenticate: Digest realm=\"Some Realm\", nonce=\"5a8b8b46cfb84466431baf454eb9ddb9\", algorithm=\"MD5\", qop=\"auth\"\r\n"

对于原始帖子中的脚本示例,我将插入以下两行:

www_auth_response = res['www-authenticate']
www_auth_response["algorithm=\"MD5\""] = "algorithm=MD5"

并修改第三行:

auth = digest_auth.auth_header uri, www_auth_response, 'GET'

如下:

...

res = h.request req

# res is a 401 response with a WWW-Authenticate header
www_auth_response = res['www-authenticate']
www_auth_response["algorithm=\"MD5\""] = "algorithm=MD5"
auth = digest_auth.auth_header uri, www_auth_response, 'GET'

# create a new request with the Authorization header
req = Net::HTTP::Get.new uri.request_uri
req.add_field 'Authorization', auth

...

这里发生的重要事情是我们正在修改从您最初的未经授权的 401 请求返回的 www-authenticate 字符串(由这个 ruby​​ 库解释)。将修改后的标头字符串 (www_auth_response) 发送到 digest_auth.auth_header 方法不会产生错误。至少这在我的剧本中对我有用!

我希望这会有所帮助!

马特

于 2013-01-27T01:03:40.363 回答