Skip to content

Commit fa80722

Browse files
dagnirzoewangg
andauthored
Introduce SNS Message Manager (#6859)
* WIP * Add skeleton SNS msg mgr module (#6788) * Add models and unmarshaller (#6790) * Add CertificateRetriever impl (#6794) CertificateRetriever is responsible for fetching the certificate, validating it, and caching it for future use. * Update parent version * Implement host and CN resolution (#6802) * Implement host and CN resolution SnsHostProvider implements the logic to determine the SNS endpoint for a given region, as well as the expected common name of a signing certificate used by SNS in that region. Both pieces of information used to ensure that the certificate we use to verify the message signature is legitimate. * Remove use of internal API Note: This is in codee that will be deleted. * Implement signature validation (#6800) * SnsMessageManager Impl (#6804) * SnsMessageManager Impl Provides an implementation of the SnsMessageManager. This mostly just ties all the other classes implemented in previous PRs related to the message manager. * Review comments * Allowlist usage of http client builder outside core * Fix test * Remove prototype files (#6830) * Remove prototype files - Remove the original prototype files for the message manager in services/sns - Remove the kiro hooks not intended for release with the sns message manager * Update version in POM Parent version changed after merge from master * Update parent version * Review comments - toString() for models - Javadoc fixes - Make ctor protected * Move design --------- Co-authored-by: Zoe Wang <33073555+zoewangg@users.noreply.github.com>
1 parent 5f0800d commit fa80722

File tree

46 files changed

+3633
-3
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

46 files changed

+3633
-3
lines changed

.brazil.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
"regions": { "packageName": "AwsJavaSdk-Core-Regions" },
3232
"s3-transfer-manager": { "packageName": "AwsJavaSdk-S3-TransferManager" },
3333
"s3-event-notifications": { "packageName": "AwsJavaSdk-S3-EventNotifications" },
34+
"sns-message-manager": { "packageName": "AwsJavaSdk-Sns-MessageManager" },
3435
"sdk-core": { "packageName": "AwsJavaSdk-Core" },
3536
"url-connection-client": { "packageName": "AwsJavaSdk-HttpClient-UrlConnectionClient" },
3637
"utils": { "packageName": "AwsJavaSdk-Core-Utils" },
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"type": "feature",
3+
"category": "Amazon SNS Message Manager",
4+
"contributor": "",
5+
"description": "This change introduces the SNS Message Manager for 2.x, a library used to parse and validate messages received from SNS. This aims to provide the same functionality as [SnsMessageManager](https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/sns/message/SnsMessageManager.html) from 1.x."
6+
}

aws-sdk-java/pom.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -698,6 +698,11 @@ Amazon AutoScaling, etc).</description>
698698
<artifactId>s3-event-notifications</artifactId>
699699
<version>${awsjavasdk.version}</version>
700700
</dependency>
701+
<dependency>
702+
<groupId>software.amazon.awssdk</groupId>
703+
<artifactId>sns-message-manager</artifactId>
704+
<version>${awsjavasdk.version}</version>
705+
</dependency>
701706
<dependency>
702707
<groupId>software.amazon.awssdk</groupId>
703708
<artifactId>sagemaker</artifactId>

bom/pom.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,11 @@
237237
<artifactId>s3-event-notifications</artifactId>
238238
<version>${awsjavasdk.version}</version>
239239
</dependency>
240+
<dependency>
241+
<groupId>software.amazon.awssdk</groupId>
242+
<artifactId>sns-message-manager</artifactId>
243+
<version>${awsjavasdk.version}</version>
244+
</dependency>
240245
<dependency>
241246
<groupId>software.amazon.awssdk</groupId>
242247
<artifactId>aws-crt-client</artifactId>

build-tools/src/main/resources/software/amazon/awssdk/spotbugs-suppressions.xml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -346,6 +346,8 @@
346346
<Class name="~software\.amazon\.awssdk\.auth\.credentials\.ContainerCredentialsProvider" />
347347
<Class name="~software\.amazon\.awssdk\.auth\.credentials\.InstanceProfileCredentialsProvider" />
348348

349+
<Class name="~software\.amazon\.awssdk\.messagemanager\.sns\.internal\.SnsHostProvider" />
350+
349351
<!-- test modules are allowed to make blocking call as parts of their testing -->
350352
<Class name="~.*testutils.*" />
351353
<Class name="~.*s3benchmarks.*" />

core/sdk-core/src/main/java/software/amazon/awssdk/core/internal/http/loader/DefaultSdkHttpClientBuilder.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515

1616
package software.amazon.awssdk.core.internal.http.loader;
1717

18-
import software.amazon.awssdk.annotations.SdkInternalApi;
18+
import software.amazon.awssdk.annotations.SdkProtectedApi;
1919
import software.amazon.awssdk.core.exception.SdkClientException;
2020
import software.amazon.awssdk.http.SdkHttpClient;
2121
import software.amazon.awssdk.http.SdkHttpService;
@@ -24,7 +24,9 @@
2424
/**
2525
* Utility to load the default HTTP client factory and create an instance of {@link SdkHttpClient}.
2626
*/
27-
@SdkInternalApi
27+
// NOTE: This was previously @SdkInternalApi, which is why it's in the .internal. package. It was moved to a protected API to
28+
// allow usage outside of core for modules that need to use an HTTP client directly, such as sns-message-manager.
29+
@SdkProtectedApi
2830
public final class DefaultSdkHttpClientBuilder implements SdkHttpClient.Builder {
2931

3032
private static final SdkHttpServiceProvider<SdkHttpService> DEFAULT_CHAIN = new CachingSdkHttpServiceProvider<>(
Lines changed: 326 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,326 @@
1+
# Design Document
2+
3+
## Overview
4+
5+
The SnsMessageManager feature provides automatic validation of SNS message signatures in AWS SDK for Java v2, following the same architectural pattern as the SqsAsyncBatchManager. This utility will be implemented as a separate manager class within the SNS service module that handles the parsing and cryptographic verification of SNS messages received via HTTP/HTTPS endpoints.
6+
7+
The design follows the established AWS SDK v2 patterns for utility classes, providing a clean API for developers to validate SNS message authenticity without requiring deep knowledge of the underlying cryptographic verification process.
8+
9+
## Usage Examples
10+
11+
### Example 1: Basic Message Validation
12+
13+
```java
14+
// Create the message manager
15+
SnsMessageManager messageManager = SnsMessageManager.builder().build();
16+
17+
// Validate a message from HTTP request body
18+
String messageBody = request.getBody(); // JSON message from SNS
19+
try {
20+
SnsMessage validatedMessage = messageManager.parseMessage(messageBody);
21+
22+
// Access message content
23+
String messageContent = validatedMessage.message();
24+
String topicArn = validatedMessage.topicArn();
25+
String messageType = validatedMessage.type();
26+
27+
// Process the validated message
28+
processNotification(messageContent, topicArn);
29+
30+
} catch (SnsMessageValidationException e) {
31+
// Handle validation failure
32+
logger.error("SNS message validation failed: {}", e.getMessage());
33+
return ResponseEntity.status(HttpStatus.BAD_REQUEST).build();
34+
}
35+
```
36+
37+
### Example 2: Custom Configuration
38+
39+
```java
40+
// Configure certificate caching and timeouts
41+
SnsMessageManager messageManager = SnsMessageManager.builder()
42+
.configuration(config -> config
43+
.certificateCacheTimeout(Duration.ofHours(1))
44+
.httpTimeout(Duration.ofSeconds(10))
45+
.strictCertificateValidation(true))
46+
.build();
47+
48+
// Validate message with custom configuration
49+
SnsMessage message = messageManager.parseMessage(inputStream);
50+
```
51+
52+
### Example 3: Handling Different Message Types
53+
54+
```java
55+
SnsMessageManager messageManager = SnsMessageManager.builder().build();
56+
57+
try {
58+
SnsMessage message = messageManager.parseMessage(messageJson);
59+
60+
switch (message.type()) {
61+
case "Notification":
62+
handleNotification(message.message(), message.subject());
63+
break;
64+
case "SubscriptionConfirmation":
65+
confirmSubscription(message.token(), message.topicArn());
66+
break;
67+
case "UnsubscribeConfirmation":
68+
handleUnsubscribe(message.token(), message.topicArn());
69+
break;
70+
default:
71+
logger.warn("Unknown message type: {}", message.type());
72+
}
73+
74+
} catch (SnsSignatureValidationException e) {
75+
logger.error("Invalid signature: {}", e.getMessage());
76+
} catch (SnsMessageParsingException e) {
77+
logger.error("Malformed message: {}", e.getMessage());
78+
} catch (SnsCertificateException e) {
79+
logger.error("Certificate error: {}", e.getMessage());
80+
}
81+
```
82+
83+
84+
85+
## Architecture
86+
87+
### Sync vs Async Support Decision
88+
89+
Unlike SqsBatchManager which provides async support for batching operations, SNS message validation is **synchronous by nature** - you receive a message and need to validate it immediately before processing.
90+
91+
We will start with **sync-only support** (`SnsMessageManager`) for the following reasons:
92+
- Most common use case is HTTP endpoint handlers requiring immediate validation
93+
- Simpler implementation and maintenance
94+
- Can add async support later if customer demand emerges
95+
- Follows YAGNI principle - avoid unnecessary complexity
96+
97+
### Package Structure
98+
```
99+
services/sns/src/main/java/software/amazon/awssdk/services/sns/
100+
├── messagemanager/
101+
│ ├── SnsMessageManager.java (public interface)
102+
│ └── MessageManagerConfiguration.java (configuration class)
103+
└── internal/
104+
└── messagemanager/
105+
├── DefaultSnsMessageManager.java (implementation)
106+
├── SnsMessageParser.java (message parsing logic)
107+
├── SignatureValidator.java (signature validation)
108+
├── CertificateRetriever.java (certificate management)
109+
└── SnsMessageImpl.java (message representation)
110+
```
111+
112+
### Core Components
113+
114+
#### 1. SnsMessageManager (Public Interface)
115+
- Main entry point for developers
116+
- Provides `parseMessage()` methods for validation
117+
- Follows builder pattern similar to other SDK utilities
118+
- Thread-safe and reusable
119+
120+
#### 2. MessageManagerConfiguration
121+
- Configuration class for customizing validation behavior
122+
- Controls certificate caching, timeout settings
123+
- Similar to other SDK configuration classes
124+
125+
#### 3. DefaultSnsMessageManager (Internal Implementation)
126+
- Implements the SnsMessageManager interface
127+
- Coordinates between parser, validator, and certificate retriever
128+
- Manages configuration and lifecycle
129+
130+
#### 4. SnsMessageParser
131+
- Parses JSON message payload
132+
- Extracts signature fields and message content
133+
- Validates message format and required fields
134+
135+
#### 5. SignatureValidator
136+
- Performs cryptographic signature verification using SHA1 (SignatureVersion1) and SHA256 (SignatureVersion2)
137+
- Uses AWS certificate to validate message authenticity
138+
- Handles different signature versions and validates certificate chain of trust
139+
140+
#### 6. CertificateRetriever
141+
- Retrieves and caches SNS certificates using HTTPS only
142+
- Validates certificate URLs against known SNS-signed domains
143+
- Supports different AWS regions and partitions (aws, aws-gov, aws-cn)
144+
- Verifies certificate chain of trust and Amazon SNS issuance
145+
146+
## Components and Interfaces
147+
148+
### SnsMessageManager Interface
149+
```java
150+
@SdkPublicApi
151+
public interface SnsMessageManager extends SdkAutoCloseable {
152+
153+
static Builder builder() {
154+
return DefaultSnsMessageManager.builder();
155+
}
156+
157+
/**
158+
* Parses and validates an SNS message from InputStream
159+
*/
160+
SnsMessage parseMessage(InputStream messageStream);
161+
162+
/**
163+
* Parses and validates an SNS message from String
164+
*/
165+
SnsMessage parseMessage(String messageContent);
166+
167+
interface Builder extends CopyableBuilder<Builder, SnsMessageManager> {
168+
Builder configuration(MessageManagerConfiguration configuration);
169+
Builder configuration(Consumer<MessageManagerConfiguration.Builder> configuration);
170+
SnsMessageManager build();
171+
}
172+
}
173+
```
174+
175+
### SnsMessage Interface
176+
```java
177+
@SdkPublicApi
178+
public interface SnsMessage {
179+
String type();
180+
String messageId();
181+
String topicArn();
182+
String subject();
183+
String message();
184+
Instant timestamp();
185+
String signatureVersion();
186+
String signature();
187+
String signingCertUrl();
188+
String unsubscribeUrl();
189+
String token();
190+
Map<String, String> messageAttributes();
191+
}
192+
```
193+
194+
### MessageManagerConfiguration
195+
```java
196+
@SdkPublicApi
197+
@Immutable
198+
@ThreadSafe
199+
public final class MessageManagerConfiguration
200+
implements ToCopyableBuilder<MessageManagerConfiguration.Builder, MessageManagerConfiguration> {
201+
202+
private final Duration certificateCacheTimeout;
203+
private final SdkHttpClient httpClient;
204+
205+
// Constructor, getters, toBuilder() implementation
206+
207+
public static Builder builder() {
208+
return new DefaultMessageManagerConfigurationBuilder();
209+
}
210+
211+
public Duration certificateCacheTimeout() { return certificateCacheTimeout; }
212+
public SdkHttpClient httpClient() { return httpClient; }
213+
214+
@NotThreadSafe
215+
public interface Builder extends CopyableBuilder<Builder, MessageManagerConfiguration> {
216+
Builder certificateCacheTimeout(Duration certificateCacheTimeout);
217+
Builder httpClient(SdkHttpClient httpClient);
218+
}
219+
}
220+
```
221+
222+
## Data Models
223+
224+
### Message Types
225+
The manager will support all standard SNS message types:
226+
- **Notification**: Standard SNS notifications
227+
- **SubscriptionConfirmation**: Subscription confirmation messages
228+
- **UnsubscribeConfirmation**: Unsubscribe confirmation messages
229+
230+
### Message Fields
231+
Standard SNS message fields that will be parsed and validated:
232+
- Type (required)
233+
- MessageId (required)
234+
- TopicArn (required)
235+
- Message (required for Notification)
236+
- Timestamp (required)
237+
- SignatureVersion (required)
238+
- Signature (required)
239+
- SigningCertURL (required)
240+
- Subject (optional)
241+
- UnsubscribeURL (optional for Notification)
242+
- Token (required for confirmations)
243+
- MessageAttributes (optional)
244+
245+
### Certificate Management
246+
- Certificate URLs will be validated against known AWS SNS-signed domains only
247+
- Certificates retrieved exclusively via HTTPS to prevent interception attacks
248+
- Certificate chain of trust validation to ensure Amazon SNS issuance
249+
- Certificates will be cached with configurable TTL
250+
- Support for different AWS partitions (aws, aws-gov, aws-cn)
251+
- Rejection of any certificates provided directly in messages without validation
252+
253+
## Error Handling
254+
255+
### Exception Hierarchy
256+
```java
257+
public class SnsMessageValidationException extends SdkException {
258+
// Base exception for all validation failures
259+
}
260+
261+
public class SnsMessageParsingException extends SnsMessageValidationException {
262+
// JSON parsing or format errors
263+
}
264+
265+
public class SnsSignatureValidationException extends SnsMessageValidationException {
266+
// Signature verification failures
267+
}
268+
269+
public class SnsCertificateException extends SnsMessageValidationException {
270+
// Certificate retrieval or validation errors
271+
}
272+
```
273+
274+
### Error Scenarios
275+
1. **Malformed JSON**: Clear parsing error with details
276+
2. **Missing Required Fields**: Specific field validation errors
277+
3. **Invalid Signature**: Cryptographic verification failure
278+
4. **Certificate Issues**: Certificate retrieval or validation problems
279+
5. **Invalid Certificate URL**: Security validation of certificate source
280+
281+
## Testing Strategy
282+
283+
### Unit Tests
284+
- **SnsMessageParser**: JSON parsing, field extraction, format validation
285+
- **SignatureValidator**: Cryptographic verification with known test vectors
286+
- **CertificateRetriever**: Certificate fetching, caching, URL validation
287+
- **DefaultSnsMessageManager**: Integration of all components
288+
289+
### Integration Tests
290+
- **Real SNS Messages**: Test with actual SNS message samples
291+
- **Different Regions**: Validate messages from various AWS regions
292+
- **Message Types**: Test all supported message types
293+
- **Error Conditions**: Verify proper error handling
294+
295+
### Test Data
296+
- Sample SNS messages for each type (Notification, SubscriptionConfirmation, UnsubscribeConfirmation)
297+
- Invalid messages for error testing
298+
- Test certificates and signatures for validation testing
299+
300+
## Implementation Considerations
301+
302+
### Security
303+
- Certificate URL validation against known AWS SNS-signed domains only
304+
- HTTPS-only certificate retrieval to prevent interception attacks
305+
- Proper certificate chain validation and Amazon SNS issuance verification
306+
- Protection against certificate spoofing attacks
307+
- Rejection of unexpected message fields or formats
308+
- Never trusting certificates provided directly in messages without validation
309+
310+
### Performance
311+
- Certificate caching to avoid repeated HTTP requests
312+
- Efficient JSON parsing
313+
- Thread-safe implementation for concurrent usage
314+
315+
### Compatibility
316+
- Support for SignatureVersion1 (SHA1) and SignatureVersion2 (SHA256) as per AWS SNS standards
317+
- Graceful handling of future signature version updates
318+
- Consistent behavior across different AWS partitions
319+
- API compatibility with AWS SDK v1 SnsMessageManager functionality
320+
321+
### Dependencies
322+
The implementation will require:
323+
- JSON parsing (Jackson, already available in SDK)
324+
- HTTP client for certificate retrieval (SDK's HTTP client)
325+
- Cryptographic libraries (Java standard library)
326+
- No additional external dependencies

0 commit comments

Comments
 (0)