OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "components/password_manager/content/renderer/credential_manager_client
.h" | 5 #include "components/password_manager/content/renderer/credential_manager_client
.h" |
6 | 6 |
7 #include <stdint.h> | 7 #include <stdint.h> |
8 | 8 |
9 #include <memory> | 9 #include <memory> |
10 #include <tuple> | 10 #include <tuple> |
11 | 11 |
12 #include "components/password_manager/content/common/credential_manager_messages
.h" | 12 #include "content/public/common/service_registry.h" |
| 13 #include "content/public/renderer/render_frame.h" |
| 14 #include "content/public/renderer/render_view.h" |
13 #include "content/public/test/render_view_test.h" | 15 #include "content/public/test/render_view_test.h" |
14 #include "ipc/ipc_test_sink.h" | 16 #include "mojo/public/cpp/bindings/binding_set.h" |
15 #include "testing/gtest/include/gtest/gtest.h" | 17 #include "testing/gtest/include/gtest/gtest.h" |
16 #include "third_party/WebKit/public/platform/WebCredential.h" | 18 #include "third_party/WebKit/public/platform/WebCredential.h" |
17 #include "third_party/WebKit/public/platform/WebCredentialManagerClient.h" | 19 #include "third_party/WebKit/public/platform/WebCredentialManagerClient.h" |
18 #include "third_party/WebKit/public/platform/WebCredentialManagerError.h" | 20 #include "third_party/WebKit/public/platform/WebCredentialManagerError.h" |
19 #include "third_party/WebKit/public/platform/WebPasswordCredential.h" | 21 #include "third_party/WebKit/public/platform/WebPasswordCredential.h" |
20 | 22 |
| 23 using content::ServiceRegistry; |
| 24 |
21 namespace password_manager { | 25 namespace password_manager { |
22 | 26 |
23 namespace { | 27 namespace { |
24 | 28 |
| 29 const char kTestCredentialPassword[] = "https://password.com/"; |
| 30 const char kTestCredentialEmpty[] = "https://empty.com/"; |
| 31 const char kTestCredentialReject[] = "https://reject.com/"; |
| 32 |
| 33 class FakeCredentialManager : public mojom::CredentialManager { |
| 34 public: |
| 35 FakeCredentialManager() {} |
| 36 ~FakeCredentialManager() override {} |
| 37 |
| 38 void BindRequest(mojom::CredentialManagerRequest request) { |
| 39 bindings_.AddBinding(this, std::move(request)); |
| 40 } |
| 41 |
| 42 private: |
| 43 // mojom::CredentialManager methods: |
| 44 void Store(mojom::CredentialInfoPtr credential, |
| 45 const StoreCallback& callback) override { |
| 46 callback.Run(); |
| 47 } |
| 48 |
| 49 void RequireUserMediation( |
| 50 const RequireUserMediationCallback& callback) override { |
| 51 callback.Run(); |
| 52 } |
| 53 |
| 54 void Get(bool zero_click_only, |
| 55 bool include_passwords, |
| 56 mojo::Array<mojo::String> federations, |
| 57 const GetCallback& callback) override { |
| 58 mojo::String& url = federations[0]; |
| 59 |
| 60 if (url == kTestCredentialPassword) { |
| 61 mojom::CredentialInfoPtr info = mojom::CredentialInfo::New(); |
| 62 info->type = mojom::CredentialType::PASSWORD; |
| 63 callback.Run(mojom::CredentialManagerError::SUCCESS, std::move(info)); |
| 64 } else if (url == kTestCredentialEmpty) { |
| 65 callback.Run(mojom::CredentialManagerError::SUCCESS, |
| 66 mojom::CredentialInfo::New()); |
| 67 } else if (url == kTestCredentialReject) { |
| 68 callback.Run(mojom::CredentialManagerError::PASSWORDSTOREUNAVAILABLE, |
| 69 nullptr); |
| 70 } |
| 71 } |
| 72 |
| 73 mojo::BindingSet<mojom::CredentialManager> bindings_; |
| 74 }; |
| 75 |
25 class CredentialManagerClientTest : public content::RenderViewTest { | 76 class CredentialManagerClientTest : public content::RenderViewTest { |
26 public: | 77 public: |
27 CredentialManagerClientTest() | 78 CredentialManagerClientTest() |
28 : callback_errored_(false), callback_succeeded_(false) {} | 79 : callback_errored_(false), callback_succeeded_(false) {} |
29 ~CredentialManagerClientTest() override {} | 80 ~CredentialManagerClientTest() override {} |
30 | 81 |
31 void SetUp() override { | 82 void SetUp() override { |
32 content::RenderViewTest::SetUp(); | 83 content::RenderViewTest::SetUp(); |
33 credential_.reset(new blink::WebPasswordCredential("", "", "", GURL())); | |
34 client_.reset(new CredentialManagerClient(view_)); | 84 client_.reset(new CredentialManagerClient(view_)); |
| 85 |
| 86 ServiceRegistry* registry = |
| 87 view_->GetMainRenderFrame()->GetServiceRegistry(); |
| 88 registry->AddServiceOverrideForTesting( |
| 89 mojom::CredentialManager::Name_, |
| 90 base::Bind(&CredentialManagerClientTest::BindCredentialManager, |
| 91 base::Unretained(this))); |
35 } | 92 } |
36 | 93 |
37 void TearDown() override { | 94 void TearDown() override { |
38 credential_.reset(); | 95 credential_.reset(); |
39 client_.reset(); | 96 client_.reset(); |
40 content::RenderViewTest::TearDown(); | 97 content::RenderViewTest::TearDown(); |
41 } | 98 } |
42 | 99 |
43 IPC::TestSink& sink() { return render_thread_->sink(); } | |
44 | |
45 blink::WebCredential* credential() { return credential_.get(); } | |
46 | |
47 // The browser's response to any of the messages the client sends must contain | |
48 // a request ID so that the client knows which request is being serviced. This | |
49 // method grabs the ID from an outgoing |message_id| message, and sets the | |
50 // |request_id| param to its value. If no request ID can be found, the method | |
51 // returns false, and the |request_id| is set to -1. | |
52 // | |
53 // Clears any pending messages upon return. | |
54 bool ExtractRequestId(uint32_t message_id, int& request_id) { | |
55 request_id = -1; | |
56 const IPC::Message* message = sink().GetFirstMessageMatching(message_id); | |
57 if (!message) | |
58 return false; | |
59 | |
60 switch (message_id) { | |
61 case CredentialManagerHostMsg_Store::ID: { | |
62 std::tuple<int, CredentialInfo> param; | |
63 CredentialManagerHostMsg_Store::Read(message, ¶m); | |
64 request_id = std::get<0>(param); | |
65 break; | |
66 } | |
67 | |
68 case CredentialManagerHostMsg_RequireUserMediation::ID: { | |
69 std::tuple<int> param; | |
70 CredentialManagerHostMsg_RequireUserMediation::Read(message, ¶m); | |
71 request_id = std::get<0>(param); | |
72 break; | |
73 } | |
74 | |
75 case CredentialManagerHostMsg_RequestCredential::ID: { | |
76 std::tuple<int, bool, bool, std::vector<GURL>> param; | |
77 CredentialManagerHostMsg_RequestCredential::Read(message, ¶m); | |
78 request_id = std::get<0>(param); | |
79 break; | |
80 } | |
81 | |
82 default: | |
83 break; | |
84 } | |
85 sink().ClearMessages(); | |
86 return request_id != -1; | |
87 } | |
88 | |
89 bool callback_errored() const { return callback_errored_; } | 100 bool callback_errored() const { return callback_errored_; } |
90 void set_callback_errored(bool state) { callback_errored_ = state; } | 101 void set_callback_errored(bool state) { callback_errored_ = state; } |
91 bool callback_succeeded() const { return callback_succeeded_; } | 102 bool callback_succeeded() const { return callback_succeeded_; } |
92 void set_callback_succeeded(bool state) { callback_succeeded_ = state; } | 103 void set_callback_succeeded(bool state) { callback_succeeded_ = state; } |
93 | 104 |
| 105 void BindCredentialManager(mojo::ScopedMessagePipeHandle handle) { |
| 106 fake_cm_.BindRequest( |
| 107 mojo::MakeRequest<mojom::CredentialManager>(std::move(handle))); |
| 108 } |
| 109 |
| 110 std::unique_ptr<blink::WebPasswordCredential> credential_; |
| 111 blink::WebCredentialManagerError error_; |
| 112 |
94 protected: | 113 protected: |
95 std::unique_ptr<CredentialManagerClient> client_; | 114 std::unique_ptr<CredentialManagerClient> client_; |
96 | 115 |
| 116 FakeCredentialManager fake_cm_; |
| 117 |
97 // True if a message's callback's 'onSuccess'/'onError' methods were called, | 118 // True if a message's callback's 'onSuccess'/'onError' methods were called, |
98 // false otherwise. We put these on the test object rather than on the | 119 // false otherwise. We put these on the test object rather than on the |
99 // Test*Callbacks objects because ownership of those objects passes into the | 120 // Test*Callbacks objects because ownership of those objects passes into the |
100 // client, which destroys the callbacks after calling them to resolve the | 121 // client, which destroys the callbacks after calling them to resolve the |
101 // pending Blink-side Promise. | 122 // pending Blink-side Promise. |
102 bool callback_errored_; | 123 bool callback_errored_; |
103 bool callback_succeeded_; | 124 bool callback_succeeded_; |
104 | |
105 std::unique_ptr<blink::WebPasswordCredential> credential_; | |
106 }; | 125 }; |
107 | 126 |
108 class TestNotificationCallbacks | 127 class TestNotificationCallbacks |
109 : public blink::WebCredentialManagerClient::NotificationCallbacks { | 128 : public blink::WebCredentialManagerClient::NotificationCallbacks { |
110 public: | 129 public: |
111 explicit TestNotificationCallbacks(CredentialManagerClientTest* test) | 130 explicit TestNotificationCallbacks(CredentialManagerClientTest* test) |
112 : test_(test) {} | 131 : test_(test) {} |
113 | 132 |
114 ~TestNotificationCallbacks() override {} | 133 ~TestNotificationCallbacks() override {} |
115 | 134 |
116 void onSuccess() override { test_->set_callback_succeeded(true); } | 135 void onSuccess() override { test_->set_callback_succeeded(true); } |
117 | 136 |
118 void onError(blink::WebCredentialManagerError reason) override { | 137 void onError(blink::WebCredentialManagerError reason) override { |
119 test_->set_callback_errored(true); | 138 test_->set_callback_errored(true); |
120 } | 139 } |
121 | 140 |
122 private: | 141 private: |
123 CredentialManagerClientTest* test_; | 142 CredentialManagerClientTest* test_; |
124 }; | 143 }; |
125 | 144 |
126 class TestRequestCallbacks | 145 class TestRequestCallbacks |
127 : public blink::WebCredentialManagerClient::RequestCallbacks { | 146 : public blink::WebCredentialManagerClient::RequestCallbacks { |
128 public: | 147 public: |
129 explicit TestRequestCallbacks(CredentialManagerClientTest* test) | 148 explicit TestRequestCallbacks(CredentialManagerClientTest* test) |
130 : test_(test) {} | 149 : test_(test) {} |
131 | 150 |
132 ~TestRequestCallbacks() override {} | 151 ~TestRequestCallbacks() override {} |
133 | 152 |
134 void onSuccess(std::unique_ptr<blink::WebCredential>) override { | 153 void onSuccess(std::unique_ptr<blink::WebCredential> credential) override { |
135 test_->set_callback_succeeded(true); | 154 test_->set_callback_succeeded(true); |
| 155 |
| 156 blink::WebCredential* ptr = credential.release(); |
| 157 test_->credential_.reset(static_cast<blink::WebPasswordCredential*>(ptr)); |
136 } | 158 } |
137 | 159 |
138 void onError(blink::WebCredentialManagerError reason) override { | 160 void onError(blink::WebCredentialManagerError reason) override { |
139 test_->set_callback_errored(true); | 161 test_->set_callback_errored(true); |
| 162 test_->credential_.reset(); |
| 163 test_->error_ = reason; |
140 } | 164 } |
141 | 165 |
142 private: | 166 private: |
143 CredentialManagerClientTest* test_; | 167 CredentialManagerClientTest* test_; |
144 }; | 168 }; |
145 | 169 |
| 170 void RunAllPendingTasks() { |
| 171 base::RunLoop run_loop; |
| 172 base::MessageLoop::current()->PostTask( |
| 173 FROM_HERE, base::MessageLoop::QuitWhenIdleClosure()); |
| 174 run_loop.Run(); |
| 175 } |
| 176 |
146 } // namespace | 177 } // namespace |
147 | 178 |
148 TEST_F(CredentialManagerClientTest, SendStore) { | 179 TEST_F(CredentialManagerClientTest, SendStore) { |
149 int request_id; | 180 credential_.reset(new blink::WebPasswordCredential("", "", "", GURL())); |
150 EXPECT_FALSE( | |
151 ExtractRequestId(CredentialManagerHostMsg_Store::ID, request_id)); | |
152 | |
153 std::unique_ptr<TestNotificationCallbacks> callbacks( | 181 std::unique_ptr<TestNotificationCallbacks> callbacks( |
154 new TestNotificationCallbacks(this)); | 182 new TestNotificationCallbacks(this)); |
155 client_->dispatchStore(*credential(), callbacks.release()); | 183 client_->dispatchStore(*credential_, callbacks.release()); |
156 | 184 |
157 EXPECT_TRUE(ExtractRequestId(CredentialManagerHostMsg_Store::ID, request_id)); | 185 RunAllPendingTasks(); |
158 | 186 |
159 client_->OnAcknowledgeStore(request_id); | |
160 EXPECT_TRUE(callback_succeeded()); | 187 EXPECT_TRUE(callback_succeeded()); |
161 EXPECT_FALSE(callback_errored()); | 188 EXPECT_FALSE(callback_errored()); |
162 } | 189 } |
163 | 190 |
164 TEST_F(CredentialManagerClientTest, SendRequestUserMediation) { | 191 TEST_F(CredentialManagerClientTest, SendRequestUserMediation) { |
165 int request_id; | |
166 EXPECT_FALSE(ExtractRequestId( | |
167 CredentialManagerHostMsg_RequireUserMediation::ID, request_id)); | |
168 | |
169 std::unique_ptr<TestNotificationCallbacks> callbacks( | 192 std::unique_ptr<TestNotificationCallbacks> callbacks( |
170 new TestNotificationCallbacks(this)); | 193 new TestNotificationCallbacks(this)); |
171 client_->dispatchRequireUserMediation(callbacks.release()); | 194 client_->dispatchRequireUserMediation(callbacks.release()); |
172 | 195 |
173 EXPECT_TRUE(ExtractRequestId( | 196 RunAllPendingTasks(); |
174 CredentialManagerHostMsg_RequireUserMediation::ID, request_id)); | |
175 | 197 |
176 client_->OnAcknowledgeRequireUserMediation(request_id); | |
177 EXPECT_TRUE(callback_succeeded()); | 198 EXPECT_TRUE(callback_succeeded()); |
178 EXPECT_FALSE(callback_errored()); | 199 EXPECT_FALSE(callback_errored()); |
179 } | 200 } |
180 | 201 |
181 TEST_F(CredentialManagerClientTest, SendRequestCredential) { | 202 TEST_F(CredentialManagerClientTest, SendRequestCredential) { |
182 int request_id; | |
183 EXPECT_FALSE(ExtractRequestId(CredentialManagerHostMsg_RequestCredential::ID, | |
184 request_id)); | |
185 | |
186 std::unique_ptr<TestRequestCallbacks> callbacks( | 203 std::unique_ptr<TestRequestCallbacks> callbacks( |
187 new TestRequestCallbacks(this)); | 204 new TestRequestCallbacks(this)); |
188 std::vector<GURL> federations; | 205 std::vector<GURL> federations; |
| 206 federations.push_back(GURL(kTestCredentialPassword)); |
189 client_->dispatchGet(false, true, federations, callbacks.release()); | 207 client_->dispatchGet(false, true, federations, callbacks.release()); |
190 | 208 |
191 EXPECT_TRUE(ExtractRequestId(CredentialManagerHostMsg_RequestCredential::ID, | 209 RunAllPendingTasks(); |
192 request_id)); | |
193 | 210 |
194 CredentialInfo info; | |
195 info.type = CredentialType::CREDENTIAL_TYPE_PASSWORD; | |
196 client_->OnSendCredential(request_id, info); | |
197 EXPECT_TRUE(callback_succeeded()); | 211 EXPECT_TRUE(callback_succeeded()); |
198 EXPECT_FALSE(callback_errored()); | 212 EXPECT_FALSE(callback_errored()); |
| 213 EXPECT_TRUE(credential_); |
| 214 EXPECT_EQ("password", credential_->type()); |
199 } | 215 } |
200 | 216 |
201 TEST_F(CredentialManagerClientTest, SendRequestCredentialEmpty) { | 217 TEST_F(CredentialManagerClientTest, SendRequestCredentialEmpty) { |
202 int request_id; | |
203 EXPECT_FALSE(ExtractRequestId(CredentialManagerHostMsg_RequestCredential::ID, | |
204 request_id)); | |
205 | |
206 std::unique_ptr<TestRequestCallbacks> callbacks( | 218 std::unique_ptr<TestRequestCallbacks> callbacks( |
207 new TestRequestCallbacks(this)); | 219 new TestRequestCallbacks(this)); |
208 std::vector<GURL> federations; | 220 std::vector<GURL> federations; |
| 221 federations.push_back(GURL(kTestCredentialEmpty)); |
209 client_->dispatchGet(false, true, federations, callbacks.release()); | 222 client_->dispatchGet(false, true, federations, callbacks.release()); |
210 | 223 |
211 EXPECT_TRUE(ExtractRequestId(CredentialManagerHostMsg_RequestCredential::ID, | 224 RunAllPendingTasks(); |
212 request_id)); | |
213 | 225 |
214 CredentialInfo info; // Send an empty credential in response. | |
215 client_->OnSendCredential(request_id, info); | |
216 EXPECT_TRUE(callback_succeeded()); | 226 EXPECT_TRUE(callback_succeeded()); |
217 EXPECT_FALSE(callback_errored()); | 227 EXPECT_FALSE(callback_errored()); |
| 228 EXPECT_FALSE(credential_); |
| 229 } |
| 230 |
| 231 TEST_F(CredentialManagerClientTest, SendRequestCredentialReject) { |
| 232 std::unique_ptr<TestRequestCallbacks> callbacks( |
| 233 new TestRequestCallbacks(this)); |
| 234 std::vector<GURL> federations; |
| 235 federations.push_back(GURL(kTestCredentialReject)); |
| 236 client_->dispatchGet(false, true, federations, callbacks.release()); |
| 237 |
| 238 RunAllPendingTasks(); |
| 239 |
| 240 EXPECT_FALSE(callback_succeeded()); |
| 241 EXPECT_TRUE(callback_errored()); |
| 242 EXPECT_FALSE(credential_); |
| 243 EXPECT_EQ(blink::WebCredentialManagerError:: |
| 244 WebCredentialManagerPasswordStoreUnavailableError, |
| 245 error_); |
218 } | 246 } |
219 | 247 |
220 } // namespace password_manager | 248 } // namespace password_manager |
OLD | NEW |