buffet: Handle XMPP authentication failures For the nightly tests there is a fake GCD server used, and as a result the XMPP client can't authenticate with the XMPP server (since the access_token is also fake). This simply closes the XMPP connection if we see a read fail, so that we don't get spammed with 0 size reads. TEST=manual and FEATURES=test emerge-whirlwind buffet BUG=brillo:338 Change-Id: Ie8db114fcc197f816f3cb56673d6f393fa05c8e5 Reviewed-on: https://chromium-review.googlesource.com/251587 Reviewed-by: David Zeuthen <zeuthen@chromium.org> Reviewed-by: Alex Vakulenko <avakulenko@chromium.org> Commit-Queue: Nathan Bullock <nathanbullock@google.com> Tested-by: Nathan Bullock <nathanbullock@google.com>
diff --git a/buffet/device_registration_info.cc b/buffet/device_registration_info.cc index 5851f04..3e8fd00 100644 --- a/buffet/device_registration_info.cc +++ b/buffet/device_registration_info.cc
@@ -373,6 +373,17 @@ xmpp_client_->StartStream(); } +void DeviceRegistrationInfo::OnFileCanReadWithoutBlocking(int fd) { + if (xmpp_client_ && xmpp_client_->GetFileDescriptor() == fd) { + if (!xmpp_client_->Read()) { + // Authentication failed or the socket was closed. + if (!fd_watcher_.StopWatchingFileDescriptor()) { + LOG(WARNING) << "Failed to stop the watcher"; + } + } + } +} + std::unique_ptr<base::DictionaryValue> DeviceRegistrationInfo::BuildDeviceResource(chromeos::ErrorPtr* error) { std::unique_ptr<base::DictionaryValue> commands =
diff --git a/buffet/device_registration_info.h b/buffet/device_registration_info.h index 780aeb3..4409d25 100644 --- a/buffet/device_registration_info.h +++ b/buffet/device_registration_info.h
@@ -54,11 +54,7 @@ ~DeviceRegistrationInfo() override; - void OnFileCanReadWithoutBlocking(int fd) override { - if (xmpp_client_ && xmpp_client_->GetFileDescriptor() == fd) { - xmpp_client_->Read(); - } - } + void OnFileCanReadWithoutBlocking(int fd) override; void OnFileCanWriteWithoutBlocking(int fd) override { LOG(FATAL) << "No write watcher is configured";
diff --git a/buffet/xmpp/xmpp_client.cc b/buffet/xmpp/xmpp_client.cc index d0f4a56..f98c6bb 100644 --- a/buffet/xmpp/xmpp_client.cc +++ b/buffet/xmpp/xmpp_client.cc
@@ -61,11 +61,11 @@ } // namespace -void XmppClient::Read() { +bool XmppClient::Read() { std::string msg; if (!connection_->Read(&msg) || msg.size() <= 0) { - LOG(ERROR) << "Failed to read from stream"; - return; + LOG(ERROR) << "Failed to read from stream. The socket was probably closed"; + return false; } // TODO(nathanbullock): Need to add support for TLS (brillo:191). @@ -82,6 +82,9 @@ if (std::string::npos != msg.find("success")) { state_ = XmppState::kStreamRestartedPostAuthentication; connection_->Write(BuildXmppStartStreamCommand()); + } else if (std::string::npos != msg.find("not-authorized")) { + state_ = XmppState::kAuthenticationFailed; + return false; } break; case XmppState::kStreamRestartedPostAuthentication: @@ -114,6 +117,7 @@ default: break; } + return true; } void XmppClient::StartStream() {
diff --git a/buffet/xmpp/xmpp_client.h b/buffet/xmpp/xmpp_client.h index 9eb5826..6d847ca 100644 --- a/buffet/xmpp/xmpp_client.h +++ b/buffet/xmpp/xmpp_client.h
@@ -31,7 +31,7 @@ } // Needs to be called when new data is available from the connection. - void Read(); + bool Read(); // Start talking to the XMPP server (authenticate, etc.) void StartStream(); @@ -41,6 +41,7 @@ kNotStarted, kStarted, kAuthenticationStarted, + kAuthenticationFailed, kStreamRestartedPostAuthentication, kBindSent, kSessionStarted,
diff --git a/buffet/xmpp/xmpp_client_unittest.cc b/buffet/xmpp/xmpp_client_unittest.cc index 9736349..ef26f2e 100644 --- a/buffet/xmpp/xmpp_client_unittest.cc +++ b/buffet/xmpp/xmpp_client_unittest.cc
@@ -34,8 +34,11 @@ "<required/></starttls><mechanisms " "xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\"><mechanism>X-OAUTH2</mechanism>" "<mechanism>X-GOOGLE-TOKEN</mechanism></mechanisms></stream:features>"; -constexpr char kAuthenticationResponse[] = +constexpr char kAuthenticationSucceededResponse[] = "<success xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\"/>"; +constexpr char kAuthenticationFailedResponse[] = + "<failure xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\"><not-authorized/>" + "</failure></stream:stream>"; constexpr char kRestartStreamResponse[] = "<stream:stream from=\"clouddevices.gserviceaccount.com\" " "id=\"BE7D34E0B7589E2A\" version=\"1.0\" " @@ -143,12 +146,13 @@ XmppClient::XmppState::kAuthenticationStarted); } -TEST_F(XmppClientTest, HandleAuthenticationResponse) { +TEST_F(XmppClientTest, HandleAuthenticationSucceededResponse) { TestHelper::SetState( xmpp_client_.get(), XmppClient::XmppState::kAuthenticationStarted); EXPECT_CALL(*connection_, Read(_)) - .WillOnce(DoAll(SetArgPointee<0>(kAuthenticationResponse), Return(true))); + .WillOnce(DoAll(SetArgPointee<0>(kAuthenticationSucceededResponse), + Return(true))); EXPECT_CALL(*connection_, Write(kStartStreamMessage)) .WillOnce(Return(true)); xmpp_client_->Read(); @@ -156,6 +160,20 @@ XmppClient::XmppState::kStreamRestartedPostAuthentication); } +TEST_F(XmppClientTest, HandleAuthenticationFailedResponse) { + TestHelper::SetState( + xmpp_client_.get(), + XmppClient::XmppState::kAuthenticationStarted); + EXPECT_CALL(*connection_, Read(_)) + .WillOnce(DoAll(SetArgPointee<0>(kAuthenticationFailedResponse), + Return(true))); + EXPECT_CALL(*connection_, Write(_)) + .Times(0); + xmpp_client_->Read(); + EXPECT_EQ(TestHelper::GetState(*xmpp_client_), + XmppClient::XmppState::kAuthenticationFailed); +} + TEST_F(XmppClientTest, HandleStreamRestartedResponse) { TestHelper::SetState( xmpp_client_.get(),