1 /* 2 * Copyright 2004 The WebRTC Project Authors. All rights reserved. 3 * 4 * Use of this source code is governed by a BSD-style license 5 * that can be found in the LICENSE file in the root of the source 6 * tree. An additional intellectual property rights grant can be found 7 * in the file PATENTS. All contributing project authors may 8 * be found in the AUTHORS file in the root of the source tree. 9 */ 10 11 #include <iostream> 12 #include <sstream> 13 #include <string> 14 #include "webrtc/libjingle/xmllite/xmlelement.h" 15 #include "webrtc/libjingle/xmpp/constants.h" 16 #include "webrtc/libjingle/xmpp/plainsaslhandler.h" 17 #include "webrtc/libjingle/xmpp/saslplainmechanism.h" 18 #include "webrtc/libjingle/xmpp/util_unittest.h" 19 #include "webrtc/libjingle/xmpp/xmppengine.h" 20 #include "webrtc/base/common.h" 21 #include "webrtc/base/cryptstring.h" 22 #include "webrtc/base/gunit.h" 23 24 using buzz::Jid; 25 using buzz::QName; 26 using buzz::XmlElement; 27 using buzz::XmppEngine; 28 using buzz::XmppTestHandler; 29 30 enum XlttStage { 31 XLTT_STAGE_CONNECT = 0, 32 XLTT_STAGE_STREAMSTART, 33 XLTT_STAGE_TLS_FEATURES, 34 XLTT_STAGE_TLS_PROCEED, 35 XLTT_STAGE_ENCRYPTED_START, 36 XLTT_STAGE_AUTH_FEATURES, 37 XLTT_STAGE_AUTH_SUCCESS, 38 XLTT_STAGE_AUTHENTICATED_START, 39 XLTT_STAGE_BIND_FEATURES, 40 XLTT_STAGE_BIND_SUCCESS, 41 XLTT_STAGE_SESSION_SUCCESS, 42 }; 43 44 class XmppLoginTaskTest : public testing::Test { 45 public: 46 XmppEngine* engine() { return engine_.get(); } 47 XmppTestHandler* handler() { return handler_.get(); } 48 virtual void SetUp() { 49 engine_.reset(XmppEngine::Create()); 50 handler_.reset(new XmppTestHandler(engine_.get())); 51 52 Jid jid("david@my-server"); 53 rtc::InsecureCryptStringImpl pass; 54 pass.password() = "david"; 55 engine_->SetSessionHandler(handler_.get()); 56 engine_->SetOutputHandler(handler_.get()); 57 engine_->AddStanzaHandler(handler_.get()); 58 engine_->SetUser(jid); 59 engine_->SetSaslHandler( 60 new buzz::PlainSaslHandler(jid, rtc::CryptString(pass), true)); 61 } 62 virtual void TearDown() { 63 handler_.reset(); 64 engine_.reset(); 65 } 66 void RunPartialLogin(XlttStage startstage, XlttStage endstage); 67 void SetTlsOptions(buzz::TlsOptions option); 68 69 private: 70 rtc::scoped_ptr<XmppEngine> engine_; 71 rtc::scoped_ptr<XmppTestHandler> handler_; 72 }; 73 74 void XmppLoginTaskTest::SetTlsOptions(buzz::TlsOptions option) { 75 engine_->SetTls(option); 76 } 77 void XmppLoginTaskTest::RunPartialLogin(XlttStage startstage, 78 XlttStage endstage) { 79 std::string input; 80 81 switch (startstage) { 82 case XLTT_STAGE_CONNECT: { 83 engine_->Connect(); 84 XmlElement appStanza(QName("test", "app-stanza")); 85 appStanza.AddText("this-is-a-test"); 86 engine_->SendStanza(&appStanza); 87 88 EXPECT_EQ("<stream:stream to=\"my-server\" xml:lang=\"*\" " 89 "version=\"1.0\" xmlns:stream=\"http://etherx.jabber.org/streams\" " 90 "xmlns=\"jabber:client\">\r\n", handler_->OutputActivity()); 91 EXPECT_EQ("[OPENING]", handler_->SessionActivity()); 92 EXPECT_EQ("", handler_->StanzaActivity()); 93 if (endstage == XLTT_STAGE_CONNECT) 94 return; 95 FALLTHROUGH(); 96 } 97 98 case XLTT_STAGE_STREAMSTART: { 99 input = "<stream:stream id=\"a5f2d8c9\" version=\"1.0\" " 100 "xmlns:stream=\"http://etherx.jabber.org/streams\" " 101 "xmlns=\"jabber:client\">"; 102 engine_->HandleInput(input.c_str(), input.length()); 103 EXPECT_EQ("", handler_->StanzaActivity()); 104 EXPECT_EQ("", handler_->SessionActivity()); 105 EXPECT_EQ("", handler_->OutputActivity()); 106 if (endstage == XLTT_STAGE_STREAMSTART) 107 return; 108 FALLTHROUGH(); 109 } 110 111 case XLTT_STAGE_TLS_FEATURES: { 112 input = "<stream:features>" 113 "<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>" 114 "</stream:features>"; 115 engine_->HandleInput(input.c_str(), input.length()); 116 EXPECT_EQ("<starttls xmlns=\"urn:ietf:params:xml:ns:xmpp-tls\"/>", 117 handler_->OutputActivity()); 118 EXPECT_EQ("", handler_->StanzaActivity()); 119 EXPECT_EQ("", handler_->SessionActivity()); 120 if (endstage == XLTT_STAGE_TLS_FEATURES) 121 return; 122 FALLTHROUGH(); 123 } 124 125 case XLTT_STAGE_TLS_PROCEED: { 126 input = std::string("<proceed xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>"); 127 engine_->HandleInput(input.c_str(), input.length()); 128 EXPECT_EQ("[START-TLS my-server]" 129 "<stream:stream to=\"my-server\" xml:lang=\"*\" " 130 "version=\"1.0\" xmlns:stream=\"http://etherx.jabber.org/streams\" " 131 "xmlns=\"jabber:client\">\r\n", handler_->OutputActivity()); 132 EXPECT_EQ("", handler_->StanzaActivity()); 133 EXPECT_EQ("", handler_->SessionActivity()); 134 if (endstage == XLTT_STAGE_TLS_PROCEED) 135 return; 136 FALLTHROUGH(); 137 } 138 139 case XLTT_STAGE_ENCRYPTED_START: { 140 input = std::string("<stream:stream id=\"01234567\" version=\"1.0\" " 141 "xmlns:stream=\"http://etherx.jabber.org/streams\" " 142 "xmlns=\"jabber:client\">"); 143 engine_->HandleInput(input.c_str(), input.length()); 144 EXPECT_EQ("", handler_->StanzaActivity()); 145 EXPECT_EQ("", handler_->SessionActivity()); 146 EXPECT_EQ("", handler_->OutputActivity()); 147 if (endstage == XLTT_STAGE_ENCRYPTED_START) 148 return; 149 FALLTHROUGH(); 150 } 151 152 case XLTT_STAGE_AUTH_FEATURES: { 153 input = "<stream:features>" 154 "<mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>" 155 "<mechanism>DIGEST-MD5</mechanism>" 156 "<mechanism>PLAIN</mechanism>" 157 "</mechanisms>" 158 "</stream:features>"; 159 engine_->HandleInput(input.c_str(), input.length()); 160 EXPECT_EQ("<auth xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\" " 161 "mechanism=\"PLAIN\" " 162 "auth:allow-non-google-login=\"true\" " 163 "auth:client-uses-full-bind-result=\"true\" " 164 "xmlns:auth=\"http://www.google.com/talk/protocol/auth\"" 165 ">AGRhdmlkAGRhdmlk</auth>", 166 handler_->OutputActivity()); 167 EXPECT_EQ("", handler_->StanzaActivity()); 168 EXPECT_EQ("", handler_->SessionActivity()); 169 if (endstage == XLTT_STAGE_AUTH_FEATURES) 170 return; 171 FALLTHROUGH(); 172 } 173 174 case XLTT_STAGE_AUTH_SUCCESS: { 175 input = "<success xmlns='urn:ietf:params:xml:ns:xmpp-sasl'/>"; 176 engine_->HandleInput(input.c_str(), input.length()); 177 EXPECT_EQ("<stream:stream to=\"my-server\" xml:lang=\"*\" " 178 "version=\"1.0\" xmlns:stream=\"http://etherx.jabber.org/streams\" " 179 "xmlns=\"jabber:client\">\r\n", handler_->OutputActivity()); 180 EXPECT_EQ("", handler_->StanzaActivity()); 181 EXPECT_EQ("", handler_->SessionActivity()); 182 if (endstage == XLTT_STAGE_AUTH_SUCCESS) 183 return; 184 FALLTHROUGH(); 185 } 186 187 case XLTT_STAGE_AUTHENTICATED_START: { 188 input = std::string("<stream:stream id=\"01234567\" version=\"1.0\" " 189 "xmlns:stream=\"http://etherx.jabber.org/streams\" " 190 "xmlns=\"jabber:client\">"); 191 engine_->HandleInput(input.c_str(), input.length()); 192 EXPECT_EQ("", handler_->StanzaActivity()); 193 EXPECT_EQ("", handler_->SessionActivity()); 194 EXPECT_EQ("", handler_->OutputActivity()); 195 if (endstage == XLTT_STAGE_AUTHENTICATED_START) 196 return; 197 FALLTHROUGH(); 198 } 199 200 case XLTT_STAGE_BIND_FEATURES: { 201 input = "<stream:features>" 202 "<bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'/>" 203 "<session xmlns='urn:ietf:params:xml:ns:xmpp-session'/>" 204 "</stream:features>"; 205 engine_->HandleInput(input.c_str(), input.length()); 206 EXPECT_EQ("<iq type=\"set\" id=\"0\">" 207 "<bind xmlns=\"urn:ietf:params:xml:ns:xmpp-bind\"/></iq>", 208 handler_->OutputActivity()); 209 EXPECT_EQ("", handler_->StanzaActivity()); 210 EXPECT_EQ("", handler_->SessionActivity()); 211 if (endstage == XLTT_STAGE_BIND_FEATURES) 212 return; 213 FALLTHROUGH(); 214 } 215 216 case XLTT_STAGE_BIND_SUCCESS: { 217 input = "<iq type='result' id='0'>" 218 "<bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'>" 219 "<jid>david@my-server/test</jid></bind></iq>"; 220 engine_->HandleInput(input.c_str(), input.length()); 221 EXPECT_EQ("<iq type=\"set\" id=\"1\">" 222 "<session xmlns=\"urn:ietf:params:xml:ns:xmpp-session\"/></iq>", 223 handler_->OutputActivity()); 224 EXPECT_EQ("", handler_->StanzaActivity()); 225 EXPECT_EQ("", handler_->SessionActivity()); 226 if (endstage == XLTT_STAGE_BIND_SUCCESS) 227 return; 228 FALLTHROUGH(); 229 } 230 231 case XLTT_STAGE_SESSION_SUCCESS: { 232 input = "<iq type='result' id='1'/>"; 233 engine_->HandleInput(input.c_str(), input.length()); 234 EXPECT_EQ("<test:app-stanza xmlns:test=\"test\">this-is-a-test" 235 "</test:app-stanza>", handler_->OutputActivity()); 236 EXPECT_EQ("[OPEN]", handler_->SessionActivity()); 237 EXPECT_EQ("", handler_->StanzaActivity()); 238 if (endstage == XLTT_STAGE_SESSION_SUCCESS) 239 return; 240 FALLTHROUGH(); 241 } 242 default: 243 break; 244 } 245 } 246 247 TEST_F(XmppLoginTaskTest, TestUtf8Good) { 248 RunPartialLogin(XLTT_STAGE_CONNECT, XLTT_STAGE_CONNECT); 249 250 std::string input = "<?xml version='1.0' encoding='UTF-8'?>" 251 "<stream:stream id=\"a5f2d8c9\" version=\"1.0\" " 252 "xmlns:stream=\"http://etherx.jabber.org/streams\" " 253 "xmlns=\"jabber:client\">"; 254 engine()->HandleInput(input.c_str(), input.length()); 255 EXPECT_EQ("", handler()->OutputActivity()); 256 EXPECT_EQ("", handler()->SessionActivity()); 257 EXPECT_EQ("", handler()->StanzaActivity()); 258 } 259 260 TEST_F(XmppLoginTaskTest, TestNonUtf8Bad) { 261 RunPartialLogin(XLTT_STAGE_CONNECT, XLTT_STAGE_CONNECT); 262 263 std::string input = "<?xml version='1.0' encoding='ISO-8859-1'?>" 264 "<stream:stream id=\"a5f2d8c9\" version=\"1.0\" " 265 "xmlns:stream=\"http://etherx.jabber.org/streams\" " 266 "xmlns=\"jabber:client\">"; 267 engine()->HandleInput(input.c_str(), input.length()); 268 EXPECT_EQ("[CLOSED]", handler()->OutputActivity()); 269 EXPECT_EQ("[CLOSED][ERROR-XML]", handler()->SessionActivity()); 270 EXPECT_EQ("", handler()->StanzaActivity()); 271 } 272 273 TEST_F(XmppLoginTaskTest, TestNoFeatures) { 274 RunPartialLogin(XLTT_STAGE_CONNECT, XLTT_STAGE_STREAMSTART); 275 276 std::string input = "<iq type='get' id='1'/>"; 277 engine()->HandleInput(input.c_str(), input.length()); 278 279 EXPECT_EQ("[CLOSED]", handler()->OutputActivity()); 280 EXPECT_EQ("[CLOSED][ERROR-VERSION]", handler()->SessionActivity()); 281 EXPECT_EQ("", handler()->StanzaActivity()); 282 } 283 284 TEST_F(XmppLoginTaskTest, TestTlsRequiredNotPresent) { 285 RunPartialLogin(XLTT_STAGE_CONNECT, XLTT_STAGE_STREAMSTART); 286 287 std::string input = "<stream:features>" 288 "<mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>" 289 "<mechanism>DIGEST-MD5</mechanism>" 290 "<mechanism>PLAIN</mechanism>" 291 "</mechanisms>" 292 "</stream:features>"; 293 engine()->HandleInput(input.c_str(), input.length()); 294 295 EXPECT_EQ("[CLOSED]", handler()->OutputActivity()); 296 EXPECT_EQ("[CLOSED][ERROR-TLS]", handler()->SessionActivity()); 297 EXPECT_EQ("", handler()->StanzaActivity()); 298 } 299 300 TEST_F(XmppLoginTaskTest, TestTlsRequeiredAndPresent) { 301 RunPartialLogin(XLTT_STAGE_CONNECT, XLTT_STAGE_STREAMSTART); 302 303 std::string input = "<stream:features>" 304 "<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'>" 305 "<required/>" 306 "</starttls>" 307 "<mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>" 308 "<mechanism>X-GOOGLE-TOKEN</mechanism>" 309 "<mechanism>PLAIN</mechanism>" 310 "<mechanism>X-OAUTH2</mechanism>" 311 "</mechanisms>" 312 "</stream:features>"; 313 engine()->HandleInput(input.c_str(), input.length()); 314 315 EXPECT_EQ("<starttls xmlns=\"urn:ietf:params:xml:ns:xmpp-tls\"/>", 316 handler()->OutputActivity()); 317 EXPECT_EQ("", handler()->SessionActivity()); 318 EXPECT_EQ("", handler()->StanzaActivity()); 319 } 320 321 TEST_F(XmppLoginTaskTest, TestTlsEnabledNotPresent) { 322 SetTlsOptions(buzz::TLS_ENABLED); 323 RunPartialLogin(XLTT_STAGE_CONNECT, XLTT_STAGE_STREAMSTART); 324 325 std::string input = "<stream:features>" 326 "<mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>" 327 "<mechanism>DIGEST-MD5</mechanism>" 328 "<mechanism>PLAIN</mechanism>" 329 "</mechanisms>" 330 "</stream:features>"; 331 engine()->HandleInput(input.c_str(), input.length()); 332 333 EXPECT_EQ("<auth xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\" " 334 "mechanism=\"PLAIN\" auth:allow-non-google-login=\"true\" " 335 "auth:client-uses-full-bind-result=\"true\" " 336 "xmlns:auth=\"http://www.google.com/talk/protocol/auth\"" 337 ">AGRhdmlkAGRhdmlk</auth>", handler()->OutputActivity()); 338 EXPECT_EQ("", handler()->SessionActivity()); 339 EXPECT_EQ("", handler()->StanzaActivity()); 340 } 341 342 TEST_F(XmppLoginTaskTest, TestTlsEnabledAndPresent) { 343 SetTlsOptions(buzz::TLS_ENABLED); 344 RunPartialLogin(XLTT_STAGE_CONNECT, XLTT_STAGE_STREAMSTART); 345 346 std::string input = "<stream:features>" 347 "<mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>" 348 "<mechanism>X-GOOGLE-TOKEN</mechanism>" 349 "<mechanism>PLAIN</mechanism>" 350 "<mechanism>X-OAUTH2</mechanism>" 351 "</mechanisms>" 352 "</stream:features>"; 353 engine()->HandleInput(input.c_str(), input.length()); 354 355 EXPECT_EQ("<auth xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\" " 356 "mechanism=\"PLAIN\" auth:allow-non-google-login=\"true\" " 357 "auth:client-uses-full-bind-result=\"true\" " 358 "xmlns:auth=\"http://www.google.com/talk/protocol/auth\"" 359 ">AGRhdmlkAGRhdmlk</auth>", handler()->OutputActivity()); 360 EXPECT_EQ("", handler()->SessionActivity()); 361 EXPECT_EQ("", handler()->StanzaActivity()); 362 } 363 364 TEST_F(XmppLoginTaskTest, TestTlsDisabledNotPresent) { 365 SetTlsOptions(buzz::TLS_DISABLED); 366 RunPartialLogin(XLTT_STAGE_CONNECT, XLTT_STAGE_STREAMSTART); 367 368 std::string input = "<stream:features>" 369 "<mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>" 370 "<mechanism>DIGEST-MD5</mechanism>" 371 "<mechanism>PLAIN</mechanism>" 372 "</mechanisms>" 373 "</stream:features>"; 374 engine()->HandleInput(input.c_str(), input.length()); 375 376 EXPECT_EQ("<auth xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\" " 377 "mechanism=\"PLAIN\" auth:allow-non-google-login=\"true\" " 378 "auth:client-uses-full-bind-result=\"true\" " 379 "xmlns:auth=\"http://www.google.com/talk/protocol/auth\"" 380 ">AGRhdmlkAGRhdmlk</auth>", handler()->OutputActivity()); 381 EXPECT_EQ("", handler()->SessionActivity()); 382 EXPECT_EQ("", handler()->StanzaActivity()); 383 } 384 385 TEST_F(XmppLoginTaskTest, TestTlsDisabledAndPresent) { 386 SetTlsOptions(buzz::TLS_DISABLED); 387 RunPartialLogin(XLTT_STAGE_CONNECT, XLTT_STAGE_STREAMSTART); 388 389 std::string input = "<stream:features>" 390 "<mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>" 391 "<mechanism>X-GOOGLE-TOKEN</mechanism>" 392 "<mechanism>PLAIN</mechanism>" 393 "<mechanism>X-OAUTH2</mechanism>" 394 "</mechanisms>" 395 "</stream:features>"; 396 engine()->HandleInput(input.c_str(), input.length()); 397 398 EXPECT_EQ("<auth xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\" " 399 "mechanism=\"PLAIN\" auth:allow-non-google-login=\"true\" " 400 "auth:client-uses-full-bind-result=\"true\" " 401 "xmlns:auth=\"http://www.google.com/talk/protocol/auth\"" 402 ">AGRhdmlkAGRhdmlk</auth>", handler()->OutputActivity()); 403 EXPECT_EQ("", handler()->SessionActivity()); 404 EXPECT_EQ("", handler()->StanzaActivity()); 405 } 406 407 TEST_F(XmppLoginTaskTest, TestTlsFailure) { 408 RunPartialLogin(XLTT_STAGE_CONNECT, XLTT_STAGE_TLS_FEATURES); 409 410 std::string input = "<failure xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>"; 411 engine()->HandleInput(input.c_str(), input.length()); 412 413 EXPECT_EQ("[CLOSED]", handler()->OutputActivity()); 414 EXPECT_EQ("[CLOSED][ERROR-TLS]", handler()->SessionActivity()); 415 EXPECT_EQ("", handler()->StanzaActivity()); 416 } 417 418 TEST_F(XmppLoginTaskTest, TestTlsBadStream) { 419 RunPartialLogin(XLTT_STAGE_CONNECT, XLTT_STAGE_TLS_PROCEED); 420 421 std::string input = "<wrongtag>"; 422 engine()->HandleInput(input.c_str(), input.length()); 423 424 EXPECT_EQ("[CLOSED]", handler()->OutputActivity()); 425 EXPECT_EQ("[CLOSED][ERROR-VERSION]", handler()->SessionActivity()); 426 EXPECT_EQ("", handler()->StanzaActivity()); 427 } 428 429 TEST_F(XmppLoginTaskTest, TestMissingSaslPlain) { 430 RunPartialLogin(XLTT_STAGE_CONNECT, XLTT_STAGE_ENCRYPTED_START); 431 432 std::string input = "<stream:features>" 433 "<mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>" 434 "<mechanism>DIGEST-MD5</mechanism>" 435 "</mechanisms>" 436 "</stream:features>"; 437 engine()->HandleInput(input.c_str(), input.length()); 438 439 EXPECT_EQ("[CLOSED]", handler()->OutputActivity()); 440 EXPECT_EQ("[CLOSED][ERROR-AUTH]", handler()->SessionActivity()); 441 EXPECT_EQ("", handler()->StanzaActivity()); 442 } 443 444 TEST_F(XmppLoginTaskTest, TestWrongPassword) { 445 RunPartialLogin(XLTT_STAGE_CONNECT, XLTT_STAGE_AUTH_FEATURES); 446 447 std::string input = "<failure xmlns='urn:ietf:params:xml:ns:xmpp-sasl'/>"; 448 engine()->HandleInput(input.c_str(), input.length()); 449 450 EXPECT_EQ("[CLOSED]", handler()->OutputActivity()); 451 EXPECT_EQ("[CLOSED][ERROR-UNAUTHORIZED]", handler()->SessionActivity()); 452 EXPECT_EQ("", handler()->StanzaActivity()); 453 } 454 455 TEST_F(XmppLoginTaskTest, TestAuthBadStream) { 456 RunPartialLogin(XLTT_STAGE_CONNECT, XLTT_STAGE_AUTH_SUCCESS); 457 458 std::string input = "<wrongtag>"; 459 engine()->HandleInput(input.c_str(), input.length()); 460 461 EXPECT_EQ("[CLOSED]", handler()->OutputActivity()); 462 EXPECT_EQ("[CLOSED][ERROR-VERSION]", handler()->SessionActivity()); 463 EXPECT_EQ("", handler()->StanzaActivity()); 464 } 465 466 TEST_F(XmppLoginTaskTest, TestMissingBindFeature) { 467 RunPartialLogin(XLTT_STAGE_CONNECT, XLTT_STAGE_AUTHENTICATED_START); 468 469 std::string input = "<stream:features>" 470 "<session xmlns='urn:ietf:params:xml:ns:xmpp-session'/>" 471 "</stream:features>"; 472 engine()->HandleInput(input.c_str(), input.length()); 473 474 EXPECT_EQ("[CLOSED]", handler()->OutputActivity()); 475 EXPECT_EQ("[CLOSED][ERROR-BIND]", handler()->SessionActivity()); 476 } 477 478 TEST_F(XmppLoginTaskTest, TestMissingSessionFeature) { 479 RunPartialLogin(XLTT_STAGE_CONNECT, XLTT_STAGE_AUTHENTICATED_START); 480 481 std::string input = "<stream:features>" 482 "<bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'/>" 483 "</stream:features>"; 484 engine()->HandleInput(input.c_str(), input.length()); 485 486 EXPECT_EQ("[CLOSED]", handler()->OutputActivity()); 487 EXPECT_EQ("[CLOSED][ERROR-BIND]", handler()->SessionActivity()); 488 EXPECT_EQ("", handler()->StanzaActivity()); 489 } 490 491 /* TODO: Handle this case properly inside XmppLoginTask. 492 TEST_F(XmppLoginTaskTest, TestBindFailure1) { 493 // check wrong JID 494 RunPartialLogin(XLTT_STAGE_CONNECT, XLTT_STAGE_BIND_FEATURES); 495 496 std::string input = "<iq type='result' id='0'>" 497 "<bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'>" 498 "<jid>davey@my-server/test</jid></bind></iq>"; 499 engine()->HandleInput(input.c_str(), input.length()); 500 501 EXPECT_EQ("[CLOSED]", handler()->OutputActivity()); 502 EXPECT_EQ("[CLOSED][ERROR-BIND]", handler()->SessionActivity()); 503 EXPECT_EQ("", handler()->StanzaActivity()); 504 } 505 */ 506 507 TEST_F(XmppLoginTaskTest, TestBindFailure2) { 508 // check missing JID 509 RunPartialLogin(XLTT_STAGE_CONNECT, XLTT_STAGE_BIND_FEATURES); 510 511 std::string input = "<iq type='result' id='0'>" 512 "<bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'/></iq>"; 513 engine()->HandleInput(input.c_str(), input.length()); 514 515 EXPECT_EQ("[CLOSED]", handler()->OutputActivity()); 516 EXPECT_EQ("[CLOSED][ERROR-BIND]", handler()->SessionActivity()); 517 EXPECT_EQ("", handler()->StanzaActivity()); 518 } 519 520 TEST_F(XmppLoginTaskTest, TestBindFailure3) { 521 // check plain failure 522 RunPartialLogin(XLTT_STAGE_CONNECT, XLTT_STAGE_BIND_FEATURES); 523 524 std::string input = "<iq type='error' id='0'/>"; 525 engine()->HandleInput(input.c_str(), input.length()); 526 527 EXPECT_EQ("[CLOSED]", handler()->OutputActivity()); 528 EXPECT_EQ("[CLOSED][ERROR-BIND]", handler()->SessionActivity()); 529 EXPECT_EQ("", handler()->StanzaActivity()); 530 } 531 532 TEST_F(XmppLoginTaskTest, TestBindFailure4) { 533 // check wrong id to ignore 534 RunPartialLogin(XLTT_STAGE_CONNECT, XLTT_STAGE_BIND_FEATURES); 535 536 std::string input = "<iq type='error' id='1'/>"; 537 engine()->HandleInput(input.c_str(), input.length()); 538 539 // continue after an ignored iq 540 RunPartialLogin(XLTT_STAGE_BIND_SUCCESS, XLTT_STAGE_SESSION_SUCCESS); 541 } 542 543 TEST_F(XmppLoginTaskTest, TestSessionFailurePlain1) { 544 RunPartialLogin(XLTT_STAGE_CONNECT, XLTT_STAGE_BIND_SUCCESS); 545 546 std::string input = "<iq type='error' id='1'/>"; 547 engine()->HandleInput(input.c_str(), input.length()); 548 549 EXPECT_EQ("[CLOSED]", handler()->OutputActivity()); 550 EXPECT_EQ("[CLOSED][ERROR-BIND]", handler()->SessionActivity()); 551 } 552 553 TEST_F(XmppLoginTaskTest, TestSessionFailurePlain2) { 554 RunPartialLogin(XLTT_STAGE_CONNECT, XLTT_STAGE_BIND_SUCCESS); 555 556 // check reverse iq to ignore 557 // TODO: consider queueing or passing through? 558 std::string input = "<iq type='get' id='1'/>"; 559 engine()->HandleInput(input.c_str(), input.length()); 560 561 EXPECT_EQ("", handler()->OutputActivity()); 562 EXPECT_EQ("", handler()->SessionActivity()); 563 564 // continue after an ignored iq 565 RunPartialLogin(XLTT_STAGE_SESSION_SUCCESS, XLTT_STAGE_SESSION_SUCCESS); 566 } 567 568 TEST_F(XmppLoginTaskTest, TestBadXml) { 569 int errorKind = 0; 570 for (XlttStage stage = XLTT_STAGE_CONNECT; 571 stage <= XLTT_STAGE_SESSION_SUCCESS; 572 stage = static_cast<XlttStage>(stage + 1)) { 573 RunPartialLogin(XLTT_STAGE_CONNECT, stage); 574 575 std::string input; 576 switch (errorKind++ % 5) { 577 case 0: input = "&syntax;"; break; 578 case 1: input = "<nons:iq/>"; break; 579 case 2: input = "<iq a='b' a='dupe'/>"; break; 580 case 3: input = "<>"; break; 581 case 4: input = "<iq a='<wrong>'>"; break; 582 } 583 584 engine()->HandleInput(input.c_str(), input.length()); 585 586 EXPECT_EQ("[CLOSED]", handler()->OutputActivity()); 587 EXPECT_EQ("[CLOSED][ERROR-XML]", handler()->SessionActivity()); 588 589 TearDown(); 590 SetUp(); 591 } 592 } 593 594 TEST_F(XmppLoginTaskTest, TestStreamError) { 595 for (XlttStage stage = XLTT_STAGE_CONNECT; 596 stage <= XLTT_STAGE_SESSION_SUCCESS; 597 stage = static_cast<XlttStage>(stage + 1)) { 598 switch (stage) { 599 case XLTT_STAGE_CONNECT: 600 case XLTT_STAGE_TLS_PROCEED: 601 case XLTT_STAGE_AUTH_SUCCESS: 602 continue; 603 default: 604 break; 605 } 606 607 RunPartialLogin(XLTT_STAGE_CONNECT, stage); 608 609 std::string input = "<stream:error>" 610 "<xml-not-well-formed xmlns='urn:ietf:params:xml:ns:xmpp-streams'/>" 611 "<text xml:lang='en' xmlns='urn:ietf:params:xml:ns:xmpp-streams'>" 612 "Some special application diagnostic information!" 613 "</text>" 614 "<escape-your-data xmlns='application-ns'/>" 615 "</stream:error>"; 616 617 engine()->HandleInput(input.c_str(), input.length()); 618 619 EXPECT_EQ("[CLOSED]", handler()->OutputActivity()); 620 EXPECT_EQ("[CLOSED][ERROR-STREAM]", handler()->SessionActivity()); 621 622 EXPECT_EQ("<str:error xmlns:str=\"http://etherx.jabber.org/streams\">" 623 "<xml-not-well-formed xmlns=\"urn:ietf:params:xml:ns:xmpp-streams\"/>" 624 "<text xml:lang=\"en\" xmlns=\"urn:ietf:params:xml:ns:xmpp-streams\">" 625 "Some special application diagnostic information!" 626 "</text>" 627 "<escape-your-data xmlns=\"application-ns\"/>" 628 "</str:error>", engine()->GetStreamError()->Str()); 629 630 TearDown(); 631 SetUp(); 632 } 633 } 634 635