protected async override Task <AuthenticateResult> HandleAuthenticateAsync() { var header = SplitAuthenticationHeader(); if (header == null) { return(AuthenticateResult.NoResult()); } // Verify that request data is within acceptable time if (!DateTimeOffset.TryParseExact(Request.Headers[DateHeader], "r", System.Globalization.CultureInfo.InvariantCulture, System.Globalization.DateTimeStyles.AssumeUniversal, out DateTimeOffset requestDate)) { return(AuthenticateResult.Fail("Unable to parse Date header")); } if (requestDate > Clock.UtcNow.Add(Options.AllowedDateDrift) || requestDate < Clock.UtcNow.Subtract(Options.AllowedDateDrift)) { return(AuthenticateResult.Fail("Date is drifted more than allowed, adjust your time settings.")); } // Lookup and verify secret Logger.LogDebug("Looking up secret for {Id}", header.Value.id); var secret = await lookup.LookupAsync(header.Value.id); if (secret == null) { Logger.LogInformation("No secret found for {Id}", header.Value.id); return(AuthenticateResult.Fail("Invalid id")); } else if (secret.Length != 32) { Logger.LogError("Secret must be 32 bytes in size"); throw new InvalidOperationException("Incorrect secret size"); } // Check signature string serverSignature = SignatureHelper.Calculate(secret, SignatureHelper.Generate(requestDate, Request.ContentLength ?? 0, Request.Method, Request.Path, Request.QueryString.Value)); Logger.LogDebug("Calculated server side signature {signature}", serverSignature); if (serverSignature.Equals(header.Value.signature)) { return(AuthenticateResult.Success(new AuthenticationTicket( new GenericPrincipal(new GenericIdentity(header.Value.id), Options.GetRolesForId?.Invoke(header.Value.id) ?? null), new AuthenticationProperties() { IsPersistent = false, AllowRefresh = false }, Options.Schema))); } else { return(AuthenticateResult.Fail("Invalid signature")); } }
protected async override Task <AuthenticateResult> HandleAuthenticateAsync() { var header = SplitAuthenticationHeader(); if (header == null) { return(AuthenticateResult.NoResult()); } // Verify that request data is within acceptable time if (!DateTimeOffset.TryParseExact(Request.Headers[DateHeader], "r", System.Globalization.CultureInfo.InvariantCulture, System.Globalization.DateTimeStyles.AssumeUniversal, out DateTimeOffset requestDate)) { return(AuthenticateResult.Fail("Unable to parse Date header")); } if (requestDate > Clock.UtcNow.Add(Options.AllowedDateDrift) || requestDate < Clock.UtcNow.Subtract(Options.AllowedDateDrift)) { return(AuthenticateResult.Fail("Date drifted more than allowed, adjust your time settings.")); } var nonce = Request.Headers[NonceHeader]; if (!string.IsNullOrEmpty(nonce)) { if (cache.TryGetValue(nonce, out string _)) { return(AuthenticateResult.Fail("This message has already been processed")); } //At two times the allowed drift the nonce cache will make sure we never have a repeat message within the allowed drift and outside the allowed drift the message will be invalid due to drift cache.Set <string>(nonce, nonce, TimeSpan.FromTicks(Options.AllowedDateDrift.Ticks * 2)); } // Lookup and verify secret Logger.LogDebug("Looking up secret for {Id}", header.Value.id); var secret = await lookup.LookupAsync(header.Value.id); if (secret == null) { Logger.LogInformation("No secret found for {Id}", header.Value.id); return(AuthenticateResult.Fail("Invalid id")); } // Check signature string serverSignature = SignatureHelper.Calculate(secret, SignatureHelper.Generate(requestDate, await StreamToStringAsync(Request), Request.Method, Request.Path, Request.QueryString.Value, nonce.ToString()));; Logger.LogDebug("Calculated server side signature {signature}", serverSignature); if (serverSignature.Equals(header.Value.signature)) { return(AuthenticateResult.Success(new AuthenticationTicket( new GenericPrincipal(new GenericIdentity(header.Value.id), Options.GetRolesForId?.Invoke(header.Value.id) ?? null), new AuthenticationProperties() { IsPersistent = false, AllowRefresh = false }, Options.Schema))); } else { return(AuthenticateResult.Fail("Invalid signature")); } }