• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License").
5  * You may not use this file except in compliance with the License.
6  * A copy of the License is located at
7  *
8  *  http://aws.amazon.com/apache2.0
9  *
10  * or in the "license" file accompanying this file. This file is distributed
11  * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
12  * express or implied. See the License for the specific language governing
13  * permissions and limitations under the License.
14  */
15 
16 package software.amazon.awssdk.awscore.internal;
17 
18 import static software.amazon.awssdk.auth.signer.internal.util.SignerMethodResolver.resolveSigningMethodUsed;
19 import static software.amazon.awssdk.core.interceptor.SdkExecutionAttribute.RESOLVED_CHECKSUM_SPECS;
20 
21 import java.util.Map;
22 import software.amazon.awssdk.annotations.SdkInternalApi;
23 import software.amazon.awssdk.auth.signer.AwsSignerExecutionAttribute;
24 import software.amazon.awssdk.awscore.AwsExecutionAttribute;
25 import software.amazon.awssdk.awscore.AwsRequestOverrideConfiguration;
26 import software.amazon.awssdk.awscore.client.config.AwsClientOption;
27 import software.amazon.awssdk.awscore.internal.authcontext.AuthorizationStrategy;
28 import software.amazon.awssdk.awscore.internal.authcontext.AuthorizationStrategyFactory;
29 import software.amazon.awssdk.awscore.util.SignerOverrideUtils;
30 import software.amazon.awssdk.core.HttpChecksumConstant;
31 import software.amazon.awssdk.core.RequestOverrideConfiguration;
32 import software.amazon.awssdk.core.SdkRequest;
33 import software.amazon.awssdk.core.SdkResponse;
34 import software.amazon.awssdk.core.SelectedAuthScheme;
35 import software.amazon.awssdk.core.client.config.SdkAdvancedClientOption;
36 import software.amazon.awssdk.core.client.config.SdkClientConfiguration;
37 import software.amazon.awssdk.core.client.config.SdkClientOption;
38 import software.amazon.awssdk.core.client.handler.ClientExecutionParams;
39 import software.amazon.awssdk.core.http.ExecutionContext;
40 import software.amazon.awssdk.core.interceptor.ExecutionAttributes;
41 import software.amazon.awssdk.core.interceptor.ExecutionInterceptorChain;
42 import software.amazon.awssdk.core.interceptor.InterceptorContext;
43 import software.amazon.awssdk.core.interceptor.SdkExecutionAttribute;
44 import software.amazon.awssdk.core.interceptor.SdkInternalExecutionAttribute;
45 import software.amazon.awssdk.core.internal.InternalCoreExecutionAttribute;
46 import software.amazon.awssdk.core.internal.util.HttpChecksumResolver;
47 import software.amazon.awssdk.core.signer.Signer;
48 import software.amazon.awssdk.endpoints.EndpointProvider;
49 import software.amazon.awssdk.http.auth.scheme.NoAuthAuthScheme;
50 import software.amazon.awssdk.http.auth.spi.scheme.AuthScheme;
51 import software.amazon.awssdk.http.auth.spi.scheme.AuthSchemeProvider;
52 import software.amazon.awssdk.identity.spi.IdentityProviders;
53 import software.amazon.awssdk.metrics.MetricCollector;
54 
55 @SdkInternalApi
56 public final class AwsExecutionContextBuilder {
57 
AwsExecutionContextBuilder()58     private AwsExecutionContextBuilder() {
59 
60     }
61 
62     /**
63      * Used by both sync and async clients to create the execution context, and run initial interceptors.
64      */
65     public static <InputT extends SdkRequest, OutputT extends SdkResponse> ExecutionContext
invokeInterceptorsAndCreateExecutionContext(ClientExecutionParams<InputT, OutputT> executionParams, SdkClientConfiguration clientConfig)66         invokeInterceptorsAndCreateExecutionContext(ClientExecutionParams<InputT, OutputT> executionParams,
67                                                     SdkClientConfiguration clientConfig) {
68         // Note: This is currently copied to DefaultS3Presigner and other presigners.
69         // Don't edit this without considering those
70 
71         SdkRequest originalRequest = executionParams.getInput();
72         MetricCollector metricCollector = resolveMetricCollector(executionParams);
73 
74         ExecutionAttributes executionAttributes = mergeExecutionAttributeOverrides(
75             executionParams.executionAttributes(),
76             clientConfig.option(SdkClientOption.EXECUTION_ATTRIBUTES),
77             originalRequest.overrideConfiguration().map(c -> c.executionAttributes()).orElse(null));
78 
79         executionAttributes.putAttributeIfAbsent(SdkExecutionAttribute.API_CALL_METRIC_COLLECTOR, metricCollector);
80 
81         executionAttributes
82             .putAttribute(InternalCoreExecutionAttribute.EXECUTION_ATTEMPT, 1)
83             .putAttribute(AwsSignerExecutionAttribute.SERVICE_CONFIG,
84                           clientConfig.option(SdkClientOption.SERVICE_CONFIGURATION))
85             .putAttribute(AwsSignerExecutionAttribute.SERVICE_SIGNING_NAME,
86                           clientConfig.option(AwsClientOption.SERVICE_SIGNING_NAME))
87             .putAttribute(AwsExecutionAttribute.AWS_REGION, clientConfig.option(AwsClientOption.AWS_REGION))
88             .putAttribute(AwsExecutionAttribute.ENDPOINT_PREFIX, clientConfig.option(AwsClientOption.ENDPOINT_PREFIX))
89             .putAttribute(AwsSignerExecutionAttribute.SIGNING_REGION, clientConfig.option(AwsClientOption.SIGNING_REGION))
90             .putAttribute(SdkInternalExecutionAttribute.IS_FULL_DUPLEX, executionParams.isFullDuplex())
91             .putAttribute(SdkInternalExecutionAttribute.HAS_INITIAL_REQUEST_EVENT, executionParams.hasInitialRequestEvent())
92             .putAttribute(SdkExecutionAttribute.CLIENT_TYPE, clientConfig.option(SdkClientOption.CLIENT_TYPE))
93             .putAttribute(SdkExecutionAttribute.SERVICE_NAME, clientConfig.option(SdkClientOption.SERVICE_NAME))
94             .putAttribute(SdkInternalExecutionAttribute.PROTOCOL_METADATA, executionParams.getProtocolMetadata())
95             .putAttribute(SdkExecutionAttribute.PROFILE_FILE, clientConfig.option(SdkClientOption.PROFILE_FILE_SUPPLIER) != null ?
96                                                               clientConfig.option(SdkClientOption.PROFILE_FILE_SUPPLIER).get() :
97                                                               null)
98             .putAttribute(SdkExecutionAttribute.PROFILE_FILE_SUPPLIER, clientConfig.option(SdkClientOption.PROFILE_FILE_SUPPLIER))
99             .putAttribute(SdkExecutionAttribute.PROFILE_NAME, clientConfig.option(SdkClientOption.PROFILE_NAME))
100             .putAttribute(AwsExecutionAttribute.DUALSTACK_ENDPOINT_ENABLED,
101                           clientConfig.option(AwsClientOption.DUALSTACK_ENDPOINT_ENABLED))
102             .putAttribute(AwsExecutionAttribute.FIPS_ENDPOINT_ENABLED,
103                           clientConfig.option(AwsClientOption.FIPS_ENDPOINT_ENABLED))
104             .putAttribute(SdkExecutionAttribute.OPERATION_NAME, executionParams.getOperationName())
105             .putAttribute(SdkExecutionAttribute.CLIENT_ENDPOINT, clientConfig.option(SdkClientOption.ENDPOINT))
106             .putAttribute(SdkExecutionAttribute.ENDPOINT_OVERRIDDEN, clientConfig.option(SdkClientOption.ENDPOINT_OVERRIDDEN))
107             .putAttribute(SdkInternalExecutionAttribute.ENDPOINT_PROVIDER,
108                           resolveEndpointProvider(originalRequest, clientConfig))
109             .putAttribute(SdkInternalExecutionAttribute.CLIENT_CONTEXT_PARAMS,
110                           clientConfig.option(SdkClientOption.CLIENT_CONTEXT_PARAMS))
111             .putAttribute(SdkInternalExecutionAttribute.DISABLE_HOST_PREFIX_INJECTION,
112                           clientConfig.option(SdkAdvancedClientOption.DISABLE_HOST_PREFIX_INJECTION))
113             .putAttribute(SdkInternalExecutionAttribute.SDK_CLIENT, clientConfig.option(SdkClientOption.SDK_CLIENT))
114             .putAttribute(SdkExecutionAttribute.SIGNER_OVERRIDDEN, clientConfig.option(SdkClientOption.SIGNER_OVERRIDDEN))
115             .putAttribute(AwsExecutionAttribute.USE_GLOBAL_ENDPOINT,
116                           clientConfig.option(AwsClientOption.USE_GLOBAL_ENDPOINT))
117             .putAttribute(RESOLVED_CHECKSUM_SPECS, HttpChecksumResolver.resolveChecksumSpecs(executionAttributes));
118 
119         // Auth Scheme resolution related attributes
120         putAuthSchemeResolutionAttributes(executionAttributes, clientConfig, originalRequest);
121 
122         ExecutionInterceptorChain executionInterceptorChain =
123                 new ExecutionInterceptorChain(clientConfig.option(SdkClientOption.EXECUTION_INTERCEPTORS));
124 
125         InterceptorContext interceptorContext = InterceptorContext.builder()
126                                                      .request(originalRequest)
127                                                      .asyncRequestBody(executionParams.getAsyncRequestBody())
128                                                      .requestBody(executionParams.getRequestBody())
129                                                      .build();
130         interceptorContext = runInitialInterceptors(interceptorContext, executionAttributes, executionInterceptorChain);
131 
132         Signer signer = null;
133         if (loadOldSigner(executionAttributes, originalRequest)) {
134             AuthorizationStrategyFactory authorizationStrategyFactory =
135                 new AuthorizationStrategyFactory(interceptorContext.request(), metricCollector, clientConfig);
136             AuthorizationStrategy authorizationStrategy =
137                 authorizationStrategyFactory.strategyFor(executionParams.credentialType());
138             authorizationStrategy.addCredentialsToExecutionAttributes(executionAttributes);
139             signer = authorizationStrategy.resolveSigner();
140         }
141 
142         executionAttributes.putAttribute(HttpChecksumConstant.SIGNING_METHOD,
143                                          resolveSigningMethodUsed(
144                                              signer, executionAttributes, executionAttributes.getOptionalAttribute(
145                                                  AwsSignerExecutionAttribute.AWS_CREDENTIALS).orElse(null)));
146 
147         return ExecutionContext.builder()
148                                .interceptorChain(executionInterceptorChain)
149                                .interceptorContext(interceptorContext)
150                                .executionAttributes(executionAttributes)
151                                .signer(signer)
152                                .metricCollector(metricCollector)
153                                .build();
154     }
155 
156     /**
157      * We will load the old (non-SRA) signer if this client seems like an old version or the customer has provided a signer
158      * override. We assume that if there's no auth schemes defined, we're on the old code path.
159      * <p>
160      * In addition, if authType=none, we don't need to use the old signer, even if overridden.
161      */
loadOldSigner(ExecutionAttributes attributes, SdkRequest request)162     private static boolean loadOldSigner(ExecutionAttributes attributes, SdkRequest request) {
163         Map<String, AuthScheme<?>> authSchemes = attributes.getAttribute(SdkInternalExecutionAttribute.AUTH_SCHEMES);
164         if (authSchemes == null) {
165             // pre SRA case.
166             // We used to set IS_NONE_AUTH_TYPE_REQUEST = false when authType=none. Yes, false.
167             return attributes.getOptionalAttribute(SdkInternalExecutionAttribute.IS_NONE_AUTH_TYPE_REQUEST).orElse(true);
168         }
169 
170         // post SRA case.
171         // By default, SRA uses new HttpSigner, so we shouldn't use old non-SRA Signer, unless the customer has provided a signer
172         // override.
173         // But, if the operation was modeled as authTpye=None, we don't want to use the provided overridden Signer either. In
174         // post SRA, modeled authType=None would default to NoAuthAuthScheme.
175         // Note, for authType=None operation, technically, customer could override the AuthSchemeProvider and select a different
176         // AuthScheme (than NoAuthAuthScheme). In this case, we are choosing to use the customer's overridden Signer.
177         SelectedAuthScheme<?> selectedAuthScheme = attributes.getAttribute(SdkInternalExecutionAttribute.SELECTED_AUTH_SCHEME);
178         return SignerOverrideUtils.isSignerOverridden(request, attributes) &&
179                selectedAuthScheme != null &&
180                !NoAuthAuthScheme.SCHEME_ID.equals(selectedAuthScheme.authSchemeOption().schemeId());
181     }
182 
putAuthSchemeResolutionAttributes(ExecutionAttributes executionAttributes, SdkClientConfiguration clientConfig, SdkRequest originalRequest)183     private static void putAuthSchemeResolutionAttributes(ExecutionAttributes executionAttributes,
184                                                           SdkClientConfiguration clientConfig,
185                                                           SdkRequest originalRequest) {
186 
187         // TODO(sra-identity-and-auth): When request-level auth scheme provider is added, use the request-level auth scheme
188         //  provider if the customer specified an override, otherwise fall back to the one on the client.
189         AuthSchemeProvider authSchemeProvider = clientConfig.option(SdkClientOption.AUTH_SCHEME_PROVIDER);
190 
191         // Use auth schemes that the user specified at the request level with
192         // preference over those on the client.
193         // TODO(sra-identity-and-auth): The request level schemes should be "merged" with client level, with request preferred
194         //  over client.
195         Map<String, AuthScheme<?>> authSchemes = clientConfig.option(SdkClientOption.AUTH_SCHEMES);
196 
197         IdentityProviders identityProviders = resolveIdentityProviders(originalRequest, clientConfig);
198 
199         executionAttributes
200             .putAttribute(SdkInternalExecutionAttribute.AUTH_SCHEME_RESOLVER, authSchemeProvider)
201             .putAttribute(SdkInternalExecutionAttribute.AUTH_SCHEMES, authSchemes)
202             .putAttribute(SdkInternalExecutionAttribute.IDENTITY_PROVIDERS, identityProviders);
203     }
204 
205     // TODO(sra-identity-and-auth): This is hard coding the logic for the credentialsIdentityProvider from
206     //  AwsRequestOverrideConfiguration. Currently, AwsRequestOverrideConfiguration does not support overriding the
207     //  tokenIdentityProvider. When adding that support this method will need to be updated.
resolveIdentityProviders(SdkRequest originalRequest, SdkClientConfiguration clientConfig)208     private static IdentityProviders resolveIdentityProviders(SdkRequest originalRequest,
209                                                               SdkClientConfiguration clientConfig) {
210         IdentityProviders identityProviders =
211             clientConfig.option(SdkClientOption.IDENTITY_PROVIDERS);
212 
213         // identityProviders can be null, for new core with old client. In this case, even if AwsRequestOverrideConfiguration
214         // has credentialsIdentityProvider set (because it is in new core), it is ok to not setup IDENTITY_PROVIDERS, as old
215         // client won't have AUTH_SCHEME_PROVIDER/AUTH_SCHEMES set either, which are also needed for SRA logic.
216         if (identityProviders == null) {
217             return null;
218         }
219 
220         return originalRequest.overrideConfiguration()
221                               .filter(c -> c instanceof AwsRequestOverrideConfiguration)
222                               .map(c -> (AwsRequestOverrideConfiguration) c)
223                               .flatMap(AwsRequestOverrideConfiguration::credentialsIdentityProvider)
224                               .map(identityProvider ->
225                                        identityProviders.copy(b -> b.putIdentityProvider(identityProvider)))
226                               .orElse(identityProviders);
227     }
228 
229     /**
230      * Finalize {@link SdkRequest} by running beforeExecution and modifyRequest interceptors.
231      *
232      * @param interceptorContext containing the immutable SdkRequest information the interceptor can act on
233      * @param executionAttributes mutable container of attributes concerning the execution and request
234      * @return the {@link InterceptorContext} returns a context with a new SdkRequest
235      */
runInitialInterceptors(InterceptorContext interceptorContext, ExecutionAttributes executionAttributes, ExecutionInterceptorChain executionInterceptorChain)236     public static InterceptorContext runInitialInterceptors(InterceptorContext interceptorContext,
237                                                             ExecutionAttributes executionAttributes,
238                                                             ExecutionInterceptorChain executionInterceptorChain) {
239         executionInterceptorChain.beforeExecution(interceptorContext, executionAttributes);
240         return executionInterceptorChain.modifyRequest(interceptorContext, executionAttributes);
241     }
242 
243 
mergeExecutionAttributeOverrides( ExecutionAttributes executionAttributes, ExecutionAttributes clientOverrideExecutionAttributes, ExecutionAttributes requestOverrideExecutionAttributes)244     private static <InputT extends SdkRequest, OutputT extends SdkResponse> ExecutionAttributes mergeExecutionAttributeOverrides(
245         ExecutionAttributes executionAttributes,
246         ExecutionAttributes clientOverrideExecutionAttributes,
247         ExecutionAttributes requestOverrideExecutionAttributes) {
248 
249 
250         executionAttributes.putAbsentAttributes(requestOverrideExecutionAttributes);
251         executionAttributes.putAbsentAttributes(clientOverrideExecutionAttributes);
252 
253         return executionAttributes;
254     }
255 
resolveMetricCollector(ClientExecutionParams<?, ?> params)256     private static MetricCollector resolveMetricCollector(ClientExecutionParams<?, ?> params) {
257         MetricCollector metricCollector = params.getMetricCollector();
258         if (metricCollector == null) {
259             metricCollector = MetricCollector.create("ApiCall");
260         }
261         return metricCollector;
262     }
263 
264 
265     /**
266      * Resolves the endpoint provider, with the request override configuration taking precedence over the
267      * provided default client clientConfig.
268      * @return The endpoint provider that will be used by the SDK to resolve endpoints.
269      */
resolveEndpointProvider(SdkRequest request, SdkClientConfiguration clientConfig)270     private static EndpointProvider resolveEndpointProvider(SdkRequest request,
271                                                            SdkClientConfiguration clientConfig) {
272         return request.overrideConfiguration()
273                       .flatMap(RequestOverrideConfiguration::endpointProvider)
274                       .orElse(clientConfig.option(SdkClientOption.ENDPOINT_PROVIDER));
275     }
276 
277 
278 }
279