/* * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"). * You may not use this file except in compliance with the License. * A copy of the License is located at * * http://aws.amazon.com/apache2.0 * * or in the "license" file accompanying this file. This file is distributed * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either * express or implied. See the License for the specific language governing * permissions and limitations under the License. */ using Amazon.Runtime.Internal.Auth; using Amazon.Runtime.Internal.Util; using Amazon.Util; using System; using System.IO; #if AWS_ASYNC_API using System.Threading.Tasks; #endif namespace Amazon.Runtime.Internal { /// /// This handler signs the request. /// public class Signer : PipelineHandler { /// /// Calls pre invoke logic before calling the next handler /// in the pipeline. /// /// The execution context which contains both the /// requests and response context. public override void InvokeSync(IExecutionContext executionContext) { PreInvoke(executionContext); base.InvokeSync(executionContext); } #if AWS_ASYNC_API /// /// Calls pre invoke logic before calling the next handler /// in the pipeline. /// /// The response type for the current request. /// The execution context, it contains the /// request and response context. /// A task that represents the asynchronous operation. public override async System.Threading.Tasks.Task InvokeAsync(IExecutionContext executionContext) { await PreInvokeAsync(executionContext).ConfigureAwait(false); return await base.InvokeAsync(executionContext).ConfigureAwait(false); } #elif AWS_APM_API /// /// Calls pre invoke logic before calling the next handler /// in the pipeline. /// /// The execution context which contains both the /// requests and response context. /// IAsyncResult which represent an async operation. public override IAsyncResult InvokeAsync(IAsyncExecutionContext executionContext) { PreInvoke(ExecutionContext.CreateFromAsyncContext(executionContext)); return base.InvokeAsync(executionContext); } #endif /// /// Signs the request before invoking the next handler. /// /// /// The execution context, it contains the request and response context. /// protected static void PreInvoke(IExecutionContext executionContext) { if (ShouldSign(executionContext.RequestContext)) { SignRequest(executionContext.RequestContext); executionContext.RequestContext.IsSigned = true; } } #if AWS_ASYNC_API protected static async System.Threading.Tasks.Task PreInvokeAsync(IExecutionContext executionContext) { if (ShouldSign(executionContext.RequestContext)) { await SignRequestAsync(executionContext.RequestContext).ConfigureAwait(false); executionContext.RequestContext.IsSigned = true; } } #endif /// /// Determines if the request should be signed. /// /// The request context. /// A boolean value that indicated if the request should be signed. private static bool ShouldSign(IRequestContext requestContext) { return !requestContext.IsSigned || requestContext.ClientConfig.ResignRetries; } /// /// Signs the request. /// /// The request context. public static void SignRequest(IRequestContext requestContext) { ImmutableCredentials immutableCredentials = requestContext.ImmutableCredentials; // credentials would be null in the case of anonymous users getting public resources from S3 if (immutableCredentials == null && requestContext.Signer.RequiresCredentials) return; using (requestContext.Metrics.StartEvent(Metric.RequestSigningTime)) { if (immutableCredentials?.UseToken == true && !(requestContext.Signer is NullSigner) && !(requestContext.Signer is BearerTokenSigner)) { ClientProtocol protocol = requestContext.Signer.Protocol; switch (protocol) { case ClientProtocol.QueryStringProtocol: requestContext.Request.Parameters["SecurityToken"] = immutableCredentials.Token; break; case ClientProtocol.RestProtocol: requestContext.Request.Headers[HeaderKeys.XAmzSecurityTokenHeader] = immutableCredentials.Token; break; default: throw new InvalidDataException("Cannot determine protocol"); } } requestContext.Signer.Sign(requestContext.Request, requestContext.ClientConfig, requestContext.Metrics, immutableCredentials); } } #if AWS_ASYNC_API /// /// Signs the request. /// /// The request context. private static async Task SignRequestAsync(IRequestContext requestContext) { ImmutableCredentials immutableCredentials = requestContext.ImmutableCredentials; // credentials would be null in the case of anonymous users getting public resources from S3 if (immutableCredentials == null && requestContext.Signer.RequiresCredentials) return; using (requestContext.Metrics.StartEvent(Metric.RequestSigningTime)) { if (immutableCredentials?.UseToken == true && !(requestContext.Signer is NullSigner) && !(requestContext.Signer is BearerTokenSigner)) { ClientProtocol protocol = requestContext.Signer.Protocol; switch (protocol) { case ClientProtocol.QueryStringProtocol: requestContext.Request.Parameters["SecurityToken"] = immutableCredentials.Token; break; case ClientProtocol.RestProtocol: requestContext.Request.Headers[HeaderKeys.XAmzSecurityTokenHeader] = immutableCredentials.Token; break; default: throw new InvalidDataException("Cannot determine protocol"); } } await requestContext.Signer .SignAsync( requestContext.Request, requestContext.ClientConfig, requestContext.Metrics, immutableCredentials) .ConfigureAwait(false); } } #endif } }