[ARVADOS] created: aeff59bfaf199eec6884ccf3ff60968bec81f581

git at public.curoverse.com git at public.curoverse.com
Fri May 2 15:10:36 EDT 2014


        at  aeff59bfaf199eec6884ccf3ff60968bec81f581 (commit)


commit aeff59bfaf199eec6884ccf3ff60968bec81f581
Author: Tim Pierce <twp at curoverse.com>
Date:   Fri May 2 15:09:46 2014 -0400

    Update docs. (refs #2328)

diff --git a/services/keep/src/keep/perms.go b/services/keep/src/keep/perms.go
index 7bbae4f..217afb4 100644
--- a/services/keep/src/keep/perms.go
+++ b/services/keep/src/keep/perms.go
@@ -43,12 +43,13 @@ import (
 	"strings"
 )
 
-// The PermissionSecret is the secret key used to generate SHA1 digests
-// for permission hints. apiserver and Keep must use the same key.
+// The PermissionSecret is the secret key used to generate SHA1
+// digests for permission hints. apiserver and Keep must use the same
+// key.
 var PermissionSecret []byte
 
-// GeneratePerms returns a string representing the permission hint for a blob
-// with the given hash, API token and timestamp.
+// GeneratePerms returns a string representing the signed permission
+// hint for the blob identified by blob_hash, api_token and timestamp.
 func GeneratePerms(blob_hash string, api_token string, timestamp string) string {
 	hmac := hmac.New(sha1.New, PermissionSecret)
 	hmac.Write([]byte(blob_hash))
@@ -60,6 +61,8 @@ func GeneratePerms(blob_hash string, api_token string, timestamp string) string
 	return fmt.Sprintf("%x", digest)
 }
 
+// SignLocator takes a blob_locator, an api_token and a timestamp, and
+// returns a signed locator string.
 func SignLocator(blob_locator string, api_token string, timestamp string) string {
 	// Extract the hash from the blob locator, omitting any size hint that may be present.
 	blob_hash := strings.Split(blob_locator, "+")[0]
@@ -67,6 +70,8 @@ func SignLocator(blob_locator string, api_token string, timestamp string) string
 	return blob_locator + "+A" + GeneratePerms(blob_hash, api_token, timestamp) + "@" + timestamp
 }
 
+// VerifySignature returns true if the signature on the signed_locator
+// can be verified using the given api_token.
 func VerifySignature(signed_locator string, api_token string) bool {
 	if re, err := regexp.Compile(`^(.*)\+A(.*)@(.*)$`); err == nil {
 		if matches := re.FindStringSubmatch(signed_locator); matches != nil {

commit 8023ae393e2c9ce115bf67bbcf632798a3d17b87
Author: Tim Pierce <twp at curoverse.com>
Date:   Fri May 2 15:05:07 2014 -0400

    Added permission helper functions.
    
    GeneratePerms returns a string representing the signed permission hint
    for the blob identified by blob_hash, api_token and timestamp.
    
    SignLocator takes a blob_locator, an api_token and a timestamp, and
    returns a signed locator string.
    
    VerifySignature returns true if the signature on the signed_locator can
    be verified using the given api_token.
    
    Refs #2328.

diff --git a/services/keep/src/keep/perms.go b/services/keep/src/keep/perms.go
new file mode 100644
index 0000000..7bbae4f
--- /dev/null
+++ b/services/keep/src/keep/perms.go
@@ -0,0 +1,79 @@
+/*
+Permissions management on Arvados locator hashes.
+
+The permissions structure for Arvados is as follows (from
+https://arvados.org/issues/2328)
+
+A Keep locator string has the following format:
+
+    [hash]+[size]+A[signature]@[timestamp]
+
+The "signature" string here is a cryptographic hash, expressed as a
+string of hexadecimal digits, and timestamp is a 32-bit Unix timestamp
+expressed as a hexadecimal number.  e.g.:
+
+    acbd18db4cc2f85cedef654fccc4a4d8+3+A257f3f5f5f0a4e4626a18fc74bd42ec34dcb228a at 7fffffff
+
+The signature represents a guarantee that this locator was generated
+by either Keep or the API server for the user with the supplied API
+token.  If a request to Keep includes a locator with a valid signature
+and is accompanied by the proper API token, the user has permission to
+perform any action on that object (GET, PUT or DELETE).
+
+The signature may be generated either by Keep (after the user writes a
+block) or by the API server (if the user has can_read permission on
+the specified object). Keep and API server share a secret that is used
+to generate signatures.
+
+To verify a permission hint, Keep generates a new hint for the
+requested object (using the locator string, the timestamp, the
+permission secret and the user's API token, which must appear in the
+request headers) and compares it against the hint included in the
+request. If the permissions do not match, or if the API token is not
+present, Keep returns a 401 error.
+*/
+
+package main
+
+import (
+	"crypto/hmac"
+	"crypto/sha1"
+	"fmt"
+	"regexp"
+	"strings"
+)
+
+// The PermissionSecret is the secret key used to generate SHA1 digests
+// for permission hints. apiserver and Keep must use the same key.
+var PermissionSecret []byte
+
+// GeneratePerms returns a string representing the permission hint for a blob
+// with the given hash, API token and timestamp.
+func GeneratePerms(blob_hash string, api_token string, timestamp string) string {
+	hmac := hmac.New(sha1.New, PermissionSecret)
+	hmac.Write([]byte(blob_hash))
+	hmac.Write([]byte("@"))
+	hmac.Write([]byte(api_token))
+	hmac.Write([]byte("@"))
+	hmac.Write([]byte(timestamp))
+	digest := hmac.Sum(nil)
+	return fmt.Sprintf("%x", digest)
+}
+
+func SignLocator(blob_locator string, api_token string, timestamp string) string {
+	// Extract the hash from the blob locator, omitting any size hint that may be present.
+	blob_hash := strings.Split(blob_locator, "+")[0]
+	// Return the signed locator string.
+	return blob_locator + "+A" + GeneratePerms(blob_hash, api_token, timestamp) + "@" + timestamp
+}
+
+func VerifySignature(signed_locator string, api_token string) bool {
+	if re, err := regexp.Compile(`^(.*)\+A(.*)@(.*)$`); err == nil {
+		if matches := re.FindStringSubmatch(signed_locator); matches != nil {
+			blob_locator := matches[1]
+			timestamp := matches[3]
+			return signed_locator == SignLocator(blob_locator, api_token, timestamp)
+		}
+	}
+	return false
+}
diff --git a/services/keep/src/keep/perms_test.go b/services/keep/src/keep/perms_test.go
new file mode 100644
index 0000000..fcd17e1
--- /dev/null
+++ b/services/keep/src/keep/perms_test.go
@@ -0,0 +1,97 @@
+package main
+
+import (
+	"testing"
+)
+
+var (
+	known_hash    = "acbd18db4cc2f85cedef654fccc4a4d8"
+	known_locator = known_hash + "+3"
+	known_token   = "hocfupkn2pjhrpgp2vxv8rsku7tvtx49arbc9s4bvu7p7wxqvk"
+	known_key     = "13u9fkuccnboeewr0ne3mvapk28epf68a3bhj9q8sb4l6e4e5mkk" +
+		"p6nhj2mmpscgu1zze5h5enydxfe3j215024u16ij4hjaiqs5u4pzsl3nczmaoxnc" +
+		"ljkm4875xqn4xv058koz3vkptmzhyheiy6wzevzjmdvxhvcqsvr5abhl15c2d4o4" +
+		"jhl0s91lojy1mtrzqqvprqcverls0xvy9vai9t1l1lvvazpuadafm71jl4mrwq2y" +
+		"gokee3eamvjy8qq1fvy238838enjmy5wzy2md7yvsitp5vztft6j4q866efym7e6" +
+		"vu5wm9fpnwjyxfldw3vbo01mgjs75rgo7qioh8z8ij7jpyp8508okhgbbex3ceei" +
+		"786u5rw2a9gx743dj3fgq2irk"
+	known_signature      = "257f3f5f5f0a4e4626a18fc74bd42ec34dcb228a"
+	known_timestamp      = "7fffffff"
+	known_signed_locator = known_locator + "+A" + known_signature + "@" + known_timestamp
+)
+
+func TestGeneratePerms(t *testing.T) {
+	PermissionSecret = []byte(known_key)
+	defer func() { PermissionSecret = nil }()
+
+	if known_signature != GeneratePerms(known_hash, known_token, known_timestamp) {
+		t.Fail()
+	}
+}
+
+func TestSignLocator(t *testing.T) {
+	PermissionSecret = []byte(known_key)
+	defer func() { PermissionSecret = nil }()
+
+	if known_signed_locator != SignLocator(known_locator, known_token, known_timestamp) {
+		t.Fail()
+	}
+}
+
+func TestVerifySignature(t *testing.T) {
+	PermissionSecret = []byte(known_key)
+	defer func() { PermissionSecret = nil }()
+
+	if !VerifySignature(known_signed_locator, known_token) {
+		t.Fail()
+	}
+}
+
+// The size hint on the locator string should not affect signature validation.
+func TestVerifySignatureWrongSize(t *testing.T) {
+	PermissionSecret = []byte(known_key)
+	defer func() { PermissionSecret = nil }()
+
+	signed_locator_wrong_size := known_hash + "+999999+A" + known_signature + "@" + known_timestamp
+	if !VerifySignature(signed_locator_wrong_size, known_token) {
+		t.Fail()
+	}
+}
+
+func TestVerifySignatureBadSig(t *testing.T) {
+	PermissionSecret = []byte(known_key)
+	defer func() { PermissionSecret = nil }()
+
+	bad_locator := known_locator + "+Aaaaaaaaaaaaaaaa@" + known_timestamp
+	if VerifySignature(bad_locator, known_token) {
+		t.Fail()
+	}
+}
+
+func TestVerifySignatureBadTimestamp(t *testing.T) {
+	PermissionSecret = []byte(known_key)
+	defer func() { PermissionSecret = nil }()
+
+	bad_locator := known_locator + "+A" + known_signature + "@00000000"
+	if VerifySignature(bad_locator, known_token) {
+		t.Fail()
+	}
+}
+
+func TestVerifySignatureBadSecret(t *testing.T) {
+	PermissionSecret = []byte("00000000000000000000")
+	defer func() { PermissionSecret = nil }()
+
+	if VerifySignature(known_signed_locator, known_token) {
+		t.Fail()
+	}
+}
+
+func TestVerifySignatureBadToken(t *testing.T) {
+	PermissionSecret = []byte(known_key)
+	defer func() { PermissionSecret = nil }()
+
+	if VerifySignature(known_signed_locator, "00000000") {
+		t.Fail()
+	}
+}

-----------------------------------------------------------------------


hooks/post-receive
-- 




More information about the arvados-commits mailing list