Commit 310ef922 authored by Asanka Herath's avatar Asanka Herath Committed by Commit Bot

[net/auth] Add NetLog support to Posix GSSAPI implementation.

This change uses the plumbing introduced in prior CLs to perform
detailed logging of GSSAPI library invocations.

R=eroman@chromium.org

Bug: 884313
Change-Id: Id010fda54f32691a092edd97385470502d18d15f
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1698942
Commit-Queue: Asanka Herath <asanka@chromium.org>
Reviewed-by: default avatarMaks Orlovich <morlovich@chromium.org>
Reviewed-by: default avatarBo <boliu@chromium.org>
Reviewed-by: default avatarEric Roman <eroman@chromium.org>
Cr-Commit-Position: refs/heads/master@{#680116}
parent 29d3cc04
...@@ -695,7 +695,7 @@ void NetworkServiceClient::OnGenerateHttpNegotiateAuthToken( ...@@ -695,7 +695,7 @@ void NetworkServiceClient::OnGenerateHttpNegotiateAuthToken(
auth_negotiate->set_can_delegate(can_delegate); auth_negotiate->set_can_delegate(can_delegate);
auto auth_token = std::make_unique<std::string>(); auto auth_token = std::make_unique<std::string>();
auth_negotiate_raw->GenerateAuthToken( auth_negotiate_raw->GenerateAuthTokenAndroid(
nullptr, spn, std::string(), auth_token.get(), nullptr, spn, std::string(), auth_token.get(),
base::BindOnce(&FinishGenerateNegotiateAuthToken, base::BindOnce(&FinishGenerateNegotiateAuthToken,
std::move(auth_negotiate), std::move(auth_token), std::move(auth_negotiate), std::move(auth_token),
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include "net/http/http_auth_challenge_tokenizer.h" #include "net/http/http_auth_challenge_tokenizer.h"
#include "net/http/http_auth_multi_round_parse.h" #include "net/http/http_auth_multi_round_parse.h"
#include "net/http/http_auth_preferences.h" #include "net/http/http_auth_preferences.h"
#include "net/log/net_log_with_source.h"
#include "net/net_jni_headers/HttpNegotiateAuthenticator_jni.h" #include "net/net_jni_headers/HttpNegotiateAuthenticator_jni.h"
using base::android::AttachCurrentThread; using base::android::AttachCurrentThread;
...@@ -69,7 +70,7 @@ HttpAuthNegotiateAndroid::HttpAuthNegotiateAndroid( ...@@ -69,7 +70,7 @@ HttpAuthNegotiateAndroid::HttpAuthNegotiateAndroid(
HttpAuthNegotiateAndroid::~HttpAuthNegotiateAndroid() { HttpAuthNegotiateAndroid::~HttpAuthNegotiateAndroid() {
} }
bool HttpAuthNegotiateAndroid::Init() { bool HttpAuthNegotiateAndroid::Init(const NetLogWithSource& net_log) {
return true; return true;
} }
...@@ -92,11 +93,22 @@ HttpAuth::AuthorizationResult HttpAuthNegotiateAndroid::ParseChallenge( ...@@ -92,11 +93,22 @@ HttpAuth::AuthorizationResult HttpAuthNegotiateAndroid::ParseChallenge(
&decoded_auth_token); &decoded_auth_token);
} }
int HttpAuthNegotiateAndroid::GenerateAuthTokenAndroid(
const AuthCredentials* credentials,
const std::string& spn,
const std::string& channel_bindings,
std::string* auth_token,
net::CompletionOnceCallback callback) {
return GenerateAuthToken(credentials, spn, channel_bindings, auth_token,
NetLogWithSource(), std::move(callback));
}
int HttpAuthNegotiateAndroid::GenerateAuthToken( int HttpAuthNegotiateAndroid::GenerateAuthToken(
const AuthCredentials* credentials, const AuthCredentials* credentials,
const std::string& spn, const std::string& spn,
const std::string& channel_bindings, const std::string& channel_bindings,
std::string* auth_token, std::string* auth_token,
const NetLogWithSource& net_log,
net::CompletionOnceCallback callback) { net::CompletionOnceCallback callback) {
if (GetAuthAndroidNegotiateAccountType().empty()) { if (GetAuthAndroidNegotiateAccountType().empty()) {
// This can happen if there is a policy change, removing the account type, // This can happen if there is a policy change, removing the account type,
......
...@@ -74,7 +74,7 @@ class NET_EXPORT_PRIVATE HttpAuthNegotiateAndroid ...@@ -74,7 +74,7 @@ class NET_EXPORT_PRIVATE HttpAuthNegotiateAndroid
~HttpAuthNegotiateAndroid() override; ~HttpAuthNegotiateAndroid() override;
// HttpNegotiateAuthSystem implementation: // HttpNegotiateAuthSystem implementation:
bool Init() override; bool Init(const NetLogWithSource& net_log) override;
bool NeedsIdentity() const override; bool NeedsIdentity() const override;
bool AllowsExplicitCredentials() const override; bool AllowsExplicitCredentials() const override;
HttpAuth::AuthorizationResult ParseChallenge( HttpAuth::AuthorizationResult ParseChallenge(
...@@ -83,9 +83,20 @@ class NET_EXPORT_PRIVATE HttpAuthNegotiateAndroid ...@@ -83,9 +83,20 @@ class NET_EXPORT_PRIVATE HttpAuthNegotiateAndroid
const std::string& spn, const std::string& spn,
const std::string& channel_bindings, const std::string& channel_bindings,
std::string* auth_token, std::string* auth_token,
const NetLogWithSource& net_log,
CompletionOnceCallback callback) override; CompletionOnceCallback callback) override;
void SetDelegation(HttpAuth::DelegationType delegation_type) override; void SetDelegation(HttpAuth::DelegationType delegation_type) override;
// Unlike the platform agnostic GenerateAuthToken(), the Android specific
// version doesn't require a NetLogWithSource. The call is made across service
// boundaries, so currently the goings-on within the GenerateAuthToken()
// handler is outside the scope of the NetLog.
int GenerateAuthTokenAndroid(const AuthCredentials* credentials,
const std::string& spn,
const std::string& channel_bindings,
std::string* auth_token,
CompletionOnceCallback callback);
bool can_delegate() const { return can_delegate_; } bool can_delegate() const { return can_delegate_; }
void set_can_delegate(bool can_delegate) { can_delegate_ = can_delegate; } void set_can_delegate(bool can_delegate) { can_delegate_ = can_delegate; }
......
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include "net/base/test_completion_callback.h" #include "net/base/test_completion_callback.h"
#include "net/http/http_auth_challenge_tokenizer.h" #include "net/http/http_auth_challenge_tokenizer.h"
#include "net/http/mock_allow_http_auth_preferences.h" #include "net/http/mock_allow_http_auth_preferences.h"
#include "net/log/net_log_with_source.h"
#include "testing/gtest/include/gtest/gtest.h" #include "testing/gtest/include/gtest/gtest.h"
namespace net { namespace net {
...@@ -32,12 +33,12 @@ TEST(HttpAuthNegotiateAndroidTest, GenerateAuthToken) { ...@@ -32,12 +33,12 @@ TEST(HttpAuthNegotiateAndroidTest, GenerateAuthToken) {
prefs.set_auth_android_negotiate_account_type( prefs.set_auth_android_negotiate_account_type(
"org.chromium.test.DummySpnegoAuthenticator"); "org.chromium.test.DummySpnegoAuthenticator");
HttpAuthNegotiateAndroid auth(&prefs); HttpAuthNegotiateAndroid auth(&prefs);
EXPECT_TRUE(auth.Init()); EXPECT_TRUE(auth.Init(NetLogWithSource()));
TestCompletionCallback callback; TestCompletionCallback callback;
EXPECT_EQ(OK, callback.GetResult( EXPECT_EQ(OK, callback.GetResult(auth.GenerateAuthToken(
auth.GenerateAuthToken(nullptr, "Dummy", std::string(), nullptr, "Dummy", std::string(), &auth_token,
&auth_token, callback.callback()))); NetLogWithSource(), callback.callback())));
EXPECT_EQ("Negotiate DummyToken", auth_token); EXPECT_EQ("Negotiate DummyToken", auth_token);
......
This diff is collapsed.
...@@ -43,7 +43,7 @@ class NET_EXPORT_PRIVATE GSSAPILibrary { ...@@ -43,7 +43,7 @@ class NET_EXPORT_PRIVATE GSSAPILibrary {
// Initializes the library, including any necessary dynamic libraries. // Initializes the library, including any necessary dynamic libraries.
// This is done separately from construction (which happens at startup time) // This is done separately from construction (which happens at startup time)
// in order to delay work until the class is actually needed. // in order to delay work until the class is actually needed.
virtual bool Init() = 0; virtual bool Init(const NetLogWithSource& net_log) = 0;
// These methods match the ones in the GSSAPI library. // These methods match the ones in the GSSAPI library.
virtual OM_uint32 import_name( virtual OM_uint32 import_name(
...@@ -116,7 +116,7 @@ class NET_EXPORT_PRIVATE GSSAPISharedLibrary : public GSSAPILibrary { ...@@ -116,7 +116,7 @@ class NET_EXPORT_PRIVATE GSSAPISharedLibrary : public GSSAPILibrary {
~GSSAPISharedLibrary() override; ~GSSAPISharedLibrary() override;
// GSSAPILibrary methods: // GSSAPILibrary methods:
bool Init() override; bool Init(const NetLogWithSource& net_log) override;
OM_uint32 import_name(OM_uint32* minor_status, OM_uint32 import_name(OM_uint32* minor_status,
const gss_buffer_t input_name_buffer, const gss_buffer_t input_name_buffer,
const gss_OID input_name_type, const gss_OID input_name_type,
...@@ -171,12 +171,14 @@ class NET_EXPORT_PRIVATE GSSAPISharedLibrary : public GSSAPILibrary { ...@@ -171,12 +171,14 @@ class NET_EXPORT_PRIVATE GSSAPISharedLibrary : public GSSAPILibrary {
private: private:
FRIEND_TEST_ALL_PREFIXES(HttpAuthGSSAPIPOSIXTest, GSSAPIStartup); FRIEND_TEST_ALL_PREFIXES(HttpAuthGSSAPIPOSIXTest, GSSAPIStartup);
bool InitImpl(); bool InitImpl(const NetLogWithSource& net_log);
// Finds a usable dynamic library for GSSAPI and loads it. The criteria are: // Finds a usable dynamic library for GSSAPI and loads it. The criteria are:
// 1. The library must exist. // 1. The library must exist.
// 2. The library must export the functions we need. // 2. The library must export the functions we need.
base::NativeLibrary LoadSharedLibrary(); base::NativeLibrary LoadSharedLibrary(const NetLogWithSource& net_log);
bool BindMethods(base::NativeLibrary lib); bool BindMethods(base::NativeLibrary lib,
base::StringPiece library_name,
const NetLogWithSource& net_log);
bool initialized_ = false; bool initialized_ = false;
...@@ -207,7 +209,7 @@ class ScopedSecurityContext { ...@@ -207,7 +209,7 @@ class ScopedSecurityContext {
gss_ctx_id_t* receive() { return &security_context_; } gss_ctx_id_t* receive() { return &security_context_; }
private: private:
gss_ctx_id_t security_context_; gss_ctx_id_t security_context_ = GSS_C_NO_CONTEXT;
GSSAPILibrary* gssapi_lib_; GSSAPILibrary* gssapi_lib_;
DISALLOW_COPY_AND_ASSIGN(ScopedSecurityContext); DISALLOW_COPY_AND_ASSIGN(ScopedSecurityContext);
...@@ -223,7 +225,7 @@ class NET_EXPORT_PRIVATE HttpAuthGSSAPI : public HttpNegotiateAuthSystem { ...@@ -223,7 +225,7 @@ class NET_EXPORT_PRIVATE HttpAuthGSSAPI : public HttpNegotiateAuthSystem {
~HttpAuthGSSAPI() override; ~HttpAuthGSSAPI() override;
// HttpNegotiateAuthSystem implementation: // HttpNegotiateAuthSystem implementation:
bool Init() override; bool Init(const NetLogWithSource& net_log) override;
bool NeedsIdentity() const override; bool NeedsIdentity() const override;
bool AllowsExplicitCredentials() const override; bool AllowsExplicitCredentials() const override;
HttpAuth::AuthorizationResult ParseChallenge( HttpAuth::AuthorizationResult ParseChallenge(
...@@ -232,6 +234,7 @@ class NET_EXPORT_PRIVATE HttpAuthGSSAPI : public HttpNegotiateAuthSystem { ...@@ -232,6 +234,7 @@ class NET_EXPORT_PRIVATE HttpAuthGSSAPI : public HttpNegotiateAuthSystem {
const std::string& spn, const std::string& spn,
const std::string& channel_bindings, const std::string& channel_bindings,
std::string* auth_token, std::string* auth_token,
const NetLogWithSource& net_log,
CompletionOnceCallback callback) override; CompletionOnceCallback callback) override;
void SetDelegation(HttpAuth::DelegationType delegation_type) override; void SetDelegation(HttpAuth::DelegationType delegation_type) override;
...@@ -239,7 +242,8 @@ class NET_EXPORT_PRIVATE HttpAuthGSSAPI : public HttpNegotiateAuthSystem { ...@@ -239,7 +242,8 @@ class NET_EXPORT_PRIVATE HttpAuthGSSAPI : public HttpNegotiateAuthSystem {
int GetNextSecurityToken(const std::string& spn, int GetNextSecurityToken(const std::string& spn,
const std::string& channel_bindings, const std::string& channel_bindings,
gss_buffer_t in_token, gss_buffer_t in_token,
gss_buffer_t out_token); gss_buffer_t out_token,
const NetLogWithSource& net_log);
std::string scheme_; std::string scheme_;
gss_OID gss_oid_; gss_OID gss_oid_;
......
...@@ -16,6 +16,9 @@ ...@@ -16,6 +16,9 @@
#include "net/base/net_errors.h" #include "net/base/net_errors.h"
#include "net/http/http_auth_challenge_tokenizer.h" #include "net/http/http_auth_challenge_tokenizer.h"
#include "net/http/mock_gssapi_library_posix.h" #include "net/http/mock_gssapi_library_posix.h"
#include "net/log/net_log_with_source.h"
#include "net/log/test_net_log.h"
#include "net/log/test_net_log_util.h"
#include "net/net_buildflags.h" #include "net/net_buildflags.h"
#include "testing/gtest/include/gtest/gtest.h" #include "testing/gtest/include/gtest/gtest.h"
...@@ -86,30 +89,74 @@ void UnexpectedCallback(int result) { ...@@ -86,30 +89,74 @@ void UnexpectedCallback(int result) {
} // namespace } // namespace
TEST(HttpAuthGSSAPIPOSIXTest, GSSAPIStartup) { TEST(HttpAuthGSSAPIPOSIXTest, GSSAPIStartup) {
BoundTestNetLog log;
// TODO(ahendrickson): Manipulate the libraries and paths to test each of the // TODO(ahendrickson): Manipulate the libraries and paths to test each of the
// libraries we expect, and also whether or not they have the interface // libraries we expect, and also whether or not they have the interface
// functions we want. // functions we want.
std::unique_ptr<GSSAPILibrary> gssapi(new GSSAPISharedLibrary(std::string())); std::unique_ptr<GSSAPILibrary> gssapi(new GSSAPISharedLibrary(std::string()));
DCHECK(gssapi.get()); DCHECK(gssapi.get());
EXPECT_TRUE(gssapi.get()->Init()); EXPECT_TRUE(gssapi.get()->Init(log.bound()));
// Should've logged a AUTH_LIBRARY_LOAD event, but not
// AUTH_LIBRARY_BIND_FAILED.
auto entries = log.GetEntries();
auto offset = ExpectLogContainsSomewhere(
entries, 0u, NetLogEventType::AUTH_LIBRARY_LOAD, NetLogEventPhase::BEGIN);
offset = ExpectLogContainsSomewhereAfter(entries, offset,
NetLogEventType::AUTH_LIBRARY_LOAD,
NetLogEventPhase::END);
ASSERT_LT(offset, entries.size());
auto& entry = entries[offset];
const std::string* library_name = entry.params.FindStringKey("library_name");
const std::string* load_result = entry.params.FindStringPath("load_result");
ASSERT_TRUE(library_name);
EXPECT_FALSE(library_name->empty());
EXPECT_FALSE(load_result); // No load_result since it succeeded.
} }
TEST(HttpAuthGSSAPIPOSIXTest, CustomLibraryMissing) { TEST(HttpAuthGSSAPIPOSIXTest, CustomLibraryMissing) {
BoundTestNetLog log;
std::unique_ptr<GSSAPILibrary> gssapi( std::unique_ptr<GSSAPILibrary> gssapi(
new GSSAPISharedLibrary("/this/library/does/not/exist")); new GSSAPISharedLibrary("/this/library/does/not/exist"));
EXPECT_FALSE(gssapi.get()->Init()); EXPECT_FALSE(gssapi.get()->Init(log.bound()));
auto entries = log.GetEntries();
auto offset = ExpectLogContainsSomewhere(
entries, 0, NetLogEventType::AUTH_LIBRARY_LOAD, NetLogEventPhase::END);
ASSERT_LT(offset, entries.size());
auto& entry = entries[offset];
const std::string* load_result = entry.params.FindStringKey("load_result");
ASSERT_TRUE(load_result);
EXPECT_FALSE(load_result->empty());
} }
TEST(HttpAuthGSSAPIPOSIXTest, CustomLibraryExists) { TEST(HttpAuthGSSAPIPOSIXTest, CustomLibraryExists) {
BoundTestNetLog log;
base::FilePath module; base::FilePath module;
ASSERT_TRUE(base::PathService::Get(base::DIR_MODULE, &module)); ASSERT_TRUE(base::PathService::Get(base::DIR_MODULE, &module));
auto basename = base::GetNativeLibraryName("test_gssapi"); auto basename = base::GetNativeLibraryName("test_gssapi");
module = module.AppendASCII(basename); module = module.AppendASCII(basename);
auto gssapi = std::make_unique<GSSAPISharedLibrary>(module.value()); auto gssapi = std::make_unique<GSSAPISharedLibrary>(module.value());
EXPECT_TRUE(gssapi.get()->Init()); EXPECT_TRUE(gssapi.get()->Init(log.bound()));
auto entries = log.GetEntries();
auto offset = ExpectLogContainsSomewhere(
entries, 0, NetLogEventType::AUTH_LIBRARY_LOAD, NetLogEventPhase::END);
ASSERT_LT(offset, entries.size());
auto& entry = entries[offset];
const std::string* load_result = entry.params.FindStringKey("load_result");
const std::string* library_name = entry.params.FindStringKey("library_name");
EXPECT_FALSE(load_result);
ASSERT_TRUE(library_name);
EXPECT_EQ(*library_name, module.AsUTF8Unsafe());
} }
TEST(HttpAuthGSSAPIPOSIXTest, CustomLibraryMethodsMissing) { TEST(HttpAuthGSSAPIPOSIXTest, CustomLibraryMethodsMissing) {
BoundTestNetLog log;
base::FilePath module; base::FilePath module;
ASSERT_TRUE(base::PathService::Get(base::DIR_MODULE, &module)); ASSERT_TRUE(base::PathService::Get(base::DIR_MODULE, &module));
auto basename = base::GetNativeLibraryName("test_badgssapi"); auto basename = base::GetNativeLibraryName("test_badgssapi");
...@@ -124,18 +171,25 @@ TEST(HttpAuthGSSAPIPOSIXTest, CustomLibraryMethodsMissing) { ...@@ -124,18 +171,25 @@ TEST(HttpAuthGSSAPIPOSIXTest, CustomLibraryMethodsMissing) {
// //
// To resolve this issue, make sure that //net:test_badgssapi target in // To resolve this issue, make sure that //net:test_badgssapi target in
// //net/BUILD.gn should have an empty `deps` and an empty `libs`. // //net/BUILD.gn should have an empty `deps` and an empty `libs`.
EXPECT_FALSE(gssapi.get()->Init()); EXPECT_FALSE(gssapi.get()->Init(log.bound()));
// Logs something like "gss_import_name" during loading process. auto entries = log.GetEntries();
// TODO(asanka): Once GSSAPI library loading starts emitting NetLogs verify auto offset = ExpectLogContainsSomewhere(
// that the missing method is correctly identified. entries, 0, NetLogEventType::AUTH_LIBRARY_BIND_FAILED,
NetLogEventPhase::NONE);
ASSERT_LT(offset, entries.size());
auto& entry = entries[offset];
const std::string* method = entry.params.FindStringKey("method");
ASSERT_TRUE(method);
EXPECT_EQ(*method, "gss_import_name");
} }
TEST(HttpAuthGSSAPIPOSIXTest, GSSAPICycle) { TEST(HttpAuthGSSAPIPOSIXTest, GSSAPICycle) {
std::unique_ptr<test::MockGSSAPILibrary> mock_library( std::unique_ptr<test::MockGSSAPILibrary> mock_library(
new test::MockGSSAPILibrary); new test::MockGSSAPILibrary);
DCHECK(mock_library.get()); DCHECK(mock_library.get());
mock_library->Init(); mock_library->Init(NetLogWithSource());
const char kAuthResponse[] = "Mary had a little lamb"; const char kAuthResponse[] = "Mary had a little lamb";
test::GssContextMockImpl context1( test::GssContextMockImpl context1(
"localhost", // Source name "localhost", // Source name
...@@ -231,6 +285,7 @@ TEST(HttpAuthGSSAPITest, ParseChallenge_FirstRound) { ...@@ -231,6 +285,7 @@ TEST(HttpAuthGSSAPITest, ParseChallenge_FirstRound) {
} }
TEST(HttpAuthGSSAPITest, ParseChallenge_TwoRounds) { TEST(HttpAuthGSSAPITest, ParseChallenge_TwoRounds) {
BoundTestNetLog log;
// The first round should just have "Negotiate", and the second round should // The first round should just have "Negotiate", and the second round should
// have a valid base64 token associated with it. // have a valid base64 token associated with it.
test::MockGSSAPILibrary mock_library; test::MockGSSAPILibrary mock_library;
...@@ -245,15 +300,30 @@ TEST(HttpAuthGSSAPITest, ParseChallenge_TwoRounds) { ...@@ -245,15 +300,30 @@ TEST(HttpAuthGSSAPITest, ParseChallenge_TwoRounds) {
// Generate an auth token and create another thing. // Generate an auth token and create another thing.
EstablishInitialContext(&mock_library); EstablishInitialContext(&mock_library);
std::string auth_token; std::string auth_token;
EXPECT_EQ(OK, auth_gssapi.GenerateAuthToken( EXPECT_EQ(
nullptr, "HTTP/intranet.google.com", std::string(), OK, auth_gssapi.GenerateAuthToken(nullptr, "HTTP/intranet.google.com",
&auth_token, base::BindOnce(&UnexpectedCallback))); std::string(), &auth_token, log.bound(),
base::BindOnce(&UnexpectedCallback)));
std::string second_challenge_text = "Negotiate Zm9vYmFy"; std::string second_challenge_text = "Negotiate Zm9vYmFy";
HttpAuthChallengeTokenizer second_challenge(second_challenge_text.begin(), HttpAuthChallengeTokenizer second_challenge(second_challenge_text.begin(),
second_challenge_text.end()); second_challenge_text.end());
EXPECT_EQ(HttpAuth::AUTHORIZATION_RESULT_ACCEPT, EXPECT_EQ(HttpAuth::AUTHORIZATION_RESULT_ACCEPT,
auth_gssapi.ParseChallenge(&second_challenge)); auth_gssapi.ParseChallenge(&second_challenge));
auto entries = log.GetEntries();
auto offset = ExpectLogContainsSomewhere(
entries, 0, NetLogEventType::AUTH_LIBRARY_INIT_SEC_CTX,
NetLogEventPhase::END);
// There should be two of these.
offset = ExpectLogContainsSomewhere(
entries, offset, NetLogEventType::AUTH_LIBRARY_INIT_SEC_CTX,
NetLogEventPhase::END);
ASSERT_LT(offset, entries.size());
const std::string* source =
entries[offset].params.FindStringPath("context.source.name");
ASSERT_TRUE(source);
EXPECT_EQ("localhost", *source);
} }
TEST(HttpAuthGSSAPITest, ParseChallenge_UnexpectedTokenFirstRound) { TEST(HttpAuthGSSAPITest, ParseChallenge_UnexpectedTokenFirstRound) {
...@@ -283,9 +353,10 @@ TEST(HttpAuthGSSAPITest, ParseChallenge_MissingTokenSecondRound) { ...@@ -283,9 +353,10 @@ TEST(HttpAuthGSSAPITest, ParseChallenge_MissingTokenSecondRound) {
EstablishInitialContext(&mock_library); EstablishInitialContext(&mock_library);
std::string auth_token; std::string auth_token;
EXPECT_EQ(OK, auth_gssapi.GenerateAuthToken( EXPECT_EQ(OK,
nullptr, "HTTP/intranet.google.com", std::string(), auth_gssapi.GenerateAuthToken(
&auth_token, base::BindOnce(&UnexpectedCallback))); nullptr, "HTTP/intranet.google.com", std::string(), &auth_token,
NetLogWithSource(), base::BindOnce(&UnexpectedCallback)));
std::string second_challenge_text = "Negotiate"; std::string second_challenge_text = "Negotiate";
HttpAuthChallengeTokenizer second_challenge(second_challenge_text.begin(), HttpAuthChallengeTokenizer second_challenge(second_challenge_text.begin(),
second_challenge_text.end()); second_challenge_text.end());
...@@ -307,9 +378,10 @@ TEST(HttpAuthGSSAPITest, ParseChallenge_NonBase64EncodedToken) { ...@@ -307,9 +378,10 @@ TEST(HttpAuthGSSAPITest, ParseChallenge_NonBase64EncodedToken) {
EstablishInitialContext(&mock_library); EstablishInitialContext(&mock_library);
std::string auth_token; std::string auth_token;
EXPECT_EQ(OK, auth_gssapi.GenerateAuthToken( EXPECT_EQ(OK,
nullptr, "HTTP/intranet.google.com", std::string(), auth_gssapi.GenerateAuthToken(
&auth_token, base::BindOnce(&UnexpectedCallback))); nullptr, "HTTP/intranet.google.com", std::string(), &auth_token,
NetLogWithSource(), base::BindOnce(&UnexpectedCallback)));
std::string second_challenge_text = "Negotiate =happyjoy="; std::string second_challenge_text = "Negotiate =happyjoy=";
HttpAuthChallengeTokenizer second_challenge(second_challenge_text.begin(), HttpAuthChallengeTokenizer second_challenge(second_challenge_text.begin(),
second_challenge_text.end()); second_challenge_text.end());
...@@ -332,7 +404,7 @@ TEST(HttpAuthGSSAPITest, OidToValue_Known) { ...@@ -332,7 +404,7 @@ TEST(HttpAuthGSSAPITest, OidToValue_Known) {
{ {
"oid" : "GSS_C_NT_ANONYMOUS", "oid" : "GSS_C_NT_ANONYMOUS",
"length": 6, "length": 6,
"bytes" : "0x0000: 2b06 0105 0603 +.....\n" "bytes" : "KwYBBQYD"
} }
)"); )");
ASSERT_TRUE(expected.has_value()); ASSERT_TRUE(expected.has_value());
...@@ -345,7 +417,7 @@ TEST(HttpAuthGSSAPITest, OidToValue_Unknown) { ...@@ -345,7 +417,7 @@ TEST(HttpAuthGSSAPITest, OidToValue_Unknown) {
auto expected = base::JSONReader::Read(R"( auto expected = base::JSONReader::Read(R"(
{ {
"length": 6, "length": 6,
"bytes" : "0x0000: 2b06 0105 0605 +.....\n" "bytes" : "KwYBBQYF"
} }
)"); )");
ASSERT_TRUE(expected.has_value()); ASSERT_TRUE(expected.has_value());
......
...@@ -131,7 +131,7 @@ int HttpAuthHandlerNegotiate::Factory::CreateAuthHandler( ...@@ -131,7 +131,7 @@ int HttpAuthHandlerNegotiate::Factory::CreateAuthHandler(
if (!http_auth_preferences()->AllowGssapiLibraryLoad()) if (!http_auth_preferences()->AllowGssapiLibraryLoad())
return ERR_UNSUPPORTED_AUTH_SCHEME; return ERR_UNSUPPORTED_AUTH_SCHEME;
#endif #endif
if (!auth_library_->Init()) { if (!auth_library_->Init(net_log)) {
is_unsupported_ = true; is_unsupported_ = true;
return ERR_UNSUPPORTED_AUTH_SCHEME; return ERR_UNSUPPORTED_AUTH_SCHEME;
} }
...@@ -185,7 +185,7 @@ bool HttpAuthHandlerNegotiate::AllowsExplicitCredentials() { ...@@ -185,7 +185,7 @@ bool HttpAuthHandlerNegotiate::AllowsExplicitCredentials() {
bool HttpAuthHandlerNegotiate::Init(HttpAuthChallengeTokenizer* challenge, bool HttpAuthHandlerNegotiate::Init(HttpAuthChallengeTokenizer* challenge,
const SSLInfo& ssl_info) { const SSLInfo& ssl_info) {
#if defined(OS_POSIX) #if defined(OS_POSIX)
if (!auth_system_->Init()) { if (!auth_system_->Init(net_log())) {
VLOG(1) << "can't initialize GSSAPI library"; VLOG(1) << "can't initialize GSSAPI library";
return false; return false;
} }
...@@ -387,7 +387,7 @@ int HttpAuthHandlerNegotiate::DoGenerateAuthToken() { ...@@ -387,7 +387,7 @@ int HttpAuthHandlerNegotiate::DoGenerateAuthToken() {
next_state_ = STATE_GENERATE_AUTH_TOKEN_COMPLETE; next_state_ = STATE_GENERATE_AUTH_TOKEN_COMPLETE;
AuthCredentials* credentials = has_credentials_ ? &credentials_ : nullptr; AuthCredentials* credentials = has_credentials_ ? &credentials_ : nullptr;
return auth_system_->GenerateAuthToken( return auth_system_->GenerateAuthToken(
credentials, spn_, channel_bindings_, auth_token_, credentials, spn_, channel_bindings_, auth_token_, net_log(),
base::BindOnce(&HttpAuthHandlerNegotiate::OnIOComplete, base::BindOnce(&HttpAuthHandlerNegotiate::OnIOComplete,
base::Unretained(this))); base::Unretained(this)));
} }
......
...@@ -426,7 +426,7 @@ class TestAuthSystem : public HttpNegotiateAuthSystem { ...@@ -426,7 +426,7 @@ class TestAuthSystem : public HttpNegotiateAuthSystem {
~TestAuthSystem() override = default; ~TestAuthSystem() override = default;
// HttpNegotiateAuthSystem implementation: // HttpNegotiateAuthSystem implementation:
bool Init() override { return true; } bool Init(const NetLogWithSource&) override { return true; }
bool NeedsIdentity() const override { return true; } bool NeedsIdentity() const override { return true; }
bool AllowsExplicitCredentials() const override { return true; } bool AllowsExplicitCredentials() const override { return true; }
...@@ -439,6 +439,7 @@ class TestAuthSystem : public HttpNegotiateAuthSystem { ...@@ -439,6 +439,7 @@ class TestAuthSystem : public HttpNegotiateAuthSystem {
const std::string& spn, const std::string& spn,
const std::string& channel_bindings, const std::string& channel_bindings,
std::string* auth_token, std::string* auth_token,
const NetLogWithSource& net_log,
net::CompletionOnceCallback callback) override { net::CompletionOnceCallback callback) override {
*auth_token = kFakeToken; *auth_token = kFakeToken;
return net::OK; return net::OK;
......
...@@ -41,7 +41,7 @@ int HttpAuthHandlerNTLM::GenerateAuthTokenImpl( ...@@ -41,7 +41,7 @@ int HttpAuthHandlerNTLM::GenerateAuthTokenImpl(
std::string* auth_token) { std::string* auth_token) {
#if defined(NTLM_SSPI) #if defined(NTLM_SSPI)
return auth_sspi_.GenerateAuthToken(credentials, CreateSPN(origin_), return auth_sspi_.GenerateAuthToken(credentials, CreateSPN(origin_),
channel_bindings_, auth_token, channel_bindings_, auth_token, net_log(),
std::move(callback)); std::move(callback));
#else // !defined(NTLM_SSPI) #else // !defined(NTLM_SSPI)
// TODO(cbentzel): Shouldn't be hitting this case. // TODO(cbentzel): Shouldn't be hitting this case.
......
...@@ -263,7 +263,7 @@ HttpAuthSSPI::~HttpAuthSSPI() { ...@@ -263,7 +263,7 @@ HttpAuthSSPI::~HttpAuthSSPI() {
} }
} }
bool HttpAuthSSPI::Init() { bool HttpAuthSSPI::Init(const NetLogWithSource&) {
return true; return true;
} }
...@@ -300,6 +300,7 @@ int HttpAuthSSPI::GenerateAuthToken(const AuthCredentials* credentials, ...@@ -300,6 +300,7 @@ int HttpAuthSSPI::GenerateAuthToken(const AuthCredentials* credentials,
const std::string& spn, const std::string& spn,
const std::string& channel_bindings, const std::string& channel_bindings,
std::string* auth_token, std::string* auth_token,
const NetLogWithSource&,
CompletionOnceCallback /*callback*/) { CompletionOnceCallback /*callback*/) {
// Initial challenge. // Initial challenge.
if (!SecIsValidHandle(&cred_)) { if (!SecIsValidHandle(&cred_)) {
......
...@@ -116,7 +116,7 @@ class NET_EXPORT_PRIVATE HttpAuthSSPI : public HttpNegotiateAuthSystem { ...@@ -116,7 +116,7 @@ class NET_EXPORT_PRIVATE HttpAuthSSPI : public HttpNegotiateAuthSystem {
~HttpAuthSSPI() override; ~HttpAuthSSPI() override;
// HttpNegotiateAuthSystem implementation: // HttpNegotiateAuthSystem implementation:
bool Init() override; bool Init(const NetLogWithSource& net_log) override;
bool NeedsIdentity() const override; bool NeedsIdentity() const override;
bool AllowsExplicitCredentials() const override; bool AllowsExplicitCredentials() const override;
HttpAuth::AuthorizationResult ParseChallenge( HttpAuth::AuthorizationResult ParseChallenge(
...@@ -125,6 +125,7 @@ class NET_EXPORT_PRIVATE HttpAuthSSPI : public HttpNegotiateAuthSystem { ...@@ -125,6 +125,7 @@ class NET_EXPORT_PRIVATE HttpAuthSSPI : public HttpNegotiateAuthSystem {
const std::string& spn, const std::string& spn,
const std::string& channel_bindings, const std::string& channel_bindings,
std::string* auth_token, std::string* auth_token,
const NetLogWithSource& net_log,
CompletionOnceCallback callback) override; CompletionOnceCallback callback) override;
void SetDelegation(HttpAuth::DelegationType delegation_type) override; void SetDelegation(HttpAuth::DelegationType delegation_type) override;
......
...@@ -3,10 +3,12 @@ ...@@ -3,10 +3,12 @@
// found in the LICENSE file. // found in the LICENSE file.
#include "net/http/http_auth_sspi_win.h" #include "net/http/http_auth_sspi_win.h"
#include "base/bind.h" #include "base/bind.h"
#include "net/base/net_errors.h" #include "net/base/net_errors.h"
#include "net/http/http_auth_challenge_tokenizer.h" #include "net/http/http_auth_challenge_tokenizer.h"
#include "net/http/mock_sspi_library_win.h" #include "net/http/mock_sspi_library_win.h"
#include "net/log/net_log_with_source.h"
#include "net/test/gtest_util.h" #include "net/test/gtest_util.h"
#include "testing/gmock/include/gmock/gmock.h" #include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h" #include "testing/gtest/include/gtest/gtest.h"
...@@ -96,9 +98,10 @@ TEST(HttpAuthSSPITest, ParseChallenge_TwoRounds) { ...@@ -96,9 +98,10 @@ TEST(HttpAuthSSPITest, ParseChallenge_TwoRounds) {
// Generate an auth token and create another thing. // Generate an auth token and create another thing.
std::string auth_token; std::string auth_token;
EXPECT_EQ(OK, auth_sspi.GenerateAuthToken( EXPECT_EQ(OK,
nullptr, "HTTP/intranet.google.com", std::string(), auth_sspi.GenerateAuthToken(
&auth_token, base::BindOnce(&UnexpectedCallback))); nullptr, "HTTP/intranet.google.com", std::string(), &auth_token,
NetLogWithSource(), base::BindOnce(&UnexpectedCallback)));
std::string second_challenge_text = "Negotiate Zm9vYmFy"; std::string second_challenge_text = "Negotiate Zm9vYmFy";
HttpAuthChallengeTokenizer second_challenge(second_challenge_text.begin(), HttpAuthChallengeTokenizer second_challenge(second_challenge_text.begin(),
...@@ -133,9 +136,10 @@ TEST(HttpAuthSSPITest, ParseChallenge_MissingTokenSecondRound) { ...@@ -133,9 +136,10 @@ TEST(HttpAuthSSPITest, ParseChallenge_MissingTokenSecondRound) {
auth_sspi.ParseChallenge(&first_challenge)); auth_sspi.ParseChallenge(&first_challenge));
std::string auth_token; std::string auth_token;
EXPECT_EQ(OK, auth_sspi.GenerateAuthToken( EXPECT_EQ(OK,
nullptr, "HTTP/intranet.google.com", std::string(), auth_sspi.GenerateAuthToken(
&auth_token, base::BindOnce(&UnexpectedCallback))); nullptr, "HTTP/intranet.google.com", std::string(), &auth_token,
NetLogWithSource(), base::BindOnce(&UnexpectedCallback)));
std::string second_challenge_text = "Negotiate"; std::string second_challenge_text = "Negotiate";
HttpAuthChallengeTokenizer second_challenge(second_challenge_text.begin(), HttpAuthChallengeTokenizer second_challenge(second_challenge_text.begin(),
second_challenge_text.end()); second_challenge_text.end());
...@@ -156,9 +160,10 @@ TEST(HttpAuthSSPITest, ParseChallenge_NonBase64EncodedToken) { ...@@ -156,9 +160,10 @@ TEST(HttpAuthSSPITest, ParseChallenge_NonBase64EncodedToken) {
auth_sspi.ParseChallenge(&first_challenge)); auth_sspi.ParseChallenge(&first_challenge));
std::string auth_token; std::string auth_token;
EXPECT_EQ(OK, auth_sspi.GenerateAuthToken( EXPECT_EQ(OK,
nullptr, "HTTP/intranet.google.com", std::string(), auth_sspi.GenerateAuthToken(
&auth_token, base::BindOnce(&UnexpectedCallback))); nullptr, "HTTP/intranet.google.com", std::string(), &auth_token,
NetLogWithSource(), base::BindOnce(&UnexpectedCallback)));
std::string second_challenge_text = "Negotiate =happyjoy="; std::string second_challenge_text = "Negotiate =happyjoy=";
HttpAuthChallengeTokenizer second_challenge(second_challenge_text.begin(), HttpAuthChallengeTokenizer second_challenge(second_challenge_text.begin(),
second_challenge_text.end()); second_challenge_text.end());
......
...@@ -13,12 +13,13 @@ namespace net { ...@@ -13,12 +13,13 @@ namespace net {
class AuthCredentials; class AuthCredentials;
class HttpAuthChallengeTokenizer; class HttpAuthChallengeTokenizer;
class NetLogWithSource;
class NET_EXPORT_PRIVATE HttpNegotiateAuthSystem { class NET_EXPORT_PRIVATE HttpNegotiateAuthSystem {
public: public:
virtual ~HttpNegotiateAuthSystem() = default; virtual ~HttpNegotiateAuthSystem() = default;
virtual bool Init() = 0; virtual bool Init(const NetLogWithSource& net_log) = 0;
// True if authentication needs the identity of the user from Chrome. // True if authentication needs the identity of the user from Chrome.
virtual bool NeedsIdentity() const = 0; virtual bool NeedsIdentity() const = 0;
...@@ -57,6 +58,7 @@ class NET_EXPORT_PRIVATE HttpNegotiateAuthSystem { ...@@ -57,6 +58,7 @@ class NET_EXPORT_PRIVATE HttpNegotiateAuthSystem {
const std::string& spn, const std::string& spn,
const std::string& channel_bindings, const std::string& channel_bindings,
std::string* auth_token, std::string* auth_token,
const NetLogWithSource& net_log,
CompletionOnceCallback callback) = 0; CompletionOnceCallback callback) = 0;
// Sets the delegation type allowed on the Kerberos ticket. This allows // Sets the delegation type allowed on the Kerberos ticket. This allows
......
...@@ -253,7 +253,7 @@ void MockGSSAPILibrary::ExpectSecurityContext( ...@@ -253,7 +253,7 @@ void MockGSSAPILibrary::ExpectSecurityContext(
expected_security_queries_.push_back(security_query); expected_security_queries_.push_back(security_query);
} }
bool MockGSSAPILibrary::Init() { bool MockGSSAPILibrary::Init(const NetLogWithSource&) {
return true; return true;
} }
......
...@@ -113,7 +113,7 @@ class MockGSSAPILibrary : public GSSAPILibrary { ...@@ -113,7 +113,7 @@ class MockGSSAPILibrary : public GSSAPILibrary {
// Initializes the library, including any necessary dynamic libraries. // Initializes the library, including any necessary dynamic libraries.
// This is done separately from construction (which happens at startup time) // This is done separately from construction (which happens at startup time)
// in order to delay work until the class is actually needed. // in order to delay work until the class is actually needed.
bool Init() override; bool Init(const NetLogWithSource& net_log) override;
// These methods match the ones in the GSSAPI library. // These methods match the ones in the GSSAPI library.
OM_uint32 import_name(OM_uint32* minor_status, OM_uint32 import_name(OM_uint32* minor_status,
......
...@@ -2169,6 +2169,79 @@ EVENT_TYPE(SOCKS5_HANDSHAKE_READ) ...@@ -2169,6 +2169,79 @@ EVENT_TYPE(SOCKS5_HANDSHAKE_READ)
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
// HTTP Authentication // HTTP Authentication
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
//
// Structure of common GSSAPI / SSPI values.
// -----------------------------------------
// For convenience some structured GSSAPI/SSPI values are serialized
// consistently across different events. They are explained below.
//
// ** GSSAPI Status:
//
// A major/minor status code returned by a GSSAPI function. The major status
// code indicates the GSSAPI level error, while the minor code provides a
// mechanism specific error code if a specific GSSAPI mechanism was involved in
// the error.
//
// The status value has the following structure:
// {
// "function": <name of GSSAPI function that returned the error>
// "major_status": {
// "status" : <status value as a number>,
// "message": [
// <list of strings hopefully explaining what that number means>
// ]
// },
// "minor_status": {
// "status" : <status value as a number>,
// "message": [
// <list of strings hopefully explaining what that number means>
// ]
// }
// }
//
// ** OID:
//
// An ASN.1 OID that's used for GSSAPI is serialized thusly:
// {
// "oid": <symbolic name of OID if it is known>
// "length": <length in bytes of serialized OID>,
// "bytes": <serialized bytes of OID encoded via NetLogBinaryValue()>
// }
//
// ** GSS Display Name:
//
// A serialization of GSSAPI principal name to something that can be consumed by
// humans. If the encoding of the string is not UTF-8 (since there's no
// requirement that they use any specific encoding) the field is serialized
// using NetLogBinaryValue().
// {
// "name" : <GSSAPI principal name>
// "type" : <OID indicating type of name. See OID above.>
// "error": <If the display name lookup operation failed, then this field
// contains the error in the form of a GSSAPI Status.>
// }
//
// ** GSSAPI Context Description
//
// A serialization of the GSSAPI context. It takes the following form:
// {
// "source" : <GSS Display Name for the source of the authentication
// attempt. In practice this is always the user's identity.>
// "target" : <GSS Display Name for the target of the authentication
// attempt. This the target server or proxy service
// principal.>
// "open" : <Boolean indicating whether the context is "open", which
// means that the handshake is still in progress. In
// particular, the flags, lifetime, and mechanism fields are
// not considered final until "open" is false.
// "lifetime": <A decimal string indicating the lifetime in seconds of the
// authentication context. The identity as established by this
// handshake is only valid for this long since the time at
// which it was established.>
// "mechanism":<OID indicating inner authentication mechanism.>
// "flags" :<Flags. See RFC 2744 Section 5.19 for meanings. Flag
// bitmasks can be found in RFC 2744 Appendix A.>
// }
// Lifetime event for HttpAuthController. // Lifetime event for HttpAuthController.
// //
...@@ -2212,11 +2285,56 @@ EVENT_TYPE(AUTH_GENERATE_TOKEN) ...@@ -2212,11 +2285,56 @@ EVENT_TYPE(AUTH_GENERATE_TOKEN)
// } // }
EVENT_TYPE(AUTH_HANDLE_CHALLENGE) EVENT_TYPE(AUTH_HANDLE_CHALLENGE)
// An attempt was made to load an authentication library.
//
// If the request succeeded, the parameters are:
// {
// "library_name": <Name of library>
// }
// Otherwise, the parameters are:
// {
// "library_name": <Name of library>
// "load_error": <An error string>
// }
EVENT_TYPE(AUTH_LIBRARY_LOAD)
// A required method was not found while attempting to load an authentication
// library.
//
// Parameters are:
// {
// "library_name": <Name of the library where the method lookup failed>
// "method": <Name of method that was not found>
// }
EVENT_TYPE(AUTH_LIBRARY_BIND_FAILED)
// Construction of the GSSAPI service principal name.
//
// Parameters:
// {
// "spn": <Service principal name as a string>
// "status": <GSSAPI Status. See GSSAPI Status above. This is field is only
// logged if the operation failed.>
// }
EVENT_TYPE(AUTH_LIBRARY_IMPORT_NAME)
// Initialize security context.
//
// This operation involves invoking an external library which may perform disk,
// IPC, and network IO as a part of its work.
//
// The END phase has the following parameters.
// {
// "context": <GSSAPI Context Description>,
// "status": <GSSAPI Status if the operation failed>
// }
EVENT_TYPE(AUTH_LIBRARY_INIT_SEC_CTX)
// The channel bindings generated for the connection. // The channel bindings generated for the connection.
// { // {
// "token": <Hex encoded RFC 5929 'tls-server-endpoint' channel binding // "token": <Hex encoded RFC 5929 'tls-server-endpoint' channel binding
// token. Could be empty if one could not be generated (e.g. // token. Could be empty if one could not be generated (e.g.
// because the underlying channel was not TLS> // because the underlying channel was not TLS.)>
// } // }
EVENT_TYPE(AUTH_CHANNEL_BINDINGS) EVENT_TYPE(AUTH_CHANNEL_BINDINGS)
......
...@@ -150,7 +150,9 @@ class NetworkServiceAuthNegotiateAndroid : public net::HttpNegotiateAuthSystem { ...@@ -150,7 +150,9 @@ class NetworkServiceAuthNegotiateAndroid : public net::HttpNegotiateAuthSystem {
~NetworkServiceAuthNegotiateAndroid() override = default; ~NetworkServiceAuthNegotiateAndroid() override = default;
// HttpNegotiateAuthSystem implementation: // HttpNegotiateAuthSystem implementation:
bool Init() override { return auth_negotiate_.Init(); } bool Init(const net::NetLogWithSource& net_log) override {
return auth_negotiate_.Init(net_log);
}
bool NeedsIdentity() const override { bool NeedsIdentity() const override {
return auth_negotiate_.NeedsIdentity(); return auth_negotiate_.NeedsIdentity();
...@@ -169,6 +171,7 @@ class NetworkServiceAuthNegotiateAndroid : public net::HttpNegotiateAuthSystem { ...@@ -169,6 +171,7 @@ class NetworkServiceAuthNegotiateAndroid : public net::HttpNegotiateAuthSystem {
const std::string& spn, const std::string& spn,
const std::string& channel_bindings, const std::string& channel_bindings,
std::string* auth_token, std::string* auth_token,
const net::NetLogWithSource& net_log,
net::CompletionOnceCallback callback) override { net::CompletionOnceCallback callback) override {
network_service_->client()->OnGenerateHttpNegotiateAuthToken( network_service_->client()->OnGenerateHttpNegotiateAuthToken(
auth_negotiate_.server_auth_token(), auth_negotiate_.can_delegate(), auth_negotiate_.server_auth_token(), auth_negotiate_.can_delegate(),
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment