// PasswordValid returns whether the given password // is valid for the user. func (u *User) PasswordValid(password string) bool { // If the user is deactivated, no point in carrying on if u.IsDeactivated() { return false } // Since these are potentially set by a User, we intentionally use the // slower pbkdf2 style hashing. Also, we don't expect to have thousands // of Users trying to log in at the same time (which we *do* expect of // Unit and Machine agents.) if u.doc.PasswordSalt != "" { return utils.UserPasswordHash(password, u.doc.PasswordSalt) == u.doc.PasswordHash } // In Juju 1.16 and older, we did not set a Salt for the user password, // so check if the password hash matches using CompatSalt. if it // does, then set the password again so that we get a proper salt if utils.UserPasswordHash(password, utils.CompatSalt) == u.doc.PasswordHash { // This will set a new Salt for the password. We ignore if it // fails because we will try again at the next request logger.Debugf("User %s logged in with CompatSalt resetting password for new salt", u.Name()) err := u.SetPassword(password) if err != nil { logger.Errorf("Cannot set resalted password for user %q", u.Name()) } return true } return false }
func (s *UserSuite) TestPasswordValidUpdatesSalt(c *gc.C) { u, err := s.State.AddUser("someuser", "password") c.Assert(err, gc.IsNil) compatHash := utils.UserPasswordHash("foo", utils.CompatSalt) err = u.SetPasswordHash(compatHash, "") c.Assert(err, gc.IsNil) beforeSalt, beforeHash := state.GetUserPasswordSaltAndHash(u) c.Assert(beforeSalt, gc.Equals, "") c.Assert(beforeHash, gc.Equals, compatHash) c.Assert(u.PasswordValid("bar"), jc.IsFalse) // A bad password doesn't trigger a rewrite afterBadSalt, afterBadHash := state.GetUserPasswordSaltAndHash(u) c.Assert(afterBadSalt, gc.Equals, "") c.Assert(afterBadHash, gc.Equals, compatHash) // When we get a valid check, we then add a salt and rewrite the hash c.Assert(u.PasswordValid("foo"), jc.IsTrue) afterSalt, afterHash := state.GetUserPasswordSaltAndHash(u) c.Assert(afterSalt, gc.Not(gc.Equals), "") c.Assert(afterHash, gc.Not(gc.Equals), compatHash) c.Assert(afterHash, gc.Equals, utils.UserPasswordHash("foo", afterSalt)) // running PasswordValid again doesn't trigger another rewrite c.Assert(u.PasswordValid("foo"), jc.IsTrue) lastSalt, lastHash := state.GetUserPasswordSaltAndHash(u) c.Assert(lastSalt, gc.Equals, afterSalt) c.Assert(lastHash, gc.Equals, afterHash) }
func (s *UserSuite) TestSetPasswordHashWithSalt(c *gc.C) { u, err := s.State.AddUser("someuser", "password") c.Assert(err, gc.IsNil) err = u.SetPasswordHash(utils.UserPasswordHash("foo", "salted"), "salted") c.Assert(err, gc.IsNil) c.Assert(u.PasswordValid("foo"), jc.IsTrue) salt, hash := state.GetUserPasswordSaltAndHash(u) c.Assert(salt, gc.Equals, "salted") c.Assert(hash, gc.Not(gc.Equals), utils.UserPasswordHash("foo", utils.CompatSalt)) }
// resetAdminPasswordAndFetchDBNames logs into the database with a // plausible password and returns all the database's db names. We need // to try several passwords because we don't know what state the mongo // server is in when Reset is called. If the test has set a custom // password, we're out of luck, but if they are using // DefaultStatePassword, we can succeed. func resetAdminPasswordAndFetchDBNames(session *mgo.Session) ([]string, bool) { // First try with no password dbnames, err := session.DatabaseNames() if err == nil { return dbnames, true } if !isUnauthorized(err) { panic(err) } // Then try the two most likely passwords in turn. for _, password := range []string{ DefaultMongoPassword, utils.UserPasswordHash(DefaultMongoPassword, utils.CompatSalt), } { admin := session.DB("admin") if err := admin.Login("admin", password); err != nil { logger.Infof("failed to log in with password %q", password) continue } dbnames, err := session.DatabaseNames() if err == nil { if err := admin.RemoveUser("admin"); err != nil { panic(err) } return dbnames, true } if !isUnauthorized(err) { panic(err) } logger.Infof("unauthorized access when getting database names; password %q", password) } return nil, false }
// SetPassword sets the password associated with the user. func (u *User) SetPassword(password string) error { salt, err := utils.RandomSalt() if err != nil { return err } return u.SetPasswordHash(utils.UserPasswordHash(password, salt), salt) }
// AddUser adds a user to the state. func (st *State) AddUser(name, password string) (*User, error) { if !validUser.MatchString(name) { return nil, fmt.Errorf("invalid user name %q", name) } salt, err := utils.RandomSalt() if err != nil { return nil, err } u := &User{ st: st, doc: userDoc{ Name: name, PasswordHash: utils.UserPasswordHash(password, salt), PasswordSalt: salt, }, } ops := []txn.Op{{ C: st.users.Name, Id: name, Assert: txn.DocMissing, Insert: &u.doc, }} err = st.runTransaction(ops) if err == txn.ErrAborted { err = fmt.Errorf("user already exists") } if err != nil { return nil, err } return u, nil }
func (s *UserSuite) TestAddUserSetsSalt(c *gc.C) { u, err := s.State.AddUser("someuser", "a-password") c.Assert(err, gc.IsNil) salt, hash := state.GetUserPasswordSaltAndHash(u) c.Check(hash, gc.Not(gc.Equals), "") c.Check(salt, gc.Not(gc.Equals), "") c.Check(utils.UserPasswordHash("a-password", salt), gc.Equals, hash) c.Check(u.PasswordValid("a-password"), jc.IsTrue) }
func (passwordSuite) TestUserPasswordHash(c *gc.C) { seenHashes := make(map[string]bool) for i, password := range testPasswords { for j, salt := range testSalts { c.Logf("test %d, %d %s %s", i, j, password, salt) hashed := utils.UserPasswordHash(password, salt) c.Logf("hash %q", hashed) c.Assert(len(hashed), gc.Equals, 24) c.Assert(seenHashes[hashed], gc.Equals, false) // check we're not adding base64 padding. c.Assert(hashed, gc.Matches, base64Chars) seenHashes[hashed] = true // check it's deterministic altHashed := utils.UserPasswordHash(password, salt) c.Assert(altHashed, gc.Equals, hashed) } } }
// FinishMachineConfig sets fields on a MachineConfig that can be determined by // inspecting a plain config.Config and the machine constraints at the last // moment before bootstrapping. It assumes that the supplied Config comes from // an environment that has passed through all the validation checks in the // Bootstrap func, and that has set an agent-version (via finding the tools to, // use for bootstrap, or otherwise). // TODO(fwereade) This function is not meant to be "good" in any serious way: // it is better that this functionality be collected in one place here than // that it be spread out across 3 or 4 providers, but this is its only // redeeming feature. func FinishMachineConfig(mcfg *cloudinit.MachineConfig, cfg *config.Config, cons constraints.Value) (err error) { defer errors.Maskf(&err, "cannot complete machine configuration") if err := PopulateMachineConfig( mcfg, cfg.Type(), cfg.AuthorizedKeys(), cfg.SSLHostnameVerification(), cfg.ProxySettings(), cfg.AptProxySettings(), ); err != nil { return err } // The following settings are only appropriate at bootstrap time. At the // moment, the only state server is the bootstrap node, but this // will probably change. if !mcfg.Bootstrap { return nil } if mcfg.APIInfo != nil || mcfg.StateInfo != nil { return fmt.Errorf("machine configuration already has api/state info") } caCert, hasCACert := cfg.CACert() if !hasCACert { return fmt.Errorf("environment configuration has no ca-cert") } password := cfg.AdminSecret() if password == "" { return fmt.Errorf("environment configuration has no admin-secret") } passwordHash := utils.UserPasswordHash(password, utils.CompatSalt) mcfg.APIInfo = &api.Info{Password: passwordHash, CACert: caCert} mcfg.StateInfo = &state.Info{Password: passwordHash, CACert: caCert} // These really are directly relevant to running a state server. cert, key, err := cfg.GenerateStateServerCertAndKey() if err != nil { return errgo.Annotate(err, "cannot generate state server certificate") } srvInfo := params.StateServingInfo{ StatePort: cfg.StatePort(), APIPort: cfg.APIPort(), Cert: string(cert), PrivateKey: string(key), SystemIdentity: mcfg.SystemPrivateSSHKey, } mcfg.StateServingInfo = &srvInfo mcfg.Constraints = cons if mcfg.Config, err = BootstrapConfig(cfg); err != nil { return err } return nil }
// NewConn returns a new Conn that uses the // given environment. The environment must have already // been bootstrapped. func NewConn(environ environs.Environ) (*Conn, error) { info, _, err := environ.StateInfo() if err != nil { return nil, err } password := environ.Config().AdminSecret() if password == "" { return nil, fmt.Errorf("cannot connect without admin-secret") } err = environs.CheckEnvironment(environ) if err != nil { return nil, err } info.Password = password opts := state.DefaultDialOpts() st, err := state.Open(info, opts, environs.NewStatePolicy()) if errors.IsUnauthorized(err) { logger.Infof("authorization error while connecting to state server; retrying") // We can't connect with the administrator password,; // perhaps this was the first connection and the // password has not been changed yet. info.Password = utils.UserPasswordHash(password, utils.CompatSalt) // We try for a while because we might succeed in // connecting to mongo before the state has been // initialized and the initial password set. for a := redialStrategy.Start(); a.Next(); { st, err = state.Open(info, opts, environs.NewStatePolicy()) if !errors.IsUnauthorized(err) { break } } if err != nil { return nil, err } if err := st.SetAdminMongoPassword(password); err != nil { return nil, err } } else if err != nil { return nil, err } conn := &Conn{ Environ: environ, State: st, } if err := conn.updateSecrets(); err != nil { conn.Close() return nil, fmt.Errorf("unable to push secrets: %v", err) } return conn, nil }
func (s *bootstrapSuite) TestInitializeStateFailsSecondTime(c *gc.C) { dataDir := c.MkDir() pwHash := utils.UserPasswordHash(testing.DefaultMongoPassword, utils.CompatSalt) configParams := agent.AgentConfigParams{ DataDir: dataDir, Tag: "machine-0", UpgradedToVersion: version.Current.Number, StateAddresses: []string{testing.MgoServer.Addr()}, CACert: testing.CACert, Password: pwHash, } cfg, err := agent.NewAgentConfig(configParams) c.Assert(err, gc.IsNil) cfg.SetStateServingInfo(params.StateServingInfo{ APIPort: 5555, StatePort: testing.MgoServer.Port(), Cert: "foo", PrivateKey: "bar", SharedSecret: "baz", SystemIdentity: "qux", }) expectConstraints := constraints.MustParse("mem=1024M") expectHW := instance.MustParseHardware("mem=2048M") mcfg := agent.BootstrapMachineConfig{ Constraints: expectConstraints, Jobs: []params.MachineJob{params.JobHostUnits}, InstanceId: "i-bootstrap", Characteristics: expectHW, } envAttrs := dummy.SampleConfig().Delete("admin-secret").Merge(testing.Attrs{ "agent-version": version.Current.Number.String(), "state-id": "1", // needed so policy can Open config }) envCfg, err := config.New(config.NoDefaults, envAttrs) c.Assert(err, gc.IsNil) st, _, err := agent.InitializeState(cfg, envCfg, mcfg, state.DialOpts{}, environs.NewStatePolicy()) c.Assert(err, gc.IsNil) err = st.SetAdminMongoPassword("") c.Check(err, gc.IsNil) st.Close() st, _, err = agent.InitializeState(cfg, envCfg, mcfg, state.DialOpts{}, environs.NewStatePolicy()) if err == nil { st.Close() } c.Assert(err, gc.ErrorMatches, "failed to initialize state: cannot create log collection: unauthorized mongo access: unauthorized") }
func (s *UserSuite) TestSetPasswordHash(c *gc.C) { u, err := s.State.AddUser("someuser", "password") c.Assert(err, gc.IsNil) err = u.SetPasswordHash(utils.UserPasswordHash("foo", utils.CompatSalt), utils.CompatSalt) c.Assert(err, gc.IsNil) c.Assert(u.PasswordValid("foo"), jc.IsTrue) c.Assert(u.PasswordValid("bar"), jc.IsFalse) // User passwords should *not* use the fast PasswordHash function hash := utils.AgentPasswordHash("foo-12345678901234567890") c.Assert(err, gc.IsNil) err = u.SetPasswordHash(hash, "") c.Assert(err, gc.IsNil) c.Assert(u.PasswordValid("foo-12345678901234567890"), jc.IsFalse) }
// PasswordValid returns whether the given password is valid // for the given machine. func (m *Machine) PasswordValid(password string) bool { agentHash := utils.AgentPasswordHash(password) if agentHash == m.doc.PasswordHash { return true } // In Juju 1.16 and older we used the slower password hash for unit // agents. So check to see if the supplied password matches the old // path, and if so, update it to the new mechanism. // We ignore any error in setting the password, as we'll just try again // next time if utils.UserPasswordHash(password, utils.CompatSalt) == m.doc.PasswordHash { logger.Debugf("%s logged in with old password hash, changing to AgentPasswordHash", m.Tag()) m.setPasswordHash(agentHash) return true } return false }
func (s *CloudInitSuite) TestFinishBootstrapConfig(c *gc.C) { attrs := dummySampleConfig().Merge(testing.Attrs{ "authorized-keys": "we-are-the-keys", "admin-secret": "lisboan-pork", "agent-version": "1.2.3", "state-server": false, }) cfg, err := config.New(config.NoDefaults, attrs) c.Assert(err, gc.IsNil) oldAttrs := cfg.AllAttrs() mcfg := &cloudinit.MachineConfig{ Bootstrap: true, } cons := constraints.MustParse("mem=1T cpu-power=999999999") err = environs.FinishMachineConfig(mcfg, cfg, cons) c.Assert(err, gc.IsNil) c.Check(mcfg.AuthorizedKeys, gc.Equals, "we-are-the-keys") c.Check(mcfg.DisableSSLHostnameVerification, jc.IsFalse) password := utils.UserPasswordHash("lisboan-pork", utils.CompatSalt) c.Check(mcfg.APIInfo, gc.DeepEquals, &api.Info{ Password: password, CACert: testing.CACert, }) c.Check(mcfg.StateInfo, gc.DeepEquals, &state.Info{ Password: password, CACert: testing.CACert, }) c.Check(mcfg.StateServingInfo.StatePort, gc.Equals, cfg.StatePort()) c.Check(mcfg.StateServingInfo.APIPort, gc.Equals, cfg.APIPort()) c.Check(mcfg.Constraints, gc.DeepEquals, cons) oldAttrs["ca-private-key"] = "" oldAttrs["admin-secret"] = "" c.Check(mcfg.Config.AllAttrs(), gc.DeepEquals, oldAttrs) srvCertPEM := mcfg.StateServingInfo.Cert srvKeyPEM := mcfg.StateServingInfo.PrivateKey _, _, err = cert.ParseCertAndKey(srvCertPEM, srvKeyPEM) c.Check(err, gc.IsNil) err = cert.Verify(srvCertPEM, testing.CACert, time.Now()) c.Assert(err, gc.IsNil) err = cert.Verify(srvCertPEM, testing.CACert, time.Now().AddDate(9, 0, 0)) c.Assert(err, gc.IsNil) err = cert.Verify(srvCertPEM, testing.CACert, time.Now().AddDate(10, 0, 1)) c.Assert(err, gc.NotNil) }
func (*NewConnSuite) TestConnStateSecretsSideEffect(c *gc.C) { attrs := dummy.SampleConfig().Merge(coretesting.Attrs{ "admin-secret": "side-effect secret", "secret": "pork", }) cfg, err := config.New(config.NoDefaults, attrs) c.Assert(err, gc.IsNil) ctx := coretesting.Context(c) env, err := environs.Prepare(cfg, ctx, configstore.NewMem()) c.Assert(err, gc.IsNil) envtesting.UploadFakeTools(c, env.Storage()) err = bootstrap.Bootstrap(ctx, env, environs.BootstrapParams{}) c.Assert(err, gc.IsNil) info, _, err := env.StateInfo() c.Assert(err, gc.IsNil) info.Password = utils.UserPasswordHash("side-effect secret", utils.CompatSalt) // Use a state without a nil policy, which will allow us to set an invalid config. st, err := state.Open(info, state.DefaultDialOpts(), state.Policy(nil)) c.Assert(err, gc.IsNil) defer assertClose(c, st) // Verify we have secrets in the environ config already. statecfg, err := st.EnvironConfig() c.Assert(err, gc.IsNil) c.Assert(statecfg.UnknownAttrs()["secret"], gc.Equals, "pork") // Remove the secret from state, and then make sure it gets // pushed back again. err = st.UpdateEnvironConfig(map[string]interface{}{}, []string{"secret"}, nil) c.Assert(err, gc.IsNil) // Make a new Conn, which will push the secrets. conn, err := juju.NewConn(env) c.Assert(err, gc.IsNil) defer assertClose(c, conn) statecfg, err = conn.State.EnvironConfig() c.Assert(err, gc.IsNil) c.Assert(statecfg.UnknownAttrs()["secret"], gc.Equals, "pork") // Reset the admin password so the state db can be reused. err = conn.State.SetAdminMongoPassword("") c.Assert(err, gc.IsNil) }
func (*NewConnSuite) TestConnWithPassword(c *gc.C) { attrs := dummy.SampleConfig().Merge(coretesting.Attrs{ "admin-secret": "nutkin", }) cfg, err := config.New(config.NoDefaults, attrs) c.Assert(err, gc.IsNil) ctx := coretesting.Context(c) env, err := environs.Prepare(cfg, ctx, configstore.NewMem()) c.Assert(err, gc.IsNil) envtesting.UploadFakeTools(c, env.Storage()) err = bootstrap.Bootstrap(ctx, env, environs.BootstrapParams{}) c.Assert(err, gc.IsNil) // Check that Bootstrap has correctly used a hash // of the admin password. info, _, err := env.StateInfo() c.Assert(err, gc.IsNil) info.Password = utils.UserPasswordHash("nutkin", utils.CompatSalt) st, err := state.Open(info, state.DefaultDialOpts(), environs.NewStatePolicy()) c.Assert(err, gc.IsNil) assertClose(c, st) // Check that we can connect with the original environment. conn, err := juju.NewConn(env) c.Assert(err, gc.IsNil) assertClose(c, conn) // Check that the password has now been changed to the original // admin password. info.Password = "******" st1, err := state.Open(info, state.DefaultDialOpts(), environs.NewStatePolicy()) c.Assert(err, gc.IsNil) assertClose(c, st1) // Check that we can still connect with the original // environment. conn, err = juju.NewConn(env) c.Assert(err, gc.IsNil) defer assertClose(c, conn) // Reset the admin password so the state db can be reused. err = conn.State.SetAdminMongoPassword("") c.Assert(err, gc.IsNil) }
func (e *environ) Bootstrap(ctx environs.BootstrapContext, args environs.BootstrapParams) error { selectedTools, err := common.EnsureBootstrapTools(ctx, e, config.PreferredSeries(e.Config()), args.Constraints.Arch) if err != nil { return err } defer delay() if err := e.checkBroken("Bootstrap"); err != nil { return err } password := e.Config().AdminSecret() if password == "" { return fmt.Errorf("admin-secret is required for bootstrap") } if _, ok := e.Config().CACert(); !ok { return fmt.Errorf("no CA certificate in environment configuration") } logger.Infof("would pick tools from %s", selectedTools) cfg, err := environs.BootstrapConfig(e.Config()) if err != nil { return fmt.Errorf("cannot make bootstrap config: %v", err) } estate, err := e.state() if err != nil { return err } estate.mu.Lock() defer estate.mu.Unlock() if estate.bootstrapped { return fmt.Errorf("environment is already bootstrapped") } // Write the bootstrap file just like a normal provider. However // we need to release the mutex for the save state to work, so regain // it after the call. estate.mu.Unlock() if err := bootstrap.SaveState(e.Storage(), &bootstrap.BootstrapState{StateInstances: []instance.Id{"localhost"}}); err != nil { logger.Errorf("failed to save state instances: %v", err) estate.mu.Lock() // otherwise defered unlock will fail return err } estate.mu.Lock() // back at it if e.ecfg().stateServer() { // TODO(rog) factor out relevant code from cmd/jujud/bootstrap.go // so that we can call it here. info := stateInfo() st, err := state.Initialize(info, cfg, state.DefaultDialOpts(), estate.statePolicy) if err != nil { panic(err) } if err := st.SetEnvironConstraints(args.Constraints); err != nil { panic(err) } if err := st.SetAdminMongoPassword(utils.UserPasswordHash(password, utils.CompatSalt)); err != nil { panic(err) } _, err = st.AddUser("admin", password) if err != nil { panic(err) } estate.apiServer, err = apiserver.NewServer(st, "localhost:0", []byte(testing.ServerCert), []byte(testing.ServerKey), DataDir, LogDir) if err != nil { panic(err) } estate.apiState = st } estate.bootstrapped = true estate.ops <- OpBootstrap{Context: ctx, Env: e.name, Args: args} return nil }
func (s *bootstrapSuite) TestInitializeState(c *gc.C) { dataDir := c.MkDir() pwHash := utils.UserPasswordHash(testing.DefaultMongoPassword, utils.CompatSalt) configParams := agent.AgentConfigParams{ DataDir: dataDir, Tag: "machine-0", UpgradedToVersion: version.Current.Number, StateAddresses: []string{testing.MgoServer.Addr()}, CACert: testing.CACert, Password: pwHash, } servingInfo := params.StateServingInfo{ Cert: testing.ServerCert, PrivateKey: testing.ServerKey, APIPort: 1234, StatePort: testing.MgoServer.Port(), SystemIdentity: "def456", } cfg, err := agent.NewStateMachineConfig(configParams, servingInfo) c.Assert(err, gc.IsNil) _, available := cfg.StateServingInfo() c.Assert(available, gc.Equals, true) expectConstraints := constraints.MustParse("mem=1024M") expectHW := instance.MustParseHardware("mem=2048M") mcfg := agent.BootstrapMachineConfig{ Addresses: instance.NewAddresses("0.1.2.3", "zeroonetwothree"), Constraints: expectConstraints, Jobs: []params.MachineJob{params.JobHostUnits}, InstanceId: "i-bootstrap", Characteristics: expectHW, SharedSecret: "abc123", } envAttrs := dummy.SampleConfig().Delete("admin-secret").Merge(testing.Attrs{ "agent-version": version.Current.Number.String(), "state-id": "1", // needed so policy can Open config }) envCfg, err := config.New(config.NoDefaults, envAttrs) c.Assert(err, gc.IsNil) st, m, err := agent.InitializeState(cfg, envCfg, mcfg, state.DialOpts{}, environs.NewStatePolicy()) c.Assert(err, gc.IsNil) defer st.Close() err = cfg.Write() c.Assert(err, gc.IsNil) // Check that initial admin user has been set up correctly. s.assertCanLogInAsAdmin(c, pwHash) user, err := st.User("admin") c.Assert(err, gc.IsNil) c.Assert(user.PasswordValid(testing.DefaultMongoPassword), jc.IsTrue) // Check that environment configuration has been added. newEnvCfg, err := st.EnvironConfig() c.Assert(err, gc.IsNil) c.Assert(newEnvCfg.AllAttrs(), gc.DeepEquals, envCfg.AllAttrs()) // 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.Series(), gc.Equals, version.Current.Series) c.Assert(m.CheckProvisioned(state.BootstrapNonce), jc.IsTrue) c.Assert(m.Addresses(), gc.DeepEquals, mcfg.Addresses) gotConstraints, err := m.Constraints() c.Assert(err, gc.IsNil) c.Assert(gotConstraints, gc.DeepEquals, expectConstraints) c.Assert(err, gc.IsNil) gotHW, err := m.HardwareCharacteristics() c.Assert(err, gc.IsNil) c.Assert(*gotHW, gc.DeepEquals, expectHW) gotAddrs := m.Addresses() c.Assert(gotAddrs, gc.DeepEquals, mcfg.Addresses) // Check that the API host ports are initialised correctly. apiHostPorts, err := st.APIHostPorts() c.Assert(err, gc.IsNil) c.Assert(apiHostPorts, gc.DeepEquals, [][]instance.HostPort{ instance.AddressesWithPort(mcfg.Addresses, 1234), }) // Check that the state serving info is initialised correctly. stateServingInfo, err := st.StateServingInfo() c.Assert(err, gc.IsNil) c.Assert(stateServingInfo, jc.DeepEquals, params.StateServingInfo{ APIPort: 1234, StatePort: testing.MgoServer.Port(), Cert: testing.ServerCert, PrivateKey: testing.ServerKey, SharedSecret: "abc123", SystemIdentity: "def456", }) // Check that the machine agent's config has been written // and that we can use it to connect to the state. newCfg, err := agent.ReadConfig(agent.ConfigPath(dataDir, "machine-0")) c.Assert(err, gc.IsNil) c.Assert(newCfg.Tag(), gc.Equals, "machine-0") c.Assert(agent.Password(newCfg), gc.Not(gc.Equals), pwHash) c.Assert(agent.Password(newCfg), gc.Not(gc.Equals), testing.DefaultMongoPassword) info, ok := cfg.StateInfo() c.Assert(ok, jc.IsTrue) st1, err := state.Open(info, state.DialOpts{}, environs.NewStatePolicy()) c.Assert(err, gc.IsNil) defer st1.Close() }
func testPasswordHash() string { return utils.UserPasswordHash(testPassword, utils.CompatSalt) }