1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "net/android/http_auth_negotiate_android.h"
7 #include "base/android/jni_string.h"
8 #include "base/android/scoped_java_ref.h"
10 #include "base/callback_helpers.h"
11 #include "base/location.h"
12 #include "base/thread_task_runner_handle.h"
13 #include "jni/HttpNegotiateAuthenticator_jni.h"
14 #include "net/base/auth.h"
15 #include "net/base/net_errors.h"
16 #include "net/http/http_auth_challenge_tokenizer.h"
17 #include "net/http/http_auth_multi_round_parse.h"
19 using base::android::AttachCurrentThread
;
20 using base::android::ConvertUTF8ToJavaString
;
21 using base::android::ConvertJavaStringToUTF8
;
22 using base::android::ScopedJavaLocalRef
;
27 JavaNegotiateResultWrapper::JavaNegotiateResultWrapper(
28 const scoped_refptr
<base::TaskRunner
>& callback_task_runner
,
29 const base::Callback
<void(int, const std::string
&)>& thread_safe_callback
)
30 : callback_task_runner_(callback_task_runner
),
31 thread_safe_callback_(thread_safe_callback
) {
34 JavaNegotiateResultWrapper::~JavaNegotiateResultWrapper() {
37 void JavaNegotiateResultWrapper::SetResult(JNIEnv
* env
,
41 // This will be called on the UI thread, so we have to post a task back to the
42 // correct thread to actually save the result
43 std::string raw_token
= ConvertJavaStringToUTF8(env
, token
);
44 // Always post, even if we are on the same thread. This guarantees that the
45 // result will be delayed until after the request has completed, which
46 // simplifies the logic. In practice the result will only ever come back on
47 // the original thread in an obscure error case.
48 callback_task_runner_
->PostTask(
49 FROM_HERE
, base::Bind(thread_safe_callback_
, result
, raw_token
));
50 // We will always get precisely one call to set result for each call to
51 // getNextAuthToken, so we can now delete the callback object, and must
52 // do so to avoid a memory leak.
56 HttpAuthNegotiateAndroid::HttpAuthNegotiateAndroid(
57 const std::string
& account_type
)
58 : account_type_(account_type
),
60 first_challenge_(true),
63 DCHECK(!account_type
.empty());
64 JNIEnv
* env
= AttachCurrentThread();
65 java_authenticator_
.Reset(Java_HttpNegotiateAuthenticator_create(
66 env
, ConvertUTF8ToJavaString(env
, account_type
).obj()));
69 HttpAuthNegotiateAndroid::~HttpAuthNegotiateAndroid() {
72 bool HttpAuthNegotiateAndroid::Register(JNIEnv
* env
) {
73 return RegisterNativesImpl(env
);
76 bool HttpAuthNegotiateAndroid::Init() {
80 bool HttpAuthNegotiateAndroid::NeedsIdentity() const {
84 bool HttpAuthNegotiateAndroid::AllowsExplicitCredentials() const {
88 HttpAuth::AuthorizationResult
HttpAuthNegotiateAndroid::ParseChallenge(
89 net::HttpAuthChallengeTokenizer
* tok
) {
90 if (first_challenge_
) {
91 first_challenge_
= false;
92 return net::ParseFirstRoundChallenge("negotiate", tok
);
94 std::string decoded_auth_token
;
95 return net::ParseLaterRoundChallenge("negotiate", tok
, &server_auth_token_
,
99 int HttpAuthNegotiateAndroid::GenerateAuthToken(
100 const AuthCredentials
* credentials
,
101 const std::string
& spn
,
102 std::string
* auth_token
,
103 const net::CompletionCallback
& callback
) {
105 DCHECK(completion_callback_
.is_null());
106 DCHECK(!callback
.is_null());
108 auth_token_
= auth_token
;
109 completion_callback_
= callback
;
110 scoped_refptr
<base::SingleThreadTaskRunner
> callback_task_runner
=
111 base::ThreadTaskRunnerHandle::Get();
112 base::Callback
<void(int, const std::string
&)> thread_safe_callback
=
113 base::Bind(&HttpAuthNegotiateAndroid::SetResultInternal
,
114 weak_factory_
.GetWeakPtr());
115 JNIEnv
* env
= AttachCurrentThread();
116 ScopedJavaLocalRef
<jstring
> java_server_auth_token
=
117 ConvertUTF8ToJavaString(env
, server_auth_token_
);
118 ScopedJavaLocalRef
<jstring
> java_spn
= ConvertUTF8ToJavaString(env
, spn
);
119 ScopedJavaLocalRef
<jstring
> java_account_type
=
120 ConvertUTF8ToJavaString(env
, account_type_
);
122 // It is intentional that callback_wrapper is not owned or deleted by the
123 // HttpAuthNegotiateAndroid object. The Java code will call the callback
124 // asynchronously on a different thread, and needs an object to call it on. As
125 // such, the callback_wrapper must not be deleted until the callback has been
126 // called, whatever happens to the HttpAuthNegotiateAndroid object.
128 // Unfortunately we have no automated way of managing C++ objects owned by
129 // Java, so the Java code must simply be written to guarantee that the
130 // callback is, in the end, called.
131 JavaNegotiateResultWrapper
* callback_wrapper
= new JavaNegotiateResultWrapper(
132 callback_task_runner
, thread_safe_callback
);
133 Java_HttpNegotiateAuthenticator_getNextAuthToken(
134 env
, java_authenticator_
.obj(),
135 reinterpret_cast<intptr_t>(callback_wrapper
), java_spn
.obj(),
136 java_server_auth_token
.obj(), can_delegate_
);
137 return ERR_IO_PENDING
;
140 void HttpAuthNegotiateAndroid::Delegate() {
141 can_delegate_
= true;
144 void HttpAuthNegotiateAndroid::SetResultInternal(int result
,
145 const std::string
& raw_token
) {
147 DCHECK(!completion_callback_
.is_null());
149 *auth_token_
= "Negotiate " + raw_token
;
150 base::ResetAndReturn(&completion_callback_
).Run(result
);
153 } // namespace android