Skip to content

Commit f58c4eb

Browse files
authored
Merge pull request #10 from enguerr/master
add compatibility with CEPH S3 and s3cmd
2 parents 7914025 + 8e89434 commit f58c4eb

File tree

2 files changed

+36
-2
lines changed

2 files changed

+36
-2
lines changed

handler.go

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,10 @@ import (
1717
log "github.com/sirupsen/logrus"
1818
)
1919

20-
var awsAuthorizationCredentialRegexp = regexp.MustCompile("Credential=([a-zA-Z0-9]+)/[0-9]+/([a-z]+-?[a-z]+-?[0-9]+)/s3/aws4_request")
20+
// - new less strict regexp in order to allow different region naming (compatibility with other providers)
21+
// - east-eu-1 => pass (aws style)
22+
// - gra => pass (ceph style)
23+
var awsAuthorizationCredentialRegexp = regexp.MustCompile("Credential=([a-zA-Z0-9]+)/[0-9]+/([a-zA-Z-0-9]+)/s3/aws4_request")
2124
var awsAuthorizationSignedHeadersRegexp = regexp.MustCompile("SignedHeaders=([a-zA-Z0-9;-]+)")
2225

2326
// Handler is a special handler that re-signs any AWS S3 request and sends it upstream
@@ -225,9 +228,16 @@ func (h *Handler) buildUpstreamRequest(req *http.Request) (*http.Request, error)
225228
return nil, err
226229
}
227230

231+
// WORKAROUND S3CMD which dont use white space before the some commas in the authorization header
232+
fakeAuthorizationStr := fakeReq.Header.Get("Authorization")
233+
// Sanitize fakeReq to add white spaces after the comma signature if missing
234+
authorizationStr := strings.Replace(req.Header["Authorization"][0], ",Signature", ", Signature", 1)
235+
// Sanitize fakeReq to add white spaces after the comma signheaders if missing
236+
authorizationStr = strings.Replace(authorizationStr, ",SignedHeaders", ", SignedHeaders", 1)
237+
228238
// Verify that the fake request and the incoming request have the same signature
229239
// This ensures it was sent and signed by a client with correct AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY
230-
cmpResult := subtle.ConstantTimeCompare([]byte(fakeReq.Header["Authorization"][0]), []byte(req.Header["Authorization"][0]))
240+
cmpResult := subtle.ConstantTimeCompare([]byte(fakeAuthorizationStr), []byte(authorizationStr))
231241
if cmpResult == 0 {
232242
v, _ := httputil.DumpRequest(fakeReq, false)
233243
log.Debugf("Fake request: %v", string(v))

handler_test.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,12 @@ func verifySignature(w http.ResponseWriter, r *http.Request) {
7979
signer.Sign(r, body, "s3", "eu-test-1", signTime)
8080
expectedAuthorization := r.Header["Authorization"][0]
8181

82+
// WORKAROUND S3CMD who dont use white space before the comma in the authorization header
83+
// Sanitize fakeReq to remove white spaces before the comma signature
84+
receivedAuthorization = strings.Replace(receivedAuthorization, ",Signature", ", Signature", 1)
85+
// Sanitize fakeReq to remove white spaces before the comma signheaders
86+
receivedAuthorization = strings.Replace(receivedAuthorization, ",SignedHeaders", ", SignedHeaders", 1)
87+
8288
// verify signature
8389
fmt.Fprintln(w, receivedAuthorization, expectedAuthorization)
8490
if receivedAuthorization == expectedAuthorization {
@@ -143,6 +149,24 @@ func TestHandlerValidSignature(t *testing.T) {
143149
assert.Equal(t, 200, resp.Code)
144150
assert.Contains(t, resp.Body.String(), "Hello, client")
145151
}
152+
func TestHandlerValidSignatureS3cmd(t *testing.T) {
153+
h := newTestProxy(t)
154+
155+
req := httptest.NewRequest(http.MethodGet, "http://foobar.example.com", nil)
156+
signRequest(req)
157+
// get the generated signed authorization header in order to simulate the s3cmd syntax
158+
authorizationReq := req.Header.Get("Authorization")
159+
// simulating s3cmd syntax and remove the whites space after the comma of the Signature part
160+
authorizationReq = strings.Replace(authorizationReq, ", Signature", ",Signature", 1)
161+
// simulating s3cmd syntax and remove the whites space before the comma of the SignedHeaders part
162+
authorizationReq = strings.Replace(authorizationReq, ", SignedHeaders", ",SignedHeaders", 1)
163+
// push the edited authorization header
164+
req.Header.Set("Authorization", authorizationReq)
165+
resp := httptest.NewRecorder()
166+
h.ServeHTTP(resp, req)
167+
assert.Equal(t, 200, resp.Code)
168+
assert.Contains(t, resp.Body.String(), "Hello, client")
169+
}
146170

147171
func TestHandlerInvalidCredential(t *testing.T) {
148172
h := newTestProxy(t)

0 commit comments

Comments
 (0)