@@ -7,9 +7,9 @@ namespace Microsoft.Store.PartnerCenter.PowerShell.Authenticators
77 using System . Threading ;
88 using System . Threading . Tasks ;
99 using Extensions ;
10- using Factories ;
1110 using Identity . Client ;
1211 using Models . Authentication ;
12+ using Utilities ;
1313
1414 /// <summary>
1515 /// Provides a chain of responsibility pattern for authenticators.
@@ -39,38 +39,166 @@ internal abstract class DelegatingAuthenticator : IAuthenticator
3939 public abstract bool CanAuthenticate ( AuthenticationParameters parameters ) ;
4040
4141 /// <summary>
42- ///
42+ /// Gets an aptly configured client.
4343 /// </summary>
44- /// <param name="account"></param>
45- /// <param name="environment"></param>
46- /// <param name="redirectUri"></param>
47- /// <returns></returns>
48- public IClientApplicationBase GetClient ( PartnerAccount account , PartnerEnvironment environment , string redirectUri = null )
44+ /// <param name="account">The account information to be used when generating the client. </param>
45+ /// <param name="environment">The environment where the client is connecting. </param>
46+ /// <param name="redirectUri">The redirect URI for the client. </param>
47+ /// <returns>An aptly configured client. </returns>
48+ public async Task < IClientApplicationBase > GetClientAsync ( PartnerAccount account , PartnerEnvironment environment , string redirectUri = null )
4949 {
5050 IClientApplicationBase app ;
5151
5252 if ( account . IsPropertySet ( PartnerAccountPropertyType . CertificateThumbprint ) || account . IsPropertySet ( PartnerAccountPropertyType . ServicePrincipalSecret ) )
5353 {
54- app = SharedTokenCacheClientFactory . CreateConfidentialClient (
54+ app = await CreateConfidentialClientAsync (
5555 $ "{ environment . ActiveDirectoryAuthority } { account . Tenant } ",
5656 account . GetProperty ( PartnerAccountPropertyType . ApplicationId ) ,
5757 account . GetProperty ( PartnerAccountPropertyType . ServicePrincipalSecret ) ,
5858 GetCertificate ( account . GetProperty ( PartnerAccountPropertyType . CertificateThumbprint ) ) ,
5959 redirectUri ,
60- account . Tenant ) ;
60+ account . Tenant ) . ConfigureAwait ( false ) ;
6161 }
6262 else
6363 {
64- app = SharedTokenCacheClientFactory . CreatePublicClient (
64+ app = await CreatePublicClient (
6565 $ "{ environment . ActiveDirectoryAuthority } { account . Tenant } ",
6666 account . GetProperty ( PartnerAccountPropertyType . ApplicationId ) ,
6767 redirectUri ,
68- account . Tenant ) ;
68+ account . Tenant ) . ConfigureAwait ( false ) ;
6969 }
7070
7171 return app ;
7272 }
7373
74+ /// <summary>
75+ /// Determine if this request can be authenticated using the given authenticator, and authenticate if it can.
76+ /// </summary>
77+ /// <param name="parameters">The complex object containing authentication specific information.</param>
78+ /// <param name="cancellationToken">A cancellation token that can be used by other objects or threads to receive notice of cancellation.</param>
79+ /// <returns><c>true</c> if the request can be authenticated; otherwise <c>false</c>.</returns>
80+ public async Task < AuthenticationResult > TryAuthenticateAsync ( AuthenticationParameters parameters , CancellationToken cancellationToken = default )
81+ {
82+ if ( CanAuthenticate ( parameters ) )
83+ {
84+ return await AuthenticateAsync ( parameters , cancellationToken ) . ConfigureAwait ( false ) ;
85+ }
86+
87+ if ( Next != null )
88+ {
89+ return await Next . TryAuthenticateAsync ( parameters , cancellationToken ) . ConfigureAwait ( false ) ;
90+ }
91+
92+ return null ;
93+ }
94+
95+ /// <summary>
96+ /// Creates a confidential client used for generating tokens.
97+ /// </summary>
98+ /// <param name="authority">Address of the authority to issue the token</param>
99+ /// <param name="clientId">Identifier of the client requesting the token.</param>
100+ /// <param name="certificate">Certificate used by the client requesting the token.</param>
101+ /// <param name="clientSecret">Secret of the client requesting the token.</param>
102+ /// <param name="redirectUri">The redirect URI for the client.</param>
103+ /// <param name="tenantId">Identifier of the tenant requesting the token.</param>
104+ /// <returns>An aptly configured confidential client.</returns>
105+ private static async Task < IConfidentialClientApplication > CreateConfidentialClientAsync (
106+ string authority = null ,
107+ string clientId = null ,
108+ string clientSecret = null ,
109+ X509Certificate2 certificate = null ,
110+ string redirectUri = null ,
111+ string tenantId = null )
112+ {
113+ ConfidentialClientApplicationBuilder builder = ConfidentialClientApplicationBuilder . Create ( clientId ) ;
114+
115+ if ( ! string . IsNullOrEmpty ( authority ) )
116+ {
117+ builder = builder . WithAuthority ( authority ) ;
118+ }
119+
120+ if ( ! string . IsNullOrEmpty ( clientSecret ) )
121+ {
122+ builder = builder . WithClientSecret ( clientSecret ) ;
123+ }
124+
125+ if ( certificate != null )
126+ {
127+ builder = builder . WithCertificate ( certificate ) ;
128+ }
129+
130+ if ( ! string . IsNullOrEmpty ( redirectUri ) )
131+ {
132+ builder = builder . WithRedirectUri ( redirectUri ) ;
133+ }
134+
135+ if ( ! string . IsNullOrEmpty ( tenantId ) )
136+ {
137+ builder = builder . WithTenantId ( tenantId ) ;
138+ }
139+
140+ IConfidentialClientApplication client = builder . WithLogging ( ( level , message , pii ) =>
141+ {
142+ PartnerSession . Instance . DebugMessages . Enqueue ( $ "[MSAL] { level } { message } ") ;
143+ } ) . Build ( ) ;
144+
145+
146+ PartnerTokenCache tokenCache = new PartnerTokenCache ( clientId ) ;
147+
148+ client . UserTokenCache . SetAfterAccess ( tokenCache . AfterAccessNotification ) ;
149+ client . UserTokenCache . SetBeforeAccess ( tokenCache . BeforeAccessNotification ) ;
150+
151+ await Task . CompletedTask . ConfigureAwait ( false ) ;
152+
153+ return client ;
154+ }
155+
156+ /// <summary>
157+ /// Creates a public client used for generating tokens.
158+ /// </summary>
159+ /// <param name="authority">Address of the authority to issue the token</param>
160+ /// <param name="clientId">Identifier of the client requesting the token.</param>
161+ /// <param name="redirectUri">The redirect URI for the client.</param>
162+ /// <param name="tenantId">Identifier of the tenant requesting the token.</param>
163+ /// <returns>An aptly configured public client.</returns>
164+ private static async Task < IPublicClientApplication > CreatePublicClient (
165+ string authority = null ,
166+ string clientId = null ,
167+ string redirectUri = null ,
168+ string tenantId = null )
169+ {
170+ PublicClientApplicationBuilder builder = PublicClientApplicationBuilder . Create ( clientId ) ;
171+
172+ if ( ! string . IsNullOrEmpty ( authority ) )
173+ {
174+ builder = builder . WithAuthority ( authority ) ;
175+ }
176+
177+ if ( ! string . IsNullOrEmpty ( redirectUri ) )
178+ {
179+ builder = builder . WithRedirectUri ( redirectUri ) ;
180+ }
181+
182+ if ( ! string . IsNullOrEmpty ( tenantId ) )
183+ {
184+ builder = builder . WithTenantId ( tenantId ) ;
185+ }
186+
187+ IPublicClientApplication client = builder . WithLogging ( ( level , message , pii ) =>
188+ {
189+ PartnerSession . Instance . DebugMessages . Enqueue ( $ "[MSAL] { level } { message } ") ;
190+ } ) . Build ( ) ;
191+
192+ PartnerTokenCache tokenCache = new PartnerTokenCache ( clientId ) ;
193+
194+ client . UserTokenCache . SetAfterAccess ( tokenCache . AfterAccessNotification ) ;
195+ client . UserTokenCache . SetBeforeAccess ( tokenCache . BeforeAccessNotification ) ;
196+
197+ await Task . CompletedTask . ConfigureAwait ( false ) ;
198+
199+ return client ;
200+ }
201+
74202 /// <summary>
75203 /// Gets the specified certificate.
76204 /// </summary>
@@ -121,27 +249,5 @@ private bool FindCertificateByThumbprint(string thumbprint, StoreLocation storeL
121249 store ? . Close ( ) ;
122250 }
123251 }
124-
125- /// <summary>
126- /// Determine if this request can be authenticated using the given authenticator, and authenticate if it can.
127- /// </summary>
128- /// <param name="parameters">The complex object containing authentication specific information.</param>
129- /// <param name="token">The token based authentication information.</param>
130- /// <param name="cancellationToken">A cancellation token that can be used by other objects or threads to receive notice of cancellation.</param>
131- /// <returns><c>true</c> if the request can be authenticated; otherwise <c>false</c>.</returns>
132- public async Task < AuthenticationResult > TryAuthenticateAsync ( AuthenticationParameters parameters , CancellationToken cancellationToken = default )
133- {
134- if ( CanAuthenticate ( parameters ) )
135- {
136- return await AuthenticateAsync ( parameters , cancellationToken ) . ConfigureAwait ( false ) ;
137- }
138-
139- if ( Next != null )
140- {
141- return await Next . TryAuthenticateAsync ( parameters , cancellationToken ) . ConfigureAwait ( false ) ;
142- }
143-
144- return null ;
145- }
146252 }
147253}
0 commit comments