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