[ARVADOS] updated: 297f48f2e6233da1e61cda57af30c9c6b64f0908
git at public.curoverse.com
git at public.curoverse.com
Tue May 6 23:44:36 EDT 2014
Summary of changes:
services/keep/src/keep/keep.go | 10 ++-
services/keep/src/keep/keep_test.go | 145 ++++++++++++++++++++++++++++++++++-
services/keep/src/keep/perms.go | 5 +-
3 files changed, 155 insertions(+), 5 deletions(-)
via 297f48f2e6233da1e61cda57af30c9c6b64f0908 (commit)
from b63b4b51a7bdaa38960e0b4428141c16c0a07d7a (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
commit 297f48f2e6233da1e61cda57af30c9c6b64f0908
Author: Tim Pierce <twp at curoverse.com>
Date: Tue May 6 23:40:59 2014 -0400
Require enforce_permissions and API token as necessary.
Unqualified /index requests require enforce_permissions to be enabled
and an API token to be supplied with the request.
SignLocator should return an unsigned locator if no API token was
supplied.
Refs #2328
diff --git a/services/keep/src/keep/keep.go b/services/keep/src/keep/keep.go
index 278023b..8cb45cc 100644
--- a/services/keep/src/keep/keep.go
+++ b/services/keep/src/keep/keep.go
@@ -312,9 +312,15 @@ func PutBlockHandler(w http.ResponseWriter, req *http.Request) {
func IndexHandler(w http.ResponseWriter, req *http.Request) {
prefix := mux.Vars(req)["prefix"]
- // Only the data manager may issue unqualified "GET /index" requests.
+ // Only the data manager may issue unqualified "GET /index" requests,
+ // and only if enforce_permissions is enabled.
+ // If the request is unauthenticated, or does not match the data manager's
+ // API token, return 403 Permission denied.
if prefix == "" {
- if data_manager_token != GetApiToken(req) {
+ api_token := GetApiToken(req)
+ if !enforce_permissions ||
+ api_token == "" ||
+ data_manager_token != GetApiToken(req) {
http.Error(w, PermissionError.Error(), PermissionError.HTTPCode)
return
}
diff --git a/services/keep/src/keep/keep_test.go b/services/keep/src/keep/keep_test.go
index 77cf3b5..d3536d6 100644
--- a/services/keep/src/keep/keep_test.go
+++ b/services/keep/src/keep/keep_test.go
@@ -351,7 +351,7 @@ func TestIndex(t *testing.T) {
match, err := regexp.MatchString(expected, index)
if err == nil {
if !match {
- t.Errorf("IndexLocators returned:\n-----\n%s-----\n", index)
+ t.Errorf("IndexLocators returned:\n%s", index)
}
} else {
t.Errorf("regexp.MatchString: %s", err)
@@ -481,6 +481,148 @@ func TestGetHandler(t *testing.T) {
}
}
+func TestPutHandler(t *testing.T) {
+ defer teardown()
+
+ // Prepare two test Keep volumes.
+ KeepVM = MakeTestVolumeManager(2)
+ defer func() { KeepVM.Quit() }()
+
+ // Set up a REST router for testing the handlers.
+ rest := NewRESTRouter()
+
+ // Execute a PUT request.
+ test_url := "http://localhost:25107/" + TEST_HASH
+ test_body := bytes.NewReader(TEST_BLOCK)
+ req, _ := http.NewRequest("PUT", test_url, test_body)
+ resp := httptest.NewRecorder()
+ rest.ServeHTTP(resp, req)
+
+ if resp.Code != 200 {
+ t.Errorf("bad response code: %v", resp)
+ }
+ if resp.Body.String() != TEST_HASH {
+ t.Errorf("bad response body: %v", resp)
+ }
+
+ // Add a permission key.
+ // When a permission key is available, the locator returned
+ // from a PUT request will be signed.
+ PermissionSecret = []byte(known_key)
+
+ // An authenticated PUT request returns a signed locator.
+ test_url = "http://localhost:25107/" + TEST_HASH
+ test_body = bytes.NewReader(TEST_BLOCK)
+ req, _ = http.NewRequest("PUT", test_url, test_body)
+ req.Header.Set("Authorization", "OAuth "+known_token)
+ resp = httptest.NewRecorder()
+ rest.ServeHTTP(resp, req)
+
+ if resp.Code != 200 {
+ t.Errorf("bad response code: %v", resp)
+ }
+ if !VerifySignature(resp.Body.String(), known_token) {
+ t.Errorf("bad response body: %v", resp)
+ }
+
+ // An unauthenticated PUT request returns an unsigned locator
+ // even when a permission key is available.
+ test_url = "http://localhost:25107/" + TEST_HASH
+ test_body = bytes.NewReader(TEST_BLOCK)
+ req, _ = http.NewRequest("PUT", test_url, test_body)
+ resp = httptest.NewRecorder()
+ rest.ServeHTTP(resp, req)
+
+ if resp.Code != 200 {
+ t.Errorf("bad response code: %v", resp)
+ }
+ if resp.Body.String() != TEST_HASH {
+ t.Errorf("bad response body: %v", resp)
+ }
+}
+
+func TestIndexHandler(t *testing.T) {
+ defer teardown()
+
+ // Set up Keep volumes and populate them.
+ // Include multiple blocks on different volumes, and
+ // some metadata files.
+ KeepVM = MakeTestVolumeManager(2)
+ defer func() { KeepVM.Quit() }()
+
+ vols := KeepVM.Volumes()
+ vols[0].Put(TEST_HASH, TEST_BLOCK)
+ vols[1].Put(TEST_HASH_2, TEST_BLOCK_2)
+
+ // Set up a REST router for testing the handlers.
+ rest := NewRESTRouter()
+
+ // Requests for /index with a prefix are okay even if unauthenticated.
+ test_url := "http://localhost:25107/index/" + TEST_HASH[0:5]
+ req, _ := http.NewRequest("GET", test_url, nil)
+ resp := httptest.NewRecorder()
+ rest.ServeHTTP(resp, req)
+
+ expected := `^` + TEST_HASH + `\+\d+ \d+\n$`
+ match, _ := regexp.MatchString(expected, resp.Body.String())
+ if !match {
+ t.Errorf("IndexHandler returned:\n%s", resp.Body.String())
+ }
+
+ // Unauthenticated /index requests: fail.
+ test_url = "http://localhost:25107/index"
+ req, _ = http.NewRequest("GET", test_url, nil)
+ resp = httptest.NewRecorder()
+ rest.ServeHTTP(resp, req)
+
+ if resp.Code != PermissionError.HTTPCode {
+ t.Errorf("unauthenticated /index: %+v", resp)
+ }
+
+ // Authenticated /index requests by a non-superuser: also fail.
+ test_url = "http://localhost:25107/index"
+ req, _ = http.NewRequest("GET", test_url, nil)
+ req.Header.Set("Authorization", "OAuth "+known_token)
+ resp = httptest.NewRecorder()
+ rest.ServeHTTP(resp, req)
+
+ if resp.Code != PermissionError.HTTPCode {
+ t.Errorf("authenticated /index: %+v", resp)
+ }
+
+ // Even superuser /index requests fail if enforce_permissions is off!
+ enforce_permissions = false
+ data_manager_token = "DATA MANAGER TOKEN"
+ test_url = "http://localhost:25107/index"
+ req, _ = http.NewRequest("GET", test_url, nil)
+ req.Header.Set("Authorization", "OAuth "+data_manager_token)
+ resp = httptest.NewRecorder()
+ rest.ServeHTTP(resp, req)
+
+ if resp.Code != PermissionError.HTTPCode {
+ t.Errorf("superuser /index (permissions off): %+v", resp)
+ }
+
+ // Superuser /index requests with enforce_permissions set: succeed!
+ enforce_permissions = true
+ data_manager_token = "DATA MANAGER TOKEN"
+ test_url = "http://localhost:25107/index"
+ req, _ = http.NewRequest("GET", test_url, nil)
+ req.Header.Set("Authorization", "OAuth "+data_manager_token)
+ resp = httptest.NewRecorder()
+ rest.ServeHTTP(resp, req)
+
+ if resp.Code != http.StatusOK {
+ t.Errorf("superuser /index: %+v", resp)
+ }
+ expected = `^` + TEST_HASH + `\+\d+ \d+\n` +
+ TEST_HASH_2 + `\+\d+ \d+\n$`
+ match, _ = regexp.MatchString(expected, resp.Body.String())
+ if !match {
+ t.Errorf("superuser /index:\n%s", resp.Body.String())
+ }
+}
+
// ========================================
// Helper functions for unit tests.
// ========================================
@@ -501,6 +643,7 @@ func MakeTestVolumeManager(num_volumes int) VolumeManager {
// Cleanup to perform after each test.
//
func teardown() {
+ data_manager_token = ""
enforce_permissions = false
PermissionSecret = nil
KeepVM = nil
diff --git a/services/keep/src/keep/perms.go b/services/keep/src/keep/perms.go
index 3ad7bb0..0d1b091 100644
--- a/services/keep/src/keep/perms.go
+++ b/services/keep/src/keep/perms.go
@@ -66,8 +66,9 @@ func MakePermSignature(blob_hash string, api_token string, expiry string) string
// SignLocator takes a blob_locator, an api_token and an expiry time, and
// returns a signed locator string.
func SignLocator(blob_locator string, api_token string, expiry time.Time) string {
- // If the permission secret has not been set, return an unsigned locator.
- if PermissionSecret == nil {
+ // If no permission secret or API token is available,
+ // return an unsigned locator.
+ if PermissionSecret == nil || api_token == "" {
return blob_locator
}
// Extract the hash from the blob locator, omitting any size hint that may be present.
-----------------------------------------------------------------------
hooks/post-receive
--
More information about the arvados-commits
mailing list