in aws-iot-device-sdk-java/src/main/java/com/amazonaws/services/iot/client/util/AwsIotWebSocketUrlSigner.java [224:301]
public String getSignedUrl(final Date signingDate) throws AWSIotException {
CredentialsProvider provider = null;
synchronized (this) {
provider = credentialsProvider;
}
if (provider == null) {
throw new AWSIotException("No credentials provider available for signing");
}
Credentials credentials = provider.getCredentials();
if (credentials == null) {
throw new AWSIotException("Could not source AWS credentials from provider");
}
String awsAccessKeyId = credentials.getAccessKeyId();
Date dateToUse = signingDate;
if (dateToUse == null) {
dateToUse = new Date();
}
// SigV4 canonical string uses time in two formats
String amzDate = getAmzDate(dateToUse);
String dateStamp = getDateStamp(dateToUse);
// Credential scoped to date and region
String credentialScope = dateStamp + "/" + regionName + "/" + ServiceName + "/aws4_request";
// Now build the canonical string
StringBuilder canonicalQueryStringBuilder = new StringBuilder();
canonicalQueryStringBuilder.append("X-Amz-Algorithm=").append(ALGORITHM);
canonicalQueryStringBuilder.append("&X-Amz-Credential=");
try {
canonicalQueryStringBuilder.append(URLEncoder.encode(awsAccessKeyId + "/" + credentialScope, UTF8));
} catch (UnsupportedEncodingException e) {
throw new AWSIotException("Error encoding URL when building WebSocket URL");
}
canonicalQueryStringBuilder.append("&X-Amz-Date=").append(amzDate);
canonicalQueryStringBuilder.append("&X-Amz-SignedHeaders=host");
// headers and payload for the signing request
// not used in an WebSocket URL, but encoded into the signature string
String canonicalHeaders = "host:" + endpoint + "\n";
String payloadHash = stringToHex(hash(""));
// The request to sign includes the HTTP method, path, query string,
// headers and payload
String canonicalRequest = METHOD + "\n" + CANONICAL_URI + "\n" + canonicalQueryStringBuilder.toString() + "\n"
+ canonicalHeaders + "\nhost\n" + payloadHash;
// Create a string to sign, generate a signing key...
String stringToSign = ALGORITHM + "\n" + amzDate + "\n" + credentialScope + "\n"
+ stringToHex(hash(canonicalRequest));
byte[] signingKey = getSigningKey(credentials, dateStamp);
// ...and sign the string.
byte[] signatureBytes = sign(stringToSign, signingKey);
String signature = stringToHex(signatureBytes);
// Add the signature to the query string.
canonicalQueryStringBuilder.append("&X-Amz-Signature=");
canonicalQueryStringBuilder.append(signature);
// Now build the URL.
String requestUrl = "wss://" + endpoint + CANONICAL_URI + "?" + canonicalQueryStringBuilder.toString();
// If there are session credentials (from an STS server, AssumeRole, or
// Amazon Cognito),
// append the session token to the end of the URL string after signing.
String sessionToken = credentials.getSessionToken();
if (sessionToken != null) {
try {
requestUrl += "&X-Amz-Security-Token=" + URLEncoder.encode(sessionToken, UTF8);
} catch (UnsupportedEncodingException e) {
throw new AWSIotException(e);
}
}
return requestUrl;
}