/// <summary> /// The message handler that authenticates the request using Hawk. /// </summary> /// <param name="options">Hawk authentication options</param> public HawkAuthenticationHandler(Options options) { if (options == null || options.CredentialsCallback == null) throw new ArgumentNullException("Invalid Hawk authentication options. Credentials callback cannot be null."); this.options = options; }
public void Configuration(IAppBuilder app) { var credentialStorage = new List<Credential>() { new Credential() { Id = "44363926-D61B-43C9-B743-34C58F04A356", Algorithm = SupportedAlgorithms.SHA256, User = "******", Key = Guid.Parse("36579269-7A4D-4E83-81C0-F928BDD42B11").ToByteArray() } }; var options = new Options() { ClockSkewSeconds = 60, LocalTimeOffsetMillis = 0, CredentialsCallback = (id) => credentialStorage.FirstOrDefault(c => c.Id == id), ResponsePayloadHashabilityCallback = (r) => true, VerificationCallback = (request, ext) => { if (String.IsNullOrEmpty(ext)) return true; string name = "X-Storage-Token"; return ext.Equals(name + ":" + request.Headers[name].First()); } }; app .UseHawkAuthentication(new HawkAuthenticationOptions(options)) .UseNancy(); }
/// <summary> /// Authenticates the incoming request based on the Authorize request header or bewit query string parameter /// </summary> /// <param name="request">The request object to be authenticated</param> /// <param name="options">Hawk authentication options</param> public HawkServer(IRequestMessage request, Options options) { now = DateTime.UtcNow.ToUnixTimeMillis(); // Record time before doing anything else if (options == null || options.CredentialsCallback == null) throw new ArgumentNullException("Invalid Hawk authentication options. Credentials callback cannot be null."); this.request = request; this.options = options; }
/// <summary> /// Returns an AuthenticationResult object corresponding to the result of authentication done /// using the client supplied artifacts in the HTTP authorization header in hawk scheme. /// </summary> /// <param name="now">Current UNIX time in milliseconds.</param> /// <param name="request">Request object.</param> /// <param name="options">Hawk authentication options</param> /// <returns></returns> internal static async Task<AuthenticationResult> AuthenticateAsync(ulong now, IRequestMessage request, Options options) { ArtifactsContainer artifacts = null; Credential credential = null; if (request.HasValidHawkScheme()) { if (ArtifactsContainer.TryParse(request.Authorization.Parameter, out artifacts)) { if (artifacts != null && artifacts.AreClientArtifactsValid) { credential = options.CredentialsCallback(artifacts.Id); if (credential != null && credential.IsValid) { var normalizedRequest = new NormalizedRequest(request, artifacts); var crypto = new Cryptographer(normalizedRequest, artifacts, credential); // Request body is needed only when payload hash is present in the request string body = null; if (artifacts.PayloadHash != null && artifacts.PayloadHash.Length > 0) { body = await request.ReadBodyAsStringAsync(); } if (crypto.IsSignatureValid(body, request.ContentType)) // MAC and hash checks { if (IsTimestampFresh(now, artifacts, options)) { // If you get this far, you are authentic. Welcome and thanks for flying Hawk! return new AuthenticationResult() { IsAuthentic = true, Artifacts = artifacts, Credential = credential, ApplicationSpecificData = artifacts.ApplicationSpecificData }; } else { // Authentic but for the timestamp freshness. // Give a chance to the client to correct the clocks skew. var timestamp = new NormalizedTimestamp(DateTime.UtcNow, credential, options.LocalTimeOffsetMillis); request.ChallengeParameter = timestamp.ToWwwAuthenticateHeaderParameter(); } } } } } } return new AuthenticationResult() { IsAuthentic = false }; }
public static void EnableHawkAuthentication(HttpConfiguration configuration) { var options = new Options { ClockSkewSeconds = 60, LocalTimeOffsetMillis = 0, CredentialsCallback = OnCredentialsCallback, ResponsePayloadHashabilityCallback = r => true, VerificationCallback = OnVerificationCallback }; var handler = new HawkAuthenticationHandler(options); configuration.MessageHandlers.Add(handler); }
/// <summary> /// Returns true if the timestamp sent in by the client is fresh subject to the /// maximum allowed skew and the adjustment offset. /// </summary> private static bool IsTimestampFresh(ulong now, ArtifactsContainer artifacts, Options options) { now = now + Convert.ToUInt64(options.LocalTimeOffsetMillis); ulong shelfLife = (Convert.ToUInt64(options.ClockSkewSeconds) * 1000); var age = Math.Abs((artifacts.Timestamp * 1000.0) - now); bool isFresh = (age <= shelfLife); if (!isFresh) Tracing.Information( String.Format("Stale Timestamp: Age {0} is more than shelf life of {1}", age, shelfLife)); return isFresh; }
static void Main(string[] args) { var configuration = new HttpSelfHostConfiguration("http://localhost:12345"); configuration.Routes.MapHttpRoute( name: "DefaultApi", routeTemplate: "{controller}/{id}", defaults: new { id = RouteParameter.Optional } ); var credentialStorage = new List<Credential>() { new Credential() { Id = "dh37fgj492je", Algorithm = SupportedAlgorithms.SHA256, User = "******", Key = Convert.FromBase64String("wBgvhp1lZTr4Tb6K6+5OQa1bL9fxK7j8wBsepjqVNiQ=") } }; var options = new Options() { ClockSkewSeconds = 60, LocalTimeOffsetMillis = 0, CredentialsCallback = (id) => credentialStorage.FirstOrDefault(c => c.Id == id), ResponsePayloadHashabilityCallback = (r) => true, VerificationCallback = (request, ext) => { if (String.IsNullOrEmpty(ext)) return true; string name = "X-Request-Header-To-Protect"; return ext.Equals(name + ":" + request.Headers[name].First()); } }; configuration.MessageHandlers.Add(new HawkAuthenticationHandler(options)); using (var server = new HttpSelfHostServer(configuration)) { server.OpenAsync().Wait(); Console.WriteLine("[SelfHost] Press Enter to terminate the server..."); Console.ReadLine(); } }
public void Configuration(IAppBuilder app) { var credentialStorage = new List<Credential>() { new Credential() { Id = "dh37fgj492je", Algorithm = SupportedAlgorithms.SHA256, User = "******", Key = "werxhqb98rpaxn39848xrunpaw3489ruxnpa98w4rxn" } }; var options = new Options() { ClockSkewSeconds = 60, LocalTimeOffsetMillis = 0, CredentialsCallback = (id) => credentialStorage.FirstOrDefault(c => c.Id == id), ResponsePayloadHashabilityCallback = (r) => true, VerificationCallback = (request, ext) => { if (String.IsNullOrEmpty(ext)) return true; string name = "X-Request-Header-To-Protect"; return ext.Equals(name + ":" + request.Headers[name].First()); } }; app.UseHawkAuthentication(new HawkAuthenticationOptions(options)); var config = new HttpConfiguration(); config.Routes.MapHttpRoute( "DefaultWebApi", "{controller}/{id}", new { id = RouteParameter.Optional }); app.UseWebApi(config); }
/// <summary> /// Returns true if the timestamp sent in by the client is fresh subject to the /// maximum allowed skew and the adjustment offset. /// </summary> private static bool IsTimestampFresh(ulong now, ArtifactsContainer artifacts, Options options) { now = now + Convert.ToUInt64(options.LocalTimeOffsetMillis); ulong shelfLife = (Convert.ToUInt64(options.ClockSkewSeconds) * 1000); var age = Math.Abs((artifacts.Timestamp * 1000.0) - now); bool isFresh = (age <= shelfLife); if (!isFresh) HawkEventSource.Log.StaleTimestamp(age.ToString(), shelfLife.ToString()); return isFresh; }
/// <summary> /// Returns an AuthenticationResult object corresponding to the result of authentication done /// using the client supplied artifacts in the HTTP authorization header in hawk scheme. /// </summary> /// <param name="now">Current UNIX time in milliseconds.</param> /// <param name="request">Request object.</param> /// <param name="options">Hawk authentication options</param> /// <returns></returns> internal static async Task<AuthenticationResult> AuthenticateAsync(ulong now, IRequestMessage request, Options options) { ArtifactsContainer artifacts = null; Credential credential = null; if (request.HasValidHawkScheme()) { if (ArtifactsContainer.TryParse(request.Authorization.Parameter, out artifacts)) { if (artifacts != null && artifacts.AreClientArtifactsValid) { string lastUsedBy = options.DetermineNonceReplayCallback(artifacts.Nonce); if (String.IsNullOrEmpty(lastUsedBy)) // Not an old nonce, and hence not a replay. { credential = options.CredentialsCallback(artifacts.Id); if (credential != null && credential.IsValid) { HawkEventSource.Log.Debug( String.Format("Algorithm={0} Key={1} ID={2}", credential.Algorithm.ToString(), Convert.ToBase64String(credential.Key), credential.Id)); Tuple<string, string> hostAndPort = options.DetermineHostDetailsCallback(request); var normalizedRequest = new NormalizedRequest(request, artifacts, hostAndPort.Item1, hostAndPort.Item2); var crypto = new Cryptographer(normalizedRequest, artifacts, credential); // Request body is needed only when payload hash is present in the request string body = null; if (artifacts.PayloadHash != null && artifacts.PayloadHash.Length > 0) { body = await request.ReadBodyAsStringAsync(); } if (crypto.IsSignatureValid(body, request.ContentType)) // MAC and hash checks { if (IsTimestampFresh(now, artifacts, options)) { // If you get this far, you are authentic. Welcome and thanks for flying Hawk! // Before returning the result, store nonce to detect replays. options.StoreNonceCallback(artifacts.Nonce, credential.Id, options.ClockSkewSeconds); return new AuthenticationResult() { IsAuthentic = true, Artifacts = artifacts, Credential = credential, ApplicationSpecificData = artifacts.ApplicationSpecificData }; } else { // Authentic but for the timestamp freshness. // Give a chance to the client to correct the clocks skew. var timestamp = new NormalizedTimestamp(DateTime.UtcNow, credential, options.LocalTimeOffsetMillis); request.ChallengeParameter = timestamp.ToWwwAuthenticateHeaderParameter(); } } } } else { HawkEventSource.Log.NonceReplay(artifacts.Nonce, lastUsedBy); } } } } return new AuthenticationResult() { IsAuthentic = false }; }
/// <summary> /// Returns an AuthenticationResult object corresponding to the result of authentication done /// using the client supplied artifacts in the bewit query string parameter. /// </summary> /// <param name="bewit">Value of the query string parameter with the name of 'bewit'.</param> /// <param name="now">Date and time in UTC to be used as the base for computing bewit life.</param> /// <param name="request">Request object.</param> /// <param name="options">Hawk authentication options</param> internal static AuthenticationResult Authenticate(string bewit, ulong now, IRequestMessage request, Options options) { if (!String.IsNullOrWhiteSpace(bewit)) { if (request.Method == HttpMethod.Get) { if (options != null && options.CredentialsCallback != null) { var parts = bewit.ToUtf8StringFromBase64Url().Split('\\'); if (parts.Length == 4) { ulong timestamp = 0; if (UInt64.TryParse(parts[1], out timestamp) && timestamp * 1000 > now) { string id = parts[0]; string mac = parts[2]; string ext = parts[3]; if (!String.IsNullOrWhiteSpace(id) && !String.IsNullOrWhiteSpace(mac)) { RemoveBewitFromUri(request); Credential credential = options.CredentialsCallback(id); if (credential != null && credential.IsValid) { var artifacts = new ArtifactsContainer() { Id = id, Nonce = String.Empty, Timestamp = timestamp, Mac = mac.ToBytesFromBase64(), ApplicationSpecificData = ext ?? String.Empty }; var normalizedRequest = new NormalizedRequest(request, artifacts) { IsBewit = true }; var crypto = new Cryptographer(normalizedRequest, artifacts, credential); if (crypto.IsSignatureValid()) // Bewit is for GET and GET must have no request body { return new AuthenticationResult() { IsAuthentic = true, Credential = credential, Artifacts = artifacts, ApplicationSpecificData = ext }; } } } } } } } } return new AuthenticationResult() { IsAuthentic = false }; }
private void ConfigureAuthentication(IAppBuilder builder) { var credentialStorage = s_container.Resolve<IAmACredentialStore>(); var options = new Options { ClockSkewSeconds = 60, LocalTimeOffsetMillis = 0, CredentialsCallback = (id) => credentialStorage.Credentials.FirstOrDefault(c => c.Id == id) }; builder.UseHawkAuthentication(new HawkAuthenticationOptions(options)); }
public HawkAuthenticationOptions(Options hawkOptions) : base(HawkConstants.Scheme) { this.HawkOptions = hawkOptions; }