github.com/cloud-green/juju@v0.0.0-20151002100041-a00291338d3d/state/user_test.go (about) 1 // Copyright 2013, 2014 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package state_test 5 6 import ( 7 "regexp" 8 "time" 9 10 "github.com/juju/errors" 11 "github.com/juju/names" 12 jc "github.com/juju/testing/checkers" 13 "github.com/juju/utils" 14 gc "gopkg.in/check.v1" 15 16 "github.com/juju/juju/state" 17 "github.com/juju/juju/testing/factory" 18 ) 19 20 type UserSuite struct { 21 ConnSuite 22 } 23 24 var _ = gc.Suite(&UserSuite{}) 25 26 func (s *UserSuite) TestAddInvalidNames(c *gc.C) { 27 for _, name := range []string{ 28 "", 29 "a", 30 "b^b", 31 "a.", 32 "a-", 33 "user@local", 34 "@ubuntuone", 35 } { 36 c.Logf("check invalid name %q", name) 37 user, err := s.State.AddUser(name, "ignored", "ignored", "ignored") 38 c.Check(err, gc.ErrorMatches, `invalid user name "`+regexp.QuoteMeta(name)+`"`) 39 c.Check(user, gc.IsNil) 40 } 41 } 42 43 func (s *UserSuite) TestAddUser(c *gc.C) { 44 name := "f00-Bar.ram77" 45 displayName := "Display" 46 password := "password" 47 creator := "admin" 48 49 now := time.Now().Round(time.Second).UTC() 50 51 user, err := s.State.AddUser(name, displayName, password, creator) 52 c.Assert(err, jc.ErrorIsNil) 53 c.Assert(user, gc.NotNil) 54 c.Assert(user.Name(), gc.Equals, name) 55 c.Assert(user.DisplayName(), gc.Equals, displayName) 56 c.Assert(user.PasswordValid(password), jc.IsTrue) 57 c.Assert(user.CreatedBy(), gc.Equals, creator) 58 c.Assert(user.DateCreated().After(now) || 59 user.DateCreated().Equal(now), jc.IsTrue) 60 lastLogin, err := user.LastLogin() 61 c.Assert(err, jc.Satisfies, state.IsNeverLoggedInError) 62 c.Assert(lastLogin, gc.DeepEquals, time.Time{}) 63 64 user, err = s.State.User(user.UserTag()) 65 c.Assert(err, jc.ErrorIsNil) 66 c.Assert(user, gc.NotNil) 67 c.Assert(user.Name(), gc.Equals, name) 68 c.Assert(user.DisplayName(), gc.Equals, displayName) 69 c.Assert(user.PasswordValid(password), jc.IsTrue) 70 c.Assert(user.CreatedBy(), gc.Equals, creator) 71 c.Assert(user.DateCreated().After(now) || 72 user.DateCreated().Equal(now), jc.IsTrue) 73 lastLogin, err = user.LastLogin() 74 c.Assert(err, jc.Satisfies, state.IsNeverLoggedInError) 75 c.Assert(lastLogin, gc.DeepEquals, time.Time{}) 76 } 77 78 func (s *UserSuite) TestCheckUserExists(c *gc.C) { 79 user := s.Factory.MakeUser(c, nil) 80 exists, err := state.CheckUserExists(s.State, user.Name()) 81 c.Assert(err, jc.ErrorIsNil) 82 c.Assert(exists, jc.IsTrue) 83 exists, err = state.CheckUserExists(s.State, "notAUser") 84 c.Assert(err, jc.ErrorIsNil) 85 c.Assert(exists, jc.IsFalse) 86 } 87 88 func (s *UserSuite) TestString(c *gc.C) { 89 user := s.Factory.MakeUser(c, &factory.UserParams{Name: "foo"}) 90 c.Assert(user.String(), gc.Equals, "foo@local") 91 } 92 93 func (s *UserSuite) TestUpdateLastLogin(c *gc.C) { 94 now := time.Now().Round(time.Second).UTC() 95 user := s.Factory.MakeUser(c, nil) 96 err := user.UpdateLastLogin() 97 c.Assert(err, jc.ErrorIsNil) 98 lastLogin, err := user.LastLogin() 99 c.Assert(err, jc.ErrorIsNil) 100 c.Assert(lastLogin.After(now) || 101 lastLogin.Equal(now), jc.IsTrue) 102 } 103 104 func (s *UserSuite) TestSetPassword(c *gc.C) { 105 user := s.Factory.MakeUser(c, nil) 106 testSetPassword(c, func() (state.Authenticator, error) { 107 return s.State.User(user.UserTag()) 108 }) 109 } 110 111 func (s *UserSuite) TestAddUserSetsSalt(c *gc.C) { 112 user := s.Factory.MakeUser(c, &factory.UserParams{Password: "a-password"}) 113 salt, hash := state.GetUserPasswordSaltAndHash(user) 114 c.Assert(hash, gc.Not(gc.Equals), "") 115 c.Assert(salt, gc.Not(gc.Equals), "") 116 c.Assert(utils.UserPasswordHash("a-password", salt), gc.Equals, hash) 117 c.Assert(user.PasswordValid("a-password"), jc.IsTrue) 118 } 119 120 func (s *UserSuite) TestSetPasswordChangesSalt(c *gc.C) { 121 user := s.Factory.MakeUser(c, nil) 122 origSalt, origHash := state.GetUserPasswordSaltAndHash(user) 123 c.Assert(origSalt, gc.Not(gc.Equals), "") 124 user.SetPassword("a-password") 125 newSalt, newHash := state.GetUserPasswordSaltAndHash(user) 126 c.Assert(newSalt, gc.Not(gc.Equals), "") 127 c.Assert(newSalt, gc.Not(gc.Equals), origSalt) 128 c.Assert(newHash, gc.Not(gc.Equals), origHash) 129 c.Assert(user.PasswordValid("a-password"), jc.IsTrue) 130 } 131 132 func (s *UserSuite) TestDisable(c *gc.C) { 133 user := s.Factory.MakeUser(c, &factory.UserParams{Password: "a-password"}) 134 c.Assert(user.IsDisabled(), jc.IsFalse) 135 136 err := user.Disable() 137 c.Assert(err, jc.ErrorIsNil) 138 c.Assert(user.IsDisabled(), jc.IsTrue) 139 c.Assert(user.PasswordValid("a-password"), jc.IsFalse) 140 141 err = user.Enable() 142 c.Assert(err, jc.ErrorIsNil) 143 c.Assert(user.IsDisabled(), jc.IsFalse) 144 c.Assert(user.PasswordValid("a-password"), jc.IsTrue) 145 } 146 147 func (s *UserSuite) TestSetPasswordHash(c *gc.C) { 148 user := s.Factory.MakeUser(c, nil) 149 150 err := user.SetPasswordHash(utils.UserPasswordHash("foo", utils.CompatSalt), utils.CompatSalt) 151 c.Assert(err, jc.ErrorIsNil) 152 153 c.Assert(user.PasswordValid("foo"), jc.IsTrue) 154 c.Assert(user.PasswordValid("bar"), jc.IsFalse) 155 156 // User passwords should *not* use the fast PasswordHash function 157 hash := utils.AgentPasswordHash("foo-12345678901234567890") 158 c.Assert(err, jc.ErrorIsNil) 159 err = user.SetPasswordHash(hash, "") 160 c.Assert(err, jc.ErrorIsNil) 161 162 c.Assert(user.PasswordValid("foo-12345678901234567890"), jc.IsFalse) 163 } 164 165 func (s *UserSuite) TestSetPasswordHashWithSalt(c *gc.C) { 166 user := s.Factory.MakeUser(c, nil) 167 168 err := user.SetPasswordHash(utils.UserPasswordHash("foo", "salted"), "salted") 169 c.Assert(err, jc.ErrorIsNil) 170 171 c.Assert(user.PasswordValid("foo"), jc.IsTrue) 172 salt, hash := state.GetUserPasswordSaltAndHash(user) 173 c.Assert(salt, gc.Equals, "salted") 174 c.Assert(hash, gc.Not(gc.Equals), utils.UserPasswordHash("foo", utils.CompatSalt)) 175 } 176 177 func (s *UserSuite) TestPasswordValidUpdatesSalt(c *gc.C) { 178 user := s.Factory.MakeUser(c, nil) 179 180 compatHash := utils.UserPasswordHash("foo", utils.CompatSalt) 181 err := user.SetPasswordHash(compatHash, "") 182 c.Assert(err, jc.ErrorIsNil) 183 beforeSalt, beforeHash := state.GetUserPasswordSaltAndHash(user) 184 c.Assert(beforeSalt, gc.Equals, "") 185 c.Assert(beforeHash, gc.Equals, compatHash) 186 c.Assert(user.PasswordValid("bar"), jc.IsFalse) 187 // A bad password doesn't trigger a rewrite 188 afterBadSalt, afterBadHash := state.GetUserPasswordSaltAndHash(user) 189 c.Assert(afterBadSalt, gc.Equals, "") 190 c.Assert(afterBadHash, gc.Equals, compatHash) 191 // When we get a valid check, we then add a salt and rewrite the hash 192 c.Assert(user.PasswordValid("foo"), jc.IsTrue) 193 afterSalt, afterHash := state.GetUserPasswordSaltAndHash(user) 194 c.Assert(afterSalt, gc.Not(gc.Equals), "") 195 c.Assert(afterHash, gc.Not(gc.Equals), compatHash) 196 c.Assert(afterHash, gc.Equals, utils.UserPasswordHash("foo", afterSalt)) 197 // running PasswordValid again doesn't trigger another rewrite 198 c.Assert(user.PasswordValid("foo"), jc.IsTrue) 199 lastSalt, lastHash := state.GetUserPasswordSaltAndHash(user) 200 c.Assert(lastSalt, gc.Equals, afterSalt) 201 c.Assert(lastHash, gc.Equals, afterHash) 202 } 203 204 func (s *UserSuite) TestCantDisableAdmin(c *gc.C) { 205 user, err := s.State.User(s.Owner) 206 c.Assert(err, jc.ErrorIsNil) 207 err = user.Disable() 208 c.Assert(err, gc.ErrorMatches, "cannot disable state server environment owner") 209 } 210 211 func (s *UserSuite) TestCaseSensitiveUsersErrors(c *gc.C) { 212 s.Factory.MakeUser(c, &factory.UserParams{Name: "Bob"}) 213 214 _, err := s.State.AddUser( 215 "boB", "ignored", "ignored", "ignored") 216 c.Assert(errors.IsAlreadyExists(err), jc.IsTrue) 217 c.Assert(err, gc.ErrorMatches, "user already exists") 218 } 219 220 func (s *UserSuite) TestCaseInsensitiveLookup(c *gc.C) { 221 expectedUser := s.Factory.MakeUser(c, &factory.UserParams{Name: "Bob"}) 222 223 assertCaseInsensitiveLookup := func(name string) { 224 userTag := names.NewUserTag(name) 225 obtainedUser, err := s.State.User(userTag) 226 c.Assert(err, jc.ErrorIsNil) 227 c.Assert(obtainedUser, gc.DeepEquals, expectedUser) 228 } 229 230 assertCaseInsensitiveLookup("bob") 231 assertCaseInsensitiveLookup("bOb") 232 assertCaseInsensitiveLookup("boB") 233 assertCaseInsensitiveLookup("BOB") 234 } 235 236 func (s *UserSuite) TestAllUsers(c *gc.C) { 237 // Create in non-alphabetical order. 238 s.Factory.MakeUser(c, &factory.UserParams{Name: "conrad"}) 239 s.Factory.MakeUser(c, &factory.UserParams{Name: "adam"}) 240 s.Factory.MakeUser(c, &factory.UserParams{Name: "debbie", Disabled: true}) 241 s.Factory.MakeUser(c, &factory.UserParams{Name: "barbara"}) 242 s.Factory.MakeUser(c, &factory.UserParams{Name: "fred", Disabled: true}) 243 s.Factory.MakeUser(c, &factory.UserParams{Name: "erica"}) 244 // There is the existing state server owner called "test-admin" 245 246 includeDeactivated := false 247 users, err := s.State.AllUsers(includeDeactivated) 248 c.Assert(err, jc.ErrorIsNil) 249 c.Assert(users, gc.HasLen, 5) 250 c.Check(users[0].Name(), gc.Equals, "adam") 251 c.Check(users[1].Name(), gc.Equals, "barbara") 252 c.Check(users[2].Name(), gc.Equals, "conrad") 253 c.Check(users[3].Name(), gc.Equals, "erica") 254 c.Check(users[4].Name(), gc.Equals, "test-admin") 255 256 includeDeactivated = true 257 users, err = s.State.AllUsers(includeDeactivated) 258 c.Assert(err, jc.ErrorIsNil) 259 c.Assert(users, gc.HasLen, 7) 260 c.Check(users[0].Name(), gc.Equals, "adam") 261 c.Check(users[1].Name(), gc.Equals, "barbara") 262 c.Check(users[2].Name(), gc.Equals, "conrad") 263 c.Check(users[3].Name(), gc.Equals, "debbie") 264 c.Check(users[4].Name(), gc.Equals, "erica") 265 c.Check(users[5].Name(), gc.Equals, "fred") 266 c.Check(users[6].Name(), gc.Equals, "test-admin") 267 }