[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