// 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) } u := &User{ st: st, doc: userDoc{ Name: name, PasswordHash: utils.PasswordHash(password), }, } 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 (utilsSuite) TestPasswordHash(c *C) { tests := []string{"", "a", "a longer password than i would usually bother with"} hs := make(map[string]bool) for i, t := range tests { c.Logf("test %d", i) h := utils.PasswordHash(t) c.Logf("hash %q", h) c.Assert(len(h), Equals, 24) c.Assert(hs[h], Equals, false) // check we're not adding base64 padding. c.Assert(h[len(h)-1], Not(Equals), '=') hs[h] = true // check it's deterministic h1 := utils.PasswordHash(t) c.Assert(h1, Equals, h) } }
func (e *environ) Bootstrap(cons constraints.Value) error { 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") } possibleTools, err := environs.FindBootstrapTools(e, cons) if err != nil { return err } log.Infof("environs/dummy: would pick tools from %s", possibleTools) cfg, err := environs.BootstrapConfig(e.Config()) if err != nil { return fmt.Errorf("cannot make bootstrap config: %v", err) } e.state.mu.Lock() defer e.state.mu.Unlock() if e.state.bootstrapped { return fmt.Errorf("environment is already bootstrapped") } 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()) if err != nil { panic(err) } if err := st.SetEnvironConstraints(cons); err != nil { panic(err) } if err := st.SetAdminMongoPassword(utils.PasswordHash(password)); err != nil { panic(err) } _, err = st.AddUser("admin", password) if err != nil { panic(err) } e.state.apiServer, err = apiserver.NewServer(st, "localhost:0", []byte(testing.ServerCert), []byte(testing.ServerKey)) if err != nil { panic(err) } e.state.apiState = st } e.state.bootstrapped = true e.state.ops <- OpBootstrap{Env: e.state.name, Constraints: cons} return nil }
// invalidateEnvironment alters the environment configuration // so the Settings returned from the watcher will not pass // validation. func (s *ProvisionerSuite) invalidateEnvironment(c *C) error { admindb := s.Session.DB("admin") err := admindb.Login("admin", testing.AdminSecret) if err != nil { err = admindb.Login("admin", utils.PasswordHash(testing.AdminSecret)) } c.Assert(err, IsNil) settings := s.Session.DB("juju").C("settings") return settings.UpdateId("e", bson.D{{"$unset", bson.D{{"type", 1}}}}) }
func (s *UserSuite) TestSetPasswordHash(c *C) { u, err := s.State.AddUser("someuser", "") c.Assert(err, IsNil) err = u.SetPasswordHash(utils.PasswordHash("foo")) c.Assert(err, IsNil) c.Assert(u.PasswordValid("foo"), Equals, true) c.Assert(u.PasswordValid("bar"), Equals, false) }
// 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) if errors.IsUnauthorizedError(err) { log.Noticef("juju: 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.PasswordHash(password) // 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) if !errors.IsUnauthorizedError(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 }
// 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 FindBootstrapTools, // 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 utils.ErrorContextf(&err, "cannot complete machine configuration") // Everything needs the environment's authorized keys. authKeys := cfg.AuthorizedKeys() if authKeys == "" { return fmt.Errorf("environment configuration has no authorized-keys") } mcfg.AuthorizedKeys = authKeys if mcfg.MachineEnvironment == nil { mcfg.MachineEnvironment = make(map[string]string) } mcfg.MachineEnvironment[osenv.JujuProviderType] = cfg.Type() if !mcfg.StateServer { return nil } // These 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.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.PasswordHash(password) mcfg.APIInfo = &api.Info{Password: passwordHash, CACert: caCert} mcfg.StateInfo = &state.Info{Password: passwordHash, CACert: caCert} mcfg.StatePort = cfg.StatePort() mcfg.APIPort = cfg.APIPort() mcfg.Constraints = cons if mcfg.Config, err = BootstrapConfig(cfg); err != nil { return err } // These really are directly relevant to running a state server. cert, key, err := cfg.GenerateStateServerCertAndKey() if err != nil { return fmt.Errorf("cannot generate state server certificate: %v", err) } mcfg.StateServerCert = cert mcfg.StateServerKey = key return nil }
// SetPassword sets the password for the machine's agent. func (m *Machine) SetPassword(password string) error { hp := utils.PasswordHash(password) ops := []txn.Op{{ C: m.st.machines.Name, Id: m.doc.Id, Assert: notDeadDoc, Update: D{{"$set", D{{"passwordhash", hp}}}}, }} if err := m.st.runTransaction(ops); err != nil { return fmt.Errorf("cannot set password of machine %v: %v", m, onAbort(err, errDead)) } m.doc.PasswordHash = hp return nil }
// SetPassword sets the password for the machine's agent. func (u *Unit) SetPassword(password string) error { hp := utils.PasswordHash(password) ops := []txn.Op{{ C: u.st.units.Name, Id: u.doc.Name, Assert: notDeadDoc, Update: D{{"$set", D{{"passwordhash", hp}}}}, }} err := u.st.runTransaction(ops) if err != nil { return fmt.Errorf("cannot set password of unit %q: %v", u, onAbort(err, errDead)) } u.doc.PasswordHash = hp return nil }
func (s *CloudInitSuite) TestFinishBootstrapConfig(c *C) { cfg, err := config.New(map[string]interface{}{ "name": "barbara", "type": "dummy", "admin-secret": "lisboan-pork", "authorized-keys": "we-are-the-keys", "agent-version": "1.2.3", "ca-cert": testing.CACert, "ca-private-key": testing.CAKey, "state-server": false, "secret": "british-horse", }) c.Assert(err, IsNil) oldAttrs := cfg.AllAttrs() mcfg := &cloudinit.MachineConfig{ StateServer: true, } cons := constraints.MustParse("mem=1T cpu-power=999999999") err = environs.FinishMachineConfig(mcfg, cfg, cons) c.Check(err, IsNil) c.Check(mcfg.AuthorizedKeys, Equals, "we-are-the-keys") password := utils.PasswordHash("lisboan-pork") c.Check(mcfg.APIInfo, DeepEquals, &api.Info{ Password: password, CACert: []byte(testing.CACert), }) c.Check(mcfg.StateInfo, DeepEquals, &state.Info{ Password: password, CACert: []byte(testing.CACert), }) c.Check(mcfg.StatePort, Equals, cfg.StatePort()) c.Check(mcfg.APIPort, Equals, cfg.APIPort()) c.Check(mcfg.Constraints, DeepEquals, cons) oldAttrs["ca-private-key"] = "" oldAttrs["admin-secret"] = "" delete(oldAttrs, "secret") c.Check(mcfg.Config.AllAttrs(), DeepEquals, oldAttrs) srvCertPEM := mcfg.StateServerCert srvKeyPEM := mcfg.StateServerKey _, _, err = cert.ParseCertAndKey(srvCertPEM, srvKeyPEM) c.Check(err, IsNil) err = cert.Verify(srvCertPEM, []byte(testing.CACert), time.Now()) c.Assert(err, IsNil) err = cert.Verify(srvCertPEM, []byte(testing.CACert), time.Now().AddDate(9, 0, 0)) c.Assert(err, IsNil) err = cert.Verify(srvCertPEM, []byte(testing.CACert), time.Now().AddDate(10, 0, 1)) c.Assert(err, NotNil) }
func (cs *NewConnSuite) TestConnWithPassword(c *C) { env, err := environs.NewFromAttrs(map[string]interface{}{ "name": "erewhemos", "type": "dummy", "state-server": true, "authorized-keys": "i-am-a-key", "secret": "squirrel", "admin-secret": "nutkin", "ca-cert": coretesting.CACert, "ca-private-key": coretesting.CAKey, }) c.Assert(err, IsNil) err = environs.Bootstrap(env, constraints.Value{}) c.Assert(err, IsNil) // Check that Bootstrap has correctly used a hash // of the admin password. info, _, err := env.StateInfo() c.Assert(err, IsNil) info.Password = utils.PasswordHash("nutkin") st, err := state.Open(info, state.DefaultDialOpts()) c.Assert(err, IsNil) st.Close() // Check that we can connect with the original environment. conn, err := juju.NewConn(env) c.Assert(err, IsNil) conn.Close() // Check that the password has now been changed to the original // admin password. info.Password = "******" st1, err := state.Open(info, state.DefaultDialOpts()) c.Assert(err, IsNil) st1.Close() // Check that we can still connect with the original // environment. conn, err = juju.NewConn(env) c.Assert(err, IsNil) defer conn.Close() // Reset the admin password so the state db can be reused. err = conn.State.SetAdminMongoPassword("") c.Assert(err, IsNil) }
func (cs *NewConnSuite) TestConnStateSecretsSideEffect(c *C) { attrs := map[string]interface{}{ "name": "erewhemos", "type": "dummy", "state-server": true, "authorized-keys": "i-am-a-key", "secret": "pork", "admin-secret": "side-effect secret", "ca-cert": coretesting.CACert, "ca-private-key": coretesting.CAKey, } env, err := environs.NewFromAttrs(attrs) c.Assert(err, IsNil) err = environs.Bootstrap(env, constraints.Value{}) c.Assert(err, IsNil) info, _, err := env.StateInfo() c.Assert(err, IsNil) info.Password = utils.PasswordHash("side-effect secret") st, err := state.Open(info, state.DefaultDialOpts()) c.Assert(err, IsNil) // Verify we have no secret in the environ config cfg, err := st.EnvironConfig() c.Assert(err, IsNil) c.Assert(cfg.UnknownAttrs()["secret"], IsNil) // Make a new Conn, which will push the secrets. conn, err := juju.NewConn(env) c.Assert(err, IsNil) defer conn.Close() cfg, err = conn.State.EnvironConfig() c.Assert(err, IsNil) c.Assert(cfg.UnknownAttrs()["secret"], Equals, "pork") // Reset the admin password so the state db can be reused. err = conn.State.SetAdminMongoPassword("") c.Assert(err, IsNil) }
func (env *localEnviron) initialStateConfiguration(addr string, cons constraints.Value) (*state.State, error) { // We don't check the existance of the CACert here as if it wasn't set, we // wouldn't get this far. cfg := env.config.Config caCert, _ := cfg.CACert() addr = fmt.Sprintf("%s:%d", addr, cfg.StatePort()) info := &state.Info{ Addrs: []string{addr}, CACert: caCert, } timeout := state.DialOpts{60 * time.Second} bootstrap, err := environs.BootstrapConfig(cfg) if err != nil { return nil, err } st, err := state.Initialize(info, bootstrap, timeout) if err != nil { logger.Errorf("failed to initialize state: %v", err) return nil, err } logger.Debugf("state initialized") passwordHash := utils.PasswordHash(cfg.AdminSecret()) if err := environs.BootstrapUsers(st, cfg, passwordHash); err != nil { st.Close() return nil, err } jobs := []state.MachineJob{state.JobManageEnviron, state.JobManageState} if err := environs.ConfigureBootstrapMachine( st, cons, env.config.rootDir(), jobs, instance.Id(boostrapInstanceId), instance.HardwareCharacteristics{}); err != nil { st.Close() return nil, err } // Return an open state reference. return st, nil }
func testPasswordHash() string { return utils.PasswordHash(testPassword) }
// PasswordValid returns whether the given password is valid // for the given machine. func (m *Machine) PasswordValid(password string) bool { return utils.PasswordHash(password) == m.doc.PasswordHash }
// SetPassword sets the password associated with the user. func (u *User) SetPassword(password string) error { return u.SetPasswordHash(utils.PasswordHash(password)) }
// PasswordValid returns whether the given password is valid // for the given unit. func (u *Unit) PasswordValid(password string) bool { return utils.PasswordHash(password) == u.doc.PasswordHash }