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