/// <summary>
        /// Instantiate the object without supplying a stream.  Useful for HEAD responses.
        /// </summary>
        /// <param name="ctx">S3 context.</param>
        public S3Response(S3Context ctx)
        {
            if (ctx == null)
            {
                throw new ArgumentNullException(nameof(ctx));
            }

            _Http    = ctx.Http;
            _Request = ctx.Request;
        }
        /// <summary>
        /// Instantiate the object without supplying a stream.  Useful for HEAD responses.
        /// </summary>
        /// <param name="ctx">S3 context.</param>
        /// <param name="statusCode">HTTP status code.</param>
        /// <param name="contentType">Content-type.</param>
        /// <param name="headers">HTTP headers.</param>
        /// <param name="contentLength">Content length.</param>
        public S3Response(S3Context ctx, int statusCode = 200, string contentType = "text/plain", Dictionary <string, string> headers = null, long contentLength = 0)
        {
            if (ctx == null)
            {
                throw new ArgumentNullException(nameof(ctx));
            }

            _Http    = ctx.Http;
            _Request = ctx.Request;

            StatusCode    = statusCode;
            ContentType   = contentType;
            ContentLength = contentLength;
            Chunked       = _Request.Chunked;
        }
Esempio n. 3
0
        /// <summary>
        /// Instantiates the object.
        /// </summary>
        /// <param name="ctx">S3 context.</param>
        /// <param name="baseDomains">List of base domains against which the hostname should be evaluated to identify the bucket.  For instance, to resolve buckets for *.localhost, specify '.localhost'.</param>
        /// <param name="logger">Method to invoke to send log messages.</param>
        public S3Request(S3Context ctx, List <string> baseDomains = null, Action <string> logger = null)
        {
            if (ctx == null)
            {
                throw new ArgumentNullException(nameof(ctx));
            }
            if (ctx.Http == null)
            {
                throw new ArgumentNullException(nameof(ctx.Http));
            }
            if (baseDomains != null)
            {
                _BaseDomains = baseDomains;
            }

            _Context     = ctx;
            _Logger      = logger;
            _BaseDomains = baseDomains;

            ParseHttpContext();
        }
        private async Task RequestHandler(HttpContext ctx)
        {
            if (ctx == null)
            {
                throw new ArgumentNullException(nameof(ctx));
            }
            DateTime  startTime = DateTime.Now;
            S3Context s3ctx     = null;

            try
            {
                s3ctx = new S3Context(ctx, _BaseDomains, null, (Logging.S3Requests ? Logger : null));
            }
            catch (Exception e)
            {
                if (Logging.Exceptions)
                {
                    Logger?.Invoke(_Header + "Exception:" + Environment.NewLine + Common.SerializeJson(e, true));
                }

                return;
            }

            bool success = false;

            try
            {
                if (Logging.HttpRequests)
                {
                    Logger?.Invoke(_Header + "HTTP request: " + Environment.NewLine + s3ctx.Http.ToJson(true));
                }

                if (Logging.S3Requests)
                {
                    Logger?.Invoke(_Header + "S3 request: " + Environment.NewLine + s3ctx.Request.ToJson(true));
                }

                if (PreRequestHandler != null)
                {
                    success = await PreRequestHandler(s3ctx).ConfigureAwait(false);

                    if (success)
                    {
                        await s3ctx.Response.Send().ConfigureAwait(false);

                        return;
                    }
                }

                if (AuthenticateSignatures && GetSecretKey != null)
                {
                    if (!String.IsNullOrEmpty(s3ctx.Request.AccessKey))
                    {
                        byte[] secretKey = GetSecretKey(s3ctx);
                        if (secretKey == null || secretKey.Length < 1)
                        {
                            await s3ctx.Response.Send(S3Objects.ErrorCode.InvalidRequest).ConfigureAwait(false);

                            return;
                        }

                        if (!s3ctx.Request.IsValidSignature(secretKey))
                        {
                            await s3ctx.Response.Send(S3Objects.ErrorCode.SignatureDoesNotMatch).ConfigureAwait(false);

                            return;
                        }
                    }
                }

                switch (s3ctx.Request.RequestType)
                {
                case S3RequestType.ListBuckets:
                    if (Service.ListBuckets != null)
                    {
                        await Service.ListBuckets(s3ctx).ConfigureAwait(false);

                        return;
                    }
                    break;

                case S3RequestType.BucketDelete:
                    if (Bucket.Delete != null)
                    {
                        await Bucket.Delete(s3ctx).ConfigureAwait(false);

                        return;
                    }
                    break;

                case S3RequestType.BucketDeleteTags:
                    if (Bucket.DeleteTags != null)
                    {
                        await Bucket.DeleteTags(s3ctx).ConfigureAwait(false);

                        return;
                    }
                    break;

                case S3RequestType.BucketDeleteWebsite:
                    if (Bucket.DeleteWebsite != null)
                    {
                        await Bucket.DeleteWebsite(s3ctx).ConfigureAwait(false);

                        return;
                    }
                    break;

                case S3RequestType.BucketExists:
                    if (Bucket.Exists != null)
                    {
                        await Bucket.Exists(s3ctx).ConfigureAwait(false);

                        return;
                    }
                    break;

                case S3RequestType.BucketRead:
                    if (Bucket.Read != null)
                    {
                        await Bucket.Read(s3ctx).ConfigureAwait(false);

                        return;
                    }
                    break;

                case S3RequestType.BucketReadAcl:
                    if (Bucket.ReadAcl != null)
                    {
                        await Bucket.ReadAcl(s3ctx).ConfigureAwait(false);

                        return;
                    }
                    break;

                case S3RequestType.BucketReadLocation:
                    if (Bucket.ReadLocation != null)
                    {
                        await Bucket.ReadLocation(s3ctx).ConfigureAwait(false);

                        return;
                    }
                    break;

                case S3RequestType.BucketReadLogging:
                    if (Bucket.ReadLogging != null)
                    {
                        await Bucket.ReadLogging(s3ctx).ConfigureAwait(false);

                        return;
                    }
                    break;

                case S3RequestType.BucketReadTags:
                    if (Bucket.ReadTags != null)
                    {
                        await Bucket.ReadTags(s3ctx).ConfigureAwait(false);

                        return;
                    }
                    break;

                case S3RequestType.BucketReadVersioning:
                    if (Bucket.ReadVersioning != null)
                    {
                        await Bucket.ReadVersioning(s3ctx).ConfigureAwait(false);

                        return;
                    }
                    break;

                case S3RequestType.BucketReadVersions:
                    if (Bucket.ReadVersions != null)
                    {
                        await Bucket.ReadVersions(s3ctx).ConfigureAwait(false);

                        return;
                    }
                    break;

                case S3RequestType.BucketReadWebsite:
                    if (Bucket.ReadWebsite != null)
                    {
                        await Bucket.ReadWebsite(s3ctx).ConfigureAwait(false);

                        return;
                    }
                    break;

                case S3RequestType.BucketWrite:
                    if (Bucket.Write != null)
                    {
                        await Bucket.Write(s3ctx).ConfigureAwait(false);

                        return;
                    }
                    break;

                case S3RequestType.BucketWriteAcl:
                    if (Bucket.WriteAcl != null)
                    {
                        await Bucket.WriteAcl(s3ctx).ConfigureAwait(false);

                        return;
                    }
                    break;

                case S3RequestType.BucketWriteLogging:
                    if (Bucket.WriteLogging != null)
                    {
                        await Bucket.WriteLogging(s3ctx).ConfigureAwait(false);

                        return;
                    }
                    break;

                case S3RequestType.BucketWriteTags:
                    if (Bucket.WriteTags != null)
                    {
                        await Bucket.WriteTags(s3ctx).ConfigureAwait(false);

                        return;
                    }
                    break;

                case S3RequestType.BucketWriteVersioning:
                    if (Bucket.WriteVersioning != null)
                    {
                        await Bucket.WriteVersioning(s3ctx).ConfigureAwait(false);

                        return;
                    }
                    break;

                case S3RequestType.BucketWriteWebsite:
                    if (Bucket.WriteWebsite != null)
                    {
                        await Bucket.WriteWebsite(s3ctx).ConfigureAwait(false);

                        return;
                    }
                    break;

                case S3RequestType.ObjectDelete:
                    if (Object.Delete != null)
                    {
                        await Object.Delete(s3ctx).ConfigureAwait(false);

                        return;
                    }
                    break;

                case S3RequestType.ObjectDeleteMultiple:
                    if (Object.DeleteMultiple != null)
                    {
                        await Object.DeleteMultiple(s3ctx).ConfigureAwait(false);

                        return;
                    }
                    break;

                case S3RequestType.ObjectDeleteTags:
                    if (Object.DeleteTags != null)
                    {
                        await Object.DeleteTags(s3ctx).ConfigureAwait(false);

                        return;
                    }
                    break;

                case S3RequestType.ObjectExists:
                    if (Object.Exists != null)
                    {
                        await Object.Exists(s3ctx).ConfigureAwait(false);

                        return;
                    }
                    break;

                case S3RequestType.ObjectRead:
                    if (Object.Read != null)
                    {
                        await Object.Read(s3ctx).ConfigureAwait(false);

                        return;
                    }
                    break;

                case S3RequestType.ObjectReadAcl:
                    if (Object.ReadAcl != null)
                    {
                        await Object.ReadAcl(s3ctx).ConfigureAwait(false);

                        return;
                    }
                    break;

                case S3RequestType.ObjectReadLegalHold:
                    if (Object.ReadLegalHold != null)
                    {
                        await Object.ReadLegalHold(s3ctx).ConfigureAwait(false);

                        return;
                    }
                    break;

                case S3RequestType.ObjectReadRange:
                    if (Object.ReadRange != null)
                    {
                        await Object.ReadRange(s3ctx).ConfigureAwait(false);

                        return;
                    }
                    break;

                case S3RequestType.ObjectReadRetention:
                    if (Object.ReadRetention != null)
                    {
                        await Object.ReadRetention(s3ctx).ConfigureAwait(false);

                        return;
                    }
                    break;

                case S3RequestType.ObjectReadTags:
                    if (Object.ReadTags != null)
                    {
                        await Object.ReadTags(s3ctx).ConfigureAwait(false);

                        return;
                    }
                    break;

                case S3RequestType.ObjectWrite:
                    if (Object.Write != null)
                    {
                        await Object.Write(s3ctx).ConfigureAwait(false);

                        return;
                    }
                    break;

                case S3RequestType.ObjectWriteAcl:
                    if (Object.WriteAcl != null)
                    {
                        await Object.WriteAcl(s3ctx).ConfigureAwait(false);

                        return;
                    }
                    break;

                case S3RequestType.ObjectWriteLegalHold:
                    if (Object.WriteLegalHold != null)
                    {
                        await Object.WriteLegalHold(s3ctx).ConfigureAwait(false);

                        return;
                    }
                    break;

                case S3RequestType.ObjectWriteRetention:
                    if (Object.WriteRetention != null)
                    {
                        await Object.WriteRetention(s3ctx).ConfigureAwait(false);

                        return;
                    }
                    break;

                case S3RequestType.ObjectWriteTags:
                    if (Object.WriteTags != null)
                    {
                        await Object.WriteTags(s3ctx).ConfigureAwait(false);

                        return;
                    }
                    break;
                }

                if (DefaultRequestHandler != null)
                {
                    await DefaultRequestHandler(s3ctx).ConfigureAwait(false);

                    return;
                }

                await s3ctx.Response.Send(S3Objects.ErrorCode.InvalidRequest).ConfigureAwait(false);

                return;
            }
            catch (Exception e)
            {
                if (Logging.Exceptions)
                {
                    Logger?.Invoke(_Header + "Exception:" + Environment.NewLine + Common.SerializeJson(e, true));
                }

                await s3ctx.Response.Send(S3Objects.ErrorCode.InternalError).ConfigureAwait(false);

                return;
            }
            finally
            {
                if (Logging.HttpRequests)
                {
                    Logger?.Invoke(
                        _Header +
                        "[" +
                        ctx.Request.Source.IpAddress + ":" +
                        ctx.Request.Source.Port +
                        "] " +
                        ctx.Request.Method.ToString() + " " +
                        ctx.Request.Url.RawWithoutQuery + " " +
                        s3ctx.Response.StatusCode +
                        " [" + Common.TotalMsFrom(startTime) + "ms]");
                }

                if (PostRequestHandler != null)
                {
                    await PostRequestHandler(s3ctx).ConfigureAwait(false);
                }
            }
        }
Esempio n. 5
0
        // For V2, see https://docs.aws.amazon.com/AmazonS3/latest/dev/RESTAuthentication.html
        // For V4, see https://docs.aws.amazon.com/AmazonS3/latest/API/sig-v4-header-based-auth.html

        internal static bool IsValidSignature(S3Context ctx, byte[] secretKey, Action <string> logger)
        {
            if (ctx == null)
            {
                throw new ArgumentNullException(nameof(ctx));
            }
            if (secretKey == null || secretKey.Length < 1)
            {
                throw new ArgumentNullException(nameof(secretKey));
            }

            _S3Context = ctx;
            _SecretKey = secretKey;
            _Logger    = logger;

            byte[] signingKey          = null;
            string hmacSha1Signature   = null;
            string hmacSha256Signature = null;
            string logMessage          = null;

            if (_S3Context.Request.SignatureVersion == S3SignatureVersion.Version2)
            {
                #region V2

                hmacSha1Signature = Common.BytesToBase64(
                    Common.HmacSha1(Encoding.UTF8.GetBytes(_V2StringToSign), secretKey)
                    );

                hmacSha256Signature = Common.BytesToBase64(
                    Common.HmacSha256(Encoding.UTF8.GetBytes(_V2StringToSign), secretKey)
                    );

                logMessage =
                    _Header + "Signature V2 validation:" + Environment.NewLine +
                    "  String to sign" + Environment.NewLine +
                    "  --------------" + Environment.NewLine +
                    _V2StringToSign + Environment.NewLine +
                    Environment.NewLine +
                    "  Client-supplied signature : " + _S3Context.Request.Signature + Environment.NewLine +
                    "  Generated HMAC-SHA1       : " + hmacSha1Signature + Environment.NewLine +
                    "  Generated HMAC-SHA256     : " + hmacSha256Signature + Environment.NewLine +
                    "  Success                   : ";

                if (hmacSha256Signature.Equals(_S3Context.Request.Signature) ||
                    hmacSha1Signature.Equals(_S3Context.Request.Signature))
                {
                    _Logger?.Invoke(logMessage + "true");
                    return(true);
                }
                else
                {
                    _Logger?.Invoke(logMessage + "false");
                    return(false);
                }

                #endregion
            }
            else if (_S3Context.Request.SignatureVersion == S3SignatureVersion.Version4)
            {
                #region V4

                signingKey = V4GenerateSigningKey(secretKey);

                hmacSha1Signature = Common.BytesToBase64(
                    Common.HmacSha1(Encoding.UTF8.GetBytes(_V4StringToSign), secretKey)
                    );

                hmacSha256Signature = Common.BytesToHex(
                    Common.HmacSha256(Encoding.UTF8.GetBytes(_V4StringToSign), signingKey)
                    )
                                      .ToLower();

                logMessage =
                    _Header + "Signature V4 validation:" + Environment.NewLine +
                    "  Canonical request" + Environment.NewLine +
                    "  -----------------" + Environment.NewLine +
                    _V4CanonicalRequest + Environment.NewLine +
                    Environment.NewLine +
                    "  String to sign" + Environment.NewLine +
                    "  --------------" + Environment.NewLine +
                    _V4StringToSign + Environment.NewLine +
                    Environment.NewLine +
                    "  Client-supplied signature : " + _S3Context.Request.Signature + Environment.NewLine +
                    "  Generated HMAC-SHA1       : " + hmacSha1Signature + Environment.NewLine +
                    "  Generated HMAC-SHA256     : " + hmacSha256Signature + Environment.NewLine +
                    "  Success                   : ";

                if (hmacSha256Signature.Equals(_S3Context.Request.Signature) ||
                    hmacSha1Signature.Equals(_S3Context.Request.Signature))
                {
                    _Logger?.Invoke(logMessage + "true");
                    return(true);
                }
                else
                {
                    _Logger?.Invoke(logMessage + "false");
                    return(false);
                }

                #endregion
            }
            else
            {
                throw new InvalidOperationException("Unable to validate signature unless signature version is V2 or V4.");
            }
        }