/// <summary>Gets the identity for the specified credentials.</summary> /// <param name="credentials">The credentials.</param> /// <returns>The identity.</returns> private async Task <ISentinelIdentity> GetIdentity(SignatureAuthenticationDigest credentials) { if (credentials.ClientId == credentials.UserId) { // Validate client using api key var client = await this.options.ClientManager.AuthenticateClientWithSignatureAsync(credentials); if (client.Identity.IsAuthenticated) { return(client.Identity); } } try { // Validate user var user = await this.options.UserManager.AuthenticateUserWithSignatureAsync(credentials); if (user.Identity.IsAuthenticated) { return(user.Identity); } } catch (ArgumentException ex) { this.options.Logger.Error(ex); } return(SentinelIdentity.Anonymous); }
private bool ValidateDigest(SignatureAuthenticationDigest digest) { // 1. Validate timestamp is within boundaries var serverTimestamp = DateTimeOffset.UtcNow.ToUnixTime(); if (digest.Timestamp > (serverTimestamp + this.options.MaximumClockSkew.TotalSeconds) || digest.Timestamp < (serverTimestamp - this.options.MaximumClockSkew.TotalSeconds)) { this.options.Logger.Warn("The request timestamp is outside the allowed boundaries"); return(false); } // 2. Validate nonce has not been used before in the last 5 minutes if (this.nonces.Contains($"{digest.ClientId}_{digest.Nonce}")) { this.options.Logger.Warn("The nonce has been used recently"); return(false); } else { this.nonces.Add($"{digest.ClientId}_{digest.Nonce}", digest, DateTimeOffset.UtcNow.Add(this.options.MaximumClockSkew)); } // 3. TODO: Validate uri return(true); }
public async void AuthenticateClientWithApiKeyAsync_WhenGivenInvalidApiKeyAuthenticationDigest_ReturnsNotAuthenticatedIdentity(string username, string privateKey) { var digest = new SignatureAuthenticationDigest(username, username, "http://localhost", "/openid/userinfo", DateTimeOffset.UtcNow.ToUnixTime(), Guid.NewGuid().ToString("N")); var signature = this.AsymmetricCryptoProvider.Sign(digest.GetData(), privateKey); digest.Sign(signature); var client = await this.ClientManager.AuthenticateClientWithSignatureAsync(digest); Assert.IsFalse(client.Identity.IsAuthenticated, "The client was authenticated"); }
public async void GetResource_WhenGivenInvalidUserSignatureAuthentication_ReturnsData(string username, string privateKey) { var request = new HttpRequestMessage(HttpMethod.Get, "openid/userinfo"); var digest = new SignatureAuthenticationDigest(username, "NUnit", "http://localhost", request.RequestUri.ToString(), DateTimeOffset.UtcNow.ToUnixTime(), Guid.NewGuid().ToString("N")); var signature = this.AsymmetricCryptoProvider.Sign(digest.GetData(), privateKey); digest.Sign(signature); request.Headers.Authorization = new SignatureAuthenticationHeaderValue(digest); var response = await this.Client.SendAsync(request); Assert.AreEqual(response.StatusCode, HttpStatusCode.Unauthorized, "User was authenticated"); }
public async void AuthenticateUserWithApiKeyAsync_WhenGivenInvalidApiKeyAuthenticationDigest_ReturnsNotAuthenticatedIdentity(string username, string password) { var digest = new SignatureAuthenticationDigest( username, password, "http://localhost", "http://localhost/url", DateTimeOffset.Now.ToUnixTime(), "aabbccddee"); var signature = this.asymmetricCryptoProvider.Sign(digest.GetData(), password); digest.Sign(signature); var user = await this.UserManager.AuthenticateUserWithSignatureAsync(digest); Assert.IsFalse(user.Identity.IsAuthenticated, "The user was authenticated"); }
public async void GetResource_WhenGivenValidUserSignatureAuthentication_ReturnsData(string username, string privateKey) { var request = new HttpRequestMessage(HttpMethod.Get, "openid/userinfo"); var digest = new SignatureAuthenticationDigest(username, "NUnit", "http://localhost", request.RequestUri.ToString(), DateTimeOffset.UtcNow.ToUnixTime(), Guid.NewGuid().ToString("N")); var signature = this.AsymmetricCryptoProvider.Sign(digest.GetData(), privateKey); digest.Sign(signature); request.Headers.Authorization = new SignatureAuthenticationHeaderValue(digest); var response = await this.Client.SendAsync(request); var userInfo = JsonConvert.DeserializeObject <IdentityResponse>(await response.Content.ReadAsStringAsync()); Assert.IsTrue(response.IsSuccessStatusCode, "User was not authenticated"); Assert.AreEqual(username, userInfo.Subject); }
private async Task <bool> ValidateDigest(SignatureAuthenticationDigest digest) { // 1. Validate timestamp is within boundaries var serverTimestamp = DateTimeOffset.UtcNow.ToUnixTime(); if (digest.Timestamp > (serverTimestamp + this.options.MaximumClockSkew.TotalSeconds) || digest.Timestamp < (serverTimestamp - this.options.MaximumClockSkew.TotalSeconds)) { this.options.Logger.Warn("The request timestamp is outside the allowed boundaries"); return(false); } // 2. Validate nonce has not been used before in the last 5 minutes if (this.nonces.Contains($"{digest.ClientId}_{digest.Nonce}")) { this.options.Logger.Warn("The nonce has been used recently"); return(false); } else { this.nonces.Add($"{digest.ClientId}_{digest.Nonce}", digest, DateTimeOffset.UtcNow.Add(this.options.MaximumClockSkew)); } // 3. Validate client var client = await this.options.ClientManager.AuthenticateClientAsync(digest.ClientId, digest.RedirectUri); if (!client.Identity.IsAuthenticated) { return(false); } // 4. Validate url if (!this.Request.IsSameUrl(digest.RequestUrl)) { this.options.Logger.Warn($"The request_url parameter ({digest.RequestUrl}) does not match the requested url {this.Request.Uri}"); return(false); } return(true); }
/// <summary>Authenticate the user using an API key.</summary> /// <param name="digest">The digest.</param> /// <returns>The user principal.</returns> public override async Task <ISentinelPrincipal> AuthenticateUserWithSignatureAsync(SignatureAuthenticationDigest digest) { var userKeys = await this.UserApiKeyRepository.GetForUser(digest.UserId); var matchingKey = this.ValidateApiKey(userKeys, digest.GetData(), digest.Signature); if (matchingKey != null) { var user = await this.UserRepository.GetUser(matchingKey.UserId); if (user != null) { var principal = new SentinelPrincipal( new SentinelIdentity( AuthenticationType.Signature, new SentinelClaim(JwtClaimType.Name, user.UserId), new SentinelClaim(ClaimTypes.AuthenticationMethod, AuthenticationMethod.ApiKey), new SentinelClaim(ClaimType.AuthenticationSource, "local"), new SentinelClaim(JwtClaimType.GivenName, user.FirstName), new SentinelClaim(JwtClaimType.FamilyName, user.LastName))); user.LastLogin = DateTimeOffset.UtcNow; await this.UserRepository.Update(user.GetIdentifier(), user); matchingKey.LastUsed = DateTimeOffset.UtcNow; await this.UserApiKeyRepository.Update(matchingKey.GetIdentifier(), matchingKey); return(principal); } } return(SentinelPrincipal.Anonymous); }
public async Task <ISentinelPrincipal> AuthenticateUserWithSignatureAsync(SignatureAuthenticationDigest digest) { return(new SentinelPrincipal(new SentinelIdentity(AuthenticationType.Signature, new SentinelClaim(JwtClaimType.Name, digest.UserId)))); }
/// <summary>Authenticate the user using an API key.</summary> /// <param name="digest">The digest.</param> /// <returns>The user principal.</returns> public virtual async Task <ISentinelPrincipal> AuthenticateUserWithSignatureAsync(SignatureAuthenticationDigest digest) { throw new NotImplementedException(); }
/// <summary>Authenticate client using API Key.</summary> /// <exception cref="ArgumentException"> /// Thrown when one or more arguments have unsupported or illegal values. /// </exception> /// <param name="digest">The digest.</param> /// <returns>The client principal.</returns> public override async Task <ISentinelPrincipal> AuthenticateClientWithSignatureAsync(SignatureAuthenticationDigest digest) { // 1. Validate client id and redirect uri var client = await this.ClientRepository.GetClient(digest.ClientId); if (client == null || !client.Enabled) { throw new ArgumentException(nameof(digest), "The client_id is invalid"); } if (client.RedirectUri != digest.RedirectUri) { throw new ArgumentException(nameof(digest), "The redirect_uri is invalid"); } // 2. Validate username and signature using client secret if (digest.UserId != client.ClientId) { throw new ArgumentException(nameof(digest), "The user_id is invalid, must be equal to client_id"); } if (!string.IsNullOrEmpty(client.PublicKey)) { var isValid = this.AsymmetricCryptoProvider.ValidateSignature(digest.GetData(), digest.Signature, client.PublicKey); if (isValid) { var principal = new SentinelPrincipal( new SentinelIdentity( AuthenticationType.Signature, new SentinelClaim(JwtClaimType.Name, client.ClientId), new SentinelClaim(ClaimTypes.NameIdentifier, client.ClientId), new SentinelClaim(ClaimType.Client, client.ClientId), new SentinelClaim(ClaimType.RedirectUri, client.RedirectUri), new SentinelClaim(ClaimTypes.AuthenticationMethod, AuthenticationMethod.Signature))); if (principal.Identity.IsAuthenticated) { client.LastUsed = DateTimeOffset.UtcNow; await this.ClientRepository.Update(client.GetIdentifier(), client); return(principal); } return(principal); } } return(SentinelPrincipal.Anonymous); }
public SignatureAuthenticationHeaderValue(SignatureAuthenticationDigest digest) : base("Signature", EncodeString(digest.ToString())) { }
public Task <ISentinelPrincipal> AuthenticateClientWithSignatureAsync(SignatureAuthenticationDigest digest) { throw new System.NotImplementedException(); }
/// <summary>Authenticate the user using an API key.</summary> /// <param name="digest">The digest.</param> /// <returns>The user principal.</returns> public abstract Task <ISentinelPrincipal> AuthenticateUserWithSignatureAsync(SignatureAuthenticationDigest digest);