func TestAccessFunction(t *testing.T) { db := setupTestDB(t) defer tearDownTestDB(t, db) authenticator := auth.NewAuthenticator(db.Bucket, db) var err error db.ChannelMapper, err = channels.NewChannelMapper(`function(doc){access(doc.users,doc.userChannels);}`) assertNoError(t, err, "Couldn't create channel mapper") user, _ := authenticator.NewUser("naomi", "letmein", channels.SetOf("Netflix")) user.SetRoleNames([]string{"animefan", "tumblr"}) authenticator.Save(user) 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, _ = authenticator.GetUser("naomi") expected := channels.SetOf("Hulu", "Netflix").AtSequence(1) assert.DeepEquals(t, user.Channels(), expected) expected.AddChannel("CrunchyRoll", 2) assert.DeepEquals(t, user.InheritedChannels(), expected) }
func TestGetDeleted(t *testing.T) { db := setupTestDB(t) defer tearDownTestDB(t, db) body := Body{"key1": 1234} rev1id, err := db.Put("doc1", body) assertNoError(t, err, "Put") rev2id, err := db.DeleteDoc("doc1", rev1id) assertNoError(t, err, "DeleteDoc") // Get the deleted doc with its history; equivalent to GET with ?revs=true body, err = db.GetRev("doc1", rev2id, true, nil) assertNoError(t, err, "GetRev") expectedResult := Body{ "_id": "doc1", "_rev": rev2id, "_deleted": true, "_revisions": Body{"start": 2, "ids": []string{"bc6d97f6e97c0d034a34f8aac2bf8b44", "dfd5e19813767eeddd08270fc5f385cd"}}, } assert.DeepEquals(t, body, expectedResult) // Try again but with a user who doesn't have access to this revision (see #179) authenticator := auth.NewAuthenticator(db.Bucket, db) db.user, err = authenticator.GetUser("") assertNoError(t, err, "GetUser") db.user.SetExplicitChannels(nil) body, err = db.GetRev("doc1", rev2id, true, nil) assertNoError(t, err, "GetRev") assert.DeepEquals(t, body, expectedResult) }
func TestLogin(t *testing.T) { var rt restTester a := auth.NewAuthenticator(rt.bucket(), nil) user, err := a.GetUser("") assert.Equals(t, err, nil) user.SetDisabled(true) err = a.Save(user) assert.Equals(t, err, nil) user, err = a.GetUser("") assert.Equals(t, err, nil) assert.True(t, user.Disabled()) response := rt.sendRequest("PUT", "/db/doc", `{"hi": "there"}`) assertStatus(t, response, 401) user, err = a.NewUser("pupshaw", "letmein", channels.SetOf("*")) a.Save(user) assertStatus(t, rt.sendRequest("GET", "/db/_session", ""), 200) response = rt.sendRequest("POST", "/db/_session", `{"name":"pupshaw", "password":"******"}`) assertStatus(t, response, 200) log.Printf("Set-Cookie: %s", response.Header().Get("Set-Cookie")) assert.True(t, response.Header().Get("Set-Cookie") != "") }
// Initialize REST handlers. Call this once on launch. func InitREST(bucket *couchbase.Bucket, dbName string, serverURL string) *context { if dbName == "" { dbName = bucket.Name } dbcontext, err := db.NewDatabaseContext(dbName, bucket) if err != nil { return nil } newdb, err := db.GetDatabase(dbcontext, nil) if err != nil { return nil } newdb.ReadDesignDocument() if dbcontext.ChannelMapper == nil { log.Printf("Channel mapper undefined; using default") // Always have a channel mapper object even if it does nothing: dbcontext.ChannelMapper, _ = channels.NewDefaultChannelMapper() } if dbcontext.Validator == nil { log.Printf("Validator undefined; no validation") } c := &context{ dbcontext: dbcontext, auth: auth.NewAuthenticator(bucket), serverURL: serverURL, } http.Handle("/", createHandler(c)) return c }
func TestUpdateDesignDoc(t *testing.T) { db := setupTestDB(t) defer tearDownTestDB(t, db) _, err := db.Put("_design/official", Body{}) assertNoError(t, err, "add design doc as admin") authenticator := auth.NewAuthenticator(db.Bucket, db) db.user, _ = authenticator.NewUser("naomi", "letmein", channels.SetOf("Netflix")) _, err = db.Put("_design/pwn3d", Body{}) assertHTTPError(t, err, 403) }
func TestSessionExtension(t *testing.T) { var rt restTester a := auth.NewAuthenticator(rt.bucket(), nil) user, err := a.GetUser("") assert.Equals(t, err, nil) user.SetDisabled(true) err = a.Save(user) assert.Equals(t, err, nil) user, err = a.GetUser("") assert.Equals(t, err, nil) assert.True(t, user.Disabled()) log.Printf("hello") response := rt.sendRequest("PUT", "/db/doc", `{"hi": "there"}`) assertStatus(t, response, 401) user, err = a.NewUser("pupshaw", "letmein", channels.SetOf("*")) a.Save(user) assertStatus(t, rt.sendAdminRequest("GET", "/db/_session", ""), 200) response = rt.sendAdminRequest("POST", "/db/_session", `{"name":"pupshaw", "ttl":10}`) assertStatus(t, response, 200) var body db.Body json.Unmarshal(response.Body.Bytes(), &body) sessionId := body["session_id"].(string) sessionExpiration := body["expires"].(string) assert.True(t, sessionId != "") assert.True(t, sessionExpiration != "") assert.True(t, body["cookie_name"].(string) == "SyncGatewaySession") reqHeaders := map[string]string{ "Cookie": "SyncGatewaySession=" + body["session_id"].(string), } response = rt.sendRequestWithHeaders("PUT", "/db/doc1", `{"hi": "there"}`, reqHeaders) assertStatus(t, response, 201) assert.True(t, response.Header().Get("Set-Cookie") == "") //Sleep for 2 seconds, this will ensure 10% of the 100 seconds session ttl has elapsed and //should cause a new Cookie to be sent by the server with the same session ID and an extended expiration date time.Sleep(2 * time.Second) response = rt.sendRequestWithHeaders("PUT", "/db/doc2", `{"hi": "there"}`, reqHeaders) assertStatus(t, response, 201) assert.True(t, response.Header().Get("Set-Cookie") != "") }
func TestLogin(t *testing.T) { bucket, _ := db.ConnectToBucket("walrus:", "default", "test") a := auth.NewAuthenticator(bucket, nil) user, err := a.GetUser("") assert.Equals(t, err, nil) user.SetDisabled(true) err = a.Save(user) assert.Equals(t, err, nil) user, err = a.GetUser("") assert.Equals(t, err, nil) assert.True(t, user.Disabled()) response := callRESTOn(bucket, "PUT", "/db/doc", `{"hi": "there"}`) assertStatus(t, response, 401) user, err = a.NewUser("pupshaw", "letmein", channels.SetOf("*")) a.Save(user) response = callRESTOn(bucket, "POST", "/db/_session", `{"name":"pupshaw", "password":"******"}`) assertStatus(t, response, 200) log.Printf("Set-Cookie: %s", response.Header().Get("Set-Cookie")) assert.True(t, response.Header().Get("Set-Cookie") != "") }
func TestAccessControl(t *testing.T) { type allDocsRow struct { ID string `json:"id"` Key string `json:"key"` Value struct { Rev string `json:"rev"` Channels []string `json:"channels,omitempty"` Access map[string]base.Set `json:"access,omitempty"` // for admins only } `json:"value"` Doc db.Body `json:"doc,omitempty"` Error string `json:"error"` } var allDocsResult struct { TotalRows int `json:"total_rows"` Offset int `json:"offset"` Rows []allDocsRow `json:"rows"` } // Create some docs: var rt restTester a := auth.NewAuthenticator(rt.bucket(), nil) guest, err := a.GetUser("") assert.Equals(t, err, nil) guest.SetDisabled(false) err = a.Save(guest) assert.Equals(t, err, nil) assertStatus(t, rt.sendRequest("PUT", "/db/doc1", `{"channels":[]}`), 201) assertStatus(t, rt.sendRequest("PUT", "/db/doc2", `{"channels":["CBS"]}`), 201) assertStatus(t, rt.sendRequest("PUT", "/db/doc3", `{"channels":["CBS", "Cinemax"]}`), 201) assertStatus(t, rt.sendRequest("PUT", "/db/doc4", `{"channels":["WB", "Cinemax"]}`), 201) guest.SetDisabled(true) err = a.Save(guest) assert.Equals(t, err, nil) // Create a user: alice, err := a.NewUser("alice", "letmein", channels.SetOf("Cinemax")) a.Save(alice) // Get a single doc the user has access to: request, _ := http.NewRequest("GET", "/db/doc3", nil) request.SetBasicAuth("alice", "letmein") response := rt.send(request) assertStatus(t, response, 200) // Get a single doc the user doesn't have access to: request, _ = http.NewRequest("GET", "/db/doc2", nil) request.SetBasicAuth("alice", "letmein") response = rt.send(request) assertStatus(t, response, 403) // Check that _all_docs only returns the docs the user has access to: request, _ = http.NewRequest("GET", "/db/_all_docs?channels=true", nil) request.SetBasicAuth("alice", "letmein") response = rt.send(request) assertStatus(t, response, 200) log.Printf("Response = %s", response.Body.Bytes()) err = json.Unmarshal(response.Body.Bytes(), &allDocsResult) assert.Equals(t, err, nil) assert.Equals(t, len(allDocsResult.Rows), 2) assert.Equals(t, allDocsResult.Rows[0].ID, "doc3") assert.DeepEquals(t, allDocsResult.Rows[0].Value.Channels, []string{"Cinemax"}) assert.Equals(t, allDocsResult.Rows[1].ID, "doc4") assert.DeepEquals(t, allDocsResult.Rows[1].Value.Channels, []string{"Cinemax"}) // Check _all_docs with include_docs option: request, _ = http.NewRequest("GET", "/db/_all_docs?include_docs=true", nil) request.SetBasicAuth("alice", "letmein") response = rt.send(request) assertStatus(t, response, 200) log.Printf("Response = %s", response.Body.Bytes()) err = json.Unmarshal(response.Body.Bytes(), &allDocsResult) assert.Equals(t, err, nil) assert.Equals(t, len(allDocsResult.Rows), 2) assert.Equals(t, allDocsResult.Rows[0].ID, "doc3") assert.Equals(t, allDocsResult.Rows[1].ID, "doc4") // Check POST to _all_docs: body := `{"keys": ["doc4", "doc1", "doc3", "b0gus"]}` request, _ = http.NewRequest("POST", "/db/_all_docs?channels=true", bytes.NewBufferString(body)) request.SetBasicAuth("alice", "letmein") response = rt.send(request) assertStatus(t, response, 200) log.Printf("Response from POST _all_docs = %s", response.Body.Bytes()) err = json.Unmarshal(response.Body.Bytes(), &allDocsResult) assert.Equals(t, err, nil) assert.Equals(t, len(allDocsResult.Rows), 4) assert.Equals(t, allDocsResult.Rows[0].Key, "doc4") assert.Equals(t, allDocsResult.Rows[0].ID, "doc4") assert.DeepEquals(t, allDocsResult.Rows[0].Value.Channels, []string{"Cinemax"}) assert.Equals(t, allDocsResult.Rows[1].Key, "doc1") assert.Equals(t, allDocsResult.Rows[1].Error, "forbidden") assert.Equals(t, allDocsResult.Rows[2].ID, "doc3") assert.DeepEquals(t, allDocsResult.Rows[2].Value.Channels, []string{"Cinemax"}) assert.Equals(t, allDocsResult.Rows[3].Key, "b0gus") assert.Equals(t, allDocsResult.Rows[3].Error, "not_found") // Check _all_docs as admin: response = rt.sendAdminRequest("GET", "/db/_all_docs", "") assertStatus(t, response, 200) log.Printf("Admin response = %s", response.Body.Bytes()) err = json.Unmarshal(response.Body.Bytes(), &allDocsResult) assert.Equals(t, err, nil) assert.Equals(t, len(allDocsResult.Rows), 4) assert.Equals(t, allDocsResult.Rows[0].ID, "doc1") assert.Equals(t, allDocsResult.Rows[1].ID, "doc2") }
func TestAccessControl(t *testing.T) { type viewRow struct { ID string `json:"id"` Key string `json:"key"` Value map[string]string `json:"value"` Doc db.Body `json:"doc,omitempty"` } var viewResult struct { TotalRows int `json:"total_rows"` Offset int `json:"offset"` Rows []viewRow `json:"rows"` } // Create some docs: var rt restTester a := auth.NewAuthenticator(rt.bucket(), nil) guest, err := a.GetUser("") assert.Equals(t, err, nil) guest.SetDisabled(false) err = a.Save(guest) assert.Equals(t, err, nil) assertStatus(t, rt.sendRequest("PUT", "/db/doc1", `{"channels":[]}`), 201) assertStatus(t, rt.sendRequest("PUT", "/db/doc2", `{"channels":["CBS"]}`), 201) assertStatus(t, rt.sendRequest("PUT", "/db/doc3", `{"channels":["CBS", "Cinemax"]}`), 201) assertStatus(t, rt.sendRequest("PUT", "/db/doc4", `{"channels":["WB", "Cinemax"]}`), 201) guest.SetDisabled(true) err = a.Save(guest) assert.Equals(t, err, nil) // Create a user: alice, err := a.NewUser("alice", "letmein", channels.SetOf("Cinemax")) a.Save(alice) // Get a single doc the user has access to: request, _ := http.NewRequest("GET", "/db/doc3", nil) request.SetBasicAuth("alice", "letmein") response := rt.send(request) assertStatus(t, response, 200) // Get a single doc the user doesn't have access to: request, _ = http.NewRequest("GET", "/db/doc2", nil) request.SetBasicAuth("alice", "letmein") response = rt.send(request) assertStatus(t, response, 403) // Check that _all_docs only returns the docs the user has access to: request, _ = http.NewRequest("GET", "/db/_all_docs", nil) request.SetBasicAuth("alice", "letmein") response = rt.send(request) assertStatus(t, response, 200) log.Printf("Response = %s", response.Body.Bytes()) err = json.Unmarshal(response.Body.Bytes(), &viewResult) assert.Equals(t, err, nil) assert.Equals(t, len(viewResult.Rows), 2) assert.Equals(t, viewResult.Rows[0].ID, "doc3") assert.Equals(t, viewResult.Rows[1].ID, "doc4") // Check _all_docs with include_docs option: request, _ = http.NewRequest("GET", "/db/_all_docs?include_docs=true", nil) request.SetBasicAuth("alice", "letmein") response = rt.send(request) assertStatus(t, response, 200) log.Printf("Response = %s", response.Body.Bytes()) err = json.Unmarshal(response.Body.Bytes(), &viewResult) assert.Equals(t, err, nil) assert.Equals(t, len(viewResult.Rows), 2) assert.Equals(t, viewResult.Rows[0].ID, "doc3") assert.Equals(t, viewResult.Rows[1].ID, "doc4") }
func (context *DatabaseContext) Authenticator() *auth.Authenticator { // Authenticators are lightweight & stateless, so it's OK to return a new one every time return auth.NewAuthenticator(context.Bucket, context) }