diff options
author | sergeyu@chromium.org <sergeyu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-12-13 06:28:49 +0000 |
---|---|---|
committer | sergeyu@chromium.org <sergeyu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-12-13 06:28:49 +0000 |
commit | bc407e962efd421576e6dad7cefde22ef0439f38 (patch) | |
tree | 267bea43b45377b65f4128a73c1488f8165b8de7 /remoting/protocol | |
parent | 76e68448d44901e32e2166cb53677f132b7f2bd6 (diff) | |
download | chromium_src-bc407e962efd421576e6dad7cefde22ef0439f38.zip chromium_src-bc407e962efd421576e6dad7cefde22ef0439f38.tar.gz chromium_src-bc407e962efd421576e6dad7cefde22ef0439f38.tar.bz2 |
Multi-step authentication support in JingleSession.
BUG=105214
Review URL: http://codereview.chromium.org/8774031
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@114187 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'remoting/protocol')
-rw-r--r-- | remoting/protocol/authenticator.cc | 35 | ||||
-rw-r--r-- | remoting/protocol/authenticator.h | 11 | ||||
-rw-r--r-- | remoting/protocol/content_description.cc | 8 | ||||
-rw-r--r-- | remoting/protocol/jingle_session.cc | 59 | ||||
-rw-r--r-- | remoting/protocol/jingle_session.h | 11 | ||||
-rw-r--r-- | remoting/protocol/jingle_session_unittest.cc | 41 | ||||
-rw-r--r-- | remoting/protocol/v1_authenticator.cc | 14 |
7 files changed, 141 insertions, 38 deletions
diff --git a/remoting/protocol/authenticator.cc b/remoting/protocol/authenticator.cc new file mode 100644 index 0000000..23f77e1 --- /dev/null +++ b/remoting/protocol/authenticator.cc @@ -0,0 +1,35 @@ +// Copyright (c) 2011 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/authenticator.h" + +#include "remoting/base/constants.h" +#include "third_party/libjingle/source/talk/xmllite/xmlelement.h" + +namespace remoting { +namespace protocol { + +namespace { +const buzz::StaticQName kAuthenticationQName = { kChromotingXmlNamespace, + "authentication" }; +} // namespace + +// static +bool Authenticator::IsAuthenticatorMessage(const buzz::XmlElement* message) { + return message->Name() == kAuthenticationQName; +} + +// static +buzz::XmlElement* Authenticator::CreateEmptyAuthenticatorMessage() { + return new buzz::XmlElement(kAuthenticationQName); +} + +// static +const buzz::XmlElement* Authenticator::FindAuthenticatorMessage( + const buzz::XmlElement* message) { + return message->FirstNamed(kAuthenticationQName); +} + +} // namespace protocol +} // namespace remoting diff --git a/remoting/protocol/authenticator.h b/remoting/protocol/authenticator.h index 0f382ed..b79fe78 100644 --- a/remoting/protocol/authenticator.h +++ b/remoting/protocol/authenticator.h @@ -53,6 +53,17 @@ class Authenticator { REJECTED, }; + // Returns true if |message| is an Authenticator message. + static bool IsAuthenticatorMessage(const buzz::XmlElement* message); + + // Creates an empty Authenticator message, owned by the caller. + static buzz::XmlElement* CreateEmptyAuthenticatorMessage(); + + // Finds Authenticator message among child elements of |message|, or + // returns NULL otherwise. + static const buzz::XmlElement* FindAuthenticatorMessage( + const buzz::XmlElement* message); + Authenticator() {} virtual ~Authenticator() {} diff --git a/remoting/protocol/content_description.cc b/remoting/protocol/content_description.cc index d6947d7..86aefb4 100644 --- a/remoting/protocol/content_description.cc +++ b/remoting/protocol/content_description.cc @@ -7,6 +7,7 @@ #include "base/logging.h" #include "base/string_number_conversions.h" #include "remoting/base/constants.h" +#include "remoting/protocol/authenticator.h" #include "third_party/libjingle/source/talk/xmllite/xmlelement.h" using buzz::QName; @@ -27,7 +28,6 @@ const char kControlTag[] = "control"; const char kEventTag[] = "event"; const char kVideoTag[] = "video"; const char kResolutionTag[] = "initial-resolution"; -const char kAuthenticationTag[] = "authentication"; const char kTransportAttr[] = "transport"; const char kVersionAttr[] = "version"; @@ -198,8 +198,7 @@ XmlElement* ContentDescription::ToXml() const { root->AddElement(resolution_tag); if (authenticator_message_.get()) { - DCHECK(authenticator_message_->Name() == - QName(kChromotingXmlNamespace, kAuthenticationTag)); + DCHECK(Authenticator::IsAuthenticatorMessage(authenticator_message_.get())); root->AddElement(new XmlElement(*authenticator_message_)); } @@ -266,8 +265,7 @@ ContentDescription* ContentDescription::ParseXml( *config->mutable_initial_resolution() = resolution; scoped_ptr<XmlElement> authenticator_message; - child = element->FirstNamed(QName(kChromotingXmlNamespace, - kAuthenticationTag)); + child = Authenticator::FindAuthenticatorMessage(element); if (child) authenticator_message.reset(new XmlElement(*child)); diff --git a/remoting/protocol/jingle_session.cc b/remoting/protocol/jingle_session.cc index 0d6dc4f..8abada2 100644 --- a/remoting/protocol/jingle_session.cc +++ b/remoting/protocol/jingle_session.cc @@ -45,6 +45,8 @@ JingleSession::JingleSession( jid_ = cricket_session_->remote_name(); cricket_session_->SignalState.connect(this, &JingleSession::OnSessionState); cricket_session_->SignalError.connect(this, &JingleSession::OnSessionError); + cricket_session_->SignalInfoMessage.connect( + this, &JingleSession::OnSessionInfoMessage); cricket_session_->SignalReceivedTerminateReason.connect( this, &JingleSession::OnTerminateReason); } @@ -246,6 +248,25 @@ void JingleSession::OnSessionError( } } +void JingleSession::OnSessionInfoMessage(cricket::Session* session, + const buzz::XmlElement* message) { + DCHECK_EQ(cricket_session_,session); + + const buzz::XmlElement* auth_message = + Authenticator::FindAuthenticatorMessage(message); + if (auth_message) { + if (state_ != CONNECTED || + authenticator_->state() != Authenticator::WAITING_MESSAGE) { + LOG(WARNING) << "Received unexpected authenticator message " + << auth_message->Str(); + return; + } + + authenticator_->ProcessMessage(auth_message); + ProcessAuthenticationStep(); + } +} + void JingleSession::OnTerminateReason(cricket::Session* session, const std::string& reason) { terminate_reason_ = reason; @@ -294,16 +315,10 @@ bool JingleSession::InitializeConfigFromDescription( return false; } - DCHECK(authenticator_->state() == Authenticator::WAITING_MESSAGE); + DCHECK_EQ(authenticator_->state(), Authenticator::WAITING_MESSAGE); authenticator_->ProcessMessage(auth_message); - // Support for more than two auth message is not implemented yet. - DCHECK(authenticator_->state() != Authenticator::WAITING_MESSAGE && - authenticator_->state() != Authenticator::MESSAGE_READY); - - if (authenticator_->state() != Authenticator::ACCEPTED) { - return false; - } + // Initialize session configuration. SessionConfig config; if (!content_description->config()->GetFinalConfig(&config)) { LOG(ERROR) << "Connection response does not specify configuration"; @@ -333,8 +348,12 @@ void JingleSession::OnAccept() { SetState(CONNECTED); - if (authenticator_->state() == Authenticator::ACCEPTED) + // Process authentication. + if (authenticator_->state() == Authenticator::ACCEPTED) { SetState(AUTHENTICATED); + } else { + ProcessAuthenticationStep(); + } } void JingleSession::OnTerminate() { @@ -398,8 +417,6 @@ void JingleSession::AcceptConnection() { DCHECK(authenticator_->state() == Authenticator::WAITING_MESSAGE); authenticator_->ProcessMessage(auth_message); - // Support for more than two auth message is not implemented yet. - DCHECK(authenticator_->state() != Authenticator::WAITING_MESSAGE); if (authenticator_->state() == Authenticator::REJECTED) { CloseInternal(net::ERR_CONNECTION_FAILED, AUTHENTICATION_FAILED); return; @@ -412,11 +429,29 @@ void JingleSession::AcceptConnection() { buzz::XmlElement* auth_reply = NULL; if (authenticator_->state() == Authenticator::MESSAGE_READY) auth_reply = authenticator_->GetNextMessage(); - DCHECK_EQ(authenticator_->state(), Authenticator::ACCEPTED); + DCHECK_NE(authenticator_->state(), Authenticator::MESSAGE_READY); cricket_session_->Accept( CreateSessionDescription(candidate_config, auth_reply)); } +void JingleSession::ProcessAuthenticationStep() { + DCHECK_EQ(state_, CONNECTED); + + if (authenticator_->state() == Authenticator::MESSAGE_READY) { + buzz::XmlElement* auth_message = authenticator_->GetNextMessage(); + cricket::XmlElements message; + message.push_back(auth_message); + cricket_session_->SendInfoMessage(message); + } + DCHECK_NE(authenticator_->state(), Authenticator::MESSAGE_READY); + + if (authenticator_->state() == Authenticator::ACCEPTED) { + SetState(AUTHENTICATED); + } else if (authenticator_->state() == Authenticator::REJECTED) { + CloseInternal(net::ERR_CONNECTION_ABORTED, AUTHENTICATION_FAILED); + } +} + void JingleSession::AddChannelConnector( const std::string& name, JingleChannelConnector* connector) { DCHECK(channel_connectors_.find(name) == channel_connectors_.end()); diff --git a/remoting/protocol/jingle_session.h b/remoting/protocol/jingle_session.h index 4894216..1c8b2cb 100644 --- a/remoting/protocol/jingle_session.h +++ b/remoting/protocol/jingle_session.h @@ -74,14 +74,15 @@ class JingleSession : public protocol::Session, bool InitializeConfigFromDescription( const cricket::SessionDescription* description); - // Used for Session.SignalState sigslot. + // Handlers for |cricket_session_| signals. void OnSessionState(cricket::BaseSession* session, cricket::BaseSession::State state); - // Used for Session.SignalError sigslot. void OnSessionError(cricket::BaseSession* session, cricket::BaseSession::Error error); - // Used for Session.SignalReceivedTerminateReason sigslot. - void OnTerminateReason(cricket::Session* session, const std::string& reason); + void OnSessionInfoMessage(cricket::Session* session, + const buzz::XmlElement* message); + void OnTerminateReason(cricket::Session* session, + const std::string& reason); void OnInitiate(); void OnAccept(); @@ -91,6 +92,8 @@ class JingleSession : public protocol::Session, // accepts/rejects connection. void AcceptConnection(); + void ProcessAuthenticationStep(); + void AddChannelConnector(const std::string& name, JingleChannelConnector* connector); diff --git a/remoting/protocol/jingle_session_unittest.cc b/remoting/protocol/jingle_session_unittest.cc index 8ca7dcf..6c1fdfb 100644 --- a/remoting/protocol/jingle_session_unittest.cc +++ b/remoting/protocol/jingle_session_unittest.cc @@ -171,15 +171,15 @@ class JingleSessionTest : public testing::Test { { InSequence dummy; + EXPECT_CALL(host_connection_callback_, + OnStateChange(Session::CONNECTED)) + .Times(AtMost(1)); if (expect_fail) { EXPECT_CALL(host_connection_callback_, OnStateChange(Session::FAILED)) .Times(1); } else { EXPECT_CALL(host_connection_callback_, - OnStateChange(Session::CONNECTED)) - .Times(1); - EXPECT_CALL(host_connection_callback_, OnStateChange(Session::AUTHENTICATED)) .Times(1); } @@ -191,15 +191,15 @@ class JingleSessionTest : public testing::Test { EXPECT_CALL(client_connection_callback_, OnStateChange(Session::CONNECTING)) .Times(1); + EXPECT_CALL(client_connection_callback_, + OnStateChange(Session::CONNECTED)) + .Times(AtMost(1)); if (expect_fail) { EXPECT_CALL(client_connection_callback_, OnStateChange(Session::FAILED)) .Times(1); } else { EXPECT_CALL(client_connection_callback_, - OnStateChange(Session::CONNECTED)) - .Times(1); - EXPECT_CALL(client_connection_callback_, OnStateChange(Session::AUTHENTICATED)) .Times(1); } @@ -326,12 +326,24 @@ TEST_F(JingleSessionTest, Connect) { InitiateConnection(1, FakeAuthenticator::ACCEPT, false); } -// Verify that we can't connect two endpoints with mismatched secrets. +// Verify that we can connect two endpoints with multi-step authentication. +TEST_F(JingleSessionTest, ConnectMultistep) { + CreateServerPair(3, FakeAuthenticator::ACCEPT); + InitiateConnection(3, FakeAuthenticator::ACCEPT, false); +} + +// Verify that connection is terminated when auth fails. TEST_F(JingleSessionTest, ConnectBadAuth) { CreateServerPair(1, FakeAuthenticator::REJECT); InitiateConnection(1, FakeAuthenticator::ACCEPT, true); } +// Verify that connection is terminted when multi-step auth fails. +TEST_F(JingleSessionTest, ConnectBadMultistepAuth) { + CreateServerPair(3, FakeAuthenticator::REJECT); + InitiateConnection(3, FakeAuthenticator::ACCEPT, true); +} + TEST_F(JingleSessionTest, ConnectBadChannelAuth) { CreateServerPair(1, FakeAuthenticator::REJECT_CHANNEL); ASSERT_NO_FATAL_FAILURE( @@ -374,6 +386,21 @@ TEST_F(JingleSessionTest, TestTcpChannel) { tester.CheckResults(); } +// Verify that we can connect channels with multistep auth. +TEST_F(JingleSessionTest, TestMultistepAuthTcpChannel) { + CreateServerPair(3, FakeAuthenticator::ACCEPT); + ASSERT_NO_FATAL_FAILURE( + InitiateConnection(3, FakeAuthenticator::ACCEPT, false)); + + ASSERT_NO_FATAL_FAILURE(CreateChannel()); + + StreamConnectionTester tester(host_socket_.get(), client_socket_.get(), + kMessageSize, kMessages); + tester.Start(); + message_loop_.Run(); + tester.CheckResults(); +} + // Verify that data can be transmitted over the video RTP channel. TEST_F(JingleSessionTest, TestUdpChannel) { CreateServerPair(1, FakeAuthenticator::ACCEPT); diff --git a/remoting/protocol/v1_authenticator.cc b/remoting/protocol/v1_authenticator.cc index 26eb3c7..afeb2d6 100644 --- a/remoting/protocol/v1_authenticator.cc +++ b/remoting/protocol/v1_authenticator.cc @@ -20,7 +20,6 @@ namespace remoting { namespace protocol { namespace { -const char kAuthenticationTag[] = "authentication"; const char kAuthTokenTag[] = "auth-token"; const char kCertificateTag[] = "certificate"; } // namespace @@ -64,19 +63,16 @@ void V1ClientAuthenticator::ProcessMessage(const XmlElement* message) { XmlElement* V1ClientAuthenticator::GetNextMessage() { DCHECK_EQ(state_, MESSAGE_READY); - XmlElement* authentication_tag = new XmlElement( - QName(kChromotingXmlNamespace, kAuthenticationTag)); - + XmlElement* message = CreateEmptyAuthenticatorMessage(); std::string token = protocol::GenerateSupportAuthToken(local_jid_, shared_secret_); - XmlElement* auth_token_tag = new XmlElement( QName(kChromotingXmlNamespace, kAuthTokenTag)); auth_token_tag->SetBodyText(token); - authentication_tag->AddElement(auth_token_tag); + message->AddElement(auth_token_tag); state_ = WAITING_MESSAGE; - return authentication_tag; + return message; } ChannelAuthenticator* @@ -121,9 +117,7 @@ void V1HostAuthenticator::ProcessMessage(const XmlElement* message) { XmlElement* V1HostAuthenticator::GetNextMessage() { DCHECK_EQ(state_, MESSAGE_READY); - XmlElement* message = new XmlElement( - QName(kChromotingXmlNamespace, kAuthenticationTag)); - + XmlElement* message = CreateEmptyAuthenticatorMessage(); buzz::XmlElement* certificate_tag = new XmlElement( buzz::QName(kChromotingXmlNamespace, kCertificateTag)); std::string base64_cert; |