Add configuration for AWS authentication V4

Supports aws-v2, aws-v4, aws-v2-or-v4, and none.  Fixes #156.
pull/176/merge
Andrew Gaul 2016-11-13 21:11:33 -08:00
rodzic 80e256435e
commit 04657867b8
8 zmienionych plików z 98 dodań i 21 usunięć

Wyświetl plik

@ -0,0 +1,31 @@
/*
* Copyright 2014-2016 Andrew Gaul <andrew@gaul.org>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.gaul.s3proxy;
import com.google.common.base.CaseFormat;
public enum AuthenticationType {
AWS_V2,
AWS_V4,
AWS_V2_OR_V4,
NONE;
static AuthenticationType fromString(String string) {
return AuthenticationType.valueOf(CaseFormat.LOWER_HYPHEN.to(
CaseFormat.UPPER_UNDERSCORE, string));
}
}

Wyświetl plik

@ -84,10 +84,10 @@ public final class Main {
S3ProxyConstants.PROPERTY_ENDPOINT);
String secureEndpoint = properties.getProperty(
S3ProxyConstants.PROPERTY_SECURE_ENDPOINT);
String s3ProxyAuthorization = properties.getProperty(
String s3ProxyAuthorizationString = properties.getProperty(
S3ProxyConstants.PROPERTY_AUTHORIZATION);
if ((s3ProxyEndpointString == null && secureEndpoint == null) ||
s3ProxyAuthorization == null) {
s3ProxyAuthorizationString == null) {
System.err.println("Properties file must contain:\n" +
S3ProxyConstants.PROPERTY_AUTHORIZATION + "\n" +
"and one of\n" +
@ -96,9 +96,14 @@ public final class Main {
System.exit(1);
}
AuthenticationType s3ProxyAuthorization =
AuthenticationType.fromString(s3ProxyAuthorizationString);
String localIdentity = null;
String localCredential = null;
if (s3ProxyAuthorization.equalsIgnoreCase("aws-v2")) {
switch (s3ProxyAuthorization) {
case AWS_V2:
case AWS_V4:
case AWS_V2_OR_V4:
localIdentity = properties.getProperty(
S3ProxyConstants.PROPERTY_IDENTITY);
localCredential = properties.getProperty(
@ -107,12 +112,15 @@ public final class Main {
System.err.println("Must specify both " +
S3ProxyConstants.PROPERTY_IDENTITY + " and " +
S3ProxyConstants.PROPERTY_CREDENTIAL +
" when using aws-v2 authentication");
" when using authentication");
System.exit(1);
}
} else if (!s3ProxyAuthorization.equalsIgnoreCase("none")) {
break;
case NONE:
break;
default:
System.err.println(S3ProxyConstants.PROPERTY_AUTHORIZATION +
" must be aws-v2 or none, was: " + s3ProxyAuthorization);
" invalid value, was: " + s3ProxyAuthorization);
System.exit(1);
}
@ -171,7 +179,8 @@ public final class Main {
s3ProxyBuilder.secureEndpoint(new URI(secureEndpoint));
}
if (localIdentity != null || localCredential != null) {
s3ProxyBuilder.awsAuthentication(localIdentity,
s3ProxyBuilder.awsAuthentication(
s3ProxyAuthorization, localIdentity,
localCredential);
}
if (keyStorePath != null || keyStorePassword != null) {

Wyświetl plik

@ -30,6 +30,7 @@ final class S3AuthorizationHeader {
// TODO: these fields should have accessors
// CHECKSTYLE:OFF
final AuthenticationType authenticationType;
final String hmacAlgorithm;
final String hashAlgorithm;
final String region;
@ -41,7 +42,7 @@ final class S3AuthorizationHeader {
S3AuthorizationHeader(String header) {
if (header.startsWith("AWS ")) {
// AWS v2 header
authenticationType = AuthenticationType.AWS_V2;
hmacAlgorithm = null;
hashAlgorithm = null;
region = null;
@ -58,7 +59,7 @@ final class S3AuthorizationHeader {
identity = identityTuple[0];
signature = identityTuple[1];
} else if (header.startsWith("AWS4-HMAC")) {
// AWS v4 header
authenticationType = AuthenticationType.AWS_V4;
signature = extractSignature(header);
int credentialIndex = header.indexOf(CREDENTIAL_FIELD);

Wyświetl plik

@ -101,7 +101,8 @@ public final class S3Proxy {
} else {
listenHTTPS = false;
}
handler = new S3ProxyHandlerJetty(builder.blobStore, builder.identity,
handler = new S3ProxyHandlerJetty(builder.blobStore,
builder.authenticationType, builder.identity,
builder.credential, Optional.fromNullable(builder.virtualHost),
builder.v4MaxNonChunkedRequestSize,
builder.ignoreUnknownHeaders, builder.corsAllowAll);
@ -112,6 +113,8 @@ public final class S3Proxy {
private BlobStore blobStore;
private URI endpoint;
private URI secureEndpoint;
private AuthenticationType authenticationType =
AuthenticationType.NONE;
private String identity;
private String credential;
private String keyStorePath;
@ -143,7 +146,9 @@ public final class S3Proxy {
return this;
}
public Builder awsAuthentication(String identity, String credential) {
public Builder awsAuthentication(AuthenticationType authenticationType,
String identity, String credential) {
this.authenticationType = authenticationType;
this.identity = requireNonNull(identity);
this.credential = requireNonNull(credential);
return this;
@ -223,5 +228,4 @@ public final class S3Proxy {
public void setBlobStoreLocator(BlobStoreLocator lookup) {
handler.getHandler().setBlobStoreLocator(lookup);
}
}

Wyświetl plik

@ -195,6 +195,7 @@ public class S3ProxyHandler {
private static final int B2_PUT_BLOB_BUFFER_SIZE = 1024 * 1024;
private final boolean anonymousIdentity;
private final AuthenticationType authenticationType;
private final Optional<String> virtualHost;
private final long v4MaxNonChunkedRequestSize;
private final boolean ignoreUnknownHeaders;
@ -216,7 +217,8 @@ public class S3ProxyHandler {
.expireAfterWrite(10, TimeUnit.MINUTES)
.build();
public S3ProxyHandler(final BlobStore blobStore, final String identity,
public S3ProxyHandler(final BlobStore blobStore,
AuthenticationType authenticationType, final String identity,
final String credential, Optional<String> virtualHost,
long v4MaxNonChunkedRequestSize, boolean ignoreUnknownHeaders,
boolean corsAllowAll) {
@ -244,6 +246,7 @@ public class S3ProxyHandler {
}
};
}
this.authenticationType = authenticationType;
this.virtualHost = requireNonNull(virtualHost);
this.v4MaxNonChunkedRequestSize = v4MaxNonChunkedRequestSize;
this.ignoreUnknownHeaders = ignoreUnknownHeaders;
@ -385,6 +388,30 @@ public class S3ProxyHandler {
}
}
switch (authHeader.authenticationType) {
case AWS_V2:
switch (authenticationType) {
case AWS_V2:
case AWS_V2_OR_V4:
break;
default:
throw new S3Exception(S3ErrorCode.INVALID_ARGUMENT);
}
break;
case AWS_V4:
switch (authenticationType) {
case AWS_V4:
case AWS_V2_OR_V4:
break;
default:
throw new S3Exception(S3ErrorCode.INVALID_ARGUMENT);
}
break;
default:
throw new IllegalArgumentException("Unhandled type: " +
authHeader.authenticationType);
}
String expectedSignature = null;
if (authHeader.hmacAlgorithm == null) {
expectedSignature = createAuthorizationSignature(request,

Wyświetl plik

@ -40,13 +40,14 @@ import org.jclouds.util.Throwables2;
final class S3ProxyHandlerJetty extends AbstractHandler {
private final S3ProxyHandler handler;
S3ProxyHandlerJetty(final BlobStore blobStore, final String identity,
S3ProxyHandlerJetty(final BlobStore blobStore,
AuthenticationType authenticationType, final String identity,
final String credential, Optional<String> virtualHost,
long v4MaxNonChunkedRequestSize, boolean ignoreUnknownHeaders,
boolean corsAllowAll) {
handler = new S3ProxyHandler(blobStore, identity, credential,
virtualHost, v4MaxNonChunkedRequestSize, ignoreUnknownHeaders,
corsAllowAll);
handler = new S3ProxyHandler(blobStore, authenticationType, identity,
credential, virtualHost, v4MaxNonChunkedRequestSize,
ignoreUnknownHeaders, corsAllowAll);
}
@Override

Wyświetl plik

@ -160,6 +160,10 @@ final class TestUtils {
}
String endpoint = info.getProperties().getProperty(
Constants.PROPERTY_ENDPOINT);
String s3ProxyAuthorizationString = info.getProperties().getProperty(
S3ProxyConstants.PROPERTY_AUTHORIZATION);
AuthenticationType s3ProxyAuthorization =
AuthenticationType.fromString(s3ProxyAuthorizationString);
info.s3Identity = info.getProperties().getProperty(
S3ProxyConstants.PROPERTY_IDENTITY);
info.s3Credential = info.getProperties().getProperty(
@ -193,8 +197,8 @@ final class TestUtils {
s3ProxyBuilder.secureEndpoint(new URI(secureEndpoint));
}
if (info.getS3Identity() != null || info.getS3Credential() != null) {
s3ProxyBuilder.awsAuthentication(info.getS3Identity(),
info.getS3Credential());
s3ProxyBuilder.awsAuthentication(s3ProxyAuthorization,
info.getS3Identity(), info.getS3Credential());
}
if (keyStorePath != null || keyStorePassword != null) {
s3ProxyBuilder.keyStore(

Wyświetl plik

@ -1,7 +1,7 @@
s3proxy.endpoint=http://127.0.0.1:0
s3proxy.secure-endpoint=https://127.0.0.1:0
# authorization must be aws-v2 or none
s3proxy.authorization=aws-v2
# authorization must be aws-v2, aws-v4, aws-v2-or-v4, or none
s3proxy.authorization=aws-v2-or-v4
s3proxy.identity=local-identity
s3proxy.credential=local-credential
s3proxy.keystore-path=keystore.jks