[ARVADOS] created: b938fd6d63a7dade2124d0873b20329d8a27f224

git at public.curoverse.com git at public.curoverse.com
Thu Oct 8 16:54:07 EDT 2015


        at  b938fd6d63a7dade2124d0873b20329d8a27f224 (commit)


commit b938fd6d63a7dade2124d0873b20329d8a27f224
Author: radhika <radhika at curoverse.com>
Date:   Wed Oct 7 16:47:56 2015 -0400

    7167: move perms code from keepstore into keepclient go SDK.

diff --git a/services/keepstore/perms.go b/sdk/go/keepclient/perms.go
similarity index 68%
copy from services/keepstore/perms.go
copy to sdk/go/keepclient/perms.go
index 5579238..5b792a8 100644
--- a/services/keepstore/perms.go
+++ b/sdk/go/keepclient/perms.go
@@ -33,7 +33,7 @@ request. If the permissions do not match, or if the API token is not
 present, Keep returns a 401 error.
 */
 
-package main
+package keepclient
 
 import (
 	"crypto/hmac"
@@ -45,15 +45,29 @@ import (
 	"time"
 )
 
-// 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
+// KeepError types.
+//
+type KeepError struct {
+	HTTPCode int
+	ErrMsg   string
+}
+
+var (
+	PermissionError = &KeepError{403, "Forbidden"}
+	ExpiredError    = &KeepError{401, "Expired permission signature"}
+)
+
+func (e *KeepError) Error() string {
+	return e.ErrMsg
+}
 
-// MakePermSignature returns a string representing the signed permission
-// hint for the blob identified by blobHash, apiToken and expiration timestamp.
-func MakePermSignature(blobHash string, apiToken string, expiry string) string {
-	hmac := hmac.New(sha1.New, PermissionSecret)
+// makePermSignature returns a string representing the signed permission
+// hint for the blob identified by blobHash, apiToken, expiration timestamp, and permission secret.
+//
+// The permissionSecret is the secret key used to generate SHA1 digests
+// for permission hints. apiserver and Keep must use the same key.
+func makePermSignature(blobHash string, apiToken string, expiry string, permissionSecret []byte) string {
+	hmac := hmac.New(sha1.New, permissionSecret)
 	hmac.Write([]byte(blobHash))
 	hmac.Write([]byte("@"))
 	hmac.Write([]byte(apiToken))
@@ -63,12 +77,12 @@ func MakePermSignature(blobHash string, apiToken string, expiry string) string {
 	return fmt.Sprintf("%x", digest)
 }
 
-// SignLocator takes a blobLocator, an apiToken and an expiry time, and
-// returns a signed locator string.
-func SignLocator(blobLocator string, apiToken string, expiry time.Time) string {
+// SignLocator takes a blobLocator, an apiToken, an expiry time, and a permission secret
+// and returns a signed locator string.
+func SignLocator(blobLocator string, apiToken string, expiry time.Time, permissionSecret []byte) string {
 	// If no permission secret or API token is available,
 	// return an unsigned locator.
-	if PermissionSecret == nil || apiToken == "" {
+	if permissionSecret == nil || apiToken == "" {
 		return blobLocator
 	}
 	// Extract the hash from the blob locator, omitting any size hint that may be present.
@@ -76,7 +90,7 @@ func SignLocator(blobLocator string, apiToken string, expiry time.Time) string {
 	// Return the signed locator string.
 	timestampHex := fmt.Sprintf("%08x", expiry.Unix())
 	return blobLocator +
-		"+A" + MakePermSignature(blobHash, apiToken, timestampHex) +
+		"+A" + makePermSignature(blobHash, apiToken, timestampHex, permissionSecret) +
 		"@" + timestampHex
 }
 
@@ -87,7 +101,7 @@ var signedLocatorRe = regexp.MustCompile(`^([[:xdigit:]]{32}).*\+A([[:xdigit:]]{
 // either ExpiredError (if the timestamp has expired, which is
 // something the client could have figured out independently) or
 // PermissionError.
-func VerifySignature(signedLocator string, apiToken string) error {
+func VerifySignature(signedLocator string, apiToken string, permissionSecret []byte) error {
 	matches := signedLocatorRe.FindStringSubmatch(signedLocator)
 	if matches == nil {
 		// Could not find a permission signature at all
@@ -96,19 +110,19 @@ func VerifySignature(signedLocator string, apiToken string) error {
 	blobHash := matches[1]
 	sigHex := matches[2]
 	expHex := matches[3]
-	if expTime, err := ParseHexTimestamp(expHex); err != nil {
+	if expTime, err := parseHexTimestamp(expHex); err != nil {
 		return PermissionError
 	} else if expTime.Before(time.Now()) {
 		return ExpiredError
 	}
-	if sigHex != MakePermSignature(blobHash, apiToken, expHex) {
+	if sigHex != makePermSignature(blobHash, apiToken, expHex, permissionSecret) {
 		return PermissionError
 	}
 	return nil
 }
 
-// ParseHexTimestamp parses timestamp
-func ParseHexTimestamp(timestampHex string) (ts time.Time, err error) {
+// parseHexTimestamp parses timestamp
+func parseHexTimestamp(timestampHex string) (ts time.Time, err error) {
 	if tsInt, e := strconv.ParseInt(timestampHex, 16, 0); e == nil {
 		ts = time.Unix(tsInt, 0)
 	} else {
diff --git a/services/keepstore/perms_test.go b/sdk/go/keepclient/perms_test.go
similarity index 62%
copy from services/keepstore/perms_test.go
copy to sdk/go/keepclient/perms_test.go
index 59516af..61d10c1 100644
--- a/services/keepstore/perms_test.go
+++ b/sdk/go/keepclient/perms_test.go
@@ -1,4 +1,4 @@
-package main
+package keepclient
 
 import (
 	"testing"
@@ -23,103 +23,76 @@ const (
 )
 
 func TestSignLocator(t *testing.T) {
-	PermissionSecret = []byte(knownKey)
-	defer func() { PermissionSecret = nil }()
-
-	if ts, err := ParseHexTimestamp(knownTimestamp); err != nil {
+	if ts, err := parseHexTimestamp(knownTimestamp); err != nil {
 		t.Errorf("bad knownTimestamp %s", knownTimestamp)
 	} else {
-		if knownSignedLocator != SignLocator(knownLocator, knownToken, ts) {
+		if knownSignedLocator != SignLocator(knownLocator, knownToken, ts, []byte(knownKey)) {
 			t.Fail()
 		}
 	}
 }
 
 func TestVerifySignature(t *testing.T) {
-	PermissionSecret = []byte(knownKey)
-	defer func() { PermissionSecret = nil }()
-
-	if VerifySignature(knownSignedLocator, knownToken) != nil {
+	if VerifySignature(knownSignedLocator, knownToken, []byte(knownKey)) != nil {
 		t.Fail()
 	}
 }
 
 func TestVerifySignatureExtraHints(t *testing.T) {
-	PermissionSecret = []byte(knownKey)
-	defer func() { PermissionSecret = nil }()
-
-	if VerifySignature(knownLocator+"+K at xyzzy"+knownSigHint, knownToken) != nil {
+	if VerifySignature(knownLocator+"+K at xyzzy"+knownSigHint, knownToken, []byte(knownKey)) != nil {
 		t.Fatal("Verify cannot handle hint before permission signature")
 	}
 
-	if VerifySignature(knownLocator+knownSigHint+"+Zfoo", knownToken) != nil {
+	if VerifySignature(knownLocator+knownSigHint+"+Zfoo", knownToken, []byte(knownKey)) != nil {
 		t.Fatal("Verify cannot handle hint after permission signature")
 	}
 
-	if VerifySignature(knownLocator+"+K at xyzzy"+knownSigHint+"+Zfoo", knownToken) != nil {
+	if VerifySignature(knownLocator+"+K at xyzzy"+knownSigHint+"+Zfoo", knownToken, []byte(knownKey)) != nil {
 		t.Fatal("Verify cannot handle hints around permission signature")
 	}
 }
 
 // The size hint on the locator string should not affect signature validation.
 func TestVerifySignatureWrongSize(t *testing.T) {
-	PermissionSecret = []byte(knownKey)
-	defer func() { PermissionSecret = nil }()
-
-	if VerifySignature(knownHash+"+999999"+knownSigHint, knownToken) != nil {
+	if VerifySignature(knownHash+"+999999"+knownSigHint, knownToken, []byte(knownKey)) != nil {
 		t.Fatal("Verify cannot handle incorrect size hint")
 	}
 
-	if VerifySignature(knownHash+knownSigHint, knownToken) != nil {
+	if VerifySignature(knownHash+knownSigHint, knownToken, []byte(knownKey)) != nil {
 		t.Fatal("Verify cannot handle missing size hint")
 	}
 }
 
 func TestVerifySignatureBadSig(t *testing.T) {
-	PermissionSecret = []byte(knownKey)
-	defer func() { PermissionSecret = nil }()
-
 	badLocator := knownLocator + "+Aaaaaaaaaaaaaaaa@" + knownTimestamp
-	if VerifySignature(badLocator, knownToken) != PermissionError {
+	if VerifySignature(badLocator, knownToken, []byte(knownKey)) != PermissionError {
 		t.Fail()
 	}
 }
 
 func TestVerifySignatureBadTimestamp(t *testing.T) {
-	PermissionSecret = []byte(knownKey)
-	defer func() { PermissionSecret = nil }()
-
 	badLocator := knownLocator + "+A" + knownSignature + "@OOOOOOOl"
-	if VerifySignature(badLocator, knownToken) != PermissionError {
+	if VerifySignature(badLocator, knownToken, []byte(knownKey)) != PermissionError {
 		t.Fail()
 	}
 }
 
 func TestVerifySignatureBadSecret(t *testing.T) {
-	PermissionSecret = []byte("00000000000000000000")
-	defer func() { PermissionSecret = nil }()
-
-	if VerifySignature(knownSignedLocator, knownToken) != PermissionError {
+	if VerifySignature(knownSignedLocator, knownToken, []byte("00000000000000000000")) != PermissionError {
 		t.Fail()
 	}
 }
 
 func TestVerifySignatureBadToken(t *testing.T) {
-	PermissionSecret = []byte(knownKey)
-	defer func() { PermissionSecret = nil }()
-
-	if VerifySignature(knownSignedLocator, "00000000") != PermissionError {
+	if VerifySignature(knownSignedLocator, "00000000", []byte(knownKey)) != PermissionError {
 		t.Fail()
 	}
 }
 
 func TestVerifySignatureExpired(t *testing.T) {
-	PermissionSecret = []byte(knownKey)
-	defer func() { PermissionSecret = nil }()
-
 	yesterday := time.Now().AddDate(0, 0, -1)
-	expiredLocator := SignLocator(knownHash, knownToken, yesterday)
-	if VerifySignature(expiredLocator, knownToken) != ExpiredError {
+	expiredLocator := SignLocator(knownHash, knownToken, yesterday, []byte(knownKey))
+	if VerifySignature(expiredLocator, knownToken, []byte(knownKey)) != ExpiredError {
 		t.Fail()
 	}
 }
diff --git a/services/keepstore/perms.go b/services/keepstore/perms.go
index 5579238..494e6b7 100644
--- a/services/keepstore/perms.go
+++ b/services/keepstore/perms.go
@@ -36,12 +36,7 @@ present, Keep returns a 401 error.
 package main
 
 import (
-	"crypto/hmac"
-	"crypto/sha1"
-	"fmt"
-	"regexp"
-	"strconv"
-	"strings"
+	"git.curoverse.com/arvados.git/sdk/go/keepclient"
 	"time"
 )
 
@@ -50,69 +45,25 @@ import (
 // key.
 var PermissionSecret []byte
 
-// MakePermSignature returns a string representing the signed permission
-// hint for the blob identified by blobHash, apiToken and expiration timestamp.
-func MakePermSignature(blobHash string, apiToken string, expiry string) string {
-	hmac := hmac.New(sha1.New, PermissionSecret)
-	hmac.Write([]byte(blobHash))
-	hmac.Write([]byte("@"))
-	hmac.Write([]byte(apiToken))
-	hmac.Write([]byte("@"))
-	hmac.Write([]byte(expiry))
-	digest := hmac.Sum(nil)
-	return fmt.Sprintf("%x", digest)
-}
-
 // SignLocator takes a blobLocator, an apiToken and an expiry time, and
 // returns a signed locator string.
 func SignLocator(blobLocator string, apiToken string, expiry time.Time) string {
-	// If no permission secret or API token is available,
-	// return an unsigned locator.
-	if PermissionSecret == nil || apiToken == "" {
-		return blobLocator
-	}
-	// Extract the hash from the blob locator, omitting any size hint that may be present.
-	blobHash := strings.Split(blobLocator, "+")[0]
-	// Return the signed locator string.
-	timestampHex := fmt.Sprintf("%08x", expiry.Unix())
-	return blobLocator +
-		"+A" + MakePermSignature(blobHash, apiToken, timestampHex) +
-		"@" + timestampHex
+	return keepclient.SignLocator(blobLocator, apiToken, expiry, PermissionSecret)
 }
 
-var signedLocatorRe = regexp.MustCompile(`^([[:xdigit:]]{32}).*\+A([[:xdigit:]]{40})@([[:xdigit:]]{8})`)
-
 // VerifySignature returns nil if the signature on the signedLocator
 // can be verified using the given apiToken. Otherwise it returns
 // either ExpiredError (if the timestamp has expired, which is
 // something the client could have figured out independently) or
 // PermissionError.
 func VerifySignature(signedLocator string, apiToken string) error {
-	matches := signedLocatorRe.FindStringSubmatch(signedLocator)
-	if matches == nil {
-		// Could not find a permission signature at all
-		return PermissionError
-	}
-	blobHash := matches[1]
-	sigHex := matches[2]
-	expHex := matches[3]
-	if expTime, err := ParseHexTimestamp(expHex); err != nil {
-		return PermissionError
-	} else if expTime.Before(time.Now()) {
-		return ExpiredError
-	}
-	if sigHex != MakePermSignature(blobHash, apiToken, expHex) {
-		return PermissionError
-	}
-	return nil
-}
-
-// ParseHexTimestamp parses timestamp
-func ParseHexTimestamp(timestampHex string) (ts time.Time, err error) {
-	if tsInt, e := strconv.ParseInt(timestampHex, 16, 0); e == nil {
-		ts = time.Unix(tsInt, 0)
-	} else {
-		err = e
+	err := keepclient.VerifySignature(signedLocator, apiToken, PermissionSecret)
+	if err != nil {
+		if err == keepclient.PermissionError {
+			return PermissionError
+		} else if err == keepclient.ExpiredError {
+			return ExpiredError
+		}
 	}
-	return ts, err
+	return err
 }
diff --git a/services/keepstore/perms_test.go b/services/keepstore/perms_test.go
index 59516af..9b4e30a 100644
--- a/services/keepstore/perms_test.go
+++ b/services/keepstore/perms_test.go
@@ -1,6 +1,7 @@
 package main
 
 import (
+	"strconv"
 	"testing"
 	"time"
 )
@@ -26,12 +27,12 @@ func TestSignLocator(t *testing.T) {
 	PermissionSecret = []byte(knownKey)
 	defer func() { PermissionSecret = nil }()
 
-	if ts, err := ParseHexTimestamp(knownTimestamp); err != nil {
-		t.Errorf("bad knownTimestamp %s", knownTimestamp)
-	} else {
-		if knownSignedLocator != SignLocator(knownLocator, knownToken, ts) {
-			t.Fail()
-		}
+	tsInt, err := strconv.ParseInt(knownTimestamp, 16, 0)
+	if err != nil {
+		t.Fail()
+	}
+	if knownSignedLocator != SignLocator(knownLocator, knownToken, time.Unix(tsInt, 0)) {
+		t.Fail()
 	}
 }
 

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


hooks/post-receive
-- 




More information about the arvados-commits mailing list