Skip to content

Commit

Permalink
Merge pull request #506 from axw/mongo2.6-compat
Browse files Browse the repository at this point in the history
Various changes to support Mongo 2.6

Disable auth in Mongo for all except a handful of tests, which we segregate
and enable authentication for explicitly.

Ignore all commits other than 326c231: this builds on top of PR #498.

Requires juju/testing#28
  • Loading branch information
jujubot committed Aug 14, 2014
2 parents 04ff38e + 593a6bd commit f514c88
Show file tree
Hide file tree
Showing 6 changed files with 87 additions and 48 deletions.
3 changes: 2 additions & 1 deletion agent/bootstrap_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ func (s *bootstrapSuite) SetUpTest(c *gc.C) {
s.BaseSuite.SetUpTest(c)
// Don't use MgoSuite, because we need to ensure
// we have a fresh mongo for each test case.
s.mgoInst.EnableAuth = true
err := s.mgoInst.Start(testing.Certs)
c.Assert(err, gc.IsNil)
}
Expand Down Expand Up @@ -221,7 +222,7 @@ func (s *bootstrapSuite) TestInitializeStateFailsSecondTime(c *gc.C) {
if err == nil {
st.Close()
}
c.Assert(err, gc.ErrorMatches, "failed to initialize mongo admin user: cannot set admin password: not authorized for update on admin.system.users")
c.Assert(err, gc.ErrorMatches, "failed to initialize mongo admin user: cannot set admin password: not authorized .*")
}

func (s *bootstrapSuite) assertCanLogInAsAdmin(c *gc.C, password string) {
Expand Down
14 changes: 9 additions & 5 deletions cmd/jujud/bootstrap_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -323,24 +323,28 @@ func (s *BootstrapSuite) TestInitialPassword(c *gc.C) {
err = cmd.Run(nil)
c.Assert(err, gc.IsNil)

// Check that we cannot now connect to the state without a
// password.
info := &authentication.MongoInfo{
Info: mongo.Info{
Addrs: []string{gitjujutesting.MgoServer.Addr()},
CACert: testing.CACert,
},
}
testOpenState(c, info, errors.Unauthorizedf(""))

// Check we can log in to mongo as admin.
// TODO(dfc) does passing nil for the admin user name make your skin crawl ? mine too.
info.Tag, info.Password = nil, testPasswordHash()
st, err := state.Open(info, mongo.DefaultDialOpts(), environs.NewStatePolicy())
c.Assert(err, gc.IsNil)
// Reset password so the tests can continue to use the same server.
defer st.Close()
defer st.SetAdminMongoPassword("")

// We're running Mongo with --noauth; let's explicitly verify
// that we can login as that user. Even with --noauth, an
// explicit Login will still be verified.
adminDB := st.MongoSession().DB("admin")
err = adminDB.Login("admin", "invalid-password")
c.Assert(err, gc.ErrorMatches, "auth fail(s|ed)")
err = adminDB.Login("admin", info.Password)
c.Assert(err, gc.IsNil)

// Check that the admin user has been given an appropriate
// password
Expand Down
2 changes: 1 addition & 1 deletion dependencies.tsv
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ github.com/juju/loggo git 158009fb40c4a52b3d2c23eb56e72859cfc5321a
github.com/juju/names git 93fc8cbf8111c11d4ff47e603f668a0e29fb7cec
github.com/juju/ratelimit git f9f36d11773655c0485207f0ad30dc2655f69d56
github.com/juju/schema git 27a52be50766490a6fd3531865095fda6c0eeb6d
github.com/juju/testing git 8bdbb45d87dd9724c254eb6afeacd84b127d7e76
github.com/juju/testing git 503e61bd033592d7b6003174389f68454deb7b7a
github.com/juju/txn git ee0346875f2ae9a21442f3ff64409f750f37afbc
github.com/juju/utils git 68554773385c32c354bf6357f8b6edd8a4742682
gopkg.in/juju/charm.v3 git eb7dae8ed9dfa44b89e4e8eee6e21f80e31a3b69
Expand Down
31 changes: 23 additions & 8 deletions mongo/admin_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ func (s *adminSuite) TestEnsureAdminUser(c *gc.C) {

func (s *adminSuite) TestEnsureAdminUserError(c *gc.C) {
inst := &gitjujutesting.MgoInstance{}
inst.EnableAuth = true
err := inst.Start(coretesting.Certs)
c.Assert(err, gc.IsNil)
defer inst.Destroy()
Expand All @@ -112,7 +113,7 @@ func (s *adminSuite) TestEnsureAdminUserError(c *gc.C) {
// Second call fails, as there is another user and the database doesn't
// actually get reopened with --noauth in the test; mimics AddUser failure
_, err = s.ensureAdminUser(c, dialInfo, "whomeverelse", "whateverelse")
c.Assert(err, gc.ErrorMatches, `failed to add "whomeverelse" to admin database: cannot set admin password: not authorized for update on admin.system.users`)
c.Assert(err, gc.ErrorMatches, `failed to add "whomeverelse" to admin database: cannot set admin password: not authorized .*`)
}

func (s *adminSuite) ensureAdminUser(c *gc.C, dialInfo *mgo.DialInfo, user, password string) (added bool, err error) {
Expand All @@ -138,13 +139,26 @@ func (s *adminSuite) setUpMongo(c *gc.C) *mgo.DialInfo {
return dialInfo
}

func checkRoles(c *gc.C, db *mgo.Database, user string, expected []interface{}) {
// Check the assigned roles.
func checkRoles(c *gc.C, session *mgo.Session, db, user string, expected []interface{}) {
admin := session.DB("admin")

var info map[string]interface{}
err := db.C("system.users").Find(bson.D{{"user", user}}).One(&info)
err := admin.C("system.users").Find(bson.D{{"user", user}}).One(&info)
c.Assert(err, gc.IsNil)

roles := info["roles"]
var roles []interface{}
for _, role := range info["roles"].([]interface{}) {
switch role := role.(type) {
case map[string]interface{}:
// Mongo 2.6
if role["db"] == db {
roles = append(roles, role["role"])
}
default:
// Mongo 2.4
roles = append(roles, role)
}
}
c.Assert(roles, jc.SameContents, expected)
}

Expand All @@ -153,20 +167,21 @@ func (s *adminSuite) TestSetAdminMongoPassword(c *gc.C) {
session, err := mgo.DialWithInfo(dialInfo)
c.Assert(err, gc.IsNil)
defer session.Close()
admin := session.DB("admin")

// Check that we can SetAdminMongoPassword to nothing when there's
// no password currently set.
err = mongo.SetAdminMongoPassword(session, "auser", "")
c.Assert(err, gc.IsNil)

admin := session.DB("admin")
err = mongo.SetAdminMongoPassword(session, "auser", "foo")
c.Assert(err, gc.IsNil)
err = admin.Login("auser", "")
c.Assert(err, gc.ErrorMatches, "auth fails")
c.Assert(err, gc.ErrorMatches, "auth fail(s|ed)")
err = admin.Login("auser", "foo")
c.Assert(err, gc.IsNil)
checkRoles(c, admin, "auser",

checkRoles(c, session, "admin", "auser",
[]interface{}{
string(mgo.RoleReadWriteAny),
string(mgo.RoleDBAdminAny),
Expand Down
6 changes: 4 additions & 2 deletions state/open.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ package state

import (
"fmt"
"strings"

"github.com/juju/errors"
"github.com/juju/names"
Expand Down Expand Up @@ -146,13 +147,14 @@ func isUnauthorized(err error) bool {
}
// Some unauthorized access errors have no error code,
// just a simple error string.
if err.Error() == "auth fails" {
if strings.HasPrefix(err.Error(), "auth fail") {
return true
}
if err, ok := err.(*mgo.QueryError); ok {
return err.Code == 10057 ||
err.Message == "need to login" ||
err.Message == "unauthorized"
err.Message == "unauthorized" ||
strings.HasPrefix(err.Message, "not authorized")
}
return false
}
Expand Down
79 changes: 48 additions & 31 deletions state/state_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2213,37 +2213,6 @@ type entity interface {
state.Authenticator
}

func (s *StateSuite) TestSetAdminMongoPassword(c *gc.C) {
// Check that we can SetAdminMongoPassword to nothing when there's
// no password currently set.
err := s.State.SetAdminMongoPassword("")
c.Assert(err, gc.IsNil)

err = s.State.SetAdminMongoPassword("foo")
c.Assert(err, gc.IsNil)
err = s.State.MongoSession().DB("admin").Login("admin", "foo")
c.Assert(err, gc.IsNil)
defer s.State.SetAdminMongoPassword("")
info := state.TestingMongoInfo()
err = tryOpenState(info)
c.Assert(err, jc.Satisfies, errors.IsUnauthorized)

info.Password = "foo"
err = tryOpenState(info)
c.Assert(err, gc.IsNil)

err = s.State.SetAdminMongoPassword("")
c.Assert(err, gc.IsNil)

// Check that removing the password is idempotent.
err = s.State.SetAdminMongoPassword("")
c.Assert(err, gc.IsNil)

info.Password = ""
err = tryOpenState(info)
c.Assert(err, gc.IsNil)
}

type findEntityTest struct {
tag string
err string
Expand Down Expand Up @@ -3650,3 +3619,51 @@ func (s *StateSuite) TestWatchMachineAddresses(c *gc.C) {
}
c.Assert(w.Err(), jc.Satisfies, errors.IsNotFound)
}

type SetAdminMongoPasswordSuite struct {
testing.BaseSuite
}

var _ = gc.Suite(&SetAdminMongoPasswordSuite{})

func (s *SetAdminMongoPasswordSuite) TestSetAdminMongoPassword(c *gc.C) {
inst := &gitjujutesting.MgoInstance{EnableAuth: true}
err := inst.Start(testing.Certs)
c.Assert(err, gc.IsNil)
defer inst.DestroyWithLog()

mongoInfo := &authentication.MongoInfo{
Info: mongo.Info{
Addrs: []string{inst.Addr()},
CACert: testing.CACert,
},
}
cfg := testing.EnvironConfig(c)
st, err := state.Initialize(mongoInfo, cfg, state.TestingDialOpts(), nil)
c.Assert(err, gc.IsNil)
defer st.Close()

// Check that we can SetAdminMongoPassword to nothing when there's
// no password currently set.
err = st.SetAdminMongoPassword("")
c.Assert(err, gc.IsNil)

err = st.SetAdminMongoPassword("foo")
c.Assert(err, gc.IsNil)
err = st.MongoSession().DB("admin").Login("admin", "foo")
c.Assert(err, gc.IsNil)

err = tryOpenState(mongoInfo)
c.Assert(err, jc.Satisfies, errors.IsUnauthorized)

mongoInfo.Password = "foo"
err = tryOpenState(mongoInfo)
c.Assert(err, gc.IsNil)

err = st.SetAdminMongoPassword("")
c.Assert(err, gc.IsNil)

mongoInfo.Password = ""
err = tryOpenState(mongoInfo)
c.Assert(err, gc.IsNil)
}

0 comments on commit f514c88

Please sign in to comment.