From f4f38a41a579c181e8a587b13b6947089ee98c78 Mon Sep 17 00:00:00 2001 From: Kanezoh Date: Sun, 2 Jan 2022 22:14:58 +0900 Subject: [PATCH] add challenges_for --- spec/http_auth_store_spec.cr | 72 ++++++++++++++++++++++++++-- spec/www_authenticate_parser_spec.cr | 26 +++++----- src/mechanize/http/auth_challenge.cr | 11 +++-- src/mechanize/http/auth_store.cr | 42 +++++++++++----- 4 files changed, 117 insertions(+), 34 deletions(-) diff --git a/spec/http_auth_store_spec.cr b/spec/http_auth_store_spec.cr index e52f8a7..d86b493 100644 --- a/spec/http_auth_store_spec.cr +++ b/spec/http_auth_store_spec.cr @@ -9,16 +9,80 @@ describe "Mechanize AuthStore test" do realm = "" auth_store.add_auth(url, user, password) auth_store.auth_accounts[url].size.should eq 1 - auth_store.auth_accounts[url][realm].should eq(["kanezoh", "password", nil]) + auth_store.auth_accounts[url][realm].should eq(["kanezoh", "password", ""]) end - it "credentials_for" do + it "test_add_auth_domain" do auth_store = Mechanize::HTTP::AuthStore.new url = URI.parse("http://example.com/") user = "kanezoh" password = "password" + domain = "domain" realm = "" - auth_store.add_auth(url, user, password) - auth_store.credentials_for(url, realm).should eq ["kanezoh", "password", nil] + auth_store.add_auth(url, user, password, nil, domain) + auth_store.auth_accounts[url][realm].should eq(["kanezoh", "password", "domain"]) + end + + it "test_add_auth_realm" do + auth_store = Mechanize::HTTP::AuthStore.new + url = URI.parse("http://example.com/") + auth_store.add_auth url, "user1", "pass" + auth_store.add_auth url, "user2", "pass", "realm" + + expected = { + url => { + "" => ["user1", "pass", ""], + "realm" => ["user2", "pass", ""], + }, + } + + auth_store.auth_accounts.should eq expected + end + + it "test_add_auth_realm_case" do + auth_store = Mechanize::HTTP::AuthStore.new + url = URI.parse("http://example.com/") + auth_store.add_auth url, "user1", "pass", "realm" + auth_store.add_auth url, "user2", "pass", "Realm" + + expected = { + url => { + "realm" => ["user1", "pass", ""], + "Realm" => ["user2", "pass", ""], + }, + } + + auth_store.auth_accounts.should eq expected + end + + it "test_add_auth_string" do + auth_store = Mechanize::HTTP::AuthStore.new + url = URI.parse("http://example.com/") + auth_store.add_auth "#{url}/path", "user", "pass" + + expected = { + url => { + "" => ["user", "pass", ""], + }, + } + + auth_store.auth_accounts.should eq expected + end + + it "test_credentials_eh" do + auth_store = Mechanize::HTTP::AuthStore.new + url = URI.parse("http://example.com/") + + challenges = [ + Mechanize::HTTP::AuthChallenge.new("Basic", {"realm" => "r"}), + Mechanize::HTTP::AuthChallenge.new("Digest", {"realm" => "r"}), + ] + + auth_store.credentials?(url, challenges).should_not eq true + + auth_store.add_auth url, "user", "pass" + + auth_store.credentials?(url, challenges).should eq true + auth_store.credentials?("#{url}/path", challenges).should eq true end end diff --git a/spec/www_authenticate_parser_spec.cr b/spec/www_authenticate_parser_spec.cr index f280a5e..0c271e2 100644 --- a/spec/www_authenticate_parser_spec.cr +++ b/spec/www_authenticate_parser_spec.cr @@ -65,12 +65,10 @@ describe "Mechanize HTTP Authentication test" do result[1].raw.should eq expect[1].raw end - - it "test_parse_multiple_without_comma_delimiter" do expect = [ - challenge("Basic", { "realm" => "foo" }, "Basic realm=foo"), - challenge("Digest", { "realm" => "bar" }, "Digest realm=bar"), + challenge("Basic", {"realm" => "foo"}, "Basic realm=foo"), + challenge("Digest", {"realm" => "bar"}, "Digest realm=bar"), ] parser = Mechanize::HTTP::WWWAuthenticateParser.new @@ -85,8 +83,8 @@ describe "Mechanize HTTP Authentication test" do it "test_parse_multiple_blank" do expect = [ - challenge("Basic", { "realm" => "foo" }, "Basic realm=foo"), - challenge("Digest", { "realm" => "bar" }, "Digest realm=bar"), + challenge("Basic", {"realm" => "foo"}, "Basic realm=foo"), + challenge("Digest", {"realm" => "bar"}, "Digest realm=bar"), ] parser = Mechanize::HTTP::WWWAuthenticateParser.new @@ -111,7 +109,7 @@ describe "Mechanize HTTP Authentication test" do result[0].raw.should eq expect[0].raw end - it "test_parse_ntlm_type_2_3" do + it "test_parse_ntlm_type_2_3" do expect = [ challenge("NTLM", "foo=", "NTLM foo="), ] @@ -125,7 +123,7 @@ describe "Mechanize HTTP Authentication test" do it "test_parse_realm_uppercase" do expect = [ - challenge("Basic", { "realm" => "foo" }, "Basic ReAlM=foo"), + challenge("Basic", {"realm" => "foo"}, "Basic ReAlM=foo"), ] parser = Mechanize::HTTP::WWWAuthenticateParser.new @@ -137,7 +135,7 @@ describe "Mechanize HTTP Authentication test" do it "test_parse_realm_value_case" do expect = [ - challenge("Basic", { "realm" => "Foo" }, "Basic realm=Foo"), + challenge("Basic", {"realm" => "Foo"}, "Basic realm=Foo"), ] parser = Mechanize::HTTP::WWWAuthenticateParser.new @@ -149,7 +147,7 @@ describe "Mechanize HTTP Authentication test" do it "test_parse_scheme_uppercase" do expect = [ - challenge("Basic", { "realm" => "foo" }, "BaSiC realm=foo"), + challenge("Basic", {"realm" => "foo"}, "BaSiC realm=foo"), ] parser = Mechanize::HTTP::WWWAuthenticateParser.new @@ -159,9 +157,9 @@ describe "Mechanize HTTP Authentication test" do result[0].raw.should eq expect[0].raw end - it "test_parse_bad_whitespace_around_auth_param" do + it "test_parse_bad_whitespace_around_auth_param" do expect = [ - challenge("Basic", { "realm" => "foo" }, "Basic realm = \"foo\""), + challenge("Basic", {"realm" => "foo"}, "Basic realm = \"foo\""), ] parser = Mechanize::HTTP::WWWAuthenticateParser.new @@ -173,7 +171,7 @@ describe "Mechanize HTTP Authentication test" do it "test_parse_bad_single_quote" do expect = [ - challenge("Basic", { "realm" => "'foo" }, "Basic realm='foo"), + challenge("Basic", {"realm" => "'foo"}, "Basic realm='foo"), ] parser = Mechanize::HTTP::WWWAuthenticateParser.new @@ -205,7 +203,7 @@ describe "Mechanize HTTP Authentication test" do parser = Mechanize::HTTP::WWWAuthenticateParser.new parser.scanner = StringScanner.new "\"escaped \\\" here\"" - string = parser.quoted_string + string = parser.quoted_string string.should eq "escaped \\\" here" end diff --git a/src/mechanize/http/auth_challenge.cr b/src/mechanize/http/auth_challenge.cr index dd485a9..fd78ccb 100644 --- a/src/mechanize/http/auth_challenge.cr +++ b/src/mechanize/http/auth_challenge.cr @@ -6,12 +6,12 @@ class Mechanize class AuthChallenge property scheme : String? property params : String? | Hash(String, String)? - property raw : String + property raw : String def initialize(scheme = nil, params = nil, raw = "") @scheme = scheme @params = params - @raw = raw + @raw = raw end def [](param) @@ -37,7 +37,12 @@ class Mechanize # The name of the realm for this challenge def realm_name - params["realm"] if Hash === params # NTLM has a string for params + params_value = params + if params_value.is_a?(Hash) + params_value["realm"] # NTLM has a string for params + else + nil + end end ## diff --git a/src/mechanize/http/auth_store.cr b/src/mechanize/http/auth_store.cr index d40000b..f89570d 100644 --- a/src/mechanize/http/auth_store.cr +++ b/src/mechanize/http/auth_store.cr @@ -2,38 +2,54 @@ class Mechanize module HTTP # This class store info for HTTP Authentication. class AuthStore - getter auth_accounts : Hash(URI, Hash(String, Array(String?))) + getter auth_accounts : Hash(URI, Hash(String, Array(String))) def initialize - @auth_accounts = Hash(URI, Hash(String, Array(String?))).new + @auth_accounts = Hash(URI, Hash(String, Array(String))).new end def add_auth(uri : String | URI, user : String, pass : String, realm : String? = nil, domain : String? = nil) unless uri.is_a?(URI) - uri = URI.new(uri) + uri = URI.parse(uri) end - # uri += '/' + uri.path = "/" uri.user = nil uri.password = nil - if realm.nil? - realm = "" - end + realm = "" if realm.nil? + domain = "" if domain.nil? + realm_hash = {realm => [user, pass, domain]} - auth_accounts[uri] = realm_hash + if auth_accounts.has_key?(uri) + auth_accounts[uri].merge!(realm_hash) + else + auth_accounts[uri] = realm_hash + end + end + + ## + # Returns true if credentials exist for the +challenges+ from the server at + # +uri+. + + def credentials?(uri, challenges) + challenges.any? do |challenge| + credentials_for uri, challenge.realm_name + end end # Retrieves credentials for +realm+ on the server at +uri+. - def credentials_for(uri : String | URI, realm : String) : Array(String?) + def credentials_for(uri : String | URI, realm : String?) : Array(String)? unless uri.is_a?(URI) - uri = URI.new(uri) + uri = URI.parse(uri) end - # uri += '/' + uri.path = "/" uri.user = nil uri.password = nil + realm = "" if realm.nil? - realms = auth_accounts[uri] + realms = auth_accounts.fetch(uri, nil) + return nil if realms.nil? - realms[realm] + realms.fetch(realm, nil) || realms.fetch("", nil) end end end