1
+ package software .amazon .awssdk .auth .signer ;
2
+
3
+ import static java .nio .charset .StandardCharsets .UTF_8 ;
4
+ import static org .assertj .core .api .Assertions .assertThat ;
5
+
6
+ import io .reactivex .Flowable ;
7
+ import java .net .URI ;
8
+ import java .nio .ByteBuffer ;
9
+ import java .time .Clock ;
10
+ import java .time .Instant ;
11
+ import java .time .ZoneId ;
12
+ import java .time .ZoneOffset ;
13
+ import java .util .Base64 ;
14
+ import java .util .Collections ;
15
+ import java .util .List ;
16
+ import java .util .Map ;
17
+ import java .util .concurrent .Callable ;
18
+ import org .junit .Test ;
19
+ import software .amazon .awssdk .auth .credentials .AwsBasicCredentials ;
20
+ import software .amazon .awssdk .auth .credentials .AwsCredentials ;
21
+ import software .amazon .awssdk .auth .signer .internal .SignerTestUtils ;
22
+ import software .amazon .awssdk .core .async .AsyncRequestBody ;
23
+ import software .amazon .awssdk .http .SdkHttpFullRequest ;
24
+ import software .amazon .awssdk .http .SdkHttpMethod ;
25
+ import software .amazon .awssdk .regions .Region ;
26
+ import software .amazon .eventstream .HeaderValue ;
27
+ import software .amazon .eventstream .Message ;
28
+ import software .amazon .eventstream .MessageDecoder ;
29
+
30
+ public class EventStreamAws4SignerTest {
31
+ /**
32
+ * Verify that when an event stream is open from one day to the next, the signature is properly signed for the day of the
33
+ * event.
34
+ */
35
+ @ Test
36
+ public void openStreamEventSignaturesCanRollOverBetweenDays () {
37
+ EventStreamAws4Signer signer = EventStreamAws4Signer .create ();
38
+
39
+ Region region = Region .US_WEST_2 ;
40
+ AwsCredentials credentials = AwsBasicCredentials .create ("a" , "s" );
41
+ String signingName = "name" ;
42
+ AdjustableClock clock = new AdjustableClock ();
43
+ clock .time = Instant .parse ("2020-01-01T23:59:59Z" );
44
+
45
+ SdkHttpFullRequest initialRequest = SdkHttpFullRequest .builder ()
46
+ .uri (URI .create ("http://localhost:8080" ))
47
+ .method (SdkHttpMethod .GET )
48
+ .build ();
49
+ SdkHttpFullRequest signedRequest = SignerTestUtils .signRequest (signer , initialRequest , credentials , signingName , clock ,
50
+ region .id ());
51
+
52
+ ByteBuffer event = new Message (Collections .emptyMap (), "foo" .getBytes (UTF_8 )).toByteBuffer ();
53
+
54
+ Callable <ByteBuffer > lastEvent = () -> {
55
+ clock .time = Instant .parse ("2020-01-02T00:00:00Z" );
56
+ return event ;
57
+ };
58
+
59
+ AsyncRequestBody requestBody = AsyncRequestBody .fromPublisher (Flowable .concatArray (Flowable .just (event ),
60
+ Flowable .fromCallable (lastEvent )));
61
+
62
+ AsyncRequestBody signedBody = SignerTestUtils .signAsyncRequest (signer , signedRequest , requestBody , credentials ,
63
+ signingName , clock , region .id ());
64
+
65
+ List <Message > signedMessages = readMessages (signedBody );
66
+ assertThat (signedMessages .size ()).isEqualTo (3 );
67
+
68
+ Map <String , HeaderValue > firstMessageHeaders = signedMessages .get (0 ).getHeaders ();
69
+ assertThat (firstMessageHeaders .get (":date" ).getTimestamp ()).isEqualTo ("2020-01-01T23:59:59Z" );
70
+ assertThat (Base64 .getEncoder ().encodeToString (firstMessageHeaders .get (":chunk-signature" ).getByteArray ()))
71
+ .isEqualTo ("EFt7ZU043r/TJE8U+1GxJXscmNxoqmIdGtUIl8wE9u0=" );
72
+
73
+ Map <String , HeaderValue > lastMessageHeaders = signedMessages .get (2 ).getHeaders ();
74
+ assertThat (lastMessageHeaders .get (":date" ).getTimestamp ()).isEqualTo ("2020-01-02T00:00:00Z" );
75
+ assertThat (Base64 .getEncoder ().encodeToString (lastMessageHeaders .get (":chunk-signature" ).getByteArray ()))
76
+ .isEqualTo ("vgDFcmKOVDUSSzKaBzcj0v9gUSgCK5IwnQ4dMB38NlE=" );
77
+
78
+ }
79
+
80
+ private List <Message > readMessages (AsyncRequestBody signedBody ) {
81
+ MessageDecoder decoder = new MessageDecoder ();
82
+ Flowable .fromPublisher (signedBody ).blockingForEach (x -> decoder .feed (x .array ()));
83
+ return decoder .getDecodedMessages ();
84
+ }
85
+
86
+ private static class AdjustableClock extends Clock {
87
+ private Instant time ;
88
+
89
+ @ Override
90
+ public ZoneId getZone () {
91
+ return ZoneOffset .UTC ;
92
+ }
93
+
94
+ @ Override
95
+ public Clock withZone (ZoneId zone ) {
96
+ throw new UnsupportedOperationException ();
97
+ }
98
+
99
+ @ Override
100
+ public Instant instant () {
101
+ return time ;
102
+ }
103
+ }
104
+
105
+ }
0 commit comments