X-Git-Url: https://git.arvados.org/arvados.git/blobdiff_plain/740d71d2b7a797bb2dd2e1e427c12e84c86b9ce6..46b11ba2ed71e2c074e9e6c8f5b9f7a003e7067f:/services/keepstore/perms.go diff --git a/services/keepstore/perms.go b/services/keepstore/perms.go index 143815576b..5579238112 100644 --- a/services/keepstore/perms.go +++ b/services/keepstore/perms.go @@ -51,57 +51,66 @@ import ( var PermissionSecret []byte // MakePermSignature returns a string representing the signed permission -// hint for the blob identified by blob_hash, api_token and expiration timestamp. -func MakePermSignature(blob_hash string, api_token string, expiry string) string { +// 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(blob_hash)) + hmac.Write([]byte(blobHash)) hmac.Write([]byte("@")) - hmac.Write([]byte(api_token)) + hmac.Write([]byte(apiToken)) hmac.Write([]byte("@")) hmac.Write([]byte(expiry)) digest := hmac.Sum(nil) return fmt.Sprintf("%x", digest) } -// SignLocator takes a blob_locator, an api_token and an expiry time, and +// SignLocator takes a blobLocator, an apiToken and an expiry time, and // returns a signed locator string. -func SignLocator(blob_locator string, api_token string, expiry time.Time) 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 || api_token == "" { - return blob_locator + if PermissionSecret == nil || apiToken == "" { + return blobLocator } // Extract the hash from the blob locator, omitting any size hint that may be present. - blob_hash := strings.Split(blob_locator, "+")[0] + blobHash := strings.Split(blobLocator, "+")[0] // Return the signed locator string. - timestamp_hex := fmt.Sprintf("%08x", expiry.Unix()) - return blob_locator + - "+A" + MakePermSignature(blob_hash, api_token, timestamp_hex) + - "@" + timestamp_hex + timestampHex := fmt.Sprintf("%08x", expiry.Unix()) + return blobLocator + + "+A" + MakePermSignature(blobHash, apiToken, timestampHex) + + "@" + timestampHex } -// 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-f0-9]{32}(\+[0-9]+)?).*\+A[[:xdigit:]]+@([[:xdigit:]]{8})`); err == nil { - if matches := re.FindStringSubmatch(signed_locator); matches != nil { - blob_locator := matches[1] - timestamp_hex := matches[3] - if expire_ts, err := ParseHexTimestamp(timestamp_hex); err == nil { - // Fail signatures with expired timestamps. - if expire_ts.Before(time.Now()) { - return false - } - return signed_locator == SignLocator(blob_locator, api_token, expire_ts) - } - } +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 false + return nil } -func ParseHexTimestamp(timestamp_hex string) (ts time.Time, err error) { - if ts_int, e := strconv.ParseInt(timestamp_hex, 16, 0); e == nil { - ts = time.Unix(ts_int, 0) +// 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 }