private static IEnumerable <string> CanonicalizeHeaders(IEscherRequest request, string[] headersToSign) { var headers = request.Headers .Select(NormalizeHeader) .Where(h => headersToSign.Contains(h.Name)) .OrderBy(h => h.Name) .ToArray(); var headersAsString = new List <string>(); foreach (var header in headers) { var currentHeader = header; if (headersAsString.Any(h => h.Contains(currentHeader.Name + ":"))) { continue; } var headersWithSameName = headers.Where(h => h.Name == currentHeader.Name); headersAsString.Add(currentHeader.Name + ":" + String.Join(",", headersWithSameName.Select(h => h.Value))); } return(headersAsString); }
public string Canonicalize(IEscherRequest request, string[] headersToSign, EscherConfig config) { headersToSign = headersToSign.Select(h => h.ToLower()).ToArray(); return String.Join("\n", new[] { request.Method.ToUpper(), request.Uri.AbsolutePath, CanonicalizeQueryString(request.Uri), }.Concat(CanonicalizeHeaders(request, headersToSign)).Concat(new[] { null, String.Join(";", headersToSign.OrderBy(s => s)), HashHelper.Hash(request.Body, config.HashAlgorithm) })); }
public string Canonicalize(IEscherRequest request, string[] headersToSign, EscherConfig config) { headersToSign = headersToSign.Select(h => h.ToLower()).ToArray(); return(String.Join("\n", new[] { request.Method.ToUpper(), request.Uri.AbsolutePath, CanonicalizeQueryString(request.Uri), }.Concat(CanonicalizeHeaders(request, headersToSign)).Concat(new[] { null, String.Join(";", headersToSign.OrderBy(s => s)), HashHelper.Hash(request.Body, config.HashAlgorithm) }))); }
private void AddMandatoryHeaders(IEscherRequest request, DateTime currentTime) { var dateHeaderPresent = request.Headers.Any(header => String.Equals(header.Name, Config.DateHeaderName, StringComparison.CurrentCultureIgnoreCase)); if (!dateHeaderPresent) { request.Headers.Add(new Header(Config.DateHeaderName, currentTime.ToEscherLongDate())); } var hostHeaderPresent = request.Headers.Any(header => String.Equals(header.Name, "host", StringComparison.CurrentCultureIgnoreCase)); if (!hostHeaderPresent) { request.Headers.Add(new Header("host", request.Uri.Host + (request.Uri.IsDefaultPort ? "" : ":" + request.Uri.Port))); } }
private static IEnumerable<string> CanonicalizeHeaders(IEscherRequest request, string[] headersToSign) { var headers = request.Headers .Select(NormalizeHeader) .Where(h => headersToSign.Contains(h.Name)) .OrderBy(h => h.Name) .ToArray(); var headersAsString = new List<string>(); foreach (var header in headers) { var currentHeader = header; if (headersAsString.Any(h => h.Contains(currentHeader.Name + ":"))) continue; var headersWithSameName = headers.Where(h => h.Name == currentHeader.Name); headersAsString.Add(currentHeader.Name + ":" + String.Join(",", headersWithSameName.Select(h => h.Value))); } return headersAsString; }
public string Authenticate(IEscherRequest request, IKeyDb keyDb, DateTime currentTime) { currentTime = currentTime.ToUniversalTime(); var authHeader = request.Headers.FirstOrDefault(header => header.Name == Config.AuthHeaderName); if (authHeader == null) { throw new EscherAuthenticationException("The authorization header is missing"); } var dateHeader = request.Headers.FirstOrDefault(header => header.Name == Config.DateHeaderName); if (dateHeader == null) { throw new EscherAuthenticationException("The date header is missing"); } var hostHeader = request.Headers.FirstOrDefault(header => header.Name.ToLower() == "host"); if (hostHeader == null) { throw new EscherAuthenticationException("The host header is missing"); } var match = Regex.Match(authHeader.Value, "^([^\\-]+)-HMAC-(SHA[\\d]+) Credential=([^/]+)/([\\d]{8})/([^,]+), SignedHeaders=([^,]+), Signature=([a-z0-9]+)$"); if (!match.Success) { throw new EscherAuthenticationException("Could not parse auth header"); } var algorythmPrefix = match.Groups[1].Value; var hashAlgorythm = match.Groups[2].Value; var apiKey = match.Groups[3].Value; var shortDate = match.Groups[4].Value; var credentialScope = match.Groups[5].Value; var signedHeaders = match.Groups[6].Value.Split(';'); var signature = match.Groups[7].Value; DateTime requestTime; try { requestTime = DateTime.Parse(dateHeader.Value).ToUniversalTime(); } catch (FormatException) { requestTime = DateTimeParser.FromEscherLongDate(dateHeader.Value); } if (requestTime.ToUniversalTime().Date != DateTimeParser.FromEscherShortDate(shortDate).Date) { throw new EscherAuthenticationException("The Authorization header's shortDate does not match with the request date"); } if (Math.Abs((currentTime - requestTime).TotalSeconds) > Config.ClockSkew) { throw new EscherAuthenticationException("The request date is not within the accepted time range"); } if (credentialScope != Config.CredentialScope) { throw new EscherAuthenticationException("The credential scope is invalid"); } if (!signedHeaders.Contains(Config.DateHeaderName.ToLower())) { throw new EscherAuthenticationException("The date header is not signed"); } if (!signedHeaders.Contains("host")) { throw new EscherAuthenticationException("The host header is not signed"); } if (!new[] { "SHA256", "SHA512" }.Contains(hashAlgorythm.ToUpper())) { throw new EscherAuthenticationException("Only SHA256 and SHA512 hash algorithms are allowed"); } var secret = keyDb[apiKey]; if (secret == null) { throw new EscherAuthenticationException("Invalid Escher key"); } var canonicalizedRequest = new RequestCanonicalizer().Canonicalize(request, signedHeaders, Config); var stringToSign = new StringToSignComposer().Compose(canonicalizedRequest, requestTime, Config); var calculatedSignature = SignatureCalculator.Sign(stringToSign, secret, requestTime, Config); if (calculatedSignature != signature) { throw new EscherAuthenticationException("The signatures do not match"); } return(apiKey); }
public string Authenticate(IEscherRequest request, IKeyDb keyDb) { return(Authenticate(request, keyDb, DateTime.Now)); }