Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support PUT and DELETE operation #125

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 7 additions & 6 deletions Dockerfile.oss
Original file line number Diff line number Diff line change
Expand Up @@ -16,20 +16,21 @@ ENV CORS_ENABLED 0
# 4. Explicitly install the version of njs coded in the environment variable
# above.

COPY common/etc /etc
COPY common/docker-entrypoint.sh /docker-entrypoint.sh
COPY common/docker-entrypoint.d /docker-entrypoint.d/
COPY oss/etc /etc

RUN set -eux \
export DEBIAN_FRONTEND=noninteractive; \
mkdir -p /var/cache/nginx/s3_proxy; \
chown nginx:nginx /var/cache/nginx/s3_proxy; \
chmod -R -v +x /docker-entrypoint.sh /docker-entrypoint.d/*.sh; \
echo "deb https://nginx.org/packages/mainline/debian/ $(echo $PKG_RELEASE | cut -f2 -d~) nginx" >> /etc/apt/sources.list.d/nginx.list; \
apt-get update; \
apt-get install --no-install-recommends --no-install-suggests --yes \
curl nginx-module-njs=${NGINX_VERSION}+${NJS_VERSION}-${PKG_RELEASE}; \
apt-get install --yes vim procps net-tools iputils-ping; \
apt-get remove --purge --auto-remove --yes; \
rm -rf /var/lib/apt/lists/* /etc/apt/sources.list.d/nginx.list

COPY common/docker-entrypoint.sh /docker-entrypoint.sh
COPY common/docker-entrypoint.d /docker-entrypoint.d/
COPY oss/etc /etc
COPY common/etc /etc

RUN chmod -R -v +x /docker-entrypoint.sh /docker-entrypoint.d/*.sh; \
8 changes: 4 additions & 4 deletions common/docker-entrypoint.sh
Original file line number Diff line number Diff line change
Expand Up @@ -52,11 +52,11 @@ export CORS_ENABLED="$(parseBoolean "${CORS_ENABLED}")"
# is not normally used as part of the gateway. The following variable
# defines the set of acceptable headers.
if [ "${CORS_ENABLED}" == "1" ]; then
export LIMIT_METHODS_TO="GET HEAD OPTIONS"
export LIMIT_METHODS_TO_CSV="GET, HEAD, OPTIONS"
export LIMIT_METHODS_TO="GET HEAD OPTIONS PUT DELETE"
export LIMIT_METHODS_TO_CSV="GET, HEAD, OPTIONS, PUT, DELETE"
else
export LIMIT_METHODS_TO="GET HEAD"
export LIMIT_METHODS_TO_CSV="GET, HEAD"
export LIMIT_METHODS_TO="GET HEAD PUT DELETE"
export LIMIT_METHODS_TO_CSV="GET, HEAD, PUT, DELETE"
fi

if [ -z "${CORS_ALLOWED_ORIGIN+x}" ]; then
Expand Down
20 changes: 16 additions & 4 deletions common/etc/nginx/include/awssig4.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,9 @@ const DEFAULT_SIGNED_HEADERS = 'host;x-amz-content-sha256;x-amz-date';
function signatureV4(r, timestamp, region, service, uri, queryParams, host, credentials) {
const eightDigitDate = utils.getEightDigitDate(timestamp);
const amzDatetime = utils.getAmzDatetime(timestamp, eightDigitDate);
const payloadHash = getPayloadHash(r.requestText);
const canonicalRequest = _buildCanonicalRequest(
r.method, uri, queryParams, host, amzDatetime, credentials.sessionToken);
r.method, uri, queryParams, host, amzDatetime, credentials.sessionToken, payloadHash);
const signature = _buildSignatureV4(r, amzDatetime, eightDigitDate,
credentials, region, service, canonicalRequest);
const authHeader = 'AWS4-HMAC-SHA256 Credential='
Expand All @@ -61,6 +62,16 @@ function signatureV4(r, timestamp, region, service, uri, queryParams, host, cred
return authHeader;
}

function getPayloadHash(payloadString) {
let payloadHash = EMPTY_PAYLOAD_HASH;
if (typeof payloadString !== 'undefined' && payloadString.length > 0) {
payloadHash = mod_hmac.createHash('sha256')
.update(payloadString)
.digest('hex');
}
return payloadHash;
}

/**
* Creates a canonical request that will later be signed
*
Expand All @@ -73,9 +84,9 @@ function signatureV4(r, timestamp, region, service, uri, queryParams, host, cred
* @returns {string} string with concatenated request parameters
* @private
*/
function _buildCanonicalRequest(method, uri, queryParams, host, amzDatetime, sessionToken) {
function _buildCanonicalRequest(method, uri, queryParams, host, amzDatetime, sessionToken, payloadHash) {
let canonicalHeaders = 'host:' + host + '\n' +
'x-amz-content-sha256:' + EMPTY_PAYLOAD_HASH + '\n' +
'x-amz-content-sha256:' + payloadHash + '\n' +
'x-amz-date:' + amzDatetime + '\n';

if (sessionToken) {
Expand All @@ -87,7 +98,7 @@ function _buildCanonicalRequest(method, uri, queryParams, host, amzDatetime, ses
canonicalRequest += queryParams + '\n';
canonicalRequest += canonicalHeaders + '\n';
canonicalRequest += _signedHeaders(sessionToken) + '\n';
canonicalRequest += EMPTY_PAYLOAD_HASH;
canonicalRequest += payloadHash;

return canonicalRequest;
}
Expand Down Expand Up @@ -253,6 +264,7 @@ function _splitCachedValues(cached) {

export default {
signatureV4,
getPayloadHash,
// These functions do not need to be exposed, but they are exposed so that
// unit tests can run against them.
_buildCanonicalRequest,
Expand Down
12 changes: 5 additions & 7 deletions common/etc/nginx/include/s3gateway.js
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,10 @@ function awsHeaderDate(r) {
return utils.getAmzDatetime(NOW, utils.getEightDigitDate(NOW));
}

function awsContentSHA256(r) {
return awssig4.getPayloadHash(r.requestText);
}

/**
* Creates an AWS authentication signature based on the global settings and
* the passed request parameter.
Expand Down Expand Up @@ -342,13 +346,6 @@ function _s3DirQueryParams(uriPath, method) {
* @param r {Request} HTTP request object
*/
function redirectToS3(r) {
// This is a read-only S3 gateway, so we do not support any other methods
if (!(r.method === 'GET' || r.method === 'HEAD')) {
utils.debug_log(r, 'Invalid method requested: ' + r.method);
r.internalRedirect("@error405");
return;
}

const uriPath = r.variables.uri_path;
const isDirectoryListing = ALLOW_LISTING && _isDirectory(uriPath);

Expand Down Expand Up @@ -704,6 +701,7 @@ async function _fetchWebIdentityCredentials(r) {

export default {
awsHeaderDate,
awsContentSHA256,
fetchCredentials,
s3date,
s3auth,
Expand Down
8 changes: 4 additions & 4 deletions common/etc/nginx/templates/default.conf.template
Original file line number Diff line number Diff line change
Expand Up @@ -128,10 +128,10 @@ server {

# Catch all errors from S3 and sanitize them so that the user can't
# gain intelligence about the S3 bucket being proxied.
proxy_intercept_errors on;
#proxy_intercept_errors on;

# Comment out this line to receive the error messages returned by S3
error_page 400 401 402 403 405 406 407 408 409 410 411 412 413 414 415 416 417 418 420 422 423 424 426 428 429 431 444 449 450 451 500 501 502 503 504 505 506 507 508 509 510 511 =404 @error404;
#error_page 400 401 402 403 405 406 407 408 409 410 411 412 413 414 415 416 417 418 420 422 423 424 426 428 429 431 444 449 450 451 500 501 502 503 504 505 506 507 508 509 510 511 =404 @error404;

error_page 404 @trailslashControl;

Expand Down Expand Up @@ -188,10 +188,10 @@ server {

# Catch all errors from S3 and sanitize them so that the user can't
# gain intelligence about the S3 bucket being proxied.
proxy_intercept_errors on;
proxy_intercept_errors off;

# Comment out this line to receive the error messages returned by S3
error_page 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 420 422 423 424 426 428 429 431 444 449 450 451 500 501 502 503 504 505 506 507 508 509 510 511 =404 @error404;
#error_page 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 420 422 423 424 426 428 429 431 444 449 450 451 500 501 502 503 504 505 506 507 508 509 510 511 =404 @error404;

proxy_pass ${S3_SERVER_PROTO}://storage_urls$s3Uri;
include /etc/nginx/conf.d/gateway/s3listing_location.conf;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@ proxy_set_header x-amz-date $awsDate;

# All HTTP bodies are empty because we are only doing GET/HEAD requests,
# so we can hardcode the body checksum.
proxy_set_header x-amz-content-sha256 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855';
proxy_set_header x-amz-content-sha256 $awsContentSHA256;
2 changes: 2 additions & 0 deletions common/etc/nginx/templates/gateway/v4_js_vars.conf.template
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,5 @@
# specifies the timestamp in which the signature was generated and is used with
# the x-amz-date header.
js_set $awsDate s3gateway.awsHeaderDate;

js_set $awsContentSHA256 s3gateway.awsContentSHA256;