예제 #1
0
        /// <summary>
        /// Helper method for AuthorizeS3ToPublishAsync()
        /// </summary>
        /// <param name="attributes"></param>
        /// <param name="topicArn"></param>
        /// <param name="bucket"></param>
        /// <param name="policy"></param>
        /// <param name="statement"></param>
        private static void GetNewPolicyAndStatementForTopicAttributes(Dictionary <string, string> attributes, string topicArn, string bucket, out Policy policy, out Statement statement)
        {
            if (attributes.ContainsKey("Policy") && !string.IsNullOrEmpty(attributes["Policy"]))
            {
                policy = Policy.FromJson(attributes["Policy"]);
            }
            else
            {
                policy = new Policy();
            }

            var sourceArn = string.Format(CultureInfo.InvariantCulture, "arn:aws:s3:*:*:{0}", bucket);

            statement = new Statement(Statement.StatementEffect.Allow);
            statement.Actions.Add(SNSActionIdentifiers.Publish);
            statement.Resources.Add(new Resource(topicArn));
            statement.Principals.Add(new Principal("*"));
            statement.Conditions.Add(ConditionFactory.NewSourceArnCondition(sourceArn));

            // If the arn doesn't have the required tokens then it is most likely be called from a mock or fake AWS service.
            // Since this is an existing method we don't want to introduce a new exception. So if there is no account id then
            // don't add the extra condition.
            if (Arn.TryParse(topicArn, out Arn arn) && !string.IsNullOrEmpty(arn.AccountId))
            {
                statement.Conditions.Add(ConditionFactory.NewCondition(ConditionFactory.StringComparisonType.StringEquals, ConditionFactory.SOURCE_ACCOUNT_KEY, arn.AccountId));
            }
        }
예제 #2
0
        private static void ProcessPreRequestHandlers(IExecutionContext executionContext)
        {
            var request = executionContext.RequestContext.OriginalRequest;

            // For CreateAccessPoint, the bucket needs to be extracted from the Arn before
            // it is added to the request payload. Setting outpost id so that the header isn't
            // lost in the case of an outpost request
            var createAccessPointRequest = request as CreateAccessPointRequest;
            Arn arn;

            if (createAccessPointRequest != null && createAccessPointRequest.IsSetBucket() &&
                Arn.TryParse(createAccessPointRequest.Bucket, out arn))
            {
                IS3Resource s3Resource = null;
                if (arn.IsOutpostArn())
                {
                    s3Resource = arn.ParseOutpost();
                }
                if (s3Resource != null)
                {
                    createAccessPointRequest.OutpostId = ((S3OutpostResource)s3Resource).OutpostId;
                    createAccessPointRequest.Bucket    = s3Resource.Name;
                    createAccessPointRequest.AccountId = createAccessPointRequest.AccountId ?? arn.AccountId;
                }
            }
        }
예제 #3
0
        /// <summary>
        /// Check if the value of any dictionary item
        /// is of type ARN.
        /// <b>Note:</b> this assumes that there is just 0-1 ARN in the path resource dictionary
        /// </summary>
        /// <param name="dictValues">The dictionary</param>
        /// <param name="arn">ARN found in dictionary</param>
        /// <returns>A boolean whether or not the dictionary contains an ARN in the values</returns>
        internal static bool DictionaryContainsArn(IDictionary <string, string> dictValues, out Arn arn)
        {
            Arn outArn      = null;
            var matchingKvp = dictValues.FirstOrDefault(kvp => Arn.TryParse(kvp.Value, out outArn));

            arn = matchingKvp.Value != null ? outArn : null;
            return(arn != null);
        }
예제 #4
0
        /// <summary>
        /// Replace the ARNs in the dictionary
        /// with the extracted bucket or access point name.
        /// <b>Note:</b> this assumes that there is just 0-1 ARN in the path resource dictionary
        /// </summary>
        /// <param name="dictValues">The dictionary of values</param>
        /// <param name="bucketOrAccessPointName">bucket or access point name</param>
        public static void ReplacePathResourceArns(IDictionary <string, string> dictValues, string bucketOrAccessPointName)
        {
            var matchingKvp = dictValues.FirstOrDefault(kvp => Arn.TryParse(kvp.Value, out _));

            if (!matchingKvp.Equals(default(KeyValuePair <string, string>)))
            {
                dictValues[matchingKvp.Key] = bucketOrAccessPointName;
            }
        }
예제 #5
0
        private static bool IsS3AccessPointsArn(string bucket)
        {
            Arn arn;

            if (Arn.TryParse(bucket, out arn))
            {
                string accessPointString;
                return(arn.TryParseAccessPoint(out accessPointString));
            }
            return(false);
        }
예제 #6
0
        /// <summary>
        /// Check the many places that the ARN could be in an S3 Control request
        /// for an ARN.
        /// <ul>
        /// <li> CreateAccessPoint can contain the ARN in the payload </li>
        /// <li> ListAccessPoints can contain an ARN in the query params </li>
        /// <li> Most other requests can contain an ARN in the resource path </li>
        /// </ul>
        /// </summary>
        /// <param name="request">The request being sent to S3Control</param>
        /// <param name="arn">Any ARN found in the request</param>
        /// <returns>A boolean of whether or not the request contains an ARN</returns>
        internal static bool RequestContainsArn(IRequest request, out Arn arn)
        {
            var createAccessPointRequest = request.OriginalRequest as CreateAccessPointRequest;

            if (createAccessPointRequest != null && createAccessPointRequest.IsSetBucket() &&
                Arn.TryParse(createAccessPointRequest.Bucket.Trim().Trim(separators), out arn))
            {
                return(true);
            }
            return(DictionaryContainsArn(request.PathResources, out arn) ||
                   DictionaryContainsArn(request.Parameters, out arn));
        }
예제 #7
0
 /// <summary>
 /// Creates a <see cref="TopicAddress"/> from a topic ARN.
 /// </summary>
 /// <param name="topicArn">The SNS topic ARN.</param>
 /// <returns>A <see cref="TopicAddress"/> created from the ARN.</returns>
 /// <exception cref="ArgumentException"></exception>
 public static TopicAddress FromArn(string topicArn)
 {
     if (!Arn.IsArn(topicArn) || !Arn.TryParse(topicArn, out var arn))
     {
         throw new ArgumentException("Must be a valid ARN.", nameof(topicArn));
     }
     if (!string.Equals(arn.Service, "sns", StringComparison.OrdinalIgnoreCase))
     {
         throw new ArgumentException("Must be an ARN for an SNS topic.", nameof(topicArn));
     }
     return(new TopicAddress {
         TopicArn = topicArn
     });
 }
예제 #8
0
        /// <summary>
        /// Create a signed URL allowing access to a resource that would
        /// usually require authentication.
        /// </summary>
        /// <remarks>
        /// <para>
        /// When using query string authentication you create a query,
        /// specify an expiration time for the query, sign it with your
        /// signature, place the data in an HTTP request, and distribute
        /// the request to a user or embed the request in a web page.
        /// </para>
        /// <para>
        /// A PreSigned URL can be generated for GET, PUT, DELETE and HEAD
        /// operations on your bucketName, keys, and versions.
        /// </para>
        /// </remarks>
        /// <param name="request">The GetPreSignedUrlRequest that defines the
        /// parameters of the operation.</param>
        /// <param name="useSigV2Fallback">determines if signing will fall back to SigV2 if the
        /// signing region is us-east-1</param>
        /// <returns>A string that is the signed http request.</returns>
        /// <exception cref="T:System.ArgumentException" />
        /// <exception cref="T:System.ArgumentNullException" />
        internal string GetPreSignedURLInternal(GetPreSignedUrlRequest request, bool useSigV2Fallback = true)
        {
            if (Credentials == null)
            {
                throw new AmazonS3Exception("Credentials must be specified, cannot call method anonymously");
            }

            if (request == null)
            {
                throw new ArgumentNullException("request", "The PreSignedUrlRequest specified is null!");
            }

            if (!request.IsSetExpires())
            {
                throw new InvalidOperationException("The Expires specified is null!");
            }

            var aws4Signing = AWSConfigsS3.UseSignatureVersion4;

            Arn    arn;
            string accessPoint;

            if (Arn.TryParse(request.BucketName, out arn) &&
                (arn.TryParseAccessPoint(out accessPoint) || arn.IsOutpostArn()))
            {
                aws4Signing = true;
            }
            else
            {
                var region = AWS4Signer.DetermineSigningRegion(Config, "s3", alternateEndpoint: null, request: null);
                if (aws4Signing && string.IsNullOrEmpty(region))
                {
                    throw new InvalidOperationException("To use AWS4 signing, a region must be specified in the client configuration using the AuthenticationRegion or Region properties, or be determinable from the service URL.");
                }

                RegionEndpoint endpoint = RegionEndpoint.GetBySystemName(region);
                var            s3SignatureVersionOverride = endpoint.GetEndpointForService("s3").SignatureVersionOverride;
                if (s3SignatureVersionOverride == "4" || s3SignatureVersionOverride == null)
                {
                    aws4Signing = true;
                }

                var fallbackToSigV2 = useSigV2Fallback && !AWSConfigsS3.UseSigV4SetExplicitly;
                if (endpoint?.SystemName == RegionEndpoint.USEast1.SystemName && fallbackToSigV2)
                {
                    aws4Signing = false;
                }

                // If the expiration is longer than SigV4 will allow then automatically use SigV2 instead.
                // But only if the region we're signing for allows SigV2.
                if (aws4Signing)
                {
                    var secondsUntilExpiration = GetSecondsUntilExpiration(this.Config, request, aws4Signing);

                    if (secondsUntilExpiration > AWS4PreSignedUrlSigner.MaxAWS4PreSignedUrlExpiry &&
                        s3SignatureVersionOverride == "2")
                    {
                        aws4Signing = false;
                    }
                }
            }


            var immutableCredentials = Credentials.GetCredentials();
            var irequest             = Marshall(this.Config, request, immutableCredentials.AccessKey, immutableCredentials.Token, aws4Signing);

            irequest.Endpoint = EndpointResolver.DetermineEndpoint(this.Config, irequest);

            var context = new Amazon.Runtime.Internal.ExecutionContext(new Amazon.Runtime.Internal.RequestContext(true, new NullSigner())
            {
                Request = irequest, ClientConfig = this.Config
            }, null);

            AmazonS3PostMarshallHandler.ProcessRequestHandlers(context);

            var metrics = new RequestMetrics();

            string authorization;

            if (aws4Signing)
            {
                var aws4Signer    = new AWS4PreSignedUrlSigner();
                var signingResult = aws4Signer.SignRequest(irequest,
                                                           this.Config,
                                                           metrics,
                                                           immutableCredentials.AccessKey,
                                                           immutableCredentials.SecretKey);
                authorization = "&" + signingResult.ForQueryParameters;
            }
            else
            {
                Amazon.S3.Internal.S3Signer.SignRequest(irequest, metrics, immutableCredentials.AccessKey, immutableCredentials.SecretKey);
                authorization = irequest.Headers[HeaderKeys.AuthorizationHeader];
                authorization = authorization.Substring(authorization.IndexOf(":", StringComparison.Ordinal) + 1);
                authorization = "&Signature=" + AmazonS3Util.UrlEncode(authorization, false);
            }

            Uri    url    = AmazonServiceClient.ComposeUrl(irequest);
            string result = url.AbsoluteUri + authorization;

            Protocol protocol = DetermineProtocol();

            if (request.Protocol != protocol)
            {
                switch (protocol)
                {
                case Protocol.HTTP:
                    result = result.Replace("http://", "https://");
                    break;

                case Protocol.HTTPS:
                    result = result.Replace("https://", "http://");
                    break;
                }
            }
            return(result);
        }
예제 #9
0
        internal static bool IsS3OutpostsArn(string bucket)
        {
            Arn arn;

            return(Arn.TryParse(bucket, out arn) && arn.IsOutpostArn());
        }