func TestRebuildUserRoles(t *testing.T) { computer := mockComputer{roles: ch.AtSequence(base.SetOf("role1", "role2"), 3)} auth := NewAuthenticator(gTestBucket, &computer) user, _ := auth.NewUser("testUser", "letmein", nil) user.SetExplicitRoles(ch.TimedSet{"role3": ch.NewVbSimpleSequence(1), "role1": ch.NewVbSimpleSequence(1)}) err := auth.InvalidateRoles(user) assert.Equals(t, err, nil) user2, err := auth.GetUser("testUser") assert.Equals(t, err, nil) expected := ch.AtSequence(base.SetOf("role1", "role3"), 1) expected.AddChannel("role2", 3) assert.DeepEquals(t, user2.RoleNames(), expected) }
func TestRoleInheritance(t *testing.T) { // Create some roles: auth := NewAuthenticator(gTestBucket, nil) role, _ := auth.NewRole("square", ch.SetOf("dull", "duller", "dullest")) assert.Equals(t, auth.Save(role), nil) role, _ = auth.NewRole("frood", ch.SetOf("hoopy", "hoopier", "hoopiest")) assert.Equals(t, auth.Save(role), nil) user, _ := auth.NewUser("arthur", "password", ch.SetOf("britain")) user.(*userImpl).setRolesSince(ch.TimedSet{"square": ch.NewVbSimpleSequence(0x3), "nonexistent": ch.NewVbSimpleSequence(0x42), "frood": ch.NewVbSimpleSequence(0x4)}) assert.DeepEquals(t, user.RoleNames(), ch.TimedSet{"square": ch.NewVbSimpleSequence(0x3), "nonexistent": ch.NewVbSimpleSequence(0x42), "frood": ch.NewVbSimpleSequence(0x4)}) auth.Save(user) user2, err := auth.GetUser("arthur") assert.Equals(t, err, nil) log.Printf("Channels = %s", user2.Channels()) assert.DeepEquals(t, user2.Channels(), ch.AtSequence(ch.SetOf("!", "britain"), 1)) assert.DeepEquals(t, user2.InheritedChannels(), ch.TimedSet{"!": ch.NewVbSimpleSequence(0x1), "britain": ch.NewVbSimpleSequence(0x1), "dull": ch.NewVbSimpleSequence(0x3), "duller": ch.NewVbSimpleSequence(0x3), "dullest": ch.NewVbSimpleSequence(0x3), "hoopy": ch.NewVbSimpleSequence(0x4), "hoopier": ch.NewVbSimpleSequence(0x4), "hoopiest": ch.NewVbSimpleSequence(0x4)}) assert.True(t, user2.CanSeeChannel("britain")) assert.True(t, user2.CanSeeChannel("duller")) assert.True(t, user2.CanSeeChannel("hoopy")) assert.Equals(t, user2.AuthorizeAllChannels(ch.SetOf("britain", "dull", "hoopiest")), nil) }
func TestAccessFunction(t *testing.T) { /* var logKeys = map[string]bool { "CRUD": true, "Access": true, } base.UpdateLogKeys(logKeys, true) */ db := setupTestDB(t) defer tearDownTestDB(t, db) authenticator := auth.NewAuthenticator(db.Bucket, db) var err error db.ChannelMapper = channels.NewChannelMapper(`function(doc){access(doc.users,doc.userChannels);}`) user, _ := authenticator.NewUser("naomi", "letmein", channels.SetOf("Netflix")) user.SetExplicitRoles(channels.TimedSet{"animefan": channels.NewVbSimpleSequence(1), "tumblr": channels.NewVbSimpleSequence(1)}) assertNoError(t, authenticator.Save(user), "Save") body := Body{"users": []string{"naomi"}, "userChannels": []string{"Hulu"}} _, err = db.Put("doc1", body) assertNoError(t, err, "") body = Body{"users": []string{"role:animefan"}, "userChannels": []string{"CrunchyRoll"}} _, err = db.Put("doc2", body) assertNoError(t, err, "") // Create the role _after_ creating the documents, to make sure the previously-indexed access // privileges are applied. role, _ := authenticator.NewRole("animefan", nil) authenticator.Save(role) user, err = authenticator.GetUser("naomi") assertNoError(t, err, "GetUser") expected := channels.AtSequence(channels.SetOf("Hulu", "Netflix", "!"), 1) assert.DeepEquals(t, user.Channels(), expected) expected.AddChannel("CrunchyRoll", 2) assert.DeepEquals(t, user.InheritedChannels(), expected) }
func (auth *Authenticator) UnmarshalUser(data []byte, defaultName string, defaultSequence uint64) (User, error) { user := &userImpl{auth: auth} if err := json.Unmarshal(data, user); err != nil { return nil, err } if user.Name_ == "" { user.Name_ = defaultName } defaultVbSequence := ch.NewVbSimpleSequence(defaultSequence) for channel, seq := range user.ExplicitChannels_ { if seq.Sequence == 0 { user.ExplicitChannels_[channel] = defaultVbSequence } } if err := user.validate(); err != nil { return nil, err } return user, nil }
func (auth *Authenticator) UnmarshalRole(data []byte, defaultName string, defaultSeq uint64) (Role, error) { role := &roleImpl{} if err := json.Unmarshal(data, role); err != nil { return nil, err } if role.Name_ == "" { role.Name_ = defaultName } defaultVbSeq := ch.NewVbSimpleSequence(defaultSeq) for channel, seq := range role.ExplicitChannels_ { if seq.Sequence == 0 { role.ExplicitChannels_[channel] = defaultVbSeq } } if err := role.validate(); err != nil { return nil, err } return role, nil }
// Updates any entries in the admin (explicit) channel set that have // their sequence set to zero, to the provided sequence, and invalidates the user channels. // Used during distributed index processing, where the sequence value is the vb sequence, and // isn't known at initial write time. Using bucket.Update for cas handling, similar to updatePrincipal. func (auth *Authenticator) updateVbucketSequences(docID string, factory func() Principal, seq uint64) error { sequence := ch.NewVbSimpleSequence(seq) err := auth.bucket.Update(docID, 0, func(currentValue []byte) ([]byte, error) { // Be careful: this block can be invoked multiple times if there are races! if currentValue == nil { return nil, couchbase.UpdateCancel } princ := factory() if err := json.Unmarshal(currentValue, princ); err != nil { return nil, err } channelsChanged := false for channel, vbSeq := range princ.ExplicitChannels() { seq := vbSeq.Sequence if seq == 0 { switch p := princ.(type) { case *roleImpl: p.ExplicitChannels_[channel] = sequence case *userImpl: p.ExplicitChannels_[channel] = sequence } channelsChanged = true } } // Invalidate calculated channels if changed. if channelsChanged { princ.setChannels(nil) } // If user, also check for explicit roles. rolesChanged := false if userPrinc, ok := princ.(*userImpl); ok { for role, vbSeq := range userPrinc.ExplicitRoles() { seq := vbSeq.Sequence if seq == 0 { userPrinc.ExplicitRoles_[role] = sequence rolesChanged = true } } // Invalidate calculated roles if changed. if rolesChanged { userPrinc.setRolesSince(nil) } } princ.SetSequence(seq) if channelsChanged || rolesChanged { // Save the updated principal doc. return json.Marshal(princ) } else { // No entries found requiring update, so cancel update. return nil, couchbase.UpdateCancel } }) if err != nil && err != couchbase.UpdateCancel { return err } return nil }
func TestUserAPI(t *testing.T) { // PUT a user var rt restTester assertStatus(t, rt.sendAdminRequest("GET", "/db/_user/snej", ""), 404) response := rt.sendAdminRequest("PUT", "/db/_user/snej", `{"email":"*****@*****.**", "password":"******", "admin_channels":["foo", "bar"]}`) assertStatus(t, response, 201) // GET the user and make sure the result is OK response = rt.sendAdminRequest("GET", "/db/_user/snej", "") assertStatus(t, response, 200) var body db.Body json.Unmarshal(response.Body.Bytes(), &body) assert.Equals(t, body["name"], "snej") assert.Equals(t, body["email"], "*****@*****.**") assert.DeepEquals(t, body["admin_channels"], []interface{}{"bar", "foo"}) assert.DeepEquals(t, body["all_channels"], []interface{}{"!", "bar", "foo"}) assert.Equals(t, body["password"], nil) // Check the list of all users: response = rt.sendAdminRequest("GET", "/db/_user/", "") assertStatus(t, response, 200) assert.Equals(t, string(response.Body.Bytes()), `["snej"]`) // Check that the actual User object is correct: user, _ := rt.ServerContext().Database("db").Authenticator().GetUser("snej") assert.Equals(t, user.Name(), "snej") assert.Equals(t, user.Email(), "*****@*****.**") assert.DeepEquals(t, user.ExplicitChannels(), channels.TimedSet{"bar": channels.NewVbSimpleSequence(0x1), "foo": channels.NewVbSimpleSequence(0x1)}) assert.True(t, user.Authenticate("letmein")) // Change the password and verify it: response = rt.sendAdminRequest("PUT", "/db/_user/snej", `{"email":"*****@*****.**", "password":"******", "admin_channels":["foo", "bar"]}`) assertStatus(t, response, 200) user, _ = rt.ServerContext().Database("db").Authenticator().GetUser("snej") assert.True(t, user.Authenticate("123")) // DELETE the user assertStatus(t, rt.sendAdminRequest("DELETE", "/db/_user/snej", ""), 200) assertStatus(t, rt.sendAdminRequest("GET", "/db/_user/snej", ""), 404) // POST a user response = rt.sendAdminRequest("POST", "/db/_user", `{"name":"snej", "password":"******", "admin_channels":["foo", "bar"]}`) assertStatus(t, response, 301) response = rt.sendAdminRequest("POST", "/db/_user/", `{"name":"snej", "password":"******", "admin_channels":["foo", "bar"]}`) assertStatus(t, response, 201) response = rt.sendAdminRequest("GET", "/db/_user/snej", "") assertStatus(t, response, 200) body = nil json.Unmarshal(response.Body.Bytes(), &body) assert.Equals(t, body["name"], "snej") // Create a role assertStatus(t, rt.sendAdminRequest("GET", "/db/_role/hipster", ""), 404) response = rt.sendAdminRequest("PUT", "/db/_role/hipster", `{"admin_channels":["fedoras", "fixies"]}`) assertStatus(t, response, 201) // Give the user that role response = rt.sendAdminRequest("PUT", "/db/_user/snej", `{"admin_channels":["foo", "bar"],"admin_roles":["hipster"]}`) assertStatus(t, response, 200) // GET the user and verify that it shows the channels inherited from the role response = rt.sendAdminRequest("GET", "/db/_user/snej", "") assertStatus(t, response, 200) body = nil json.Unmarshal(response.Body.Bytes(), &body) assert.DeepEquals(t, body["admin_roles"], []interface{}{"hipster"}) assert.DeepEquals(t, body["all_channels"], []interface{}{"!", "bar", "fedoras", "fixies", "foo"}) // DELETE the user assertStatus(t, rt.sendAdminRequest("DELETE", "/db/_user/snej", ""), 200) }