1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171
|
// Copyright 2015 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "net/android/http_auth_negotiate_android.h"
#include "base/android/jni_string.h"
#include "base/android/scoped_java_ref.h"
#include "base/functional/bind.h"
#include "base/functional/callback_helpers.h"
#include "base/location.h"
#include "base/task/single_thread_task_runner.h"
#include "net/base/auth.h"
#include "net/base/net_errors.h"
#include "net/http/http_auth.h"
#include "net/http/http_auth_challenge_tokenizer.h"
#include "net/http/http_auth_multi_round_parse.h"
#include "net/http/http_auth_preferences.h"
#include "net/log/net_log_with_source.h"
// Must come after all headers that specialize FromJniType() / ToJniType().
#include "net/net_jni_headers/HttpNegotiateAuthenticator_jni.h"
using base::android::AttachCurrentThread;
using base::android::ConvertUTF8ToJavaString;
using base::android::ConvertJavaStringToUTF8;
using base::android::JavaParamRef;
using base::android::ScopedJavaLocalRef;
namespace net::android {
JavaNegotiateResultWrapper::JavaNegotiateResultWrapper(
const scoped_refptr<base::TaskRunner>& callback_task_runner,
base::OnceCallback<void(int, const std::string&)> thread_safe_callback)
: callback_task_runner_(callback_task_runner),
thread_safe_callback_(std::move(thread_safe_callback)) {}
JavaNegotiateResultWrapper::~JavaNegotiateResultWrapper() = default;
void JavaNegotiateResultWrapper::SetResult(JNIEnv* env,
const JavaParamRef<jobject>& obj,
int result,
const JavaParamRef<jstring>& token) {
// This will be called on the UI thread, so we have to post a task back to the
// correct thread to actually save the result
std::string raw_token;
if (token.obj())
raw_token = ConvertJavaStringToUTF8(env, token);
// Always post, even if we are on the same thread. This guarantees that the
// result will be delayed until after the request has completed, which
// simplifies the logic. In practice the result will only ever come back on
// the original thread in an obscure error case.
callback_task_runner_->PostTask(
FROM_HERE,
base::BindOnce(std::move(thread_safe_callback_), result, raw_token));
// We will always get precisely one call to set result for each call to
// getNextAuthToken, so we can now delete the callback object, and must
// do so to avoid a memory leak.
delete this;
}
HttpAuthNegotiateAndroid::HttpAuthNegotiateAndroid(
const HttpAuthPreferences* prefs)
: prefs_(prefs) {
JNIEnv* env = AttachCurrentThread();
java_authenticator_.Reset(Java_HttpNegotiateAuthenticator_create(
env, ConvertUTF8ToJavaString(env, GetAuthAndroidNegotiateAccountType())));
}
HttpAuthNegotiateAndroid::~HttpAuthNegotiateAndroid() = default;
bool HttpAuthNegotiateAndroid::Init(const NetLogWithSource& net_log) {
return true;
}
bool HttpAuthNegotiateAndroid::NeedsIdentity() const {
return false;
}
bool HttpAuthNegotiateAndroid::AllowsExplicitCredentials() const {
return false;
}
HttpAuth::AuthorizationResult HttpAuthNegotiateAndroid::ParseChallenge(
net::HttpAuthChallengeTokenizer* tok) {
if (first_challenge_) {
first_challenge_ = false;
return net::ParseFirstRoundChallenge(HttpAuth::AUTH_SCHEME_NEGOTIATE, tok);
}
std::string decoded_auth_token;
return net::ParseLaterRoundChallenge(HttpAuth::AUTH_SCHEME_NEGOTIATE, tok,
&server_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(
const AuthCredentials* credentials,
const std::string& spn,
const std::string& channel_bindings,
std::string* auth_token,
const NetLogWithSource& net_log,
net::CompletionOnceCallback callback) {
if (GetAuthAndroidNegotiateAccountType().empty()) {
// This can happen if there is a policy change, removing the account type,
// in the middle of a negotiation.
return ERR_UNSUPPORTED_AUTH_SCHEME;
}
DCHECK(auth_token);
DCHECK(completion_callback_.is_null());
DCHECK(!callback.is_null());
auth_token_ = auth_token;
completion_callback_ = std::move(callback);
scoped_refptr<base::SingleThreadTaskRunner> callback_task_runner =
base::SingleThreadTaskRunner::GetCurrentDefault();
base::OnceCallback<void(int, const std::string&)> thread_safe_callback =
base::BindOnce(&HttpAuthNegotiateAndroid::SetResultInternal,
weak_factory_.GetWeakPtr());
JNIEnv* env = AttachCurrentThread();
ScopedJavaLocalRef<jstring> java_server_auth_token =
ConvertUTF8ToJavaString(env, server_auth_token_);
ScopedJavaLocalRef<jstring> java_spn = ConvertUTF8ToJavaString(env, spn);
// It is intentional that callback_wrapper is not owned or deleted by the
// HttpAuthNegotiateAndroid object. The Java code will call the callback
// asynchronously on a different thread, and needs an object to call it on. As
// such, the callback_wrapper must not be deleted until the callback has been
// called, whatever happens to the HttpAuthNegotiateAndroid object.
//
// Unfortunately we have no automated way of managing C++ objects owned by
// Java, so the Java code must simply be written to guarantee that the
// callback is, in the end, called.
JavaNegotiateResultWrapper* callback_wrapper = new JavaNegotiateResultWrapper(
callback_task_runner, std::move(thread_safe_callback));
Java_HttpNegotiateAuthenticator_getNextAuthToken(
env, java_authenticator_, reinterpret_cast<intptr_t>(callback_wrapper),
java_spn, java_server_auth_token, can_delegate());
return ERR_IO_PENDING;
}
void HttpAuthNegotiateAndroid::SetDelegation(
HttpAuth::DelegationType delegation_type) {
DCHECK_NE(delegation_type, HttpAuth::DelegationType::kByKdcPolicy);
can_delegate_ = delegation_type == HttpAuth::DelegationType::kUnconstrained;
}
std::string HttpAuthNegotiateAndroid::GetAuthAndroidNegotiateAccountType()
const {
return prefs_->AuthAndroidNegotiateAccountType();
}
void HttpAuthNegotiateAndroid::SetResultInternal(int result,
const std::string& raw_token) {
DCHECK(auth_token_);
DCHECK(!completion_callback_.is_null());
if (result == OK)
*auth_token_ = "Negotiate " + raw_token;
std::move(completion_callback_).Run(result);
}
} // namespace net::android
|