Skip to content

Commit

Permalink
Merge pull request #6 from SiaFoundation/chris/return-access-key
Browse files Browse the repository at this point in the history
signature: return access key when V4SignVerify is successful
  • Loading branch information
ChrisSchinnerl committed Apr 23, 2024
2 parents a980d38 + d01e417 commit d7c039f
Show file tree
Hide file tree
Showing 6 changed files with 35 additions and 29 deletions.
2 changes: 1 addition & 1 deletion backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -325,7 +325,7 @@ type MultipartBackend interface {
}

type AuthenticatedBackend interface {
AuthenticationMiddleware(http.Handler) http.Handler
AuthenticateRequest(w http.ResponseWriter, r *http.Request, bucket string) bool
}

// CopyObject is a helper function useful for quickly implementing CopyObject on
Expand Down
5 changes: 0 additions & 5 deletions gofakes3.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,11 +98,6 @@ func (g *GoFakeS3) Server() http.Handler {
} else if g.hostBucket {
handler = g.hostBucketMiddleware(handler)
}

ab, ok := g.storage.(AuthenticatedBackend)
if ok {
handler = ab.AuthenticationMiddleware(handler)
}
return handler
}

Expand Down
8 changes: 8 additions & 0 deletions routing.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,14 @@ func (g *GoFakeS3) routeBase(w http.ResponseWriter, r *http.Request) {
err error
)

// perform authentication if necessary
ab, ok := g.storage.(AuthenticatedBackend)
if ok {
if !ab.AuthenticateRequest(w, r, bucket) {
return // unable to authenticate
}
}

hdr := w.Header()

id := fmt.Sprintf("%016X", g.nextRequestID())
Expand Down
38 changes: 20 additions & 18 deletions signature/signature-v4.go
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ func getSigningKey(secretKey string, t time.Time, region string) []byte {
return signingKey
}

func authTypeSignedVerify(r *http.Request) ErrorCode {
func authTypeSignedVerify(r *http.Request) (string, ErrorCode) {
// Copy request.
req := *r
hashedPayload := getContentSha256Cksum(r)
Expand All @@ -153,32 +153,32 @@ func authTypeSignedVerify(r *http.Request) ErrorCode {
// Parse signature version '4' header.
signV4Values, Err := parseSignV4(v4Auth)
if Err != ErrNone {
return Err
return "", Err
}

cred, _, Err := checkKeyValid(r, signV4Values.Credential.accessKey)
if Err != ErrNone {
return Err
return "", Err
}

// Extract all the signed headers along with its values.
extractedSignedHeaders, ErrCode := extractSignedHeaders(signV4Values.SignedHeaders, r)
if ErrCode != ErrNone {
return ErrCode
return "", ErrCode
}

// Extract date, if not present throw Error.
var date string
if date = req.Header.Get(amzDate); date == "" {
if date = r.Header.Get(headerDate); date == "" {
return errMissingDateHeader
return "", errMissingDateHeader
}
}

// Parse date header.
t, e := time.Parse(iso8601Format, date)
if e != nil {
return errMalformedDate
return "", errMalformedDate
}

// Query string.
Expand All @@ -198,49 +198,51 @@ func authTypeSignedVerify(r *http.Request) ErrorCode {

// Verify if signature match.
if !compareSignatureV4(newSignature, signV4Values.Signature) {
return errSignatureDoesNotMatch
return "", errSignatureDoesNotMatch
}

// Return Error none.
return ErrNone
return cred.AccessKey, ErrNone
}

func authTypeStreamingVerify(r *http.Request, authType authType) ErrorCode {
func authTypeStreamingVerify(r *http.Request, authType authType) (string, ErrorCode) {
var size int64
if sizeStr, ok := r.Header["X-Amz-Decoded-Content-Length"]; ok {
if sizeStr[0] == "" {
return errMissingContentLength
return "", errMissingContentLength
}
var err error
size, err = strconv.ParseInt(sizeStr[0], 10, 64)
if err != nil {
return errMissingContentLength
return "", errMissingContentLength
}
}
var cred Credentials
var rc io.ReadCloser
var ec ErrorCode
switch authType {
case authTypeStreamingSigned, authTypeStreamingSignedTrailer:
rc, ec = newSignV4ChunkedReader(r, authType == authTypeStreamingSignedTrailer)
rc, cred, ec = newSignV4ChunkedReader(r, authType == authTypeStreamingSignedTrailer)
case authTypeStreamingUnsignedTrailer:
return errUnsupportAlgorithm // not supported
return "", errUnsupportAlgorithm // not supported
default:
panic("can't call authTypeStreamingVerify with a non streaming auth type")
}
if ec != ErrNone {
return ec
return "", ec
}
r.Body = rc
r.ContentLength = size
r.Header.Set("Content-Length", fmt.Sprint(size))
return ErrNone
return cred.AccessKey, ErrNone
}

// V4SignVerify - Verify authorization header with calculated header in accordance with
// - http://docs.aws.amazon.com/AmazonS3/latest/API/sig-v4-authenticating-requests.html
//
// returns nil if signature matches.
func V4SignVerify(r *http.Request) ErrorCode {
// returns ErrNone if signature matches alongside the access key used for the
// authentication
func V4SignVerify(r *http.Request) (string, ErrorCode) {
// Make sure the authentication type is supported.
authType := getRequestAuthType(r)
switch authType {
Expand All @@ -249,6 +251,6 @@ func V4SignVerify(r *http.Request) ErrorCode {
case authTypeSigned:
return authTypeSignedVerify(r)
default:
return errUnsupportAlgorithm
return "", errUnsupportAlgorithm
}
}
5 changes: 3 additions & 2 deletions signature/signature-v4_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@ func RandString(n int) string {
}

func TestSignatureMatch(t *testing.T) {

Body := bytes.NewReader(nil)

ak := RandString(32)
Expand All @@ -58,7 +57,9 @@ func TestSignatureMatch(t *testing.T) {
t.Error(err)
}

if result := signature.V4SignVerify(req); result != signature.ErrNone {
if accessKey, result := signature.V4SignVerify(req); result != signature.ErrNone {
t.Error(fmt.Errorf("invalid result: expect none but got %+v", signature.GetAPIError(result)))
} else if accessKey != ak {
t.Error(fmt.Errorf("invalid access key: expect %s but got %s", ak, accessKey))
}
}
6 changes: 3 additions & 3 deletions signature/streaming-signature-v4.go
Original file line number Diff line number Diff line change
Expand Up @@ -165,10 +165,10 @@ var errChunkTooBig = errors.New("chunk too big: choose chunk size <= 16MiB")
//
// NewChunkedReader is not needed by normal applications. The http package
// automatically decodes chunking when reading response bodies.
func newSignV4ChunkedReader(req *http.Request, trailer bool) (io.ReadCloser, ErrorCode) {
func newSignV4ChunkedReader(req *http.Request, trailer bool) (io.ReadCloser, Credentials, ErrorCode) {
cred, seedSignature, region, seedDate, errCode := calculateSeedSignature(req, trailer)
if errCode != ErrNone {
return nil, errCode
return nil, Credentials{}, errCode
}

if trailer {
Expand All @@ -191,7 +191,7 @@ func newSignV4ChunkedReader(req *http.Request, trailer bool) (io.ReadCloser, Err
chunkSHA256Writer: sha256.New(),
buffer: make([]byte, 64*1024),
debug: false,
}, ErrNone
}, cred, ErrNone
}

// Represents the overall state that is required for decoding a
Expand Down

0 comments on commit d7c039f

Please sign in to comment.