11// Copyright (c) Microsoft Corporation. All rights reserved.
22// Licensed under the MIT License.
33
4+ using System ;
45using System . Linq ;
6+ using System . Security . Cryptography ;
57using System . Security . Cryptography . X509Certificates ;
68using System . Threading . Tasks ;
79using Microsoft . Extensions . DependencyInjection ;
@@ -144,6 +146,70 @@ public async Task AcquireTokenWithPop_ClientCredentialsAsync()
144146 Assert . NotNull ( result . AccessToken ) ;
145147 }
146148
149+ [ IgnoreOnAzureDevopsFact ]
150+ //[Fact]
151+ public async Task AcquireTokenWithMs10AtPop_ClientCredentialsAsync ( )
152+ {
153+ TokenAcquirerFactory tokenAcquirerFactory = TokenAcquirerFactory . GetDefaultInstance ( ) ;
154+ IServiceCollection services = tokenAcquirerFactory . Services ;
155+
156+ services . Configure < MicrosoftIdentityApplicationOptions > ( s_optionName , option =>
157+ {
158+ option . Instance = "https://login.microsoftonline.com/" ;
159+ option . TenantId = "msidentitysamplestesting.onmicrosoft.com" ;
160+ option . ClientId = "6af093f3-b445-4b7a-beae-046864468ad6" ;
161+ option . ClientCredentials = s_clientCredentials ;
162+ } ) ;
163+
164+ services . AddInMemoryTokenCaches ( ) ;
165+ var serviceProvider = tokenAcquirerFactory . Build ( ) ;
166+ var options = serviceProvider . GetRequiredService < IOptionsMonitor < MicrosoftIdentityApplicationOptions > > ( ) . Get ( s_optionName ) ;
167+ var credentialsLoader = serviceProvider . GetRequiredService < ICredentialsLoader > ( ) ;
168+ await credentialsLoader . LoadCredentialsIfNeededAsync ( options . ClientCredentials ! . First ( ) ) ;
169+ var cert = options . ClientCredentials ! . First ( ) . Certificate ;
170+
171+ // Get the token acquisition service
172+ ITokenAcquirer tokenAcquirer = tokenAcquirerFactory . GetTokenAcquirer ( s_optionName ) ;
173+ RsaSecurityKey rsaSecurityKey = CreateRsaSecurityKey ( ) ;
174+ var result = await tokenAcquirer . GetTokenForAppAsync ( "https://graph.microsoft.com/.default" ,
175+ new TokenAcquisitionOptions ( )
176+ {
177+ PopPublicKey = rsaSecurityKey . KeyId ,
178+ JwkClaim = CreateJwkClaim ( rsaSecurityKey , SecurityAlgorithms . RsaSha256 )
179+ } ) ;
180+ Assert . NotNull ( result . AccessToken ) ;
181+ }
182+
183+ private static string CreateJwkClaim ( RsaSecurityKey key , string algorithm )
184+ {
185+ var parameters = key . Rsa == null ? key . Parameters : key . Rsa . ExportParameters ( false ) ;
186+ return "{\" kty\" :\" RSA\" ,\" n\" :\" " + Base64UrlEncoder . Encode ( parameters . Modulus ) + "\" ,\" e\" :\" " + Base64UrlEncoder . Encode ( parameters . Exponent ) + "\" ,\" alg\" :\" " + algorithm + "\" ,\" kid\" :\" " + key . KeyId + "\" }" ;
187+ }
188+
189+ private static RsaSecurityKey CreateRsaSecurityKey ( )
190+ {
191+ #if NET472
192+ RSA rsa = RSA . Create ( 2048 ) ;
193+ #else
194+ RSA rsa = new RSACryptoServiceProvider ( 2048 ) ;
195+ #endif
196+ // the reason for creating the RsaSecurityKey from RSAParameters is so that a SignatureProvider created with this key
197+ // will own the RSA object and dispose it. If we pass a RSA object, the SignatureProvider does not own the object, the RSA object will not be disposed.
198+ RSAParameters rsaParameters = rsa . ExportParameters ( true ) ;
199+ RsaSecurityKey rsaSecuirtyKey = new RsaSecurityKey ( rsaParameters ) { KeyId = CreateRsaKeyId ( rsaParameters ) } ;
200+ rsa . Dispose ( ) ;
201+ return rsaSecuirtyKey ;
202+ }
203+
204+ private static string CreateRsaKeyId ( RSAParameters rsaParameters )
205+ {
206+ byte [ ] kidBytes = new byte [ rsaParameters . Exponent . Length + rsaParameters . Modulus . Length ] ;
207+ Array . Copy ( rsaParameters . Exponent , 0 , kidBytes , 0 , rsaParameters . Exponent . Length ) ;
208+ Array . Copy ( rsaParameters . Modulus , 0 , kidBytes , rsaParameters . Exponent . Length , rsaParameters . Modulus . Length ) ;
209+ using ( var sha2 = SHA256 . Create ( ) )
210+ return Base64UrlEncoder . Encode ( sha2 . ComputeHash ( kidBytes ) ) ;
211+ }
212+
147213 private string ? ComputePublicKeyString ( X509Certificate2 ? certificate )
148214 {
149215 if ( certificate == null )
@@ -159,8 +225,6 @@ public async Task AcquireTokenWithPop_ClientCredentialsAsync()
159225 return keyId ;
160226 }
161227
162-
163-
164228 private static async Task CreateGraphClientAndAssert ( TokenAcquirerFactory tokenAcquirerFactory , IServiceCollection services )
165229 {
166230 services . AddInMemoryTokenCaches ( ) ;
0 commit comments