[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