Skip to content

Commit

Permalink
Only login to "admin" mongo database
Browse files Browse the repository at this point in the history
We create a user in the admin database
with read/write privileges to all databases,
so there's no need to add users to each
other database. Consequently, we can remove
the mongo.SetMongoPassword function and
change state.Machine.SetMongoPassword to
just call mongo.SetAdminMongoPassword.

Tested live:
 - juju bootstrap && juju ensure-availability
 - juju upgrade-juju
  • Loading branch information
axw committed Aug 11, 2014
1 parent 0708d09 commit 3ea8fce
Show file tree
Hide file tree
Showing 10 changed files with 63 additions and 137 deletions.
6 changes: 3 additions & 3 deletions agent/bootstrap_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ func (s *bootstrapSuite) TestInitializeState(c *gc.C) {
mcfg := agent.BootstrapMachineConfig{
Addresses: network.NewAddresses("zeroonetwothree", "0.1.2.3"),
Constraints: expectConstraints,
Jobs: []params.MachineJob{params.JobHostUnits},
Jobs: []params.MachineJob{params.JobManageEnviron},
InstanceId: "i-bootstrap",
Characteristics: expectHW,
SharedSecret: "abc123",
Expand Down Expand Up @@ -114,7 +114,7 @@ func (s *bootstrapSuite) TestInitializeState(c *gc.C) {

// Check that the bootstrap machine looks correct.
c.Assert(m.Id(), gc.Equals, "0")
c.Assert(m.Jobs(), gc.DeepEquals, []state.MachineJob{state.JobHostUnits})
c.Assert(m.Jobs(), gc.DeepEquals, []state.MachineJob{state.JobManageEnviron})
c.Assert(m.Series(), gc.Equals, version.Current.Series)
c.Assert(m.CheckProvisioned(agent.BootstrapNonce), jc.IsTrue)
c.Assert(m.Addresses(), gc.DeepEquals, mcfg.Addresses)
Expand Down Expand Up @@ -210,7 +210,7 @@ func (s *bootstrapSuite) TestInitializeStateFailsSecondTime(c *gc.C) {
expectHW := instance.MustParseHardware("mem=2048M")
mcfg := agent.BootstrapMachineConfig{
Constraints: expectConstraints,
Jobs: []params.MachineJob{params.JobHostUnits},
Jobs: []params.MachineJob{params.JobManageEnviron},
InstanceId: "i-bootstrap",
Characteristics: expectHW,
}
Expand Down
1 change: 0 additions & 1 deletion cmd/jujud/agent.go
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,6 @@ type AgentState interface {
// currently running.
SetAgentVersion(v version.Binary) error
Tag() string
SetMongoPassword(password string) error
Life() state.Life
}

Expand Down
16 changes: 0 additions & 16 deletions mongo/admin.go
Original file line number Diff line number Diff line change
Expand Up @@ -143,19 +143,3 @@ func SetAdminMongoPassword(session *mgo.Session, user, password string) error {
}
return nil
}

// SetMongoPassword sets the mongo password in the specified databases for the given user name.
// Previous passwords are invalidated.
func SetMongoPassword(name, password string, dbs ...*mgo.Database) error {
user := &mgo.User{
Username: name,
Password: password,
Roles: []mgo.Role{mgo.RoleReadWriteAny, mgo.RoleUserAdmin, mgo.RoleClusterAdmin},
}
for _, db := range dbs {
if err := db.UpsertUser(user); err != nil {
return fmt.Errorf("cannot set password in juju db %q for %q: %v", db.Name, name, err)
}
}
return nil
}
28 changes: 5 additions & 23 deletions mongo/admin_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -157,37 +157,19 @@ func (s *adminSuite) TestSetAdminMongoPassword(c *gc.C) {

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

err = mongo.SetAdminMongoPassword(session, "admin", "foo")
err = mongo.SetAdminMongoPassword(session, "auser", "foo")
c.Assert(err, gc.IsNil)
err = admin.Login("admin", "")
err = admin.Login("auser", "")
c.Assert(err, gc.ErrorMatches, "auth fails")
err = admin.Login("admin", "foo")
err = admin.Login("auser", "foo")
c.Assert(err, gc.IsNil)
checkRoles(c, admin, "admin",
checkRoles(c, admin, "auser",
[]interface{}{
string(mgo.RoleReadWriteAny),
string(mgo.RoleDBAdminAny),
string(mgo.RoleUserAdminAny),
string(mgo.RoleClusterAdmin)})
}

func (s *adminSuite) TestSetMongoPassword(c *gc.C) {
dialInfo := s.setUpMongo(c)
session, err := mgo.DialWithInfo(dialInfo)
c.Assert(err, gc.IsNil)
defer session.Close()
db := session.DB("juju")

err = db.Login("foo", "bar")
c.Assert(err, gc.ErrorMatches, "auth fails")

err = mongo.SetMongoPassword("foo", "bar", db)
c.Assert(err, gc.IsNil)
err = db.Login("foo", "bar")
c.Assert(err, gc.IsNil)
checkRoles(c, db, "foo",
[]interface{}{string(mgo.RoleReadWriteAny), string(mgo.RoleUserAdmin), string(mgo.RoleClusterAdmin)})
}
10 changes: 0 additions & 10 deletions state/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -105,16 +105,6 @@ var (
_ Authenticator = (*User)(nil)
)

// MongoPassworder represents an entity that can
// have a mongo password set for it.
type MongoPassworder interface {
SetMongoPassword(password string) error
}

var (
_ MongoPassworder = (*Machine)(nil)
)

// Annotator represents entities capable of handling annotations.
type Annotator interface {
Annotation(key string) (string, error)
Expand Down
6 changes: 5 additions & 1 deletion state/machine.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (

"github.com/juju/juju/constraints"
"github.com/juju/juju/instance"
"github.com/juju/juju/mongo"
"github.com/juju/juju/network"
"github.com/juju/juju/state/api/params"
"github.com/juju/juju/state/presence"
Expand Down Expand Up @@ -332,7 +333,10 @@ func (m *Machine) SetAgentVersion(v version.Binary) (err error) {
// should use to communicate with the state servers. Previous passwords
// are invalidated.
func (m *Machine) SetMongoPassword(password string) error {
return m.st.setMongoPassword(m.Tag().String(), password)
if !m.IsManager() {
return errors.NotSupportedf("setting mongo password for non-manager machine %v", m)
}
return mongo.SetAdminMongoPassword(m.st.db.Session, m.Tag().String(), password)
}

// SetPassword sets the password for the machine's agent.
Expand Down
50 changes: 47 additions & 3 deletions state/machine_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (

"github.com/juju/errors"
"github.com/juju/loggo"
jujutesting "github.com/juju/testing"
jc "github.com/juju/testing/checkers"
"gopkg.in/mgo.v2/bson"
gc "launchpad.net/gocheck"
Expand Down Expand Up @@ -344,9 +345,52 @@ func (s *MachineSuite) TestTag(c *gc.C) {
}

func (s *MachineSuite) TestSetMongoPassword(c *gc.C) {
testSetMongoPassword(c, func(st *state.State) (entity, error) {
return st.Machine(s.machine.Id())
})
info := state.TestingMongoInfo()
st, err := state.Open(info, state.TestingDialOpts(), state.Policy(nil))
c.Assert(err, gc.IsNil)
defer st.Close()
// Turn on fully-authenticated mode.
err = st.SetAdminMongoPassword(jujutesting.DefaultMongoPassword)
c.Assert(err, gc.IsNil)

// Set the password for the machine.
m, err := st.Machine("0")
c.Assert(err, gc.IsNil)
err = m.SetMongoPassword("foo")
c.Assert(err, gc.IsNil)

// Check that we cannot log in with the wrong password.
info.Tag = m.Tag()
info.Password = "bar"
err = tryOpenState(info)
c.Assert(err, jc.Satisfies, errors.IsUnauthorized)

// Check that we can log in with the correct password.
info.Password = "foo"
err = tryOpenState(info)
c.Assert(err, gc.IsNil)

// Change the password with an entity derived from the newly
// opened and authenticated state.
m, err = st.Machine("0")
c.Assert(err, gc.IsNil)
err = m.SetMongoPassword("bar")
c.Assert(err, gc.IsNil)

// Check that we cannot log in with the old password.
info.Password = "foo"
err = tryOpenState(info)
c.Assert(err, jc.Satisfies, errors.IsUnauthorized)

// Check that we can log in with the new password.
info.Password = "bar"
err = tryOpenState(info)
c.Assert(err, gc.IsNil)

// Check that the administrator can still log in.
info.Tag, info.Password = nil, jujutesting.DefaultMongoPassword
err = tryOpenState(info)
c.Assert(err, gc.IsNil)
}

func (s *MachineSuite) TestSetPassword(c *gc.C) {
Expand Down
10 changes: 2 additions & 8 deletions state/open.go
Original file line number Diff line number Diff line change
Expand Up @@ -168,17 +168,9 @@ func isUnauthorized(err error) bool {
}

func newState(session *mgo.Session, mongoInfo *authentication.MongoInfo, policy Policy) (st *State, resultErr error) {
db := session.DB("juju")
pdb := session.DB("presence")
admin := session.DB("admin")
authenticated := false
if mongoInfo.Tag != nil {
if err := db.Login(mongoInfo.Tag.String(), mongoInfo.Password); err != nil {
return nil, maybeUnauthorized(err, fmt.Sprintf("cannot log in to juju database as %q", mongoInfo.Tag))
}
if err := pdb.Login(mongoInfo.Tag.String(), mongoInfo.Password); err != nil {
return nil, maybeUnauthorized(err, fmt.Sprintf("cannot log in to presence database as %q", mongoInfo.Tag))
}
if err := admin.Login(mongoInfo.Tag.String(), mongoInfo.Password); err != nil {
return nil, maybeUnauthorized(err, fmt.Sprintf("cannot log in to admin database as %q", mongoInfo.Tag))
}
Expand All @@ -190,6 +182,8 @@ func newState(session *mgo.Session, mongoInfo *authentication.MongoInfo, policy
authenticated = true
}

db := session.DB("juju")
pdb := session.DB("presence")
st = &State{
mongoInfo: mongoInfo,
policy: policy,
Expand Down
12 changes: 1 addition & 11 deletions state/state.go
Original file line number Diff line number Diff line change
Expand Up @@ -1626,21 +1626,11 @@ func (st *State) StartSync() {
st.pwatcher.Sync()
}

// SetAdminMongoPassword sets the administrative password
// to access the state. If the password is non-empty,
// all subsequent attempts to access the state must
// be authorized; otherwise no authorization is required.
// SetAdminMongoPassword sets the administrative password to access the state.
func (st *State) SetAdminMongoPassword(password string) error {
return mongo.SetAdminMongoPassword(st.db.Session, AdminUser, password)
}

func (st *State) setMongoPassword(name, password string) error {
return mongo.SetMongoPassword(name, password,
st.db,
st.db.Session.DB("presence"),
st.db.Session.DB("admin"))
}

type stateServersDoc struct {
Id string `bson:"_id"`
MachineIds []string
Expand Down
61 changes: 0 additions & 61 deletions state/state_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2247,67 +2247,6 @@ func testSetAgentCompatPassword(c *gc.C, entity state.Authenticator) {
c.Assert(entity.PasswordValid("short"), jc.IsTrue)
}

type entity interface {
state.Entity
state.Lifer
state.Authenticator
state.MongoPassworder
}

func testSetMongoPassword(c *gc.C, getEntity func(st *state.State) (entity, error)) {
info := state.TestingMongoInfo()
st, err := state.Open(info, state.TestingDialOpts(), state.Policy(nil))
c.Assert(err, gc.IsNil)
defer st.Close()
// Turn on fully-authenticated mode.
err = st.SetAdminMongoPassword("admin-secret")
c.Assert(err, gc.IsNil)

// Set the password for the entity
ent, err := getEntity(st)
c.Assert(err, gc.IsNil)
err = ent.SetMongoPassword("foo")
c.Assert(err, gc.IsNil)

// Check that we cannot log in with the wrong password.
info.Tag = ent.Tag()
info.Password = "bar"
err = tryOpenState(info)
c.Assert(err, jc.Satisfies, errors.IsUnauthorized)

// Check that we can log in with the correct password.
info.Password = "foo"
st1, err := state.Open(info, state.TestingDialOpts(), state.Policy(nil))
c.Assert(err, gc.IsNil)
defer st1.Close()

// Change the password with an entity derived from the newly
// opened and authenticated state.
ent, err = getEntity(st)
c.Assert(err, gc.IsNil)
err = ent.SetMongoPassword("bar")
c.Assert(err, gc.IsNil)

// Check that we cannot log in with the old password.
info.Password = "foo"
err = tryOpenState(info)
c.Assert(err, jc.Satisfies, errors.IsUnauthorized)

// Check that we can log in with the correct password.
info.Password = "bar"
err = tryOpenState(info)
c.Assert(err, gc.IsNil)

// Check that the administrator can still log in.
info.Tag, info.Password = nil, "admin-secret"
err = tryOpenState(info)
c.Assert(err, gc.IsNil)

// Remove the admin password so that the test harness can reset the state.
err = st.SetAdminMongoPassword("")
c.Assert(err, gc.IsNil)
}

func (s *StateSuite) TestSetAdminMongoPassword(c *gc.C) {
// Check that we can SetAdminMongoPassword to nothing when there's
// no password currently set.
Expand Down

0 comments on commit 3ea8fce

Please sign in to comment.