| // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "remoting/protocol/fake_authenticator.h" |
| |
| #include "base/message_loop/message_loop.h" |
| #include "base/strings/string_number_conversions.h" |
| #include "net/base/io_buffer.h" |
| #include "net/socket/stream_socket.h" |
| #include "remoting/base/constants.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| #include "third_party/libjingle/source/talk/xmllite/xmlelement.h" |
| |
| namespace remoting { |
| namespace protocol { |
| |
| FakeChannelAuthenticator::FakeChannelAuthenticator(bool accept, bool async) |
| : result_(accept ? net::OK : net::ERR_FAILED), |
| async_(async), |
| did_read_bytes_(false), |
| did_write_bytes_(false), |
| weak_factory_(this) { |
| } |
| |
| FakeChannelAuthenticator::~FakeChannelAuthenticator() { |
| } |
| |
| void FakeChannelAuthenticator::SecureAndAuthenticate( |
| scoped_ptr<net::StreamSocket> socket, |
| const DoneCallback& done_callback) { |
| socket_ = socket.Pass(); |
| |
| if (async_) { |
| done_callback_ = done_callback; |
| |
| scoped_refptr<net::IOBuffer> write_buf = new net::IOBuffer(1); |
| write_buf->data()[0] = 0; |
| int result = |
| socket_->Write(write_buf.get(), |
| 1, |
| base::Bind(&FakeChannelAuthenticator::OnAuthBytesWritten, |
| weak_factory_.GetWeakPtr())); |
| if (result != net::ERR_IO_PENDING) { |
| // This will not call the callback because |did_read_bytes_| is |
| // still set to false. |
| OnAuthBytesWritten(result); |
| } |
| |
| scoped_refptr<net::IOBuffer> read_buf = new net::IOBuffer(1); |
| result = |
| socket_->Read(read_buf.get(), |
| 1, |
| base::Bind(&FakeChannelAuthenticator::OnAuthBytesRead, |
| weak_factory_.GetWeakPtr())); |
| if (result != net::ERR_IO_PENDING) |
| OnAuthBytesRead(result); |
| } else { |
| if (result_ != net::OK) |
| socket_.reset(); |
| done_callback.Run(result_, socket_.Pass()); |
| } |
| } |
| |
| void FakeChannelAuthenticator::OnAuthBytesWritten(int result) { |
| EXPECT_EQ(1, result); |
| EXPECT_FALSE(did_write_bytes_); |
| did_write_bytes_ = true; |
| if (did_read_bytes_) |
| done_callback_.Run(result_, socket_.Pass()); |
| } |
| |
| void FakeChannelAuthenticator::OnAuthBytesRead(int result) { |
| EXPECT_EQ(1, result); |
| EXPECT_FALSE(did_read_bytes_); |
| did_read_bytes_ = true; |
| if (did_write_bytes_) |
| done_callback_.Run(result_, socket_.Pass()); |
| } |
| |
| FakeAuthenticator::FakeAuthenticator( |
| Type type, int round_trips, Action action, bool async) |
| : type_(type), |
| round_trips_(round_trips), |
| action_(action), |
| async_(async), |
| messages_(0) { |
| } |
| |
| FakeAuthenticator::~FakeAuthenticator() { |
| } |
| |
| Authenticator::State FakeAuthenticator::state() const { |
| EXPECT_LE(messages_, round_trips_ * 2); |
| if (messages_ >= round_trips_ * 2) { |
| if (action_ == REJECT) { |
| return REJECTED; |
| } else { |
| return ACCEPTED; |
| } |
| } |
| |
| // Don't send the last message if this is a host that wants to |
| // reject a connection. |
| if (messages_ == round_trips_ * 2 - 1 && |
| type_ == HOST && action_ == REJECT) { |
| return REJECTED; |
| } |
| |
| // We are not done yet. process next message. |
| if ((messages_ % 2 == 0 && type_ == CLIENT) || |
| (messages_ % 2 == 1 && type_ == HOST)) { |
| return MESSAGE_READY; |
| } else { |
| return WAITING_MESSAGE; |
| } |
| } |
| |
| Authenticator::RejectionReason FakeAuthenticator::rejection_reason() const { |
| EXPECT_EQ(REJECTED, state()); |
| return INVALID_CREDENTIALS; |
| } |
| |
| void FakeAuthenticator::ProcessMessage(const buzz::XmlElement* message, |
| const base::Closure& resume_callback) { |
| EXPECT_EQ(WAITING_MESSAGE, state()); |
| std::string id = |
| message->TextNamed(buzz::QName(kChromotingXmlNamespace, "id")); |
| EXPECT_EQ(id, base::IntToString(messages_)); |
| ++messages_; |
| resume_callback.Run(); |
| } |
| |
| scoped_ptr<buzz::XmlElement> FakeAuthenticator::GetNextMessage() { |
| EXPECT_EQ(MESSAGE_READY, state()); |
| |
| scoped_ptr<buzz::XmlElement> result(new buzz::XmlElement( |
| buzz::QName(kChromotingXmlNamespace, "authentication"))); |
| buzz::XmlElement* id = new buzz::XmlElement( |
| buzz::QName(kChromotingXmlNamespace, "id")); |
| id->AddText(base::IntToString(messages_)); |
| result->AddElement(id); |
| |
| ++messages_; |
| return result.Pass(); |
| } |
| |
| scoped_ptr<ChannelAuthenticator> |
| FakeAuthenticator::CreateChannelAuthenticator() const { |
| EXPECT_EQ(ACCEPTED, state()); |
| return scoped_ptr<ChannelAuthenticator>( |
| new FakeChannelAuthenticator(action_ != REJECT_CHANNEL, async_)); |
| } |
| |
| FakeHostAuthenticatorFactory::FakeHostAuthenticatorFactory( |
| int round_trips, FakeAuthenticator::Action action, bool async) |
| : round_trips_(round_trips), |
| action_(action), async_(async) { |
| } |
| |
| FakeHostAuthenticatorFactory::~FakeHostAuthenticatorFactory() { |
| } |
| |
| scoped_ptr<Authenticator> FakeHostAuthenticatorFactory::CreateAuthenticator( |
| const std::string& local_jid, |
| const std::string& remote_jid, |
| const buzz::XmlElement* first_message) { |
| return scoped_ptr<Authenticator>(new FakeAuthenticator( |
| FakeAuthenticator::HOST, round_trips_, action_, async_)); |
| } |
| |
| } // namespace protocol |
| } // namespace remoting |