Merge pull request #28 from nemunaire/b/signedurl_for_custom_endpoint
Rework presign function to allow signature of clients with dedicated endpoint
This commit is contained in:
+24
-18
@@ -5,6 +5,7 @@ import (
|
|||||||
"crypto/sha256"
|
"crypto/sha256"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
"path"
|
||||||
"sort"
|
"sort"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
@@ -24,8 +25,6 @@ type PresignedInput struct {
|
|||||||
Timestamp time.Time
|
Timestamp time.Time
|
||||||
ExtraHeaders map[string]string
|
ExtraHeaders map[string]string
|
||||||
ExpirySeconds int
|
ExpirySeconds int
|
||||||
Protocol string
|
|
||||||
Endpoint string
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// GeneratePresignedURL creates a Presigned URL that can be used
|
// GeneratePresignedURL creates a Presigned URL that can be used
|
||||||
@@ -35,8 +34,9 @@ func (s3 *S3) GeneratePresignedURL(in PresignedInput) string {
|
|||||||
var (
|
var (
|
||||||
nowTime = nowTime()
|
nowTime = nowTime()
|
||||||
|
|
||||||
protocol = defaultProtocol
|
protocol = defaultProtocol
|
||||||
endpoint = defaultPresignedHost
|
hostname = defaultPresignedHost
|
||||||
|
path_prefix = ""
|
||||||
)
|
)
|
||||||
if !in.Timestamp.IsZero() {
|
if !in.Timestamp.IsZero() {
|
||||||
nowTime = in.Timestamp.UTC()
|
nowTime = in.Timestamp.UTC()
|
||||||
@@ -52,11 +52,16 @@ func (s3 *S3) GeneratePresignedURL(in PresignedInput) string {
|
|||||||
b.Reset()
|
b.Reset()
|
||||||
|
|
||||||
// Set the protocol as default if not provided.
|
// Set the protocol as default if not provided.
|
||||||
if in.Protocol != "" {
|
if endpoint, _ := url.Parse(s3.Endpoint); endpoint.Host != "" {
|
||||||
protocol = in.Protocol
|
protocol = endpoint.Scheme + "://"
|
||||||
}
|
hostname = endpoint.Host
|
||||||
if in.Endpoint != "" {
|
path_prefix = path.Join("/", endpoint.Path, in.Bucket)
|
||||||
endpoint = in.Endpoint
|
} else {
|
||||||
|
host := bytes.Buffer{}
|
||||||
|
host.WriteString(in.Bucket)
|
||||||
|
host.WriteRune('.')
|
||||||
|
host.WriteString(hostname)
|
||||||
|
hostname = host.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add host to Headers
|
// Add host to Headers
|
||||||
@@ -64,16 +69,13 @@ func (s3 *S3) GeneratePresignedURL(in PresignedInput) string {
|
|||||||
for k, v := range in.ExtraHeaders {
|
for k, v := range in.ExtraHeaders {
|
||||||
signedHeaders[k] = []byte(v)
|
signedHeaders[k] = []byte(v)
|
||||||
}
|
}
|
||||||
host := bytes.Buffer{}
|
signedHeaders["host"] = []byte(hostname)
|
||||||
host.WriteString(in.Bucket)
|
|
||||||
host.WriteRune('.')
|
|
||||||
host.WriteString(endpoint)
|
|
||||||
signedHeaders["host"] = host.Bytes()
|
|
||||||
|
|
||||||
// Start Canonical Request Formation
|
// Start Canonical Request Formation
|
||||||
h := sha256.New() // We write the canonical request directly to the SHA256 hash.
|
h := sha256.New() // We write the canonical request directly to the SHA256 hash.
|
||||||
h.Write([]byte(in.Method)) // HTTP Verb
|
h.Write([]byte(in.Method)) // HTTP Verb
|
||||||
h.Write(newLine)
|
h.Write(newLine)
|
||||||
|
h.Write([]byte(path_prefix))
|
||||||
h.Write([]byte{'/'})
|
h.Write([]byte{'/'})
|
||||||
h.Write([]byte(in.ObjectKey)) // CanonicalURL
|
h.Write([]byte(in.ObjectKey)) // CanonicalURL
|
||||||
h.Write(newLine)
|
h.Write(newLine)
|
||||||
@@ -193,10 +195,14 @@ func (s3 *S3) GeneratePresignedURL(in PresignedInput) string {
|
|||||||
b.Reset()
|
b.Reset()
|
||||||
|
|
||||||
// Start Generating URL
|
// Start Generating URL
|
||||||
b.WriteString(protocol)
|
if s3.Endpoint != "" {
|
||||||
b.WriteString(in.Bucket)
|
b.WriteString(s3.Endpoint)
|
||||||
b.WriteRune('.')
|
b.WriteRune('/')
|
||||||
b.WriteString(endpoint)
|
b.WriteString(in.Bucket)
|
||||||
|
} else {
|
||||||
|
b.WriteString(protocol)
|
||||||
|
b.WriteString(hostname)
|
||||||
|
}
|
||||||
b.WriteRune('/')
|
b.WriteRune('/')
|
||||||
b.WriteString(in.ObjectKey)
|
b.WriteString(in.ObjectKey)
|
||||||
b.WriteRune('?')
|
b.WriteRune('?')
|
||||||
|
|||||||
+4
-4
@@ -60,10 +60,10 @@ func TestS3_GeneratePresignedURL_Personal(t *testing.T) {
|
|||||||
os.Getenv("AWS_S3_ACCESS_KEY"),
|
os.Getenv("AWS_S3_ACCESS_KEY"),
|
||||||
os.Getenv("AWS_S3_SECRET_KEY"),
|
os.Getenv("AWS_S3_SECRET_KEY"),
|
||||||
)
|
)
|
||||||
|
s.Endpoint = os.Getenv("AWS_S3_ENDPOINT")
|
||||||
dontwant := ""
|
dontwant := ""
|
||||||
if got := s.GeneratePresignedURL(PresignedInput{
|
if got := s.GeneratePresignedURL(PresignedInput{
|
||||||
Bucket: os.Getenv("AWS_S3_BUCKET"),
|
Bucket: os.Getenv("AWS_S3_BUCKET"),
|
||||||
Endpoint: os.Getenv("AWS_S3_ENDPOINT"),
|
|
||||||
ObjectKey: "test1.txt",
|
ObjectKey: "test1.txt",
|
||||||
Method: "GET",
|
Method: "GET",
|
||||||
Timestamp: nowTime(),
|
Timestamp: nowTime(),
|
||||||
@@ -81,10 +81,10 @@ func TestS3_GeneratePresignedURL_ExtraHeader(t *testing.T) {
|
|||||||
os.Getenv("AWS_S3_ACCESS_KEY"),
|
os.Getenv("AWS_S3_ACCESS_KEY"),
|
||||||
os.Getenv("AWS_S3_SECRET_KEY"),
|
os.Getenv("AWS_S3_SECRET_KEY"),
|
||||||
)
|
)
|
||||||
|
s.Endpoint = os.Getenv("AWS_S3_ENDPOINT")
|
||||||
dontwant := ""
|
dontwant := ""
|
||||||
if got := s.GeneratePresignedURL(PresignedInput{
|
if got := s.GeneratePresignedURL(PresignedInput{
|
||||||
Bucket: os.Getenv("AWS_S3_BUCKET"),
|
Bucket: os.Getenv("AWS_S3_BUCKET"),
|
||||||
Endpoint: os.Getenv("AWS_S3_ENDPOINT"),
|
|
||||||
ObjectKey: "test2.txt",
|
ObjectKey: "test2.txt",
|
||||||
Method: "GET",
|
Method: "GET",
|
||||||
Timestamp: nowTime(),
|
Timestamp: nowTime(),
|
||||||
@@ -105,10 +105,10 @@ func TestS3_GeneratePresignedURL_PUT(t *testing.T) {
|
|||||||
os.Getenv("AWS_S3_ACCESS_KEY"),
|
os.Getenv("AWS_S3_ACCESS_KEY"),
|
||||||
os.Getenv("AWS_S3_SECRET_KEY"),
|
os.Getenv("AWS_S3_SECRET_KEY"),
|
||||||
)
|
)
|
||||||
|
s.Endpoint = os.Getenv("AWS_S3_ENDPOINT")
|
||||||
dontwant := ""
|
dontwant := ""
|
||||||
if got := s.GeneratePresignedURL(PresignedInput{
|
if got := s.GeneratePresignedURL(PresignedInput{
|
||||||
Bucket: os.Getenv("AWS_S3_BUCKET"),
|
Bucket: os.Getenv("AWS_S3_BUCKET"),
|
||||||
Endpoint: os.Getenv("AWS_S3_ENDPOINT"),
|
|
||||||
ObjectKey: "test2.txt",
|
ObjectKey: "test2.txt",
|
||||||
Method: "PUT",
|
Method: "PUT",
|
||||||
Timestamp: nowTime(),
|
Timestamp: nowTime(),
|
||||||
@@ -126,13 +126,13 @@ func BenchmarkS3_GeneratePresigned(b *testing.B) {
|
|||||||
os.Getenv("AWS_S3_ACCESS_KEY"),
|
os.Getenv("AWS_S3_ACCESS_KEY"),
|
||||||
os.Getenv("AWS_S3_SECRET_KEY"),
|
os.Getenv("AWS_S3_SECRET_KEY"),
|
||||||
)
|
)
|
||||||
|
s.Endpoint = os.Getenv("AWS_S3_ENDPOINT")
|
||||||
|
|
||||||
b.ReportAllocs()
|
b.ReportAllocs()
|
||||||
b.ResetTimer()
|
b.ResetTimer()
|
||||||
for n := 0; n < b.N; n++ {
|
for n := 0; n < b.N; n++ {
|
||||||
s.GeneratePresignedURL(PresignedInput{
|
s.GeneratePresignedURL(PresignedInput{
|
||||||
Bucket: os.Getenv("AWS_S3_BUCKET"),
|
Bucket: os.Getenv("AWS_S3_BUCKET"),
|
||||||
Endpoint: os.Getenv("AWS_S3_ENDPOINT"),
|
|
||||||
ObjectKey: "test.txt",
|
ObjectKey: "test.txt",
|
||||||
Method: "GET",
|
Method: "GET",
|
||||||
Timestamp: nowTime(),
|
Timestamp: nowTime(),
|
||||||
|
|||||||
Reference in New Issue
Block a user