/*
* 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.Internal;
using Amazon.Runtime;
using Amazon.Runtime.Internal;
using Amazon.Runtime.Internal.Auth;
using Amazon.Runtime.Internal.Util;
using Amazon.Util;
using System;
using System.Globalization;
namespace Amazon.RDS.Internal
{
///
/// Custom pipeline handler to populate PreSignedUrl if it's empty, and the SourceRegion paramter is populated.
///
public class PreSignedUrlRequestHandler : PipelineHandler
{
private const string UriSchemeHTTPS = "https";
private const string RDSServiceNameForSigning = "rds";
private const string HTTPGet = "GET";
private const string DestinationRegionParameterKey = "DestinationRegion";
private readonly AWSCredentials _credentials;
///
/// Construct instance of PreSignedUrlRequestHandler
///
///
public PreSignedUrlRequestHandler(AWSCredentials credentials)
{
_credentials = credentials;
}
///
/// 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 System.Threading.Tasks.Task InvokeAsync(IExecutionContext executionContext)
{
PreInvoke(executionContext);
return base.InvokeAsync(executionContext);
}
#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
///
/// Auto-generates pre-signed URLs for requests that implement .
/// if the PreSignedUrl property isn't set and the SourceRegion property is set.
///
///
protected virtual void PreInvoke(IExecutionContext executionContext)
{
var preSignedUrlRequest = executionContext.RequestContext.OriginalRequest as IPreSignedUrlRequest;
if (preSignedUrlRequest != null && preSignedUrlRequest.SourceRegion != null && preSignedUrlRequest.PreSignedUrl == null)
{
var config = executionContext.RequestContext.ClientConfig;
var endpoint = RegionEndpoint.GetBySystemName(preSignedUrlRequest.SourceRegion);
if (endpoint == null)
{
throw new AmazonRDSException(string.Format(CultureInfo.InvariantCulture, "No endpoint for region {0}.", preSignedUrlRequest.SourceRegion));
}
// Marshall this request and prepare it to be signed
var marshaller = executionContext.RequestContext.Marshaller;
var iRequest = marshaller.Marshall(preSignedUrlRequest as AmazonWebServiceRequest);
iRequest.UseQueryString = true;
iRequest.HttpMethod = HTTPGet;
iRequest.Endpoint = new UriBuilder(UriSchemeHTTPS, endpoint.GetEndpointForService(config).Hostname).Uri;
iRequest.Parameters[DestinationRegionParameterKey] = executionContext.RequestContext.ClientConfig.RegionEndpoint.SystemName;
// Most pre signed URLS also have an X-Amz-Expires header. But RDS just ignores it and always imposes a +/- 14 minute time limit instead.
var immutableCredentials = _credentials.GetCredentials();
if (immutableCredentials.UseToken)
{
// Don't use HeaderKeys.XAmzSecurityTokenHeader because RDS treats this as case-sensitive
iRequest.Parameters["X-Amz-Security-Token"] = immutableCredentials.Token;
}
// Create presigned URL and assign it
var signingResult = AWS4PreSignedUrlSigner.SignRequest(iRequest, config, new RequestMetrics(),
immutableCredentials.AccessKey, immutableCredentials.SecretKey, RDSServiceNameForSigning, preSignedUrlRequest.SourceRegion);
var authorization = "&" + signingResult.ForQueryParameters;
preSignedUrlRequest.PreSignedUrl = AmazonServiceClient.ComposeUrl(iRequest).AbsoluteUri + authorization;
}
}
}
}