/// <summary> /// Validates the token signature against the two keys. /// </summary> /// <param name="token">The token to be validated.</param> /// <param name="primaryKey"> /// The first key to be used for validation. /// </param> /// <param name="secondaryKey"> /// The second key to be used for validation if the second key fails. /// </param> /// <returns></returns> private bool ValidateTokenSignature(SimpleWebToken token, byte[] primaryKey, byte[] secondaryKey) { try { // try primary key first. bool isSignatureValid = token.VerifySignature(primaryKey); if (!isSignatureValid) { // now try secondary key. isSignatureValid = token.VerifySignature(secondaryKey); if (!isSignatureValid) { return(false); } } return(true); } catch (SecurityException) { return(false); } }
/// <summary> /// Factory method for creating a new SimpleWebToken. /// </summary> /// <param name="issuer">The token issuer.</param> /// <param name="audience">The token audience.</param> /// <param name="expiresOn">The UTC time when the token should expire.</param> /// <param name="claims">The claims to be encoded into the token.</param> /// <returns> /// A new SimpleWebToken instance with specified values. /// </returns> public static SimpleWebToken Create(string issuer, string audience, DateTime expiresOn, IEnumerable <Claim> claims) { if (string.IsNullOrEmpty(issuer)) { throw new ArgumentNullException("issuer"); } var token = new SimpleWebToken(); token.tokenAudience = audience; token.tokenExpiryTime = expiresOn; token.tokenIssuer = issuer; token.tokenClaims = new List <Claim>(); if (claims != null) { foreach (Claim claim in claims) { if (IsReservedClaimType(claim.Type)) { throw new ArgumentException("ClaimType " + claim.Type + " is reserved for system use"); } token.tokenClaims.Add(claim); } } return(token); }
public bool Validate(string swtToken) { // Validate the token (note that the signature is verified only further down). SimpleWebToken token; try { token = SimpleWebToken.Parse(swtToken); } catch (SecurityException) { return(false); } catch (Exception exception) { if (exception.IsFatal()) { throw; } return(false); } // The token was parsed successfully. // Validate issuer. TokenIssuer tokenIssuer; if ((!Enum.TryParse(token.Issuer, true, out tokenIssuer)) || (!Enum.IsDefined(typeof(TokenIssuer), token.Issuer))) { return(false); } // Validate audience TokenAudience tokenAudience; if ((!Enum.TryParse(token.Audience, true, out tokenAudience)) || (!Enum.IsDefined(typeof(TokenAudience), token.Audience))) { return(false); } // Now validate the signature using the specified issuer's keys bool isSignatureValid = this.IsSignatureValidForIssuer(token, tokenIssuer); if (!isSignatureValid) { return(false); } // Make sure the token is not expired. if (token.IsExpiredNow) { // Token expired. return(false); } return(true); }
/// <summary> /// Checks whether the token signature is valid using the specified token issuer's keys. /// </summary> /// <param name="token">the token whose signature should be validated.</param> /// <param name="tokenIssuer">The token issuer who keys are to be used for validation.</param> /// <returns> /// True if the signature could be validated with the specified issuer's keys. /// </returns> private bool IsSignatureValidForIssuer(SimpleWebToken token, TokenIssuer tokenIssuer) { if (!this.tokenSigningKeysForIssuer.ContainsKey(tokenIssuer)) { return(false); } var keys = this.tokenSigningKeysForIssuer[tokenIssuer]; return(this.ValidateTokenSignature(token, keys.Item1, keys.Item2)); }
/// <summary> /// Creates a SimpleWebToken by parsing the form-encoded /// string representation of the token. /// </summary> /// <param name="encodedToken">The encoded token string.</param> /// <returns> /// An instance of SimpleWebToken. /// </returns> /// <exception cref="SecurityException"> /// Thrown if errors are encountered while processing the token string. /// </exception> /// <exception cref="ArgumentException"> /// Thrown if the issuer secret or encoded token is null or invalid. /// </exception> public static SimpleWebToken Parse(string encodedToken) { if (string.IsNullOrWhiteSpace(encodedToken)) { throw new SecurityException("The encoded token is not valid."); } var token = new SimpleWebToken(); token.Decode(encodedToken); return(token); }
/// <summary> /// Factory method for creating SWT tokens. Use this overload when there is a requirement /// to encode additional claims into the token. /// </summary> /// <param name="issuer">The entity issuing the token.</param> /// <param name="audience">The entity receiving the token.</param> /// <param name="expiresOnUtc">The expiry time for the token in UTC.</param> /// <param name="additionalClaims"> /// Any additional claims to be included as part of the token. /// </param> /// <param name="signingKey">The token signing key.</param> /// <returns> /// An instance of SimpleWebToken class. /// </returns> public static SimpleWebToken CreateToken( TokenIssuer issuer, TokenAudience audience, DateTime expiresOnUtc, IEnumerable <Claim> additionalClaims, byte[] signingKey) { if (issuer == TokenIssuer.Unknown) { throw new ArgumentException( "{0} is not not allowed as token issuer.".FormatInvariant(issuer.ToString())); } if (audience == TokenAudience.Unknown) { throw new ArgumentException( "{0} is not allowed as token audience.".FormatInvariant(audience.ToString())); } if (signingKey == null || signingKey.Length == 0) { throw new ArgumentException("The signing key is not valid."); } var claims = new List <Claim>(); if (additionalClaims != null) { claims.AddRange(additionalClaims); } var token = SimpleWebToken.Create(issuer.ToString(), audience.ToString(), expiresOnUtc, claims); token.SignToken(signingKey); return(token); }
/// <summary> /// Authenticates the request using Bearer scheme. /// </summary> /// <param name="request">The request to be authenticated.</param> /// <returns> /// An instance of AuthenticationResult which specifies if the authentication was successful or not. /// If successful, it will contain the IPrincipal. /// If not successful, it will contain the error message. /// </returns> public override AuthenticationResult Authenticate(HttpRequestMessage request) { // Validate the request first. AuthenticationResult authenticationResult; if (!this.ValidateRequest(request, out authenticationResult)) { return(authenticationResult); } // Validate the token (note that the signature is verified only further down). SimpleWebToken token; try { string tokenString = request.Headers.Authorization.Parameter; token = SimpleWebToken.Parse(tokenString); } catch (FormatException) { return (AuthenticationResult.CreateFailedAuthenticationResult( "The bearer token is not in a valid format.")); } catch (SecurityException exception) { return(AuthenticationResult.CreateFailedAuthenticationResult(exception.Message)); } catch (Exception exception) { if (exception.IsFatal()) { throw; } return (AuthenticationResult.CreateFailedAuthenticationResult( "An unexpected error occurred while parsing the token.")); } // Validate issuer. TokenIssuer tokenIssuer; if ((!Enum.TryParse(token.Issuer, true, out tokenIssuer)) || (!Enum.IsDefined(typeof(TokenIssuer), token.Issuer))) { return(AuthenticationResult.CreateFailedAuthenticationResult( "Unrecognized token issuer: '{0}'", token.Issuer)); } // Validate audience TokenAudience tokenAudience; if ((!Enum.TryParse(token.Audience, true, out tokenAudience)) || (!Enum.IsDefined(typeof(TokenAudience), token.Audience))) { return(AuthenticationResult.CreateFailedAuthenticationResult( "Unrecognized token audience: '{0}'", token.Audience)); } // Now validate the signature using the specified issuer's keys bool isSignatureValid = this.IsSignatureValidForIssuer(token, tokenIssuer); if (!isSignatureValid) { return(AuthenticationResult.CreateFailedAuthenticationResult("The token signature is not valid.")); } // Make sure the token is not expired. if (token.IsExpiredNow) { // Token expired. return(AuthenticationResult.CreateFailedAuthenticationResult( "The token expired at {0}", token.ExpiresOn.ToRoundtripFormatString())); } // Identify the roles for this principal. IEnumerable <Claim> roleClaims = GetRoleClaims(tokenIssuer, tokenAudience); if (roleClaims == null) { return(AuthenticationResult.CreateFailedAuthenticationResult( "This combination of token issuer and audience is not allowed for this service.")); } var claims = new List <Claim>(); // We wont allow the caller to specify roles, we will assign the roles here. claims.AddRange(token.Claims.Where(c => c.Type != HolMonClaimTypes.Role)); // Adding claims as we see fit. claims.AddRange(roleClaims); claims.Add(new Claim(HolMonClaimTypes.AuthenticationScheme, this.AuthenticationScheme)); claims.Add(new Claim(HolMonClaimTypes.TokenAudience, token.Audience)); claims.Add(new Claim(HolMonClaimTypes.TokenIssuer, token.Issuer)); this.LogClaims(claims); var identity = new ClaimsIdentity(claims, request.Headers.Authorization.Scheme); var principal = new ClaimsPrincipal(identity); return(AuthenticationResult.CreateSuccessfulAuthenticationResult(principal)); }