public string SignRequest <TReq>(TReq request, TimeSpan expiresIn) where TReq : IRequest { request.Timestamp = DateTimeOffset.UtcNow; request.RequestId = Guid.NewGuid(); _logger.LogTrace("Handling {RequestType} with request id {RequestId}", typeof(TReq).Name, request.RequestId); _marshaller.MarshalRequest(_config, request); IEndpointData endpointData = _endpointBuilder.GetEndpoint(request); request.SetHeader(HttpHeaders.Host, endpointData.Host); string scope = _scopeBuilder.CreateScope("s3", request.Timestamp); request.SetQueryParameter(AmzParameters.XAmzAlgorithm, SigningConstants.AlgorithmTag); request.SetQueryParameter(AmzParameters.XAmzCredential, _config.Credentials.KeyId + '/' + scope); request.SetQueryParameter(AmzParameters.XAmzDate, request.Timestamp.ToString(DateTimeFormats.Iso8601DateTime, DateTimeFormatInfo.InvariantInfo)); request.SetQueryParameter(AmzParameters.XAmzExpires, expiresIn.TotalSeconds.ToString(NumberFormatInfo.InvariantInfo)); request.SetQueryParameter(AmzParameters.XAmzSignedHeaders, string.Join(";", HeaderWhitelist.FilterHeaders(request.Headers).Select(x => x.Key))); //Copy all headers to query parameters foreach (KeyValuePair <string, string> header in request.Headers) { if (header.Key == HttpHeaders.Host) { continue; } request.SetQueryParameter(header.Key, header.Value); } _authBuilder.BuildAuthorization(request); //Clear sensitive material from the request if (request is IContainSensitiveMaterial sensitive) { sensitive.ClearSensitiveMaterial(); } StringBuilder sb = StringBuilderPool.Shared.Rent(200); sb.Append(endpointData.Endpoint); RequestHelper.AppendPath(sb, _config, request); RequestHelper.AppendQueryParameters(sb, request); return(StringBuilderPool.Shared.ReturnString(sb)); }
internal string BuildInternal(DateTimeOffset date, IReadOnlyDictionary <string, string> headers, byte[] signature) { _logger.LogTrace("Building header based authorization"); string scope = _scopeBuilder.CreateScope("s3", date); StringBuilder header = StringBuilderPool.Shared.Rent(250); header.Append(SigningConstants.AlgorithmTag); header.AppendFormat(CultureInfo.InvariantCulture, " Credential={0}/{1},", _config.Credentials.KeyId, scope); header.AppendFormat(CultureInfo.InvariantCulture, "SignedHeaders={0},", string.Join(";", HeaderWhitelist.FilterHeaders(headers).Select(x => x.Key))); header.AppendFormat(CultureInfo.InvariantCulture, "Signature={0}", signature.HexEncode()); string authHeader = StringBuilderPool.Shared.ReturnString(header); _logger.LogDebug("AuthHeader: {AuthHeader}", authHeader); return(authHeader); }
internal string CreateCanonicalRequest(Guid requestId, string url, HttpMethodType method, IReadOnlyDictionary <string, string> headers, IReadOnlyDictionary <string, string> query, string contentHash) { _logger.LogTrace("Creating canonical request for {RequestId}", requestId); //Consists of: // HTTP Verb + \n // Canonical URI + \n // Canonical Query String + \n // Canonical Headers + \n // Signed Headers + \n // Sha256 Content Hash StringBuilder sb = StringBuilderPool.Shared.Rent(300); sb.Append(method.ToString()).Append(SigningConstants.Newline); sb.Append(url).Append(SigningConstants.Newline); sb.Append(CanonicalizeQueryParameters(query)).Append(SigningConstants.Newline); //Headers needs to be ordered by key OrderedDictionary <string, string> orderedHeaders = new OrderedDictionary <string, string>(HeaderWhitelist.FilterHeaders(headers)); sb.Append(CanonicalizeHeaders(orderedHeaders)).Append(SigningConstants.Newline); sb.Append(CanonicalizeHeaderNames(orderedHeaders)).Append(SigningConstants.Newline); sb.Append(contentHash); string canonicalRequest = StringBuilderPool.Shared.ReturnString(sb); _logger.LogDebug("CanonicalRequest: {CanonicalRequest}", canonicalRequest); return(canonicalRequest); }