blob: 75631e1fbbc40a4743f0eafe6bcdf4f8f6df7c9c [file] [log] [blame]
joedow7dc48992016-08-31 19:13:381// Copyright 2016 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.
4
5#include <memory>
6#include <string>
Victor Costanaeb7f8e2018-04-06 19:05:267#include <tuple>
joedow7dc48992016-08-31 19:13:388#include <utility>
9
10#include "base/bind.h"
11#include "base/callback.h"
12#include "base/macros.h"
13#include "base/memory/ptr_util.h"
14#include "base/message_loop/message_loop.h"
15#include "base/run_loop.h"
16#include "remoting/protocol/authenticator.h"
17#include "remoting/protocol/protocol_mock_objects.h"
18#include "remoting/protocol/validating_authenticator.h"
19#include "testing/gmock/include/gmock/gmock.h"
20#include "testing/gtest/include/gtest/gtest.h"
kjellanderf0e410b2017-01-04 14:45:0121#include "third_party/libjingle_xmpp/xmllite/xmlelement.h"
joedow7dc48992016-08-31 19:13:3822
23namespace remoting {
24namespace protocol {
25
26namespace {
27
28using testing::_;
29using testing::Return;
30
31typedef ValidatingAuthenticator::Result ValidationResult;
32
joedowf38c5d72017-03-20 15:55:4633constexpr char kRemoteTestJid[] = "ficticious_jid_for_testing";
joedow7dc48992016-08-31 19:13:3834
35// testing::InvokeArgument<N> does not work with base::Callback, fortunately
36// gmock makes it simple to create action templates that do for the various
37// possible numbers of arguments.
38ACTION_TEMPLATE(InvokeCallbackArgument,
39 HAS_1_TEMPLATE_PARAMS(int, k),
40 AND_0_VALUE_PARAMS()) {
Victor Costanaeb7f8e2018-04-06 19:05:2641 std::get<k>(args).Run();
joedow7dc48992016-08-31 19:13:3842}
43
44} // namespace
45
46class ValidatingAuthenticatorTest : public testing::Test {
47 public:
48 ValidatingAuthenticatorTest();
49 ~ValidatingAuthenticatorTest() override;
50
51 void ValidateCallback(
52 const std::string& remote_jid,
53 const ValidatingAuthenticator::ResultCallback& callback);
54
55 protected:
56 // testing::Test overrides.
57 void SetUp() override;
58
59 // Calls ProcessMessage() on |validating_authenticator_| and blocks until
60 // the result callback is called.
61 void SendMessageAndWaitForCallback();
62
63 // Used to set up our mock behaviors on the MockAuthenticator object passed
64 // to |validating_authenticator_|. Lifetime of the object is controlled by
65 // |validating_authenticator_| so this pointer is no longer valid once
66 // the owner is destroyed.
joedowf38c5d72017-03-20 15:55:4667 testing::NiceMock<MockAuthenticator>* mock_authenticator_ = nullptr;
joedow7dc48992016-08-31 19:13:3868
69 // This member is used to drive behavior in |validating_authenticator_| when
joedowf38c5d72017-03-20 15:55:4670 // its validation complete callback is run.
joedow7dc48992016-08-31 19:13:3871 ValidationResult validation_result_ = ValidationResult::SUCCESS;
72
joedowf38c5d72017-03-20 15:55:4673 // Tracks whether our validation callback has been called or not.
joedow7dc48992016-08-31 19:13:3874 bool validate_complete_called_ = false;
75
76 // The object under test.
77 std::unique_ptr<ValidatingAuthenticator> validating_authenticator_;
78
79 private:
80 base::MessageLoop message_loop_;
81
82 DISALLOW_COPY_AND_ASSIGN(ValidatingAuthenticatorTest);
83};
84
Chris Watkins6fe52aa2017-11-28 03:24:0585ValidatingAuthenticatorTest::ValidatingAuthenticatorTest() = default;
joedow7dc48992016-08-31 19:13:3886
Chris Watkins6fe52aa2017-11-28 03:24:0587ValidatingAuthenticatorTest::~ValidatingAuthenticatorTest() = default;
joedow7dc48992016-08-31 19:13:3888
89void ValidatingAuthenticatorTest::ValidateCallback(
90 const std::string& remote_jid,
91 const ValidatingAuthenticator::ResultCallback& callback) {
92 validate_complete_called_ = true;
93 callback.Run(validation_result_);
94}
95
96void ValidatingAuthenticatorTest::SetUp() {
joedowf38c5d72017-03-20 15:55:4697 mock_authenticator_ = new testing::NiceMock<MockAuthenticator>();
joedow7dc48992016-08-31 19:13:3898 std::unique_ptr<Authenticator> authenticator(mock_authenticator_);
99
100 validating_authenticator_.reset(new ValidatingAuthenticator(
101 kRemoteTestJid, base::Bind(&ValidatingAuthenticatorTest::ValidateCallback,
102 base::Unretained(this)),
103 std::move(authenticator)));
104}
105
106void ValidatingAuthenticatorTest::SendMessageAndWaitForCallback() {
107 base::RunLoop run_loop;
108 std::unique_ptr<buzz::XmlElement> first_message(
109 Authenticator::CreateEmptyAuthenticatorMessage());
110 validating_authenticator_->ProcessMessage(first_message.get(),
111 run_loop.QuitClosure());
112 run_loop.Run();
113}
114
115TEST_F(ValidatingAuthenticatorTest, ValidConnection_SingleMessage) {
116 EXPECT_CALL(*mock_authenticator_, ProcessMessage(_, _))
117 .Times(1)
118 .WillOnce(InvokeCallbackArgument<1>());
119
120 ON_CALL(*mock_authenticator_, state())
121 .WillByDefault(Return(Authenticator::ACCEPTED));
122
123 SendMessageAndWaitForCallback();
124 ASSERT_TRUE(validate_complete_called_);
joedowf38c5d72017-03-20 15:55:46125 ASSERT_EQ(Authenticator::ACCEPTED, validating_authenticator_->state());
joedow7dc48992016-08-31 19:13:38126}
127
128TEST_F(ValidatingAuthenticatorTest, ValidConnection_TwoMessages) {
129 // Send the first message to the authenticator, set the mock up to act
130 // like it is waiting for a second message.
131 EXPECT_CALL(*mock_authenticator_, ProcessMessage(_, _))
132 .Times(2)
133 .WillRepeatedly(InvokeCallbackArgument<1>());
134
135 EXPECT_CALL(*mock_authenticator_, state())
136 .WillRepeatedly(Return(Authenticator::MESSAGE_READY));
137
138 SendMessageAndWaitForCallback();
joedowf38c5d72017-03-20 15:55:46139 ASSERT_FALSE(validate_complete_called_);
140 ASSERT_EQ(Authenticator::MESSAGE_READY, validating_authenticator_->state());
joedow7dc48992016-08-31 19:13:38141
142 // Now 'retrieve' the message for the client which resets the state.
143 EXPECT_CALL(*mock_authenticator_, state())
144 .WillRepeatedly(Return(Authenticator::WAITING_MESSAGE));
145
146 // This dance is needed because GMock doesn't handle unique_ptrs very well.
147 // The mock method receives a raw pointer which it wraps and returns when
148 // GetNextMessage() is called.
149 std::unique_ptr<buzz::XmlElement> next_message(
150 Authenticator::CreateEmptyAuthenticatorMessage());
151 EXPECT_CALL(*mock_authenticator_, GetNextMessagePtr())
152 .Times(1)
153 .WillOnce(Return(next_message.release()));
154
155 validating_authenticator_->GetNextMessage();
joedowf38c5d72017-03-20 15:55:46156 ASSERT_EQ(Authenticator::WAITING_MESSAGE, validating_authenticator_->state());
joedow7dc48992016-08-31 19:13:38157
158 // Now send the second message for processing.
159 EXPECT_CALL(*mock_authenticator_, state())
160 .WillRepeatedly(Return(Authenticator::ACCEPTED));
161
joedow7dc48992016-08-31 19:13:38162 SendMessageAndWaitForCallback();
joedowf38c5d72017-03-20 15:55:46163 ASSERT_TRUE(validate_complete_called_);
164 ASSERT_EQ(Authenticator::ACCEPTED, validating_authenticator_->state());
joedow7dc48992016-08-31 19:13:38165}
166
joedowf38c5d72017-03-20 15:55:46167TEST_F(ValidatingAuthenticatorTest, ValidConnection_SendBeforeAccept) {
168 // This test simulates an authenticator which needs to send a message before
169 // transitioning to the ACCEPTED state.
170 EXPECT_CALL(*mock_authenticator_, ProcessMessage(_, _))
171 .Times(1)
172 .WillRepeatedly(InvokeCallbackArgument<1>());
joedow7dc48992016-08-31 19:13:38173
joedowf38c5d72017-03-20 15:55:46174 EXPECT_CALL(*mock_authenticator_, state())
175 .WillOnce(Return(Authenticator::MESSAGE_READY))
176 .WillOnce(Return(Authenticator::ACCEPTED));
177
178 // This dance is needed because GMock doesn't handle unique_ptrs very well.
179 // The mock method receives a raw pointer which it wraps and returns when
180 // GetNextMessage() is called.
181 std::unique_ptr<buzz::XmlElement> next_message(
182 Authenticator::CreateEmptyAuthenticatorMessage());
183 EXPECT_CALL(*mock_authenticator_, GetNextMessagePtr())
184 .Times(1)
185 .WillOnce(Return(next_message.release()));
joedow7dc48992016-08-31 19:13:38186
187 SendMessageAndWaitForCallback();
188 ASSERT_TRUE(validate_complete_called_);
joedowf38c5d72017-03-20 15:55:46189 ASSERT_EQ(Authenticator::MESSAGE_READY, validating_authenticator_->state());
190
191 // Now 'retrieve' the message for the client which resets the state.
192 validating_authenticator_->GetNextMessage();
193 ASSERT_EQ(Authenticator::ACCEPTED, validating_authenticator_->state());
joedow7dc48992016-08-31 19:13:38194}
195
joedowf38c5d72017-03-20 15:55:46196TEST_F(ValidatingAuthenticatorTest, ValidConnection_ErrorInvalidCredentials) {
joedow7dc48992016-08-31 19:13:38197 EXPECT_CALL(*mock_authenticator_, ProcessMessage(_, _))
198 .Times(1)
199 .WillOnce(InvokeCallbackArgument<1>());
200
201 ON_CALL(*mock_authenticator_, state())
joedowf38c5d72017-03-20 15:55:46202 .WillByDefault(Return(Authenticator::ACCEPTED));
joedow7dc48992016-08-31 19:13:38203
joedowf38c5d72017-03-20 15:55:46204 validation_result_ = ValidationResult::ERROR_INVALID_CREDENTIALS;
joedow7dc48992016-08-31 19:13:38205
206 SendMessageAndWaitForCallback();
207 ASSERT_TRUE(validate_complete_called_);
joedowf38c5d72017-03-20 15:55:46208 ASSERT_EQ(Authenticator::REJECTED, validating_authenticator_->state());
209 ASSERT_EQ(Authenticator::INVALID_CREDENTIALS,
210 validating_authenticator_->rejection_reason());
joedow7dc48992016-08-31 19:13:38211}
212
joedowf38c5d72017-03-20 15:55:46213TEST_F(ValidatingAuthenticatorTest, ValidConnection_ErrorRejectedByUser) {
214 EXPECT_CALL(*mock_authenticator_, ProcessMessage(_, _))
215 .Times(1)
216 .WillOnce(InvokeCallbackArgument<1>());
217
218 ON_CALL(*mock_authenticator_, state())
219 .WillByDefault(Return(Authenticator::ACCEPTED));
220
221 validation_result_ = ValidationResult::ERROR_REJECTED_BY_USER;
222
223 SendMessageAndWaitForCallback();
224 ASSERT_TRUE(validate_complete_called_);
225 ASSERT_EQ(Authenticator::REJECTED, validating_authenticator_->state());
226 ASSERT_EQ(Authenticator::REJECTED_BY_USER,
227 validating_authenticator_->rejection_reason());
228}
229
230TEST_F(ValidatingAuthenticatorTest, ValidConnection_ErrorTooManyConnections) {
231 EXPECT_CALL(*mock_authenticator_, ProcessMessage(_, _))
232 .Times(1)
233 .WillOnce(InvokeCallbackArgument<1>());
234
235 ON_CALL(*mock_authenticator_, state())
236 .WillByDefault(Return(Authenticator::ACCEPTED));
237
238 validation_result_ = ValidationResult::ERROR_TOO_MANY_CONNECTIONS;
239
240 SendMessageAndWaitForCallback();
241 ASSERT_TRUE(validate_complete_called_);
242 ASSERT_EQ(Authenticator::REJECTED, validating_authenticator_->state());
243 ASSERT_EQ(Authenticator::TOO_MANY_CONNECTIONS,
244 validating_authenticator_->rejection_reason());
245}
246
247TEST_F(ValidatingAuthenticatorTest, InvalidConnection_InvalidCredentials) {
joedow7dc48992016-08-31 19:13:38248 EXPECT_CALL(*mock_authenticator_, ProcessMessage(_, _))
249 .Times(1)
250 .WillOnce(InvokeCallbackArgument<1>());
251
252 ON_CALL(*mock_authenticator_, state())
253 .WillByDefault(Return(Authenticator::REJECTED));
254
255 ON_CALL(*mock_authenticator_, rejection_reason())
256 .WillByDefault(Return(Authenticator::INVALID_CREDENTIALS));
257
joedowf38c5d72017-03-20 15:55:46258 // Verify validation callback is not called for invalid connections.
joedow7dc48992016-08-31 19:13:38259 SendMessageAndWaitForCallback();
joedowf38c5d72017-03-20 15:55:46260 ASSERT_FALSE(validate_complete_called_);
261 ASSERT_EQ(Authenticator::REJECTED, validating_authenticator_->state());
262 ASSERT_EQ(Authenticator::INVALID_CREDENTIALS,
263 validating_authenticator_->rejection_reason());
joedow7dc48992016-08-31 19:13:38264}
265
joedowf38c5d72017-03-20 15:55:46266TEST_F(ValidatingAuthenticatorTest, InvalidConnection_InvalidAccount) {
267 EXPECT_CALL(*mock_authenticator_, ProcessMessage(_, _))
268 .Times(1)
269 .WillOnce(InvokeCallbackArgument<1>());
270
271 ON_CALL(*mock_authenticator_, state())
272 .WillByDefault(Return(Authenticator::REJECTED));
273
274 ON_CALL(*mock_authenticator_, rejection_reason())
275 .WillByDefault(Return(Authenticator::INVALID_ACCOUNT));
276
277 // Verify validation callback is not called for invalid connections.
278 SendMessageAndWaitForCallback();
279 ASSERT_FALSE(validate_complete_called_);
280 ASSERT_EQ(Authenticator::REJECTED, validating_authenticator_->state());
281 ASSERT_EQ(Authenticator::INVALID_ACCOUNT,
282 validating_authenticator_->rejection_reason());
283}
284
285TEST_F(ValidatingAuthenticatorTest, InvalidConnection_ProtocolError) {
joedow7dc48992016-08-31 19:13:38286 EXPECT_CALL(*mock_authenticator_, ProcessMessage(_, _))
287 .Times(1)
288 .WillOnce(InvokeCallbackArgument<1>());
289
290 ON_CALL(*mock_authenticator_, state())
291 .WillByDefault(Return(Authenticator::REJECTED));
292
293 ON_CALL(*mock_authenticator_, rejection_reason())
294 .WillByDefault(Return(Authenticator::PROTOCOL_ERROR));
295
joedowf38c5d72017-03-20 15:55:46296 // Verify validation callback is not called for invalid connections.
joedow7dc48992016-08-31 19:13:38297 SendMessageAndWaitForCallback();
joedowf38c5d72017-03-20 15:55:46298 ASSERT_FALSE(validate_complete_called_);
299 ASSERT_EQ(Authenticator::REJECTED, validating_authenticator_->state());
300 ASSERT_EQ(Authenticator::PROTOCOL_ERROR,
301 validating_authenticator_->rejection_reason());
joedow7dc48992016-08-31 19:13:38302}
303
304} // namespace protocol
305} // namespace remoting