We have an on premise S3 service which I try to connect using the Java AWS SDK v2.
My application uses Spring-boot 3 and my maven build file contains dependency:
<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>s3</artifactId>
<version>2.24.6</version>
</dependency>
The configuration of the S3 client looks like:
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.s3.S3Client;
@Configuration
public class FileStore2Configuration {
@Bean
S3Client s3Client(String host, String accessKey, String credentials) {
System.setProperty("aws.accessKeyId", accessKey);
System.setProperty("aws.secretAccessKey", credentials);
System.setProperty("aws.region", Region.EU_WEST_1.id());
System.setProperty("aws.endpointUrl", host);
S3Client client= S3Client.builder()
.endpointOverride(URI.create(host))
.forcePathStyle(Boolean.TRUE)
.build();
return client;
}
}
This client is injected in a Component to build a presigned url:
import software.amazon.awssdk.services.s3.S3Client;
import software.amazon.awssdk.services.s3.presigner.S3Presigner;
import software.amazon.awssdk.services.s3.presigner.model.PresignedPutObjectRequest;
import software.amazon.awssdk.services.s3.presigner.model.PutObjectPresignRequest;
@Component
public class AWS2FileStoreService implements FileStoreService {
public static final Logger LOGGER = LoggerFactory.getLogger(AWS2FileStoreService.class);
private S3Client s3Client;
public String bucket;
public AWS2FileStoreService(S3Client awsClient, String bucket) {
LOGGER.info("AWSFileStoreService initialized for bucket {}",bucket);
this.bucket=bucket;
this.s3Client = awsClient;
}
@Override
public String createUploadLink(String path, String filename) throws Exception {
String fullName = concat(path,filename);
try (S3Presigner presigner = S3Presigner.builder().s3Client(s3Client).build()) {
PutObjectRequest objectRequest = PutObjectRequest.builder()
.bucket(bucket)
.key(fullName)
.build();
PutObjectPresignRequest presignRequest = PutObjectPresignRequest.builder()
.signatureDuration(Duration.ofDays(1)) // The URL will expire in 1 day.
.putObjectRequest(objectRequest)
.build();
PresignedPutObjectRequest presignedRequest = presigner.presignPutObject(presignRequest);
LOGGER.info("Presigned URL: [{}]", presignedRequest.url());
LOGGER.info("HTTP method: [{}]", presignedRequest.httpRequest().method());
if(!presignedRequest.isBrowserExecutable())
LOGGER.warn("Presigned url [{}] is not browser executable",presignedRequest.url());
return presignedRequest.url().toExternalForm();
}
}
}
When I try this implementation:
public class AmazonS3SmokeTry {
private static String host="https://my.internal.server:9021";
private static String accessKey="internalUser";
private static String credentials="internalPW";
public static void main(String[] args) throws Exception {
S3Client client=new FileStore2Configuration().s3Client(host, accessKey, credentials);
AWS2FileStoreService filestore=new AWS2FileStoreService(client,"bucket-dev");
System.out.println("upload link to taskupload/newfile.xml:"+filestore.createUploadLink("/taskupload", "newfile.xml"));
}
}
the output is:
upload link to taskupload/newfile.xml:https://bucket-dev.s3.eu-west-1.amazonaws.com//taskupload/newfile.xml?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Date=20240613T112924Z&X-Amz-SignedHeaders=host&X-Amz-Credential=internal-user%2F20240613%2Feu-west-1%2Fs3%2Faws4_request
Notice it ignores my host configuration and the bucket name is used as part of the domain where it should be part of the path (hence call on .forcePathStyle(Boolean.TRUE)
.
I would expect a URL like : https://my.internal.server:9021/bucket-dev/taskupload/newfile.xml?…
As you can see I tried setting the system property aws.endpointUrl and setting the host through the S3Client builder .endpointOverride(host)
method. However all without success.
Any suggestions how I can make this work ?
Thanks already.