com.amazonaws.services.sns.message.SnsMessageManager Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of aws-java-sdk-sns Show documentation
Show all versions of aws-java-sdk-sns Show documentation
The AWS Java SDK for Amazon SNS module holds the client classes that are used for communicating with Amazon Simple Notification Service
/*
* Copyright 2012-2024 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance with
* the License. A copy of the License is located at
*
* http://aws.amazon.com/apache2.0
*
* or in the "license" file accompanying this file. This file 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 com.amazonaws.services.sns.message;
import static com.amazonaws.regions.Regions.AP_EAST_1;
import com.amazonaws.SdkClientException;
import com.amazonaws.annotation.SdkTestInternalApi;
import com.amazonaws.regions.DefaultAwsRegionProviderChain;
import com.amazonaws.regions.RegionUtils;
import com.amazonaws.regions.Regions;
import com.amazonaws.services.sns.AmazonSNS;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.IOException;
import java.io.InputStream;
import org.apache.http.client.HttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
/**
* Unmarshalls an SNS message and validates it using the SNS public certificate.
*/
public class SnsMessageManager {
private static final ObjectMapper MAPPER = new ObjectMapper();
/**
* HTTP client to download certificate from and visit subscription confirmation URLs.
*/
private final HttpClient client = HttpClientBuilder.create().build();
/**
* Verifies the signature of the message.
*/
private final SignatureVerifier signatureVerifier;
/**
* Unmarshalls message JSON into Java POJOs.
*/
private final SnsMessageUnmarshaller messageUnmarshaller;
/**
* Expected endpoint for messages being published.
*/
private final String endpoint;
/**
* Creates an {@link SnsMessageManager} using the AWS region obtained from the environment. See
* Region Selection
* for more information.
*/
public SnsMessageManager() {
this(new DefaultAwsRegionProviderChain().getRegion());
}
/**
* Creates an {@link SnsMessageManager} pinned to the given region. This handler will throw an exception if it
* recieves a message from another region. If you must handle messages from multiple regions then you should
* maintain a cache of region to {@link SnsMessageManager} instances.
*
* @param region Region to pin handler to.
*/
public SnsMessageManager(String region) {
this.endpoint = RegionUtils.getRegion(region).getServiceEndpoint(AmazonSNS.ENDPOINT_PREFIX);
this.signatureVerifier = new SignatureVerifier(client, endpoint, resolveCertCommonName(region));
this.messageUnmarshaller = new SnsMessageUnmarshaller(client);
}
@SdkTestInternalApi
SnsMessageManager(String region, SignatureVerifier signatureVerifier) {
this.endpoint = RegionUtils.getRegion(region).getServiceEndpoint(AmazonSNS.ENDPOINT_PREFIX);
this.signatureVerifier = signatureVerifier;
this.messageUnmarshaller = new SnsMessageUnmarshaller(client);
}
/**
* Unmarshalls a message into a subclass of {@link SnsMessage}. This will automatically validate the authenticity of the
* mesage to ensure it was sent by SNS. If the validity of the message cannot be verified an exception will be thrown.
*
* @param messageBody Input stream containing message JSON.
* @return Unmarshalled message object.
*/
public SnsMessage parseMessage(InputStream messageBody) {
JsonNode messageJson = toJson(messageBody);
signatureVerifier.verifySignature(messageJson);
return messageUnmarshaller.unmarshall(messageJson);
}
/**
* Unmarshalls a message and delivers it to the given handler.
*
* @param messageBody Input stream containing message JSON.
* @param handler Handler to process message.
*/
public void handleMessage(InputStream messageBody, SnsMessageHandler handler) {
parseMessage(messageBody).handle(handler);
}
private JsonNode toJson(InputStream messageBody) {
try {
return MAPPER.readTree(messageBody);
} catch (IOException e) {
throw new SdkClientException("Could not parse message as JSON.", e);
}
}
//TODO SNS team will use a consistent pattern for certificate naming. Then remove the special handling based on region
@SdkTestInternalApi
String resolveCertCommonName(String regionStr) {
Regions region;
try {
region = Regions.fromName(regionStr);
} catch (IllegalArgumentException exception) {
return "sns." + RegionUtils.getRegion(regionStr).getDomain();
}
switch (region) {
case CN_NORTH_1:
return "sns-cn-north-1.amazonaws.com.cn";
case CN_NORTHWEST_1:
return "sns-cn-northwest-1.amazonaws.com.cn";
case GovCloud:
case US_GOV_EAST_1:
return "sns-us-gov-west-1.amazonaws.com";
case US_ISO_EAST_1:
return "sns-us-iso-east-1.c2s.ic.gov";
case US_ISOB_EAST_1:
return "sns-us-isob-east-1.sc2s.sgov.gov";
case AP_EAST_1:
case AP_SOUTH_2:
case ME_SOUTH_1:
case ME_CENTRAL_1:
case EU_SOUTH_1:
case EU_SOUTH_2:
case EU_CENTRAL_2:
case AF_SOUTH_1:
case AP_SOUTHEAST_3:
case AP_SOUTHEAST_4:
case IL_CENTRAL_1:
case CA_WEST_1:
return "sns-signing." + regionStr + ".amazonaws.com";
default:
return "sns.amazonaws.com";
}
}
}