add auth_params

master
Kanezoh 2022-01-01 19:25:15 +09:00
parent 67051da876
commit c46539ea44
4 changed files with 247 additions and 1 deletions

View File

@ -0,0 +1,33 @@
require "./spec_helper"
describe "Mechanize HTTP Authentication test" do
it "auth_param" do
parser = Mechanize::HTTP::WWWAuthenticateParser.new
parser.scanner = StringScanner.new("realm=here")
parser.auth_param.should eq ["realm", "here"]
end
it "auth_param no value" do
parser = Mechanize::HTTP::WWWAuthenticateParser.new
parser.scanner = StringScanner.new("realm=")
parser.auth_param.should eq nil
end
it "auth_param bad token" do
parser = Mechanize::HTTP::WWWAuthenticateParser.new
parser.scanner = StringScanner.new("realm")
parser.auth_param.should eq nil
end
it "auth_param bad value" do
parser = Mechanize::HTTP::WWWAuthenticateParser.new
parser.scanner = StringScanner.new("realm=\"this ")
parser.auth_param.should eq nil
end
it "auth_param with quote" do
parser = Mechanize::HTTP::WWWAuthenticateParser.new
parser.scanner = StringScanner.new("realm=\"this site\"")
parser.auth_param.should eq ["realm", "this site"]
end
end

View File

@ -1,6 +1,7 @@
require "../cookie" require "../cookie"
require "../history" require "../history"
require "./auth_store" require "./auth_store"
require "./www_authenticate_parser"
class Mechanize class Mechanize
module HTTP module HTTP
@ -169,7 +170,7 @@ class Mechanize
private def save_response_cookies(response, uri, page) private def save_response_cookies(response, uri, page)
if page.body =~ /Set-Cookie/ if page.body =~ /Set-Cookie/
page.css("head meta[http-equiv=\"Set-Cookie\"]").each do |meta| page.css("head meta[http-equiv=\"Set-Cookie\"]").each do |meta|
cookie = meta["content"].split(";")[0] cookie = meta["content"].split(";") # [0]
key, value = cookie.split("=") key, value = cookie.split("=")
cookie = ::HTTP::Cookie.new(name: key, value: value) cookie = ::HTTP::Cookie.new(name: key, value: value)
save_cookies(uri, [cookie]) save_cookies(uri, [cookie])

View File

@ -0,0 +1,46 @@
class Mechanize
module HTTP
##
# A parsed WWW-Authenticate header
class AuthChallenge
property scheme : String?
property params : String?
def initialize(scheme = nil, params = nil)
end
# def [] param
# params[param]
# end
##
# Constructs an AuthRealm for this challenge
def realm(uri)
case scheme
when "Basic"
# raise ArgumentError, "provide uri for Basic authentication" unless uri
Mechanize::HTTP::AuthRealm.new scheme, uri + '/', self["realm"]
when "Digest"
Mechanize::HTTP::AuthRealm.new scheme, uri + '/', self["realm"]
else
# raise Mechanize::Error, "unknown HTTP authentication scheme #{scheme}"
end
end
##
# The name of the realm for this challenge
def realm_name
params["realm"] if Hash === params # NTLM has a string for params
end
##
# The raw authentication challenge
# alias to_s raw
end
end
end

View File

@ -0,0 +1,166 @@
require "string_scanner"
require "./auth_challenge"
##
# Parses the WWW-Authenticate HTTP header into separate challenges.
class Mechanize
module HTTP
class WWWAuthenticateParser
property scanner : StringScanner
# Creates a new header parser for WWW-Authenticate headers
def initialize
@scanner = StringScanner.new("")
end
# Parsers the header. Returns an Array of challenges as strings
def parse(www_authenticate : String)
challenges = [Mechanize::HTTP::AuthChallenge]
scanner = StringScanner.new(www_authenticate)
loop do
break if scanner.eos?
start = scanner.pos
challenge = Mechanize::HTTP::AuthChallenge.new
scheme = auth_scheme
if scheme == "Negotiate"
scan_comma_spaces
end
break unless scheme
challenge.scheme = scheme
space = spaces
if scheme == "NTLM"
if space
challenge.params = scanner.scan(/.*/)
end
# challenge.raw = www_authenticate[start, @scanner.pos]
challenges << challenge
next
else
scheme.capitalize!
end
# next unless space
# params = {}
# while true do
# pos = @scanner.pos
# name, value = auth_param
# name.downcase! if name =~ /^realm$/i
# unless name then
# challenge.params = params
# challenges << challenge
# if @scanner.eos? then
# challenge.raw = www_authenticate[start, @scanner.pos]
# break
# end
# @scanner.pos = pos # rewind
# challenge.raw = www_authenticate[start, @scanner.pos].sub(/(,+)? *$/, '')
# challenge = nil # a token should be next, new challenge
# break
# else
# params[name] = value
# end
# spaces
# @scanner.scan(/(, *)+/)
# end
end
challenges
end
# scans a comma followed by spaces
# needed for Negotiation, NTLM
def scan_comma_spaces
scanner.scan(/, +/)
end
# token = 1*<any CHAR except CTLs or separators>
#
# Parses a token
def token
scanner.scan(/[^\000-\037\177()<>@,;:\\"\/\[\]?={} ]+/)
end
def auth_scheme
token
end
##
# 1*SP
#
# Parses spaces
def spaces
scanner.scan(/ +/)
end
# auth-param = token "=" ( token | quoted-string )
#
# Parses an auth parameter
def auth_param : Array(String)?
return nil unless name = token
return nil unless scanner.scan(/ *= */)
value = if scanner.peek(1) == "\""
quoted_string
else
token
end
return nil unless value
return [name, value]
end
##
# quoted-string = ( <"> *(qdtext | quoted-pair ) <"> )
# qdtext = <any TEXT except <">>
# quoted-pair = "\" CHAR
#
# For TEXT, the rules of RFC 2047 are ignored.
def quoted_string
return nil unless @scanner.scan(/"/)
text = String.new
loop do
chunk = scanner.scan(/[\r\n \t\x21\x23-\x7e\x{0080}-\x{00ff}]+/) # not " which is \x22
if chunk
text += chunk
text += (scanner.scan(/./) || "") if chunk.ends_with?("\\") && "\"" == scanner.peek(1)
else
if "\"" == scanner.peek(1)
scanner.scan(/./)
break
else
return nil
end
end
end
text
end
end
end
end