2424using System . Web . Routing ;
2525
2626// The following using statements were added for this sample.
27- using System . Net . Http ;
28- using System . IdentityModel . Tokens ;
29- using System . Threading . Tasks ;
27+ using System . Net . Http ; using System . Threading . Tasks ;
3028using System . Threading ;
3129using System . Net ;
3230using System . IdentityModel . Selectors ;
3331using System . Security . Claims ;
3432using System . Net . Http . Headers ;
35- using System . IdentityModel . Metadata ;
33+ using Microsoft . IdentityModel . Tokens ;
3634using System . ServiceModel . Security ;
3735using System . Xml ;
38- using System . Security . Cryptography . X509Certificates ;
36+ using System . IdentityModel . Tokens . Jwt ;
3937using System . Globalization ;
4038using System . Configuration ;
4139using Microsoft . IdentityModel . Protocols ;
40+ using Microsoft . IdentityModel . Protocols . OpenIdConnect ;
4241
4342namespace TodoListService_ManualJwt
4443{
@@ -70,7 +69,7 @@ internal class TokenValidationHandler : DelegatingHandler
7069 string authority = String . Format ( CultureInfo . InvariantCulture , aadInstance , tenant ) ;
7170
7271 static string _issuer = string . Empty ;
73- static List < SecurityToken > _signingTokens = null ;
72+ static ICollection < SecurityKey > _signingKeys = null ;
7473 static DateTime _stsMetadataRetrievalTime = DateTime . MinValue ;
7574 static string scopeClaimType = "http://schemas.microsoft.com/identity/claims/scope" ;
7675
@@ -89,32 +88,32 @@ protected async override Task<HttpResponseMessage> SendAsync(HttpRequestMessage
8988
9089 if ( jwtToken == null )
9190 {
92- HttpResponseMessage response = BuildResponseErrorMessage ( HttpStatusCode . Unauthorized ) ;
91+ HttpResponseMessage response = this . BuildResponseErrorMessage ( HttpStatusCode . Unauthorized ) ;
9392 return response ;
9493 }
9594
9695 string issuer ;
97- List < SecurityToken > signingTokens ;
96+ ICollection < SecurityKey > signingTokens ;
9897
9998 try
10099 {
101100 // The issuer and signingTokens are cached for 24 hours. They are updated if any of the conditions in the if condition is true.
102101 if ( DateTime . UtcNow . Subtract ( _stsMetadataRetrievalTime ) . TotalHours > 24
103102 || string . IsNullOrEmpty ( _issuer )
104- || _signingTokens == null )
103+ || _signingKeys == null )
105104 {
106105 // Get tenant information that's used to validate incoming jwt tokens
107- string stsDiscoveryEndpoint = string . Format ( "{0 }/.well-known/openid-configuration", authority ) ;
108- ConfigurationManager < OpenIdConnectConfiguration > configManager = new ConfigurationManager < OpenIdConnectConfiguration > ( stsDiscoveryEndpoint ) ;
109- OpenIdConnectConfiguration config = await configManager . GetConfigurationAsync ( ) ;
106+ string stsDiscoveryEndpoint = $ " { this . authority } /.well-known/openid-configuration";
107+ Microsoft . IdentityModel . Protocols . ConfigurationManager < Microsoft . IdentityModel . Protocols . OpenIdConnect . OpenIdConnectConfiguration > configManager = new ConfigurationManager < OpenIdConnectConfiguration > ( stsDiscoveryEndpoint , new OpenIdConnectConfigurationRetriever ( ) ) ;
108+ Microsoft . IdentityModel . Protocols . OpenIdConnect . OpenIdConnectConfiguration config = await configManager . GetConfigurationAsync ( cancellationToken ) ;
110109 _issuer = config . Issuer ;
111- _signingTokens = config . SigningTokens . ToList ( ) ;
110+ _signingKeys = config . SigningKeys ;
112111
113112 _stsMetadataRetrievalTime = DateTime . UtcNow ;
114113 }
115114
116115 issuer = _issuer ;
117- signingTokens = _signingTokens ;
116+ signingTokens = _signingKeys ;
118117 }
119118 catch ( Exception )
120119 {
@@ -130,8 +129,7 @@ protected async override Task<HttpResponseMessage> SendAsync(HttpRequestMessage
130129
131130 // Supports both the Azure AD V1 and V2 endpoint
132131 ValidIssuers = new [ ] { issuer , $ "{ issuer } /v2.0" } ,
133- IssuerSigningTokens = signingTokens ,
134- CertificateValidator = X509CertificateValidator . None // Certificate validation does not make sense since AAD's metadata document is signed with a self-signed certificate.
132+ IssuerSigningKeys = signingTokens
135133 } ;
136134
137135 try
@@ -152,15 +150,15 @@ protected async override Task<HttpResponseMessage> SendAsync(HttpRequestMessage
152150 // If the token is scoped, verify that required permission is set in the scope claim.
153151 if ( ClaimsPrincipal . Current . FindFirst ( scopeClaimType ) != null && ClaimsPrincipal . Current . FindFirst ( scopeClaimType ) . Value != "user_impersonation" )
154152 {
155- HttpResponseMessage response = BuildResponseErrorMessage ( HttpStatusCode . Forbidden ) ;
153+ HttpResponseMessage response = this . BuildResponseErrorMessage ( HttpStatusCode . Forbidden ) ;
156154 return response ;
157155 }
158156
159157 return await base . SendAsync ( request , cancellationToken ) ;
160158 }
161159 catch ( SecurityTokenValidationException )
162160 {
163- HttpResponseMessage response = BuildResponseErrorMessage ( HttpStatusCode . Unauthorized ) ;
161+ HttpResponseMessage response = this . BuildResponseErrorMessage ( HttpStatusCode . Unauthorized ) ;
164162 return response ;
165163 }
166164 catch ( Exception )
0 commit comments