summaryrefslogtreecommitdiffstats
path: root/net/http
diff options
context:
space:
mode:
authorcbentzel@chromium.org <cbentzel@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-02-26 21:07:45 +0000
committercbentzel@chromium.org <cbentzel@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-02-26 21:07:45 +0000
commiteb3cac713b9d8d6f1f12f55df9e05c56ba64af41 (patch)
tree7c4b924b753067f1800ea48ae1f3a47b587aa3bf /net/http
parent71bc0d0d454034744c1657e24edae9d31b569d66 (diff)
downloadchromium_src-eb3cac713b9d8d6f1f12f55df9e05c56ba64af41.zip
chromium_src-eb3cac713b9d8d6f1f12f55df9e05c56ba64af41.tar.gz
chromium_src-eb3cac713b9d8d6f1f12f55df9e05c56ba64af41.tar.bz2
Added HttpAuthFilter.
Original patch by ahendrickson@chromium.org (http://codereview.chromium.org/646068) BUG=29596 TEST=net_unittests.exe --gtest_filter="*HttpAuthFilterTest*" Review URL: http://codereview.chromium.org/660193 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@40157 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net/http')
-rw-r--r--net/http/http_auth_filter.cc50
-rw-r--r--net/http/http_auth_filter.h63
-rw-r--r--net/http/http_auth_filter_unittest.cc86
-rw-r--r--net/http/http_auth_handler_factory.cc28
-rw-r--r--net/http/http_auth_handler_factory.h45
-rw-r--r--net/http/http_auth_handler_factory_unittest.cc145
-rw-r--r--net/http/http_auth_handler_negotiate_win.cc10
-rw-r--r--net/http/http_auth_handler_ntlm_portable.cc7
-rw-r--r--net/http/http_auth_handler_ntlm_win.cc7
-rw-r--r--net/http/http_auth_unittest.cc214
10 files changed, 646 insertions, 9 deletions
diff --git a/net/http/http_auth_filter.cc b/net/http/http_auth_filter.cc
new file mode 100644
index 0000000..a75aa727
--- /dev/null
+++ b/net/http/http_auth_filter.cc
@@ -0,0 +1,50 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/http/http_auth_filter.h"
+
+#include "base/string_util.h"
+#include "googleurl/src/gurl.h"
+
+namespace net {
+
+HttpAuthFilterWhitelist::HttpAuthFilterWhitelist() {
+}
+
+HttpAuthFilterWhitelist::~HttpAuthFilterWhitelist() {
+}
+
+bool HttpAuthFilterWhitelist::SetFilters(const std::string& server_whitelist) {
+ // Parse the input string using commas as separators.
+ rules_.ParseFromString(server_whitelist);
+ return true;
+}
+
+bool HttpAuthFilterWhitelist::IsValid(const GURL& url,
+ HttpAuth::Target target) const {
+ if ((target != HttpAuth::AUTH_SERVER) && (target != HttpAuth::AUTH_PROXY))
+ return false;
+ // All proxies pass
+ if (target == HttpAuth::AUTH_PROXY)
+ return true;
+ return rules_.Matches(url);
+}
+
+// Add a new domain |filter| to the whitelist, if it's not already there
+bool HttpAuthFilterWhitelist::AddFilter(const std::string& filter,
+ HttpAuth::Target target) {
+ if ((target != HttpAuth::AUTH_SERVER) && (target != HttpAuth::AUTH_PROXY))
+ return false;
+ // All proxies pass
+ if (target == HttpAuth::AUTH_PROXY)
+ return true;
+ rules_.AddRuleFromString(filter);
+ return true;
+}
+
+void HttpAuthFilterWhitelist::AddRuleToBypassLocal() {
+ rules_.AddRuleToBypassLocal();
+}
+
+} // namespace net
diff --git a/net/http/http_auth_filter.h b/net/http/http_auth_filter.h
new file mode 100644
index 0000000..49fbe96
--- /dev/null
+++ b/net/http/http_auth_filter.h
@@ -0,0 +1,63 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef NET_HTTP_HTTP_AUTH_FILTER_H_
+#define NET_HTTP_HTTP_AUTH_FILTER_H_
+
+#include <string>
+#include <vector>
+
+#include "net/http/http_auth.h"
+#include "net/proxy/proxy_bypass_rules.h"
+
+class GURL;
+
+namespace net {
+
+// |HttpAuthFilter|s determine whether an authentication scheme should be
+// allowed for a particular peer.
+class HttpAuthFilter {
+ public:
+ virtual ~HttpAuthFilter() {}
+
+ // Checks if (|url|, |target|) is supported by the authentication scheme.
+ // Only the host of |url| is examined.
+ virtual bool IsValid(const GURL& url, HttpAuth::Target target) const = 0;
+};
+
+// Whitelist HTTP authentication filter.
+// Explicit whitelists of domains are set via SetFilters().
+//
+// Uses the ProxyBypassRules class to do whitelisting for servers.
+// All proxies are allowed.
+class HttpAuthFilterWhitelist : public HttpAuthFilter {
+ public:
+ HttpAuthFilterWhitelist();
+ virtual ~HttpAuthFilterWhitelist();
+
+ // Checks if (|url|, |target|) is supported by the authentication scheme.
+ // Only the host of |url| is examined.
+ bool IsValid(const GURL& url, HttpAuth::Target target) const;
+
+ // Installs the whitelist filters.
+ // |server_whitelist| is parsed by ProxyBypassRules.
+ bool SetFilters(const std::string& server_whitelist);
+
+ // Adds an individual URL |filter| to the list, of the specified |target|.
+ bool AddFilter(const std::string& filter, HttpAuth::Target target);
+
+ // Adds a rule that bypasses all "local" hostnames.
+ void AddRuleToBypassLocal();
+
+ const ProxyBypassRules& rules() const { return rules_; }
+
+ private:
+ ProxyBypassRules rules_;
+
+ DISALLOW_COPY_AND_ASSIGN(HttpAuthFilterWhitelist);
+};
+
+} // namespace net
+
+#endif // NET_HTTP_HTTP_AUTH_FILTER_H_
diff --git a/net/http/http_auth_filter_unittest.cc b/net/http/http_auth_filter_unittest.cc
new file mode 100644
index 0000000..a2ffb51
--- /dev/null
+++ b/net/http/http_auth_filter_unittest.cc
@@ -0,0 +1,86 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <iostream>
+
+#include "base/logging.h"
+#include "base/scoped_ptr.h"
+#include "googleurl/src/gurl.h"
+#include "net/http/http_auth_filter.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace net {
+
+namespace {
+
+struct UrlData {
+ GURL url;
+ HttpAuth::Target target;
+ bool matches;
+};
+
+static UrlData urls[] = {
+ { GURL(""),
+ HttpAuth::AUTH_NONE, false },
+ { GURL("http://foo.cn"),
+ HttpAuth::AUTH_PROXY, true },
+ { GURL("http://foo.cn"),
+ HttpAuth::AUTH_SERVER, false },
+ { GURL("http://slashdot.org"),
+ HttpAuth::AUTH_NONE, false },
+ { GURL("http://www.google.com"),
+ HttpAuth::AUTH_SERVER, true },
+ { GURL("http://www.google.com"),
+ HttpAuth::AUTH_PROXY, true },
+ { GURL("https://login.facebook.com/login.php?login_attempt=1"),
+ HttpAuth::AUTH_NONE, false },
+ { GURL("http://codereview.chromium.org/634002/show"),
+ HttpAuth::AUTH_SERVER, true },
+ { GURL("http://code.google.com/p/chromium/issues/detail?id=34505"),
+ HttpAuth::AUTH_SERVER, true },
+ { GURL("http://code.google.com/p/chromium/issues/list?can=2&q=label:"
+ "spdy&sort=owner&colspec=ID%20Stars%20Pri%20Area%20Type%20Status%20"
+ "Summary%20Modified%20Owner%20Mstone%20OS"),
+ HttpAuth::AUTH_SERVER, true },
+ { GURL("https://www.linkedin.com/secure/login?trk=hb_signin"),
+ HttpAuth::AUTH_SERVER, true },
+ { GURL("http://www.linkedin.com/mbox?displayMBoxItem=&"
+ "itemID=I1717980652_2&trk=COMM_HP_MSGVW_MEBC_MEBC&goback=.hom"),
+ HttpAuth::AUTH_SERVER, true },
+ { GURL("http://news.slashdot.org/story/10/02/18/190236/"
+ "New-Plan-Lets-Top-HS-Students-Graduate-2-Years-Early"),
+ HttpAuth::AUTH_PROXY, true },
+ { GURL("http://codereview.chromium.org/646068/diff/4001/5003"),
+ HttpAuth::AUTH_SERVER, true },
+ { GURL("http://codereview.chromium.gag/646068/diff/4001/5003"),
+ HttpAuth::AUTH_SERVER, true },
+ { GURL("http://codereview.chromium.gog/646068/diff/4001/5003"),
+ HttpAuth::AUTH_SERVER, true },
+};
+
+} // namespace
+
+TEST(HttpAuthFilterTest, EmptyFilter) {
+ // Create an empty filter
+ HttpAuthFilterWhitelist filter;
+ for (size_t i = 0; i < arraysize(urls); i++) {
+ EXPECT_EQ(urls[i].target == HttpAuth::AUTH_PROXY,
+ filter.IsValid(urls[i].url, urls[i].target))
+ << " " << i << ": " << urls[i].url;
+ }
+}
+
+TEST(HttpAuthFilterTest, NonEmptyFilter) {
+ // Create an non-empty filter
+ HttpAuthFilterWhitelist filter;
+ std::string server_filter =
+ "*google.com,*linkedin.com,*book.com,*.chromium.org,*.gag,*gog";
+ filter.SetFilters(server_filter);
+ for (size_t i = 0; i < arraysize(urls); i++) {
+ EXPECT_EQ(urls[i].matches, filter.IsValid(urls[i].url, urls[i].target))
+ << " " << i << ": " << urls[i].url;
+ }
+}
+
+} // namespace net
diff --git a/net/http/http_auth_handler_factory.cc b/net/http/http_auth_handler_factory.cc
index 36f1fcf..de7ef59 100644
--- a/net/http/http_auth_handler_factory.cc
+++ b/net/http/http_auth_handler_factory.cc
@@ -7,6 +7,7 @@
#include "base/stl_util-inl.h"
#include "base/string_util.h"
#include "net/base/net_errors.h"
+#include "net/http/http_auth_filter.h"
#include "net/http/http_auth_handler_basic.h"
#include "net/http/http_auth_handler_digest.h"
#include "net/http/http_auth_handler_negotiate.h"
@@ -24,7 +25,7 @@ int HttpAuthHandlerFactory::CreateAuthHandlerFromString(
}
// static
-HttpAuthHandlerFactory* HttpAuthHandlerFactory::CreateDefault() {
+HttpAuthHandlerRegistryFactory* HttpAuthHandlerFactory::CreateDefault() {
HttpAuthHandlerRegistryFactory* registry_factory =
new HttpAuthHandlerRegistryFactory();
registry_factory->RegisterSchemeFactory(
@@ -46,6 +47,21 @@ HttpAuthHandlerRegistryFactory::~HttpAuthHandlerRegistryFactory() {
factory_map_.end());
}
+void HttpAuthHandlerRegistryFactory::SetFilter(const std::string& scheme,
+ HttpAuthFilter* filter) {
+ HttpAuthHandlerFactory* factory = GetSchemeFactory(scheme);
+ if (factory)
+ factory->set_filter(filter);
+}
+
+const HttpAuthFilter* HttpAuthHandlerRegistryFactory::GetFilter(
+ const std::string& scheme) const {
+ HttpAuthHandlerFactory* factory = GetSchemeFactory(scheme);
+ if (factory)
+ return factory->filter();
+ return NULL;
+}
+
void HttpAuthHandlerRegistryFactory::RegisterSchemeFactory(
const std::string& scheme,
HttpAuthHandlerFactory* factory) {
@@ -79,4 +95,14 @@ int HttpAuthHandlerRegistryFactory::CreateAuthHandler(
return it->second->CreateAuthHandler(challenge, target, origin, handler);
}
+HttpAuthHandlerFactory* HttpAuthHandlerRegistryFactory::GetSchemeFactory(
+ const std::string& scheme) const {
+ std::string lower_scheme = StringToLowerASCII(scheme);
+ FactoryMap::const_iterator it = factory_map_.find(lower_scheme);
+ if (it == factory_map_.end()) {
+ return NULL; // |scheme| is not registered.
+ }
+ return it->second;
+}
+
} // namespace net
diff --git a/net/http/http_auth_handler_factory.h b/net/http/http_auth_handler_factory.h
index d0fec29..f677455 100644
--- a/net/http/http_auth_handler_factory.h
+++ b/net/http/http_auth_handler_factory.h
@@ -2,18 +2,22 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef NET_HTTP_HTTP_AUTH_HANDLER_FACTORY_H
-#define NET_HTTP_HTTP_AUTH_HANDLER_FACTORY_H
+#ifndef NET_HTTP_HTTP_AUTH_HANDLER_FACTORY_H_
+#define NET_HTTP_HTTP_AUTH_HANDLER_FACTORY_H_
#include <map>
+#include <string>
+#include "base/scoped_ptr.h"
#include "net/http/http_auth.h"
+#include "net/http/http_auth_filter.h"
class GURL;
namespace net {
class HttpAuthHandler;
+class HttpAuthHandlerRegistryFactory;
// An HttpAuthHandlerFactory is used to create HttpAuthHandler objects.
class HttpAuthHandlerFactory {
@@ -21,6 +25,16 @@ class HttpAuthHandlerFactory {
HttpAuthHandlerFactory() {}
virtual ~HttpAuthHandlerFactory() {}
+ // Sets an authentication filter.
+ void set_filter(HttpAuthFilter* filter) {
+ filter_.reset(filter);
+ }
+
+ // Retrieves the associated authentication filter.
+ const HttpAuthFilter* filter() const {
+ return filter_.get();
+ }
+
// Creates an HttpAuthHandler object based on the authentication
// challenge specified by |*challenge|. |challenge| must point to a valid
// non-NULL tokenizer.
@@ -34,6 +48,11 @@ class HttpAuthHandlerFactory {
// If |*challenge| is improperly formed, |*handler| is set to NULL and
// ERR_INVALID_RESPONSE is returned.
//
+ // For the NTLM and Negotiate handlers:
+ // If |origin| does not match the authentication method's filters for
+ // the specified |target|, ERR_INVALID_AUTH_CREDENTIALS is returned.
+ // NOTE: This will apply to ALL |origin| values if the filters are empty.
+ //
// |*challenge| should not be reused after a call to |CreateAuthHandler()|,
virtual int CreateAuthHandler(HttpAuth::ChallengeTokenizer* challenge,
HttpAuth::Target target,
@@ -50,12 +69,15 @@ class HttpAuthHandlerFactory {
const GURL& origin,
scoped_refptr<HttpAuthHandler>* handler);
- // Creates a standard HttpAuthHandlerFactory. The caller is responsible
- // for deleting the factory.
- // The default factory support Basic, Digest, NTLM, and Negotiate schemes.
- static HttpAuthHandlerFactory* CreateDefault();
+ // Creates a standard HttpAuthHandlerRegistryFactory. The caller is
+ // responsible for deleting the factory.
+ // The default factory supports Basic, Digest, NTLM, and Negotiate schemes.
+ static HttpAuthHandlerRegistryFactory* CreateDefault();
private:
+ // The authentication filter
+ scoped_ptr<HttpAuthFilter> filter_;
+
DISALLOW_COPY_AND_ASSIGN(HttpAuthHandlerFactory);
};
@@ -66,6 +88,12 @@ class HttpAuthHandlerRegistryFactory : public HttpAuthHandlerFactory {
HttpAuthHandlerRegistryFactory();
virtual ~HttpAuthHandlerRegistryFactory();
+ // Sets an authentication filter into the factory associated with |scheme|.
+ void SetFilter(const std::string& scheme, HttpAuthFilter* filter);
+
+ // Retrieves the authentication filter associated with |scheme|.
+ const HttpAuthFilter* GetFilter(const std::string& scheme) const;
+
// Registers a |factory| that will be used for a particular HTTP
// authentication scheme such as Basic, Digest, or Negotiate.
// The |*factory| object is assumed to be new-allocated, and its lifetime
@@ -85,6 +113,9 @@ class HttpAuthHandlerRegistryFactory : public HttpAuthHandlerFactory {
scoped_refptr<HttpAuthHandler>* handler);
private:
+ // Retrieve the factory for the specified |scheme|
+ HttpAuthHandlerFactory* GetSchemeFactory(const std::string& scheme) const;
+
typedef std::map<std::string, HttpAuthHandlerFactory*> FactoryMap;
FactoryMap factory_map_;
@@ -93,4 +124,4 @@ class HttpAuthHandlerRegistryFactory : public HttpAuthHandlerFactory {
} // namespace net
-#endif // NET_HTTP_HTTP_AUTH_HANDLER_FACTORY_H
+#endif // NET_HTTP_HTTP_AUTH_HANDLER_FACTORY_H_
diff --git a/net/http/http_auth_handler_factory_unittest.cc b/net/http/http_auth_handler_factory_unittest.cc
index e67bcca..6bbc7b8 100644
--- a/net/http/http_auth_handler_factory_unittest.cc
+++ b/net/http/http_auth_handler_factory_unittest.cc
@@ -137,7 +137,114 @@ TEST(HttpAuthHandlerFactoryTest, DefaultFactory) {
server_origin,
&handler);
EXPECT_EQ(OK, rv);
+ ASSERT_FALSE(handler.get() == NULL);
+ EXPECT_STREQ("ntlm", handler->scheme().c_str());
+ EXPECT_STREQ("", handler->realm().c_str());
+ EXPECT_EQ(HttpAuth::AUTH_SERVER, handler->target());
+ EXPECT_TRUE(handler->encrypts_identity());
+ EXPECT_TRUE(handler->is_connection_based());
+ }
+#if defined(OS_WIN)
+ {
+ scoped_refptr<HttpAuthHandler> handler;
+ int rv = http_auth_handler_factory->CreateAuthHandlerFromString(
+ "Negotiate",
+ HttpAuth::AUTH_SERVER,
+ server_origin,
+ &handler);
+ EXPECT_EQ(OK, rv);
EXPECT_FALSE(handler.get() == NULL);
+ EXPECT_STREQ("negotiate", handler->scheme().c_str());
+ EXPECT_STREQ("", handler->realm().c_str());
+ EXPECT_EQ(HttpAuth::AUTH_SERVER, handler->target());
+ EXPECT_TRUE(handler->encrypts_identity());
+ EXPECT_TRUE(handler->is_connection_based());
+ }
+#else // !defined(OS_WIN)
+ {
+ scoped_refptr<HttpAuthHandler> handler;
+ int rv = http_auth_handler_factory->CreateAuthHandlerFromString(
+ "Negotiate",
+ HttpAuth::AUTH_SERVER,
+ server_origin,
+ &handler);
+ EXPECT_EQ(ERR_UNSUPPORTED_AUTH_SCHEME, rv);
+ EXPECT_TRUE(handler.get() == NULL);
+ }
+#endif // !defined(OS_WIN)
+}
+
+TEST(HttpAuthHandlerFactoryTest, DefaultFactoryWithFilters) {
+ std::string ntlm_server_whitelist = "*example.com";
+ std::string negotiate_server_whitelist = "*example.com";
+ std::string ntlm_server_whitelist2 = "*example.org";
+ std::string negotiate_server_whitelist2 = "*example.org";
+
+ HttpAuthHandlerRegistryFactory* http_auth_handler_registry_factory =
+ HttpAuthHandlerFactory::CreateDefault();
+ scoped_ptr<HttpAuthHandlerFactory> http_auth_handler_factory(
+ http_auth_handler_registry_factory);
+ HttpAuthFilterWhitelist* ntlm_whitelist = new HttpAuthFilterWhitelist;
+ HttpAuthFilterWhitelist* negotiate_whitelist = new HttpAuthFilterWhitelist;
+
+ ntlm_whitelist->SetFilters(ntlm_server_whitelist);
+ negotiate_whitelist->SetFilters(negotiate_server_whitelist);
+
+ http_auth_handler_registry_factory->SetFilter("ntlm", ntlm_whitelist);
+ http_auth_handler_registry_factory->SetFilter("negotiate",
+ negotiate_whitelist);
+
+ GURL server_origin("http://www.example.com");
+ GURL proxy_origin("http://cache.example.com:3128");
+ {
+ scoped_refptr<HttpAuthHandler> handler;
+ int rv = http_auth_handler_factory->CreateAuthHandlerFromString(
+ "Basic realm=\"FooBar\"",
+ HttpAuth::AUTH_SERVER,
+ server_origin,
+ &handler);
+ EXPECT_EQ(OK, rv);
+ EXPECT_FALSE(handler.get() == NULL);
+ EXPECT_STREQ("basic", handler->scheme().c_str());
+ EXPECT_STREQ("FooBar", handler->realm().c_str());
+ EXPECT_EQ(HttpAuth::AUTH_SERVER, handler->target());
+ EXPECT_FALSE(handler->encrypts_identity());
+ EXPECT_FALSE(handler->is_connection_based());
+ }
+ {
+ scoped_refptr<HttpAuthHandler> handler;
+ int rv = http_auth_handler_factory->CreateAuthHandlerFromString(
+ "UNSUPPORTED realm=\"FooBar\"",
+ HttpAuth::AUTH_SERVER,
+ server_origin,
+ &handler);
+ EXPECT_EQ(ERR_UNSUPPORTED_AUTH_SCHEME, rv);
+ EXPECT_TRUE(handler.get() == NULL);
+ }
+ {
+ scoped_refptr<HttpAuthHandler> handler;
+ int rv = http_auth_handler_factory->CreateAuthHandlerFromString(
+ "Digest realm=\"FooBar\", nonce=\"xyz\"",
+ HttpAuth::AUTH_PROXY,
+ proxy_origin,
+ &handler);
+ EXPECT_EQ(OK, rv);
+ EXPECT_FALSE(handler.get() == NULL);
+ EXPECT_STREQ("digest", handler->scheme().c_str());
+ EXPECT_STREQ("FooBar", handler->realm().c_str());
+ EXPECT_EQ(HttpAuth::AUTH_PROXY, handler->target());
+ EXPECT_TRUE(handler->encrypts_identity());
+ EXPECT_FALSE(handler->is_connection_based());
+ }
+ {
+ scoped_refptr<HttpAuthHandler> handler;
+ int rv = http_auth_handler_factory->CreateAuthHandlerFromString(
+ "NTLM",
+ HttpAuth::AUTH_SERVER,
+ server_origin,
+ &handler);
+ EXPECT_EQ(OK, rv);
+ ASSERT_FALSE(handler.get() == NULL);
EXPECT_STREQ("ntlm", handler->scheme().c_str());
EXPECT_STREQ("", handler->realm().c_str());
EXPECT_EQ(HttpAuth::AUTH_SERVER, handler->target());
@@ -172,6 +279,44 @@ TEST(HttpAuthHandlerFactoryTest, DefaultFactory) {
EXPECT_TRUE(handler.get() == NULL);
}
#endif // !defined(OS_WIN)
+
+ // Now change the whitelist and expect failures.
+ ntlm_whitelist->SetFilters(ntlm_server_whitelist2);
+ negotiate_whitelist->SetFilters(negotiate_server_whitelist2);
+
+ {
+ scoped_refptr<HttpAuthHandler> handler;
+ int rv = http_auth_handler_factory->CreateAuthHandlerFromString(
+ "NTLM",
+ HttpAuth::AUTH_SERVER,
+ server_origin,
+ &handler);
+ EXPECT_EQ(ERR_INVALID_AUTH_CREDENTIALS, rv);
+ ASSERT_TRUE(handler.get() == NULL);
+ }
+#if defined(OS_WIN)
+ {
+ scoped_refptr<HttpAuthHandler> handler;
+ int rv = http_auth_handler_factory->CreateAuthHandlerFromString(
+ "Negotiate",
+ HttpAuth::AUTH_SERVER,
+ server_origin,
+ &handler);
+ EXPECT_EQ(ERR_INVALID_AUTH_CREDENTIALS, rv);
+ ASSERT_TRUE(handler.get() == NULL);
+ }
+#else // !defined(OS_WIN)
+ {
+ scoped_refptr<HttpAuthHandler> handler;
+ int rv = http_auth_handler_factory->CreateAuthHandlerFromString(
+ "Negotiate",
+ HttpAuth::AUTH_SERVER,
+ server_origin,
+ &handler);
+ EXPECT_EQ(ERR_UNSUPPORTED_AUTH_SCHEME, rv);
+ EXPECT_TRUE(handler.get() == NULL);
+ }
+#endif // !defined(OS_WIN)
}
} // namespace net
diff --git a/net/http/http_auth_handler_negotiate_win.cc b/net/http/http_auth_handler_negotiate_win.cc
index ffa48ef9..c09beb0 100644
--- a/net/http/http_auth_handler_negotiate_win.cc
+++ b/net/http/http_auth_handler_negotiate_win.cc
@@ -4,7 +4,9 @@
#include "net/http/http_auth_handler_negotiate.h"
+#include "base/logging.h"
#include "net/base/net_errors.h"
+#include "net/http/http_auth_filter.h"
namespace net {
@@ -92,6 +94,14 @@ int HttpAuthHandlerNegotiate::Factory::CreateAuthHandler(
scoped_refptr<HttpAuthHandler>* handler) {
if (is_unsupported_)
return ERR_UNSUPPORTED_AUTH_SCHEME;
+ if (filter() && !filter()->IsValid(origin, target)) {
+ LOG(INFO) << "URL " << origin
+ << "fails filter validation for authentication method "
+ << "Negotiate";
+
+ return ERR_INVALID_AUTH_CREDENTIALS;
+ }
+
if (max_token_length_ == 0) {
int rv = DetermineMaxTokenLength(sspi_library_, NEGOSSP_NAME,
&max_token_length_);
diff --git a/net/http/http_auth_handler_ntlm_portable.cc b/net/http/http_auth_handler_ntlm_portable.cc
index b6c7d32..c1ecdca 100644
--- a/net/http/http_auth_handler_ntlm_portable.cc
+++ b/net/http/http_auth_handler_ntlm_portable.cc
@@ -730,6 +730,13 @@ int HttpAuthHandlerNTLM::Factory::CreateAuthHandler(
HttpAuth::Target target,
const GURL& origin,
scoped_refptr<HttpAuthHandler>* handler) {
+ if (filter() && !filter()->IsValid(origin, target)) {
+ LOG(INFO) << "URL " << origin
+ << "fails filter validation for authentication method "
+ << "NTLM";
+
+ return ERR_INVALID_AUTH_CREDENTIALS;
+ }
// TODO(cbentzel): Move towards model of parsing in the factory
// method and only constructing when valid.
scoped_refptr<HttpAuthHandler> tmp_handler(new HttpAuthHandlerNTLM());
diff --git a/net/http/http_auth_handler_ntlm_win.cc b/net/http/http_auth_handler_ntlm_win.cc
index 989f1db..2de3411 100644
--- a/net/http/http_auth_handler_ntlm_win.cc
+++ b/net/http/http_auth_handler_ntlm_win.cc
@@ -79,6 +79,13 @@ int HttpAuthHandlerNTLM::Factory::CreateAuthHandler(
scoped_refptr<HttpAuthHandler>* handler) {
if (is_unsupported_)
return ERR_UNSUPPORTED_AUTH_SCHEME;
+ if (filter() && !filter()->IsValid(origin, target)) {
+ LOG(INFO) << "URL " << origin
+ << "fails filter validation for authentication method "
+ << "NTLM";
+
+ return ERR_INVALID_AUTH_CREDENTIALS;
+ }
if (max_token_length_ == 0) {
int rv = DetermineMaxTokenLength(sspi_library_, NTLMSP_NAME,
&max_token_length_);
diff --git a/net/http/http_auth_unittest.cc b/net/http/http_auth_unittest.cc
index 14308a0..70fc194 100644
--- a/net/http/http_auth_unittest.cc
+++ b/net/http/http_auth_unittest.cc
@@ -6,7 +6,9 @@
#include "base/ref_counted.h"
#include "base/scoped_ptr.h"
+#include "base/string_util.h"
#include "net/http/http_auth.h"
+#include "net/http/http_auth_filter.h"
#include "net/http/http_auth_handler.h"
#include "net/http/http_auth_handler_factory.h"
#include "net/http/http_response_headers.h"
@@ -70,7 +72,6 @@ TEST(HttpAuthTest, ChooseBestChallenge) {
}
};
GURL origin("http://www.example.com");
-
scoped_ptr<HttpAuthHandlerFactory> http_auth_handler_factory(
HttpAuthHandlerFactory::CreateDefault());
@@ -154,6 +155,217 @@ TEST(HttpAuthTest, ChooseBestChallengeConnectionBased) {
if (i != 0)
EXPECT_EQ(old_handler, handler);
+ ASSERT_NE(reinterpret_cast<net::HttpAuthHandler *>(NULL), handler.get());
+
+ EXPECT_STREQ(tests[i].challenge_realm, handler->realm().c_str());
+ }
+}
+
+TEST(HttpAuthTest, ChooseBestChallengeFiltered) {
+ static const struct {
+ const char* filter_string;
+ const char* headers;
+ const char* challenge_scheme;
+ const char* challenge_realm;
+ } tests[] = {
+ {
+ // Test that the filter does not affect Basic.
+ "*example.com",
+ "Y: Digest realm=\"X\", nonce=\"aaaaaaaaaa\"\n"
+ "www-authenticate: Basic realm=\"BasicRealm\"\n",
+
+ // Basic is the only challenge type, pick it.
+ "basic",
+ "BasicRealm",
+ },
+ {
+ // Test that the filter does not affect Fake.
+ "*example.com",
+ "Y: Digest realm=\"FooBar\", nonce=\"aaaaaaaaaa\"\n"
+ "www-authenticate: Fake realm=\"FooBar\"\n",
+
+ // Fake is the only challenge type, but it is unsupported.
+ "",
+ "",
+ },
+ {
+ // Test that the filter does not affect Digest vs. Basic.
+ "*example.com",
+ "www-authenticate: Basic realm=\"FooBar\"\n"
+ "www-authenticate: Fake realm=\"FooBar\"\n"
+ "www-authenticate: nonce=\"aaaaaaaaaa\"\n"
+ "www-authenticate: Digest realm=\"DigestRealm\", nonce=\"aaaaaaaaaa\"\n",
+
+ // Pick Digest over Basic.
+ "digest",
+ "DigestRealm",
+ },
+ {
+ // Test that the filter does not affect null header.
+ "*example.com",
+ "Y: Digest realm=\"X\", nonce=\"aaaaaaaaaa\"\n"
+ "www-authenticate:\n",
+
+ // Handle null header value.
+ "",
+ "",
+ },
+ {
+ // Test that the filter works with a valid whitelist.
+ "*example.com",
+ "WWW-Authenticate: Negotiate\n"
+ "WWW-Authenticate: NTLM\n",
+
+ // Negotiate is not currently support on non-Windows platforms, so
+ // the choice varies depending on platform.
+#if defined(OS_WIN)
+ "negotiate",
+ "",
+#else
+ "ntlm",
+ "",
+#endif
+ },
+ {
+ // Test that fall back does not occur if NTLM is allowed by whitelist.
+ "*example.com",
+ "WWW-Authenticate: NTLM\n"
+ "www-authenticate: Digest realm=\"DigestRealm\", nonce=\"aaaaaaaaaa\"\n",
+
+ "ntlm",
+ "",
+ },
+ {
+ // Test that the filter prevents access if URL is not in whitelist.
+ "*example.org",
+ "WWW-Authenticate: Negotiate\n"
+ "WWW-Authenticate: NTLM\n",
+
+ // Negotiate is not currently support on non-Windows platforms, so
+ // the choice varies depending on platform.
+ "",
+ "",
+ },
+ {
+ // Test that fall back occurs if NTLM is not allowed by whitelist.
+ "*example.org",
+ "WWW-Authenticate: NTLM\n"
+ "www-authenticate: Digest realm=\"DigestRealm\", nonce=\"aaaaaaaaaa\"\n",
+
+ "digest",
+ "DigestRealm",
+ }
+ };
+ GURL origin("http://www.example.com");
+
+ HttpAuthHandlerRegistryFactory* http_auth_handler_registry_factory =
+ HttpAuthHandlerFactory::CreateDefault();
+ scoped_ptr<HttpAuthHandlerFactory> http_auth_handler_factory(
+ http_auth_handler_registry_factory);
+ HttpAuthFilterWhitelist* ntlm_whitelist = new HttpAuthFilterWhitelist;
+ HttpAuthFilterWhitelist* negotiate_whitelist = new HttpAuthFilterWhitelist;
+ http_auth_handler_registry_factory->SetFilter("ntlm", ntlm_whitelist);
+ http_auth_handler_registry_factory->SetFilter("negotiate",
+ negotiate_whitelist);
+
+ for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
+ ntlm_whitelist->SetFilters(tests[i].filter_string);
+ negotiate_whitelist->SetFilters(tests[i].filter_string);
+ // Make a HttpResponseHeaders object.
+ std::string headers_with_status_line("HTTP/1.1 401 Unauthorized\n");
+ headers_with_status_line += tests[i].headers;
+ scoped_refptr<net::HttpResponseHeaders> headers(
+ new net::HttpResponseHeaders(
+ net::HttpUtil::AssembleRawHeaders(
+ headers_with_status_line.c_str(),
+ headers_with_status_line.length())));
+
+ scoped_refptr<HttpAuthHandler> handler;
+ HttpAuth::ChooseBestChallenge(http_auth_handler_factory.get(),
+ headers.get(),
+ HttpAuth::AUTH_SERVER,
+ origin,
+ &handler);
+
+ if (handler) {
+ EXPECT_STREQ(tests[i].challenge_scheme, handler->scheme().c_str());
+ EXPECT_STREQ(tests[i].challenge_realm, handler->realm().c_str());
+ } else {
+ EXPECT_STREQ("", tests[i].challenge_scheme);
+ EXPECT_STREQ("", tests[i].challenge_realm);
+ }
+ }
+}
+
+TEST(HttpAuthTest, ChooseBestChallengeConnectionBasedFiltered) {
+ static const struct {
+ const char* headers;
+ const char* challenge_realm;
+ } tests[] = {
+ {
+ "WWW-Authenticate: NTLM\r\n",
+
+ "",
+ },
+ {
+ "WWW-Authenticate: NTLM "
+ "TlRMTVNTUAACAAAADAAMADgAAAAFgokCTroKF1e/DRcAAAAAAAAAALo"
+ "AugBEAAAABQEoCgAAAA9HAE8ATwBHAEwARQACAAwARwBPAE8ARwBMAE"
+ "UAAQAaAEEASwBFAEUAUwBBAFIAQQAtAEMATwBSAFAABAAeAGMAbwByA"
+ "HAALgBnAG8AbwBnAGwAZQAuAGMAbwBtAAMAQABhAGsAZQBlAHMAYQBy"
+ "AGEALQBjAG8AcgBwAC4AYQBkAC4AYwBvAHIAcAAuAGcAbwBvAGcAbAB"
+ "lAC4AYwBvAG0ABQAeAGMAbwByAHAALgBnAG8AbwBnAGwAZQAuAGMAbw"
+ "BtAAAAAAA=\r\n",
+
+ // Realm is empty.
+ "",
+ }
+ };
+ GURL origin("http://www.example.com");
+
+ scoped_refptr<HttpAuthHandler> handler;
+ std::string ntlm_server_whitelist = "*example.com";
+ std::string negotiate_server_whitelist = "*example.com";
+
+ HttpAuthHandlerRegistryFactory* http_auth_handler_registry_factory =
+ HttpAuthHandlerFactory::CreateDefault();
+ scoped_ptr<HttpAuthHandlerFactory> http_auth_handler_factory(
+ http_auth_handler_registry_factory);
+ HttpAuthFilterWhitelist* ntlm_whitelist = new HttpAuthFilterWhitelist;
+ HttpAuthFilterWhitelist* negotiate_whitelist = new HttpAuthFilterWhitelist;
+
+ ntlm_whitelist->SetFilters(ntlm_server_whitelist);
+ negotiate_whitelist->SetFilters(negotiate_server_whitelist);
+
+ http_auth_handler_registry_factory->SetFilter("ntlm", ntlm_whitelist);
+ http_auth_handler_registry_factory->SetFilter("negotiate",
+ negotiate_whitelist);
+
+ for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
+ // Make a HttpResponseHeaders object.
+ std::string headers_with_status_line("HTTP/1.1 401 Unauthorized\n");
+ headers_with_status_line += tests[i].headers;
+ scoped_refptr<net::HttpResponseHeaders> headers(
+ new net::HttpResponseHeaders(
+ net::HttpUtil::AssembleRawHeaders(
+ headers_with_status_line.c_str(),
+ headers_with_status_line.length())));
+
+ scoped_refptr<HttpAuthHandler> old_handler = handler;
+ HttpAuth::ChooseBestChallenge(http_auth_handler_factory.get(),
+ headers.get(),
+ HttpAuth::AUTH_SERVER,
+ origin,
+ &handler);
+
+ EXPECT_TRUE(handler != NULL);
+ // Since NTLM is connection-based, we should continue to use the existing
+ // handler rather than creating a new one.
+ if (i != 0)
+ EXPECT_EQ(old_handler, handler);
+
+ ASSERT_NE(reinterpret_cast<net::HttpAuthHandler *>(NULL), handler.get());
+
EXPECT_STREQ(tests[i].challenge_realm, handler->realm().c_str());
}
}