13
13
14
14
package com .amazonaws .encryptionsdk .kms ;
15
15
16
- import com .amazonaws .ClientConfiguration ;
17
16
import com .amazonaws .arn .Arn ;
18
- import com .amazonaws .auth .AWSCredentialsProvider ;
19
17
import com .amazonaws .encryptionsdk .exception .UnsupportedRegionException ;
20
18
import com .amazonaws .services .kms .AWSKMS ;
21
- import com .amazonaws .services .kms .AWSKMSClientBuilder ;
22
- import com .amazonaws .services .kms .model .AWSKMSException ;
23
19
24
20
import javax .annotation .Nullable ;
25
- import java .lang .reflect .InvocationTargetException ;
26
- import java .lang .reflect .Proxy ;
27
- import java .util .Collections ;
28
- import java .util .HashMap ;
29
- import java .util .HashSet ;
30
- import java .util .Map ;
31
- import java .util .Set ;
32
21
33
22
import static java .util .Objects .requireNonNull ;
34
- import static org .apache .commons .lang3 .Validate .isTrue ;
35
- import static org .apache .commons .lang3 .Validate .notEmpty ;
36
23
37
24
/**
38
25
* Represents a function that accepts an AWS region and returns an {@code AWSKMS} client for that region. The
@@ -51,15 +38,6 @@ public interface AwsKmsClientSupplier {
51
38
*/
52
39
AWSKMS getClient (@ Nullable String regionId ) throws UnsupportedRegionException ;
53
40
54
- /**
55
- * Gets a Builder for constructing an AwsKmsClientSupplier
56
- *
57
- * @return The builder
58
- */
59
- static Builder builder () {
60
- return new Builder (AWSKMSClientBuilder .standard ());
61
- }
62
-
63
41
/**
64
42
* Parses region from the given key id (if possible) and passes that region to the
65
43
* given clientSupplier to produce an {@code AWSKMS} client.
@@ -78,156 +56,4 @@ static AWSKMS getClientByKeyId(AwsKmsCmkId keyId, AwsKmsClientSupplier clientSup
78
56
79
57
return clientSupplier .getClient (null );
80
58
}
81
-
82
- /**
83
- * Builder to construct an AwsKmsClientSupplier given various
84
- * optional settings.
85
- */
86
- class Builder {
87
-
88
- private AWSCredentialsProvider credentialsProvider ;
89
- private ClientConfiguration clientConfiguration ;
90
- private Set <String > allowedRegions = Collections .emptySet ();
91
- private Set <String > excludedRegions = Collections .emptySet ();
92
- private boolean clientCachingEnabled = true ;
93
- private final Map <String , AWSKMS > clientsCache = new HashMap <>();
94
- private static final Set <String > AWSKMS_METHODS = new HashSet <>();
95
- private AWSKMSClientBuilder awsKmsClientBuilder ;
96
-
97
- static {
98
- AWSKMS_METHODS .add ("generateDataKey" );
99
- AWSKMS_METHODS .add ("encrypt" );
100
- AWSKMS_METHODS .add ("decrypt" );
101
- }
102
-
103
- Builder (AWSKMSClientBuilder awsKmsClientBuilder ) {
104
- this .awsKmsClientBuilder = awsKmsClientBuilder ;
105
- }
106
-
107
- public AwsKmsClientSupplier build () {
108
- isTrue (allowedRegions .isEmpty () || excludedRegions .isEmpty (),
109
- "Either allowed regions or excluded regions may be set, not both." );
110
-
111
- return regionId -> {
112
- if (!allowedRegions .isEmpty () && !allowedRegions .contains (regionId )) {
113
- throw new UnsupportedRegionException (String .format ("Region %s is not in the list of allowed regions %s" ,
114
- regionId , allowedRegions ));
115
- }
116
-
117
- if (excludedRegions .contains (regionId )) {
118
- throw new UnsupportedRegionException (String .format ("Region %s is in the list of excluded regions %s" ,
119
- regionId , excludedRegions ));
120
- }
121
-
122
- if (clientsCache .containsKey (regionId )) {
123
- return clientsCache .get (regionId );
124
- }
125
-
126
- if (credentialsProvider != null ) {
127
- awsKmsClientBuilder = awsKmsClientBuilder .withCredentials (credentialsProvider );
128
- }
129
-
130
- if (clientConfiguration != null ) {
131
- awsKmsClientBuilder = awsKmsClientBuilder .withClientConfiguration (clientConfiguration );
132
- }
133
-
134
- if (regionId != null ) {
135
- awsKmsClientBuilder = awsKmsClientBuilder .withRegion (regionId );
136
- }
137
-
138
- AWSKMS client = awsKmsClientBuilder .build ();
139
-
140
- if (clientCachingEnabled ) {
141
- client = newCachingProxy (client , regionId );
142
- }
143
-
144
- return client ;
145
- };
146
- }
147
-
148
- /**
149
- * Sets the AWSCredentialsProvider used by the client.
150
- *
151
- * @param credentialsProvider New AWSCredentialsProvider to use.
152
- */
153
- public Builder credentialsProvider (AWSCredentialsProvider credentialsProvider ) {
154
- this .credentialsProvider = credentialsProvider ;
155
- return this ;
156
- }
157
-
158
- /**
159
- * Sets the ClientConfiguration to be used by the client.
160
- *
161
- * @param clientConfiguration Custom configuration to use.
162
- */
163
- public Builder clientConfiguration (ClientConfiguration clientConfiguration ) {
164
- this .clientConfiguration = clientConfiguration ;
165
- return this ;
166
- }
167
-
168
- /**
169
- * Sets the AWS regions that the client supplier is permitted to use.
170
- *
171
- * @param regions The set of regions.
172
- */
173
- public Builder allowedRegions (Set <String > regions ) {
174
- notEmpty (regions , "At least one region is required" );
175
- this .allowedRegions = Collections .unmodifiableSet (new HashSet <>(regions ));
176
- return this ;
177
- }
178
-
179
- /**
180
- * Sets the AWS regions that the client supplier is not permitted to use.
181
- *
182
- * @param regions The set of regions.
183
- */
184
- public Builder excludedRegions (Set <String > regions ) {
185
- requireNonNull (regions , "regions is required" );
186
- this .excludedRegions = Collections .unmodifiableSet (new HashSet <>(regions ));
187
- return this ;
188
- }
189
-
190
- /**
191
- * When set to false, disables the AWSKMS client for each region from being cached and reused.
192
- * By default, client caching is enabled.
193
- *
194
- * @param enabled Whether or not caching is enabled.
195
- */
196
- public Builder clientCaching (boolean enabled ) {
197
- this .clientCachingEnabled = enabled ;
198
- return this ;
199
- }
200
-
201
- /**
202
- * Creates a proxy for the AWSKMS client that will populate the client into the client cache
203
- * after an AWS KMS method successfully completes or an AWS KMS exception occurs. This is to prevent a
204
- * a malicious user from causing a local resource DOS by sending ciphertext with a large number
205
- * of spurious regions, thereby filling the cache with regions and exhausting resources.
206
- *
207
- * @param client The client to proxy
208
- * @param regionId The region the client is associated with
209
- * @return The proxy
210
- */
211
- private AWSKMS newCachingProxy (AWSKMS client , String regionId ) {
212
- return (AWSKMS ) Proxy .newProxyInstance (
213
- AWSKMS .class .getClassLoader (),
214
- new Class []{AWSKMS .class },
215
- (proxy , method , methodArgs ) -> {
216
- try {
217
- final Object result = method .invoke (client , methodArgs );
218
- if (AWSKMS_METHODS .contains (method .getName ())) {
219
- clientsCache .put (regionId , client );
220
- }
221
- return result ;
222
- } catch (InvocationTargetException e ) {
223
- if (e .getTargetException () instanceof AWSKMSException &&
224
- AWSKMS_METHODS .contains (method .getName ())) {
225
- clientsCache .put (regionId , client );
226
- }
227
-
228
- throw e .getTargetException ();
229
- }
230
- });
231
- }
232
- }
233
59
}
0 commit comments