github.com/lianghucheng/zrddz@v0.0.0-20200923083010-c71f680932e2/src/gopkg.in/mgo.v2/auth_test.go (about) 1 // mgo - MongoDB driver for Go 2 // 3 // Copyright (c) 2010-2012 - Gustavo Niemeyer <gustavo@niemeyer.net> 4 // 5 // All rights reserved. 6 // 7 // Redistribution and use in source and binary forms, with or without 8 // modification, are permitted provided that the following conditions are met: 9 // 10 // 1. Redistributions of source code must retain the above copyright notice, this 11 // list of conditions and the following disclaimer. 12 // 2. Redistributions in binary form must reproduce the above copyright notice, 13 // this list of conditions and the following disclaimer in the documentation 14 // and/or other materials provided with the distribution. 15 // 16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 17 // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 20 // ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 23 // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 25 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 27 package mgo_test 28 29 import ( 30 "crypto/tls" 31 "flag" 32 "fmt" 33 "io/ioutil" 34 "net" 35 "net/url" 36 "os" 37 "runtime" 38 "sync" 39 "time" 40 41 . "gopkg.in/check.v1" 42 "gopkg.in/mgo.v2" 43 ) 44 45 func (s *S) TestAuthLoginDatabase(c *C) { 46 // Test both with a normal database and with an authenticated shard. 47 for _, addr := range []string{"localhost:40002", "localhost:40203"} { 48 session, err := mgo.Dial(addr) 49 c.Assert(err, IsNil) 50 defer session.Close() 51 52 coll := session.DB("mydb").C("mycoll") 53 err = coll.Insert(M{"n": 1}) 54 c.Assert(err, ErrorMatches, "unauthorized|need to login|not authorized .*") 55 56 admindb := session.DB("admin") 57 58 err = admindb.Login("root", "wrong") 59 c.Assert(err, ErrorMatches, "auth fail(s|ed)|.*Authentication failed.") 60 61 err = admindb.Login("root", "rapadura") 62 c.Assert(err, IsNil) 63 64 err = coll.Insert(M{"n": 1}) 65 c.Assert(err, IsNil) 66 } 67 } 68 69 func (s *S) TestAuthLoginSession(c *C) { 70 // Test both with a normal database and with an authenticated shard. 71 for _, addr := range []string{"localhost:40002", "localhost:40203"} { 72 session, err := mgo.Dial(addr) 73 c.Assert(err, IsNil) 74 defer session.Close() 75 76 coll := session.DB("mydb").C("mycoll") 77 err = coll.Insert(M{"n": 1}) 78 c.Assert(err, ErrorMatches, "unauthorized|need to login|not authorized .*") 79 80 cred := mgo.Credential{ 81 Username: "root", 82 Password: "wrong", 83 } 84 err = session.Login(&cred) 85 c.Assert(err, ErrorMatches, "auth fail(s|ed)|.*Authentication failed.") 86 87 cred.Password = "rapadura" 88 89 err = session.Login(&cred) 90 c.Assert(err, IsNil) 91 92 err = coll.Insert(M{"n": 1}) 93 c.Assert(err, IsNil) 94 } 95 } 96 97 func (s *S) TestAuthLoginLogout(c *C) { 98 // Test both with a normal database and with an authenticated shard. 99 for _, addr := range []string{"localhost:40002", "localhost:40203"} { 100 session, err := mgo.Dial(addr) 101 c.Assert(err, IsNil) 102 defer session.Close() 103 104 admindb := session.DB("admin") 105 err = admindb.Login("root", "rapadura") 106 c.Assert(err, IsNil) 107 108 admindb.Logout() 109 110 coll := session.DB("mydb").C("mycoll") 111 err = coll.Insert(M{"n": 1}) 112 c.Assert(err, ErrorMatches, "unauthorized|need to login|not authorized .*") 113 114 // Must have dropped auth from the session too. 115 session = session.Copy() 116 defer session.Close() 117 118 coll = session.DB("mydb").C("mycoll") 119 err = coll.Insert(M{"n": 1}) 120 c.Assert(err, ErrorMatches, "unauthorized|need to login|not authorized .*") 121 } 122 } 123 124 func (s *S) TestAuthLoginLogoutAll(c *C) { 125 session, err := mgo.Dial("localhost:40002") 126 c.Assert(err, IsNil) 127 defer session.Close() 128 129 admindb := session.DB("admin") 130 err = admindb.Login("root", "rapadura") 131 c.Assert(err, IsNil) 132 133 session.LogoutAll() 134 135 coll := session.DB("mydb").C("mycoll") 136 err = coll.Insert(M{"n": 1}) 137 c.Assert(err, ErrorMatches, "unauthorized|need to login|not authorized .*") 138 139 // Must have dropped auth from the session too. 140 session = session.Copy() 141 defer session.Close() 142 143 coll = session.DB("mydb").C("mycoll") 144 err = coll.Insert(M{"n": 1}) 145 c.Assert(err, ErrorMatches, "unauthorized|need to login|not authorized .*") 146 } 147 148 func (s *S) TestAuthUpsertUserErrors(c *C) { 149 session, err := mgo.Dial("localhost:40002") 150 c.Assert(err, IsNil) 151 defer session.Close() 152 153 admindb := session.DB("admin") 154 err = admindb.Login("root", "rapadura") 155 c.Assert(err, IsNil) 156 157 mydb := session.DB("mydb") 158 159 err = mydb.UpsertUser(&mgo.User{}) 160 c.Assert(err, ErrorMatches, "user has no Username") 161 162 err = mydb.UpsertUser(&mgo.User{Username: "user", Password: "pass", UserSource: "source"}) 163 c.Assert(err, ErrorMatches, "user has both Password/PasswordHash and UserSource set") 164 165 err = mydb.UpsertUser(&mgo.User{Username: "user", Password: "pass", OtherDBRoles: map[string][]mgo.Role{"db": nil}}) 166 c.Assert(err, ErrorMatches, "user with OtherDBRoles is only supported in the admin or \\$external databases") 167 } 168 169 func (s *S) TestAuthUpsertUser(c *C) { 170 if !s.versionAtLeast(2, 4) { 171 c.Skip("UpsertUser only works on 2.4+") 172 } 173 session, err := mgo.Dial("localhost:40002") 174 c.Assert(err, IsNil) 175 defer session.Close() 176 177 admindb := session.DB("admin") 178 err = admindb.Login("root", "rapadura") 179 c.Assert(err, IsNil) 180 181 mydb := session.DB("mydb") 182 183 ruser := &mgo.User{ 184 Username: "myruser", 185 Password: "mypass", 186 Roles: []mgo.Role{mgo.RoleRead}, 187 } 188 rwuser := &mgo.User{ 189 Username: "myrwuser", 190 Password: "mypass", 191 Roles: []mgo.Role{mgo.RoleReadWrite}, 192 } 193 194 err = mydb.UpsertUser(ruser) 195 c.Assert(err, IsNil) 196 err = mydb.UpsertUser(rwuser) 197 c.Assert(err, IsNil) 198 199 err = mydb.Login("myruser", "mypass") 200 c.Assert(err, IsNil) 201 202 admindb.Logout() 203 204 coll := session.DB("mydb").C("mycoll") 205 err = coll.Insert(M{"n": 1}) 206 c.Assert(err, ErrorMatches, "unauthorized|not authorized .*") 207 208 err = mydb.Login("myrwuser", "mypass") 209 c.Assert(err, IsNil) 210 211 err = coll.Insert(M{"n": 1}) 212 c.Assert(err, IsNil) 213 214 myotherdb := session.DB("myotherdb") 215 216 err = admindb.Login("root", "rapadura") 217 c.Assert(err, IsNil) 218 219 // Test UserSource. 220 rwuserother := &mgo.User{ 221 Username: "myrwuser", 222 UserSource: "mydb", 223 Roles: []mgo.Role{mgo.RoleRead}, 224 } 225 226 err = myotherdb.UpsertUser(rwuserother) 227 if s.versionAtLeast(2, 6) { 228 c.Assert(err, ErrorMatches, `MongoDB 2.6\+ does not support the UserSource setting`) 229 return 230 } 231 c.Assert(err, IsNil) 232 233 admindb.Logout() 234 235 // Test indirection via UserSource: we can't write to it, because 236 // the roles for myrwuser are different there. 237 othercoll := myotherdb.C("myothercoll") 238 err = othercoll.Insert(M{"n": 1}) 239 c.Assert(err, ErrorMatches, "unauthorized|not authorized .*") 240 241 // Reading works, though. 242 err = othercoll.Find(nil).One(nil) 243 c.Assert(err, Equals, mgo.ErrNotFound) 244 245 // Can't login directly into the database using UserSource, though. 246 err = myotherdb.Login("myrwuser", "mypass") 247 c.Assert(err, ErrorMatches, "auth fail(s|ed)|.*Authentication failed.") 248 } 249 250 func (s *S) TestAuthUpsertUserOtherDBRoles(c *C) { 251 if !s.versionAtLeast(2, 4) { 252 c.Skip("UpsertUser only works on 2.4+") 253 } 254 session, err := mgo.Dial("localhost:40002") 255 c.Assert(err, IsNil) 256 defer session.Close() 257 258 admindb := session.DB("admin") 259 err = admindb.Login("root", "rapadura") 260 c.Assert(err, IsNil) 261 262 ruser := &mgo.User{ 263 Username: "myruser", 264 Password: "mypass", 265 OtherDBRoles: map[string][]mgo.Role{"mydb": []mgo.Role{mgo.RoleRead}}, 266 } 267 268 err = admindb.UpsertUser(ruser) 269 c.Assert(err, IsNil) 270 defer admindb.RemoveUser("myruser") 271 272 admindb.Logout() 273 err = admindb.Login("myruser", "mypass") 274 275 coll := session.DB("mydb").C("mycoll") 276 err = coll.Insert(M{"n": 1}) 277 c.Assert(err, ErrorMatches, "unauthorized|not authorized .*") 278 279 err = coll.Find(nil).One(nil) 280 c.Assert(err, Equals, mgo.ErrNotFound) 281 } 282 283 func (s *S) TestAuthUpsertUserUpdates(c *C) { 284 if !s.versionAtLeast(2, 4) { 285 c.Skip("UpsertUser only works on 2.4+") 286 } 287 session, err := mgo.Dial("localhost:40002") 288 c.Assert(err, IsNil) 289 defer session.Close() 290 291 admindb := session.DB("admin") 292 err = admindb.Login("root", "rapadura") 293 c.Assert(err, IsNil) 294 295 mydb := session.DB("mydb") 296 297 // Insert a user that can read. 298 user := &mgo.User{ 299 Username: "myruser", 300 Password: "mypass", 301 Roles: []mgo.Role{mgo.RoleRead}, 302 } 303 err = mydb.UpsertUser(user) 304 c.Assert(err, IsNil) 305 306 // Now update the user password. 307 user = &mgo.User{ 308 Username: "myruser", 309 Password: "mynewpass", 310 } 311 err = mydb.UpsertUser(user) 312 c.Assert(err, IsNil) 313 314 // Login with the new user. 315 usession, err := mgo.Dial("myruser:mynewpass@localhost:40002/mydb") 316 c.Assert(err, IsNil) 317 defer usession.Close() 318 319 // Can read, but not write. 320 err = usession.DB("mydb").C("mycoll").Find(nil).One(nil) 321 c.Assert(err, Equals, mgo.ErrNotFound) 322 err = usession.DB("mydb").C("mycoll").Insert(M{"ok": 1}) 323 c.Assert(err, ErrorMatches, "unauthorized|not authorized .*") 324 325 // Update the user role. 326 user = &mgo.User{ 327 Username: "myruser", 328 Roles: []mgo.Role{mgo.RoleReadWrite}, 329 } 330 err = mydb.UpsertUser(user) 331 c.Assert(err, IsNil) 332 333 // Dial again to ensure the password hasn't changed. 334 usession, err = mgo.Dial("myruser:mynewpass@localhost:40002/mydb") 335 c.Assert(err, IsNil) 336 defer usession.Close() 337 338 // Now it can write. 339 err = usession.DB("mydb").C("mycoll").Insert(M{"ok": 1}) 340 c.Assert(err, IsNil) 341 } 342 343 func (s *S) TestAuthAddUser(c *C) { 344 session, err := mgo.Dial("localhost:40002") 345 c.Assert(err, IsNil) 346 defer session.Close() 347 348 admindb := session.DB("admin") 349 err = admindb.Login("root", "rapadura") 350 c.Assert(err, IsNil) 351 352 mydb := session.DB("mydb") 353 err = mydb.AddUser("myruser", "mypass", true) 354 c.Assert(err, IsNil) 355 err = mydb.AddUser("mywuser", "mypass", false) 356 c.Assert(err, IsNil) 357 358 err = mydb.Login("myruser", "mypass") 359 c.Assert(err, IsNil) 360 361 admindb.Logout() 362 363 coll := session.DB("mydb").C("mycoll") 364 err = coll.Insert(M{"n": 1}) 365 c.Assert(err, ErrorMatches, "unauthorized|not authorized .*") 366 367 err = mydb.Login("mywuser", "mypass") 368 c.Assert(err, IsNil) 369 370 err = coll.Insert(M{"n": 1}) 371 c.Assert(err, IsNil) 372 } 373 374 func (s *S) TestAuthAddUserReplaces(c *C) { 375 session, err := mgo.Dial("localhost:40002") 376 c.Assert(err, IsNil) 377 defer session.Close() 378 379 admindb := session.DB("admin") 380 err = admindb.Login("root", "rapadura") 381 c.Assert(err, IsNil) 382 383 mydb := session.DB("mydb") 384 err = mydb.AddUser("myuser", "myoldpass", false) 385 c.Assert(err, IsNil) 386 err = mydb.AddUser("myuser", "mynewpass", true) 387 c.Assert(err, IsNil) 388 389 admindb.Logout() 390 391 err = mydb.Login("myuser", "myoldpass") 392 c.Assert(err, ErrorMatches, "auth fail(s|ed)|.*Authentication failed.") 393 err = mydb.Login("myuser", "mynewpass") 394 c.Assert(err, IsNil) 395 396 // ReadOnly flag was changed too. 397 err = mydb.C("mycoll").Insert(M{"n": 1}) 398 c.Assert(err, ErrorMatches, "unauthorized|not authorized .*") 399 } 400 401 func (s *S) TestAuthRemoveUser(c *C) { 402 session, err := mgo.Dial("localhost:40002") 403 c.Assert(err, IsNil) 404 defer session.Close() 405 406 admindb := session.DB("admin") 407 err = admindb.Login("root", "rapadura") 408 c.Assert(err, IsNil) 409 410 mydb := session.DB("mydb") 411 err = mydb.AddUser("myuser", "mypass", true) 412 c.Assert(err, IsNil) 413 err = mydb.RemoveUser("myuser") 414 c.Assert(err, IsNil) 415 err = mydb.RemoveUser("myuser") 416 c.Assert(err, Equals, mgo.ErrNotFound) 417 418 err = mydb.Login("myuser", "mypass") 419 c.Assert(err, ErrorMatches, "auth fail(s|ed)|.*Authentication failed.") 420 } 421 422 func (s *S) TestAuthLoginTwiceDoesNothing(c *C) { 423 session, err := mgo.Dial("localhost:40002") 424 c.Assert(err, IsNil) 425 defer session.Close() 426 427 admindb := session.DB("admin") 428 err = admindb.Login("root", "rapadura") 429 c.Assert(err, IsNil) 430 431 oldStats := mgo.GetStats() 432 433 err = admindb.Login("root", "rapadura") 434 c.Assert(err, IsNil) 435 436 newStats := mgo.GetStats() 437 c.Assert(newStats.SentOps, Equals, oldStats.SentOps) 438 } 439 440 func (s *S) TestAuthLoginLogoutLoginDoesNothing(c *C) { 441 session, err := mgo.Dial("localhost:40002") 442 c.Assert(err, IsNil) 443 defer session.Close() 444 445 admindb := session.DB("admin") 446 err = admindb.Login("root", "rapadura") 447 c.Assert(err, IsNil) 448 449 oldStats := mgo.GetStats() 450 451 admindb.Logout() 452 err = admindb.Login("root", "rapadura") 453 c.Assert(err, IsNil) 454 455 newStats := mgo.GetStats() 456 c.Assert(newStats.SentOps, Equals, oldStats.SentOps) 457 } 458 459 func (s *S) TestAuthLoginSwitchUser(c *C) { 460 session, err := mgo.Dial("localhost:40002") 461 c.Assert(err, IsNil) 462 defer session.Close() 463 464 admindb := session.DB("admin") 465 err = admindb.Login("root", "rapadura") 466 c.Assert(err, IsNil) 467 468 coll := session.DB("mydb").C("mycoll") 469 err = coll.Insert(M{"n": 1}) 470 c.Assert(err, IsNil) 471 472 err = admindb.Login("reader", "rapadura") 473 c.Assert(err, IsNil) 474 475 // Can't write. 476 err = coll.Insert(M{"n": 1}) 477 c.Assert(err, ErrorMatches, "unauthorized|not authorized .*") 478 479 // But can read. 480 result := struct{ N int }{} 481 err = coll.Find(nil).One(&result) 482 c.Assert(err, IsNil) 483 c.Assert(result.N, Equals, 1) 484 } 485 486 func (s *S) TestAuthLoginChangePassword(c *C) { 487 session, err := mgo.Dial("localhost:40002") 488 c.Assert(err, IsNil) 489 defer session.Close() 490 491 admindb := session.DB("admin") 492 err = admindb.Login("root", "rapadura") 493 c.Assert(err, IsNil) 494 495 mydb := session.DB("mydb") 496 err = mydb.AddUser("myuser", "myoldpass", false) 497 c.Assert(err, IsNil) 498 499 err = mydb.Login("myuser", "myoldpass") 500 c.Assert(err, IsNil) 501 502 err = mydb.AddUser("myuser", "mynewpass", true) 503 c.Assert(err, IsNil) 504 505 err = mydb.Login("myuser", "mynewpass") 506 c.Assert(err, IsNil) 507 508 admindb.Logout() 509 510 // The second login must be in effect, which means read-only. 511 err = mydb.C("mycoll").Insert(M{"n": 1}) 512 c.Assert(err, ErrorMatches, "unauthorized|not authorized .*") 513 } 514 515 func (s *S) TestAuthLoginCachingWithSessionRefresh(c *C) { 516 session, err := mgo.Dial("localhost:40002") 517 c.Assert(err, IsNil) 518 defer session.Close() 519 520 admindb := session.DB("admin") 521 err = admindb.Login("root", "rapadura") 522 c.Assert(err, IsNil) 523 524 session.Refresh() 525 526 coll := session.DB("mydb").C("mycoll") 527 err = coll.Insert(M{"n": 1}) 528 c.Assert(err, IsNil) 529 } 530 531 func (s *S) TestAuthLoginCachingWithSessionCopy(c *C) { 532 session, err := mgo.Dial("localhost:40002") 533 c.Assert(err, IsNil) 534 defer session.Close() 535 536 admindb := session.DB("admin") 537 err = admindb.Login("root", "rapadura") 538 c.Assert(err, IsNil) 539 540 session = session.Copy() 541 defer session.Close() 542 543 coll := session.DB("mydb").C("mycoll") 544 err = coll.Insert(M{"n": 1}) 545 c.Assert(err, IsNil) 546 } 547 548 func (s *S) TestAuthLoginCachingWithSessionClone(c *C) { 549 session, err := mgo.Dial("localhost:40002") 550 c.Assert(err, IsNil) 551 defer session.Close() 552 553 admindb := session.DB("admin") 554 err = admindb.Login("root", "rapadura") 555 c.Assert(err, IsNil) 556 557 session = session.Clone() 558 defer session.Close() 559 560 coll := session.DB("mydb").C("mycoll") 561 err = coll.Insert(M{"n": 1}) 562 c.Assert(err, IsNil) 563 } 564 565 func (s *S) TestAuthLoginCachingWithNewSession(c *C) { 566 session, err := mgo.Dial("localhost:40002") 567 c.Assert(err, IsNil) 568 defer session.Close() 569 570 admindb := session.DB("admin") 571 err = admindb.Login("root", "rapadura") 572 c.Assert(err, IsNil) 573 574 session = session.New() 575 defer session.Close() 576 577 coll := session.DB("mydb").C("mycoll") 578 err = coll.Insert(M{"n": 1}) 579 c.Assert(err, ErrorMatches, "unauthorized|need to login|not authorized .*") 580 } 581 582 func (s *S) TestAuthLoginCachingAcrossPool(c *C) { 583 // Logins are cached even when the conenction goes back 584 // into the pool. 585 586 session, err := mgo.Dial("localhost:40002") 587 c.Assert(err, IsNil) 588 defer session.Close() 589 590 admindb := session.DB("admin") 591 err = admindb.Login("root", "rapadura") 592 c.Assert(err, IsNil) 593 594 // Add another user to test the logout case at the same time. 595 mydb := session.DB("mydb") 596 err = mydb.AddUser("myuser", "mypass", false) 597 c.Assert(err, IsNil) 598 599 err = mydb.Login("myuser", "mypass") 600 c.Assert(err, IsNil) 601 602 // Logout root explicitly, to test both cases. 603 admindb.Logout() 604 605 // Give socket back to pool. 606 session.Refresh() 607 608 // Brand new session, should use socket from the pool. 609 other := session.New() 610 defer other.Close() 611 612 oldStats := mgo.GetStats() 613 614 err = other.DB("admin").Login("root", "rapadura") 615 c.Assert(err, IsNil) 616 err = other.DB("mydb").Login("myuser", "mypass") 617 c.Assert(err, IsNil) 618 619 // Both logins were cached, so no ops. 620 newStats := mgo.GetStats() 621 c.Assert(newStats.SentOps, Equals, oldStats.SentOps) 622 623 // And they actually worked. 624 err = other.DB("mydb").C("mycoll").Insert(M{"n": 1}) 625 c.Assert(err, IsNil) 626 627 other.DB("admin").Logout() 628 629 err = other.DB("mydb").C("mycoll").Insert(M{"n": 1}) 630 c.Assert(err, IsNil) 631 } 632 633 func (s *S) TestAuthLoginCachingAcrossPoolWithLogout(c *C) { 634 // Now verify that logouts are properly flushed if they 635 // are not revalidated after leaving the pool. 636 637 session, err := mgo.Dial("localhost:40002") 638 c.Assert(err, IsNil) 639 defer session.Close() 640 641 admindb := session.DB("admin") 642 err = admindb.Login("root", "rapadura") 643 c.Assert(err, IsNil) 644 645 // Add another user to test the logout case at the same time. 646 mydb := session.DB("mydb") 647 err = mydb.AddUser("myuser", "mypass", true) 648 c.Assert(err, IsNil) 649 650 err = mydb.Login("myuser", "mypass") 651 c.Assert(err, IsNil) 652 653 // Just some data to query later. 654 err = session.DB("mydb").C("mycoll").Insert(M{"n": 1}) 655 c.Assert(err, IsNil) 656 657 // Give socket back to pool. 658 session.Refresh() 659 660 // Brand new session, should use socket from the pool. 661 other := session.New() 662 defer other.Close() 663 664 oldStats := mgo.GetStats() 665 666 err = other.DB("mydb").Login("myuser", "mypass") 667 c.Assert(err, IsNil) 668 669 // Login was cached, so no ops. 670 newStats := mgo.GetStats() 671 c.Assert(newStats.SentOps, Equals, oldStats.SentOps) 672 673 // Can't write, since root has been implicitly logged out 674 // when the collection went into the pool, and not revalidated. 675 err = other.DB("mydb").C("mycoll").Insert(M{"n": 1}) 676 c.Assert(err, ErrorMatches, "unauthorized|not authorized .*") 677 678 // But can read due to the revalidated myuser login. 679 result := struct{ N int }{} 680 err = other.DB("mydb").C("mycoll").Find(nil).One(&result) 681 c.Assert(err, IsNil) 682 c.Assert(result.N, Equals, 1) 683 } 684 685 func (s *S) TestAuthEventual(c *C) { 686 // Eventual sessions don't keep sockets around, so they are 687 // an interesting test case. 688 session, err := mgo.Dial("localhost:40002") 689 c.Assert(err, IsNil) 690 defer session.Close() 691 692 admindb := session.DB("admin") 693 err = admindb.Login("root", "rapadura") 694 c.Assert(err, IsNil) 695 696 err = session.DB("mydb").C("mycoll").Insert(M{"n": 1}) 697 c.Assert(err, IsNil) 698 699 var wg sync.WaitGroup 700 wg.Add(20) 701 702 for i := 0; i != 10; i++ { 703 go func() { 704 defer wg.Done() 705 var result struct{ N int } 706 err := session.DB("mydb").C("mycoll").Find(nil).One(&result) 707 c.Assert(err, IsNil) 708 c.Assert(result.N, Equals, 1) 709 }() 710 } 711 712 for i := 0; i != 10; i++ { 713 go func() { 714 defer wg.Done() 715 err := session.DB("mydb").C("mycoll").Insert(M{"n": 1}) 716 c.Assert(err, IsNil) 717 }() 718 } 719 720 wg.Wait() 721 } 722 723 func (s *S) TestAuthURL(c *C) { 724 session, err := mgo.Dial("mongodb://root:rapadura@localhost:40002/") 725 c.Assert(err, IsNil) 726 defer session.Close() 727 728 err = session.DB("mydb").C("mycoll").Insert(M{"n": 1}) 729 c.Assert(err, IsNil) 730 } 731 732 func (s *S) TestAuthURLWrongCredentials(c *C) { 733 session, err := mgo.Dial("mongodb://root:wrong@localhost:40002/") 734 if session != nil { 735 session.Close() 736 } 737 c.Assert(err, ErrorMatches, "auth fail(s|ed)|.*Authentication failed.") 738 c.Assert(session, IsNil) 739 } 740 741 func (s *S) TestAuthURLWithNewSession(c *C) { 742 // When authentication is in the URL, the new session will 743 // actually carry it on as well, even if logged out explicitly. 744 session, err := mgo.Dial("mongodb://root:rapadura@localhost:40002/") 745 c.Assert(err, IsNil) 746 defer session.Close() 747 748 session.DB("admin").Logout() 749 750 // Do it twice to ensure it passes the needed data on. 751 session = session.New() 752 defer session.Close() 753 session = session.New() 754 defer session.Close() 755 756 err = session.DB("mydb").C("mycoll").Insert(M{"n": 1}) 757 c.Assert(err, IsNil) 758 } 759 760 func (s *S) TestAuthURLWithDatabase(c *C) { 761 session, err := mgo.Dial("mongodb://root:rapadura@localhost:40002") 762 c.Assert(err, IsNil) 763 defer session.Close() 764 765 mydb := session.DB("mydb") 766 err = mydb.AddUser("myruser", "mypass", true) 767 c.Assert(err, IsNil) 768 769 // Test once with database, and once with source. 770 for i := 0; i < 2; i++ { 771 var url string 772 if i == 0 { 773 url = "mongodb://myruser:mypass@localhost:40002/mydb" 774 } else { 775 url = "mongodb://myruser:mypass@localhost:40002/admin?authSource=mydb" 776 } 777 usession, err := mgo.Dial(url) 778 c.Assert(err, IsNil) 779 defer usession.Close() 780 781 ucoll := usession.DB("mydb").C("mycoll") 782 err = ucoll.FindId(0).One(nil) 783 c.Assert(err, Equals, mgo.ErrNotFound) 784 err = ucoll.Insert(M{"n": 1}) 785 c.Assert(err, ErrorMatches, "unauthorized|not authorized .*") 786 } 787 } 788 789 func (s *S) TestDefaultDatabase(c *C) { 790 tests := []struct{ url, db string }{ 791 {"mongodb://root:rapadura@localhost:40002", "test"}, 792 {"mongodb://root:rapadura@localhost:40002/admin", "admin"}, 793 {"mongodb://localhost:40001", "test"}, 794 {"mongodb://localhost:40001/", "test"}, 795 {"mongodb://localhost:40001/mydb", "mydb"}, 796 } 797 798 for _, test := range tests { 799 session, err := mgo.Dial(test.url) 800 c.Assert(err, IsNil) 801 defer session.Close() 802 803 c.Logf("test: %#v", test) 804 c.Assert(session.DB("").Name, Equals, test.db) 805 806 scopy := session.Copy() 807 c.Check(scopy.DB("").Name, Equals, test.db) 808 scopy.Close() 809 } 810 } 811 812 func (s *S) TestAuthDirect(c *C) { 813 // Direct connections must work to the master and slaves. 814 for _, port := range []string{"40031", "40032", "40033"} { 815 url := fmt.Sprintf("mongodb://root:rapadura@localhost:%s/?connect=direct", port) 816 session, err := mgo.Dial(url) 817 c.Assert(err, IsNil) 818 defer session.Close() 819 820 session.SetMode(mgo.Monotonic, true) 821 822 var result struct{} 823 err = session.DB("mydb").C("mycoll").Find(nil).One(&result) 824 c.Assert(err, Equals, mgo.ErrNotFound) 825 } 826 } 827 828 func (s *S) TestAuthDirectWithLogin(c *C) { 829 // Direct connections must work to the master and slaves. 830 for _, port := range []string{"40031", "40032", "40033"} { 831 url := fmt.Sprintf("mongodb://localhost:%s/?connect=direct", port) 832 session, err := mgo.Dial(url) 833 c.Assert(err, IsNil) 834 defer session.Close() 835 836 session.SetMode(mgo.Monotonic, true) 837 session.SetSyncTimeout(3 * time.Second) 838 839 err = session.DB("admin").Login("root", "rapadura") 840 c.Assert(err, IsNil) 841 842 var result struct{} 843 err = session.DB("mydb").C("mycoll").Find(nil).One(&result) 844 c.Assert(err, Equals, mgo.ErrNotFound) 845 } 846 } 847 848 func (s *S) TestAuthScramSha1Cred(c *C) { 849 if !s.versionAtLeast(2, 7, 7) { 850 c.Skip("SCRAM-SHA-1 tests depend on 2.7.7") 851 } 852 cred := &mgo.Credential{ 853 Username: "root", 854 Password: "rapadura", 855 Mechanism: "SCRAM-SHA-1", 856 Source: "admin", 857 } 858 host := "localhost:40002" 859 c.Logf("Connecting to %s...", host) 860 session, err := mgo.Dial(host) 861 c.Assert(err, IsNil) 862 defer session.Close() 863 864 mycoll := session.DB("admin").C("mycoll") 865 866 c.Logf("Connected! Testing the need for authentication...") 867 err = mycoll.Find(nil).One(nil) 868 c.Assert(err, ErrorMatches, "unauthorized|not authorized .*") 869 870 c.Logf("Authenticating...") 871 err = session.Login(cred) 872 c.Assert(err, IsNil) 873 c.Logf("Authenticated!") 874 875 c.Logf("Connected! Testing the need for authentication...") 876 err = mycoll.Find(nil).One(nil) 877 c.Assert(err, Equals, mgo.ErrNotFound) 878 } 879 880 func (s *S) TestAuthScramSha1URL(c *C) { 881 if !s.versionAtLeast(2, 7, 7) { 882 c.Skip("SCRAM-SHA-1 tests depend on 2.7.7") 883 } 884 host := "localhost:40002" 885 c.Logf("Connecting to %s...", host) 886 session, err := mgo.Dial(fmt.Sprintf("root:rapadura@%s?authMechanism=SCRAM-SHA-1", host)) 887 c.Assert(err, IsNil) 888 defer session.Close() 889 890 mycoll := session.DB("admin").C("mycoll") 891 892 c.Logf("Connected! Testing the need for authentication...") 893 err = mycoll.Find(nil).One(nil) 894 c.Assert(err, Equals, mgo.ErrNotFound) 895 } 896 897 func (s *S) TestAuthX509Cred(c *C) { 898 session, err := mgo.Dial("localhost:40001") 899 c.Assert(err, IsNil) 900 defer session.Close() 901 binfo, err := session.BuildInfo() 902 c.Assert(err, IsNil) 903 if binfo.OpenSSLVersion == "" { 904 c.Skip("server does not support SSL") 905 } 906 907 clientCertPEM, err := ioutil.ReadFile("harness/certs/client.pem") 908 c.Assert(err, IsNil) 909 910 clientCert, err := tls.X509KeyPair(clientCertPEM, clientCertPEM) 911 c.Assert(err, IsNil) 912 913 tlsConfig := &tls.Config{ 914 // Isolating tests to client certs, don't care about server validation. 915 InsecureSkipVerify: true, 916 Certificates: []tls.Certificate{clientCert}, 917 } 918 919 var host = "localhost:40003" 920 c.Logf("Connecting to %s...", host) 921 session, err = mgo.DialWithInfo(&mgo.DialInfo{ 922 Addrs: []string{host}, 923 DialServer: func(addr *mgo.ServerAddr) (net.Conn, error) { 924 return tls.Dial("tcp", addr.String(), tlsConfig) 925 }, 926 }) 927 c.Assert(err, IsNil) 928 defer session.Close() 929 930 err = session.Login(&mgo.Credential{Username: "root", Password: "rapadura"}) 931 c.Assert(err, IsNil) 932 933 // This needs to be kept in sync with client.pem 934 x509Subject := "CN=localhost,OU=Client,O=MGO,L=MGO,ST=MGO,C=GO" 935 936 externalDB := session.DB("$external") 937 var x509User mgo.User = mgo.User{ 938 Username: x509Subject, 939 OtherDBRoles: map[string][]mgo.Role{"admin": []mgo.Role{mgo.RoleRoot}}, 940 } 941 err = externalDB.UpsertUser(&x509User) 942 c.Assert(err, IsNil) 943 944 session.LogoutAll() 945 946 c.Logf("Connected! Ensuring authentication is required...") 947 names, err := session.DatabaseNames() 948 c.Assert(err, ErrorMatches, "not authorized .*") 949 950 cred := &mgo.Credential{ 951 Username: x509Subject, 952 Mechanism: "MONGODB-X509", 953 Source: "$external", 954 } 955 956 c.Logf("Authenticating...") 957 err = session.Login(cred) 958 c.Assert(err, IsNil) 959 c.Logf("Authenticated!") 960 961 names, err = session.DatabaseNames() 962 c.Assert(err, IsNil) 963 c.Assert(len(names) > 0, Equals, true) 964 } 965 966 var ( 967 plainFlag = flag.String("plain", "", "Host to test PLAIN authentication against (depends on custom environment)") 968 plainUser = "einstein" 969 plainPass = "password" 970 ) 971 972 func (s *S) TestAuthPlainCred(c *C) { 973 if *plainFlag == "" { 974 c.Skip("no -plain") 975 } 976 cred := &mgo.Credential{ 977 Username: plainUser, 978 Password: plainPass, 979 Source: "$external", 980 Mechanism: "PLAIN", 981 } 982 c.Logf("Connecting to %s...", *plainFlag) 983 session, err := mgo.Dial(*plainFlag) 984 c.Assert(err, IsNil) 985 defer session.Close() 986 987 records := session.DB("records").C("records") 988 989 c.Logf("Connected! Testing the need for authentication...") 990 err = records.Find(nil).One(nil) 991 c.Assert(err, ErrorMatches, "unauthorized|not authorized .*") 992 993 c.Logf("Authenticating...") 994 err = session.Login(cred) 995 c.Assert(err, IsNil) 996 c.Logf("Authenticated!") 997 998 c.Logf("Connected! Testing the need for authentication...") 999 err = records.Find(nil).One(nil) 1000 c.Assert(err, Equals, mgo.ErrNotFound) 1001 } 1002 1003 func (s *S) TestAuthPlainURL(c *C) { 1004 if *plainFlag == "" { 1005 c.Skip("no -plain") 1006 } 1007 c.Logf("Connecting to %s...", *plainFlag) 1008 session, err := mgo.Dial(fmt.Sprintf("%s:%s@%s?authMechanism=PLAIN", url.QueryEscape(plainUser), url.QueryEscape(plainPass), *plainFlag)) 1009 c.Assert(err, IsNil) 1010 defer session.Close() 1011 1012 c.Logf("Connected! Testing the need for authentication...") 1013 err = session.DB("records").C("records").Find(nil).One(nil) 1014 c.Assert(err, Equals, mgo.ErrNotFound) 1015 } 1016 1017 var ( 1018 kerberosFlag = flag.Bool("kerberos", false, "Test Kerberos authentication (depends on custom environment)") 1019 kerberosHost = "ldaptest.10gen.cc" 1020 kerberosUser = "drivers@LDAPTEST.10GEN.CC" 1021 1022 winKerberosPasswordEnv = "MGO_KERBEROS_PASSWORD" 1023 ) 1024 1025 // Kerberos has its own suite because it talks to a remote server 1026 // that is prepared to authenticate against a kerberos deployment. 1027 type KerberosSuite struct{} 1028 1029 var _ = Suite(&KerberosSuite{}) 1030 1031 func (kerberosSuite *KerberosSuite) SetUpSuite(c *C) { 1032 mgo.SetDebug(true) 1033 mgo.SetStats(true) 1034 } 1035 1036 func (kerberosSuite *KerberosSuite) TearDownSuite(c *C) { 1037 mgo.SetDebug(false) 1038 mgo.SetStats(false) 1039 } 1040 1041 func (kerberosSuite *KerberosSuite) SetUpTest(c *C) { 1042 mgo.SetLogger((*cLogger)(c)) 1043 mgo.ResetStats() 1044 } 1045 1046 func (kerberosSuite *KerberosSuite) TearDownTest(c *C) { 1047 mgo.SetLogger(nil) 1048 } 1049 1050 func (kerberosSuite *KerberosSuite) TestAuthKerberosCred(c *C) { 1051 if !*kerberosFlag { 1052 c.Skip("no -kerberos") 1053 } 1054 cred := &mgo.Credential{ 1055 Username: kerberosUser, 1056 Mechanism: "GSSAPI", 1057 } 1058 windowsAppendPasswordToCredential(cred) 1059 c.Logf("Connecting to %s...", kerberosHost) 1060 session, err := mgo.Dial(kerberosHost) 1061 c.Assert(err, IsNil) 1062 defer session.Close() 1063 1064 c.Logf("Connected! Testing the need for authentication...") 1065 n, err := session.DB("kerberos").C("test").Find(M{}).Count() 1066 c.Assert(err, ErrorMatches, ".*authorized.*") 1067 1068 c.Logf("Authenticating...") 1069 err = session.Login(cred) 1070 c.Assert(err, IsNil) 1071 c.Logf("Authenticated!") 1072 1073 n, err = session.DB("kerberos").C("test").Find(M{}).Count() 1074 c.Assert(err, IsNil) 1075 c.Assert(n, Equals, 1) 1076 } 1077 1078 func (kerberosSuite *KerberosSuite) TestAuthKerberosURL(c *C) { 1079 if !*kerberosFlag { 1080 c.Skip("no -kerberos") 1081 } 1082 c.Logf("Connecting to %s...", kerberosHost) 1083 connectUri := url.QueryEscape(kerberosUser) + "@" + kerberosHost + "?authMechanism=GSSAPI" 1084 if runtime.GOOS == "windows" { 1085 connectUri = url.QueryEscape(kerberosUser) + ":" + url.QueryEscape(getWindowsKerberosPassword()) + "@" + kerberosHost + "?authMechanism=GSSAPI" 1086 } 1087 session, err := mgo.Dial(connectUri) 1088 c.Assert(err, IsNil) 1089 defer session.Close() 1090 n, err := session.DB("kerberos").C("test").Find(M{}).Count() 1091 c.Assert(err, IsNil) 1092 c.Assert(n, Equals, 1) 1093 } 1094 1095 func (kerberosSuite *KerberosSuite) TestAuthKerberosServiceName(c *C) { 1096 if !*kerberosFlag { 1097 c.Skip("no -kerberos") 1098 } 1099 1100 wrongServiceName := "wrong" 1101 rightServiceName := "mongodb" 1102 1103 cred := &mgo.Credential{ 1104 Username: kerberosUser, 1105 Mechanism: "GSSAPI", 1106 Service: wrongServiceName, 1107 } 1108 windowsAppendPasswordToCredential(cred) 1109 1110 c.Logf("Connecting to %s...", kerberosHost) 1111 session, err := mgo.Dial(kerberosHost) 1112 c.Assert(err, IsNil) 1113 defer session.Close() 1114 1115 c.Logf("Authenticating with incorrect service name...") 1116 err = session.Login(cred) 1117 c.Assert(err, ErrorMatches, ".*@LDAPTEST.10GEN.CC not found.*") 1118 1119 cred.Service = rightServiceName 1120 c.Logf("Authenticating with correct service name...") 1121 err = session.Login(cred) 1122 c.Assert(err, IsNil) 1123 c.Logf("Authenticated!") 1124 1125 n, err := session.DB("kerberos").C("test").Find(M{}).Count() 1126 c.Assert(err, IsNil) 1127 c.Assert(n, Equals, 1) 1128 } 1129 1130 func (kerberosSuite *KerberosSuite) TestAuthKerberosServiceHost(c *C) { 1131 if !*kerberosFlag { 1132 c.Skip("no -kerberos") 1133 } 1134 1135 wrongServiceHost := "eggs.bacon.tk" 1136 rightServiceHost := kerberosHost 1137 1138 cred := &mgo.Credential{ 1139 Username: kerberosUser, 1140 Mechanism: "GSSAPI", 1141 ServiceHost: wrongServiceHost, 1142 } 1143 windowsAppendPasswordToCredential(cred) 1144 1145 c.Logf("Connecting to %s...", kerberosHost) 1146 session, err := mgo.Dial(kerberosHost) 1147 c.Assert(err, IsNil) 1148 defer session.Close() 1149 1150 c.Logf("Authenticating with incorrect service host...") 1151 err = session.Login(cred) 1152 c.Assert(err, ErrorMatches, ".*@LDAPTEST.10GEN.CC not found.*") 1153 1154 cred.ServiceHost = rightServiceHost 1155 c.Logf("Authenticating with correct service host...") 1156 err = session.Login(cred) 1157 c.Assert(err, IsNil) 1158 c.Logf("Authenticated!") 1159 1160 n, err := session.DB("kerberos").C("test").Find(M{}).Count() 1161 c.Assert(err, IsNil) 1162 c.Assert(n, Equals, 1) 1163 } 1164 1165 // No kinit on SSPI-style Kerberos, so we need to provide a password. In order 1166 // to avoid inlining password, require it to be set as an environment variable, 1167 // for instance: `SET MGO_KERBEROS_PASSWORD=this_isnt_the_password` 1168 func getWindowsKerberosPassword() string { 1169 pw := os.Getenv(winKerberosPasswordEnv) 1170 if pw == "" { 1171 panic(fmt.Sprintf("Need to set %v environment variable to run Kerberos tests on Windows", winKerberosPasswordEnv)) 1172 } 1173 return pw 1174 } 1175 1176 func windowsAppendPasswordToCredential(cred *mgo.Credential) { 1177 if runtime.GOOS == "windows" { 1178 cred.Password = getWindowsKerberosPassword() 1179 } 1180 }