func TestAccessFunctionValidation(t *testing.T) { db := setupTestDB(t) defer tearDownTestDB(t, db) var err error db.ChannelMapper = channels.NewChannelMapper(`function(doc){access(doc.users,doc.userChannels);}`) body := Body{"users": []string{"username"}, "userChannels": []string{"BBC1"}} _, err = db.Put("doc1", body) assertNoError(t, err, "") body = Body{"users": []string{"role:rolename"}, "userChannels": []string{"BBC1"}} _, err = db.Put("doc2", body) assertNoError(t, err, "") body = Body{"users": []string{"bad username"}, "userChannels": []string{"BBC1"}} _, err = db.Put("doc3", body) assertHTTPError(t, err, 500) body = Body{"users": []string{"role:bad rolename"}, "userChannels": []string{"BBC1"}} _, err = db.Put("doc4", body) assertHTTPError(t, err, 500) body = Body{"users": []string{"roll:over"}, "userChannels": []string{"BBC1"}} _, err = db.Put("doc5", body) assertHTTPError(t, err, 500) body = Body{"users": []string{"username"}, "userChannels": []string{"bad name"}} _, err = db.Put("doc6", body) assertHTTPError(t, err, 500) }
func TestSyncFnOnPush(t *testing.T) { db := setupTestDB(t) defer tearDownTestDB(t, db) db.ChannelMapper = channels.NewChannelMapper(`function(doc, oldDoc) { log("doc _id = "+doc._id+", _rev = "+doc._rev); if (oldDoc) log("oldDoc _id = "+oldDoc._id+", _rev = "+oldDoc._rev); channel(doc.channels); }`) // Create first revision: body := Body{"key1": "value1", "key2": 1234, "channels": []string{"public"}} rev1id, err := db.Put("doc1", body) assertNoError(t, err, "Couldn't create document") // Add several revisions at once to a doc, as on a push: log.Printf("Check PutExistingRev...") body["_rev"] = "4-four" body["key1"] = "fourth value" body["key2"] = int64(4444) body["channels"] = "clibup" history := []string{"4-four", "3-three", "2-488724414d0ed6b398d6d2aeb228d797", rev1id} err = db.PutExistingRev("doc1", body, history) assertNoError(t, err, "PutExistingRev failed") // Check that the doc has the correct channel (test for issue #300) doc, err := db.GetDoc("doc1") assert.DeepEquals(t, doc.Channels, channels.ChannelMap{ "clibup": nil, // i.e. it is currently in this channel (no removal) "public": &channels.ChannelRemoval{Seq: 2, RevID: "4-four"}, }) assert.DeepEquals(t, doc.History["4-four"].Channels, base.SetOf("clibup")) }
func CouchbaseTestAccessFunctionWithVbuckets(t *testing.T) { //base.LogKeys["CRUD"] = true //base.LogKeys["Access"] = true db := setupTestDB(t) defer tearDownTestDB(t, db) db.SequenceType = ClockSequenceType authenticator := auth.NewAuthenticator(db.Bucket, db) var err error db.ChannelMapper = channels.NewChannelMapper(`function(doc){access(doc.users,doc.userChannels);}`) user, _ := authenticator.NewUser("bernard", "letmein", channels.SetOf("Netflix")) assertNoError(t, authenticator.Save(user), "Save") body := Body{"users": []string{"bernard"}, "userChannels": []string{"ABC"}} _, err = db.Put("doc1", body) assertNoError(t, err, "") time.Sleep(100 * time.Millisecond) user, err = authenticator.GetUser("bernard") assertNoError(t, err, "GetUser") expected := channels.TimedSetFromString("ABC:5.1,Netflix:1,!:1") assert.DeepEquals(t, user.Channels(), expected) body = Body{"users": []string{"bernard"}, "userChannels": []string{"NBC"}} _, err = db.Put("doc2", body) assertNoError(t, err, "") time.Sleep(100 * time.Millisecond) user, err = authenticator.GetUser("bernard") assertNoError(t, err, "GetUser") expected = channels.TimedSetFromString("ABC:5.1,NBC:12.1,Netflix:1,!:1") assert.DeepEquals(t, user.Channels(), expected) // Have another doc assign a new channel, and one of the previously present channels body = Body{"users": []string{"bernard"}, "userChannels": []string{"ABC", "PBS"}} _, err = db.Put("doc3", body) assertNoError(t, err, "") time.Sleep(100 * time.Millisecond) user, err = authenticator.GetUser("bernard") assertNoError(t, err, "GetUser") expected = channels.TimedSetFromString("ABC:5.1,NBC:12.1,PBS:11.1,Netflix:1,!:1") assert.DeepEquals(t, user.Channels(), expected) }
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) }
// Sets the database context's sync function based on the JS code from config. // Returns a boolean indicating whether the function is different from the saved one. // If multiple gateway instances try to update the function at the same time (to the same new // value) only one of them will get a changed=true result. func (context *DatabaseContext) UpdateSyncFun(syncFun string) (changed bool, err error) { if syncFun == "" { context.ChannelMapper = nil } else if context.ChannelMapper != nil { _, err = context.ChannelMapper.SetFunction(syncFun) } else { context.ChannelMapper = channels.NewChannelMapper(syncFun) } if err != nil { base.Warn("Error setting sync function: %s", err) return } var syncData struct { // format of the sync-fn document Sync string } err = context.Bucket.Update(kSyncDataKey, 0, func(currentValue []byte) ([]byte, error) { // The first time opening a new db, currentValue will be nil. Don't treat this as a change. if currentValue != nil { parseErr := json.Unmarshal(currentValue, &syncData) if parseErr != nil || syncData.Sync != syncFun { changed = true } } if changed || currentValue == nil { syncData.Sync = syncFun return json.Marshal(syncData) } else { return nil, couchbase.UpdateCancel // value unchanged, no need to save } }) if err == couchbase.UpdateCancel { err = nil } return }
func TestAttachmentForRejectedDocument(t *testing.T) { context, err := NewDatabaseContext("db", testBucket(), false, DatabaseContextOptions{}) assertNoError(t, err, "Couldn't create context for database 'db'") defer context.Close() db, err := CreateDatabase(context) assertNoError(t, err, "Couldn't create database 'db'") db.ChannelMapper = channels.NewChannelMapper(`function(doc, oldDoc) { throw({forbidden: "None shall pass!"}); }`) docBody := `{"_attachments": {"hello.txt": {"data":"aGVsbG8gd29ybGQ="}}}` var body Body json.Unmarshal([]byte(docBody), &body) _, err = db.Put("doc1", unjson(docBody)) log.Printf("Got error on put doc:%v", err) db.Bucket.Dump() // Attempt to retrieve the attachment doc _, _, err = db.Bucket.GetRaw("_sync:att:sha1-Kq5sNclPz7QV2+lfQIuc6R7oRu0=") assertTrue(t, err != nil, "Expect error when attempting to retrieve attachment document after doc is rejected.") }
func CouchbaseTestIndexChangesAccessBackfill(t *testing.T) { // Not walrus compatible, until we add support for meta.vb and meta.vbseq to walrus views. db := setupTestDBForChangeIndex(t) defer tearDownTestDB(t, db) base.EnableLogKey("IndexChanges") base.EnableLogKey("Changes+") base.EnableLogKey("Backfill") db.ChannelMapper = channels.NewChannelMapper(`function(doc, oldDoc) { if (doc.accessGrant) { console.log("access grant to " + doc.accessGrant); access(doc.accessGrant, "PBS"); } channel(doc.channels); }`) // Create a user with access to channel ABC authenticator := db.Authenticator() user, _ := authenticator.NewUser("naomi", "letmein", channels.SetOf("ABC")) authenticator.Save(user) // Create docs on multiple channels: _, err := db.Put("both_1", Body{"channels": []string{"ABC", "PBS"}}) assertNoError(t, err, "Put failed") _, err = db.Put("doc0000609", Body{"channels": []string{"PBS"}}) assertNoError(t, err, "Put failed") _, err = db.Put("doc0000799", Body{"channels": []string{"ABC"}}) assertNoError(t, err, "Put failed") time.Sleep(2000 * time.Millisecond) // Check the _changes feed: db.user, _ = authenticator.GetUser("naomi") changes, err := db.GetChanges(base.SetOf("*"), getZeroSequence(db)) assertNoError(t, err, "Couldn't GetChanges") printChanges(changes) assert.Equals(t, len(changes), 2) // Write a doc to grant user access to PBS: db.Put("doc_grant", Body{"accessGrant": "naomi"}) time.Sleep(1000 * time.Millisecond) // Write a few more docs (that should be returned as non-backfill) db.Put("doc_nobackfill_1", Body{"channels": []string{"PBS"}}) db.Put("doc_nobackfill_2", Body{"channels": []string{"PBS"}}) time.Sleep(1000 * time.Millisecond) // Check the _changes feed: log.Println("Get User") db.user, _ = authenticator.GetUser("naomi") db.changeCache.waitForSequence(1) time.Sleep(1000 * time.Millisecond) lastSeq := getLastSeq(changes) lastSeq, _ = db.ParseSequenceID(lastSeq.String()) log.Println("Get Changes") changes, err = db.GetChanges(base.SetOf("*"), ChangesOptions{Since: lastSeq}) assertNoError(t, err, "Couldn't GetChanges") printChanges(changes) assert.Equals(t, len(changes), 5) verifyChange(t, changes, "both_1", true) verifyChange(t, changes, "doc0000609", true) verifyChange(t, changes, "doc_nobackfill_1", false) verifyChange(t, changes, "doc_nobackfill_2", false) }