Backend API. Server-side code: this runs in a Codename One backend, not in the app on the device.
public final class Aws
- Object
- Aws
AWS Signature Version 4, and the request plumbing every AWS service shares.
This is the whole of what an AWS client needs that is not service specific:
canonicalise a request, derive a signing key, and send it. S3 is one
service built on it; SQS, DynamoDB and Secrets Manager are the same three steps
with a different host and payload, which is why the signer is a separate class
rather than something private to S3.
Written rather than pulled in because the AWS SDK is not an option here: it wants reflection, a class loader and a threading model a translated server binary does not have. SigV4 itself is a hash chain – five HMACs and a SHA-256 – over a canonical form of the request, and the specification is public and stable.
The part that is easy to get wrong, and the reason for the length of this file, is the CANONICAL form: the signature covers a normalised URI, a sorted query string, sorted lower-cased headers and a hash of the body, and a single difference from what the service computes produces a 403 with no indication of which field disagreed.
Fields
public static final String UNSIGNED_PAYLOAD = "UNSIGNED-PAYLOAD" | The unsigned-payload marker, for a body the caller does not want hashed. |
Methods
Inherited methods
Field details
UNSIGNED_PAYLOAD
public static final String UNSIGNED_PAYLOAD = "UNSIGNED-PAYLOAD"Method details
send
public static Web.Result send(Credentials credentials, String region, String service, String method, String host, String path, Map query, Map headers, byte[] body, String timestamp)
throws IOExceptionA signed, sent request.
headers are extra “Name: value” strings; Host, x-amz-date and
x-amz-content-sha256 are added here because they are part of the signature.
Throws
send
public static Web.Result send(Credentials credentials, String region, String service, String method, String host, String path, Map query, Map headers, byte[] body, String timestamp, boolean secure)
throws IOExceptionAs above, over plain HTTP when secure is false.
The signature covers the host and not the scheme, so this changes only how the request travels. It exists for a local MinIO or a test double on loopback; nothing reachable off the machine should use it, and AWS itself does not accept it.
Throws
authorization
public static String authorization(Credentials credentials, String region, String service, String method, String path, Map query, Map headers, String payloadHash, String timestamp)
throws IOExceptionThrows
presign
public static String presign(Credentials credentials, String region, String service, String method, String host, String path, Map query, int expiresSeconds, String timestamp)
throws IOExceptionA presigned URL: the signature travels in the query string, so anyone holding the URL can make that one request until it expires.
This is what hands a mobile client a direct download or upload without proxying the bytes through the server, which is most of the reason to use object storage from an app at all.
Throws
presign
public static String presign(Credentials credentials, String region, String service, String method, String host, String path, Map query, int expiresSeconds, String timestamp, boolean secure)
throws IOExceptionsecure is false. See send.Throws
signingKey
public static byte[] signingKey(String secretKey, String date, String region, String service)
throws IOExceptionThe four-step key derivation. The signing key is scoped to a date, a region and a service, which is what keeps a leaked signature from being reusable anywhere else.
Public, along with the four canonicalisation helpers below, because a service this class does not wrap – SQS, DynamoDB, Secrets Manager – is the same signature over a different payload, and because these are the pieces a known-answer test can pin. A signature implementation that can only be tested end to end is one whose failures all look like 403.
Throws
canonicalQuery
public static String canonicalQuery(Map query)encodePath
public static String encodePath(String path)encode on the whole path.encode
public static String encode(String value)collapse
public static String collapse(String value)sha256Hex
public static String sha256Hex(byte[] data)hex
public static String hex(byte[] data)