From 45a9f7b328baf8c47bef98351e376859005a06d0 Mon Sep 17 00:00:00 2001 From: Chris Ross Date: Tue, 27 May 2014 14:43:18 -0700 Subject: [PATCH] Restore JwtFormat IIssuerSecurityTokenProvider lazy usage so refreshing providers work. --- ...nServicesBearerAuthenticationExtensions.cs | 31 ++++++----- ...DirectoryBearerAuthenticationExtensions.cs | 31 ++++++----- src/Microsoft.Owin.Security.Jwt/JwtFormat.cs | 54 +++++++++++++++---- .../JwtHandlerTests.cs | 3 +- 4 files changed, 76 insertions(+), 43 deletions(-) diff --git a/src/Microsoft.Owin.Security.ActiveDirectory/ActiveDirectoryFederationServicesBearerAuthenticationExtensions.cs b/src/Microsoft.Owin.Security.ActiveDirectory/ActiveDirectoryFederationServicesBearerAuthenticationExtensions.cs index 8e573a88..e192792b 100644 --- a/src/Microsoft.Owin.Security.ActiveDirectory/ActiveDirectoryFederationServicesBearerAuthenticationExtensions.cs +++ b/src/Microsoft.Owin.Security.ActiveDirectory/ActiveDirectoryFederationServicesBearerAuthenticationExtensions.cs @@ -33,25 +33,24 @@ namespace Owin JwtFormat jwtFormat = null; if (options.TokenValidationParameters != null) { - // Don't override explicit user settings. - if (options.TokenValidationParameters.IssuerSigningTokens == null - || !options.TokenValidationParameters.IssuerSigningTokens.Any()) - { - options.TokenValidationParameters.IssuerSigningTokens = cachingSecurityTokenProvider.SecurityTokens; - } - if (string.IsNullOrWhiteSpace(options.TokenValidationParameters.ValidIssuer) - && (options.TokenValidationParameters.ValidIssuers == null - || !options.TokenValidationParameters.ValidIssuers.Any()) - && options.TokenValidationParameters.IssuerValidator == null) - { - options.TokenValidationParameters.ValidIssuer = cachingSecurityTokenProvider.Issuer; - } - // Carry over obsolete property if set if (!string.IsNullOrWhiteSpace(options.Audience)) { - options.TokenValidationParameters.ValidAudience = options.Audience; + // Carry over obsolete property if set + if (string.IsNullOrWhiteSpace(options.TokenValidationParameters.ValidAudience)) + { + options.TokenValidationParameters.ValidAudience = options.Audience; + } + else if (options.TokenValidationParameters.ValidAudiences == null) + { + options.TokenValidationParameters.ValidAudiences = new[] { options.Audience }; + } + else + { + options.TokenValidationParameters.ValidAudiences = options.TokenValidationParameters.ValidAudiences.Concat(new[] { options.Audience }); + } } - jwtFormat = new JwtFormat(options.TokenValidationParameters); + + jwtFormat = new JwtFormat(options.TokenValidationParameters, cachingSecurityTokenProvider); } else { diff --git a/src/Microsoft.Owin.Security.ActiveDirectory/WindowsAzureActiveDirectoryBearerAuthenticationExtensions.cs b/src/Microsoft.Owin.Security.ActiveDirectory/WindowsAzureActiveDirectoryBearerAuthenticationExtensions.cs index 59d82de4..92720a84 100644 --- a/src/Microsoft.Owin.Security.ActiveDirectory/WindowsAzureActiveDirectoryBearerAuthenticationExtensions.cs +++ b/src/Microsoft.Owin.Security.ActiveDirectory/WindowsAzureActiveDirectoryBearerAuthenticationExtensions.cs @@ -45,25 +45,24 @@ namespace Owin JwtFormat jwtFormat = null; if (options.TokenValidationParameters != null) { - // Don't override explicit user settings. - if (options.TokenValidationParameters.IssuerSigningTokens == null - || !options.TokenValidationParameters.IssuerSigningTokens.Any()) - { - options.TokenValidationParameters.IssuerSigningTokens = cachingSecurityTokenProvider.SecurityTokens; - } - if (string.IsNullOrWhiteSpace(options.TokenValidationParameters.ValidIssuer) - && (options.TokenValidationParameters.ValidIssuers == null - || !options.TokenValidationParameters.ValidIssuers.Any()) - && options.TokenValidationParameters.IssuerValidator == null) - { - options.TokenValidationParameters.ValidIssuer = cachingSecurityTokenProvider.Issuer; - } - // Carry over obsolete property if set if (!string.IsNullOrWhiteSpace(options.Audience)) { - options.TokenValidationParameters.ValidAudience = options.Audience; + // Carry over obsolete property if set + if (string.IsNullOrWhiteSpace(options.TokenValidationParameters.ValidAudience)) + { + options.TokenValidationParameters.ValidAudience = options.Audience; + } + else if (options.TokenValidationParameters.ValidAudiences == null) + { + options.TokenValidationParameters.ValidAudiences = new[] { options.Audience }; + } + else + { + options.TokenValidationParameters.ValidAudiences = options.TokenValidationParameters.ValidAudiences.Concat(new[] { options.Audience }); + } } - jwtFormat = new JwtFormat(options.TokenValidationParameters); + + jwtFormat = new JwtFormat(options.TokenValidationParameters, cachingSecurityTokenProvider); } else { diff --git a/src/Microsoft.Owin.Security.Jwt/JwtFormat.cs b/src/Microsoft.Owin.Security.Jwt/JwtFormat.cs index 29b81ff1..48f1288d 100644 --- a/src/Microsoft.Owin.Security.Jwt/JwtFormat.cs +++ b/src/Microsoft.Owin.Security.Jwt/JwtFormat.cs @@ -15,7 +15,8 @@ namespace Microsoft.Owin.Security.Jwt /// public class JwtFormat : ISecureDataFormat { - private TokenValidationParameters _validationParameters; + private readonly TokenValidationParameters _validationParameters; + private readonly IEnumerable _issuerCredentialProviders; /// /// Initializes a new instance of the class. @@ -39,10 +40,8 @@ namespace Microsoft.Owin.Security.Jwt _validationParameters = new TokenValidationParameters() { ValidAudience = allowedAudience, - ValidIssuer = issuerCredentialProvider.Issuer, - IssuerSigningTokens = issuerCredentialProvider.SecurityTokens.ToList(), - ValidateIssuer = true }; + _issuerCredentialProviders = new[] { issuerCredentialProvider }; } /// @@ -78,12 +77,8 @@ namespace Microsoft.Owin.Security.Jwt _validationParameters = new TokenValidationParameters() { ValidAudiences = audiences, - ValidIssuers = credentialProviders.Select(provider => provider.Issuer).ToList(), - IssuerSigningTokens = credentialProviders - .Select(provider => provider.SecurityTokens.ToList()) - .Aggregate((l1, l2) => { l1.AddRange(l2); return l1; }), - ValidateIssuer = true }; + _issuerCredentialProviders = issuerCredentialProviders; } /// @@ -103,6 +98,17 @@ namespace Microsoft.Owin.Security.Jwt _validationParameters = validationParameters; } + public JwtFormat(TokenValidationParameters validationParameters, IIssuerSecurityTokenProvider issuerCredentialProvider) + : this(validationParameters) + { + if (issuerCredentialProvider == null) + { + throw new ArgumentNullException("issuerCredentialProvider"); + } + + _issuerCredentialProviders = new[] { issuerCredentialProvider }; + } + /// /// Gets or sets a value indicating whether JWT issuers should be validated. /// @@ -162,7 +168,35 @@ namespace Microsoft.Owin.Security.Jwt throw new ArgumentOutOfRangeException("protectedText", Properties.Resources.Exception_InvalidJwt); } - ClaimsPrincipal claimsPrincipal = TokenHandler.ValidateToken(protectedText, _validationParameters); + TokenValidationParameters validationParameters = _validationParameters; + if (_issuerCredentialProviders != null) + { + // Lazy augment with issuers and tokens. Note these may be refreshed periodically. + validationParameters = new TokenValidationParameters(validationParameters); + + IEnumerable issuers = _issuerCredentialProviders.Select(provider => provider.Issuer); + if (validationParameters.ValidIssuers == null) + { + validationParameters.ValidIssuers = issuers; + } + else + { + validationParameters.ValidIssuers = validationParameters.ValidAudiences.Concat(issuers); + } + + IEnumerable tokens = _issuerCredentialProviders.Select(provider => provider.SecurityTokens) + .Aggregate((left, right) => left.Concat(right)); + if (validationParameters.IssuerSigningTokens == null) + { + validationParameters.IssuerSigningTokens = tokens; + } + else + { + validationParameters.IssuerSigningTokens = validationParameters.IssuerSigningTokens.Concat(tokens); + } + } + + ClaimsPrincipal claimsPrincipal = TokenHandler.ValidateToken(protectedText, validationParameters); var claimsIdentity = (ClaimsIdentity)claimsPrincipal.Identity; // Fill out the authenticationProperties issued and expires times if the equivalent claims are in the JWT diff --git a/tests/Microsoft.Owin.Security.Tests/JwtHandlerTests.cs b/tests/Microsoft.Owin.Security.Tests/JwtHandlerTests.cs index 2aaf51bb..1170d47f 100644 --- a/tests/Microsoft.Owin.Security.Tests/JwtHandlerTests.cs +++ b/tests/Microsoft.Owin.Security.Tests/JwtHandlerTests.cs @@ -17,7 +17,8 @@ namespace Microsoft.Owin.Security.Tests [Fact] public void HandlerConstructorShouldThrowWhenAnAllowedAudienceIsNotSpecified() { - Should.Throw(() => new JwtFormat(null, (IIssuerSecurityTokenProvider)null)); + Should.Throw(() => new JwtFormat((string)null, (IIssuerSecurityTokenProvider)null)); + Should.Throw(() => new JwtFormat((TokenValidationParameters)null, (IIssuerSecurityTokenProvider)null)); } [Fact]