@@ -7,9 +7,9 @@ namespace Microsoft.Store.PartnerCenter.PowerShell.Authenticators
7
7
using System . Threading ;
8
8
using System . Threading . Tasks ;
9
9
using Extensions ;
10
- using Factories ;
11
10
using Identity . Client ;
12
11
using Models . Authentication ;
12
+ using Utilities ;
13
13
14
14
/// <summary>
15
15
/// Provides a chain of responsibility pattern for authenticators.
@@ -39,38 +39,166 @@ internal abstract class DelegatingAuthenticator : IAuthenticator
39
39
public abstract bool CanAuthenticate ( AuthenticationParameters parameters ) ;
40
40
41
41
/// <summary>
42
- ///
42
+ /// Gets an aptly configured client.
43
43
/// </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 )
49
49
{
50
50
IClientApplicationBase app ;
51
51
52
52
if ( account . IsPropertySet ( PartnerAccountPropertyType . CertificateThumbprint ) || account . IsPropertySet ( PartnerAccountPropertyType . ServicePrincipalSecret ) )
53
53
{
54
- app = SharedTokenCacheClientFactory . CreateConfidentialClient (
54
+ app = await CreateConfidentialClientAsync (
55
55
$ "{ environment . ActiveDirectoryAuthority } { account . Tenant } ",
56
56
account . GetProperty ( PartnerAccountPropertyType . ApplicationId ) ,
57
57
account . GetProperty ( PartnerAccountPropertyType . ServicePrincipalSecret ) ,
58
58
GetCertificate ( account . GetProperty ( PartnerAccountPropertyType . CertificateThumbprint ) ) ,
59
59
redirectUri ,
60
- account . Tenant ) ;
60
+ account . Tenant ) . ConfigureAwait ( false ) ;
61
61
}
62
62
else
63
63
{
64
- app = SharedTokenCacheClientFactory . CreatePublicClient (
64
+ app = await CreatePublicClient (
65
65
$ "{ environment . ActiveDirectoryAuthority } { account . Tenant } ",
66
66
account . GetProperty ( PartnerAccountPropertyType . ApplicationId ) ,
67
67
redirectUri ,
68
- account . Tenant ) ;
68
+ account . Tenant ) . ConfigureAwait ( false ) ;
69
69
}
70
70
71
71
return app ;
72
72
}
73
73
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
+
74
202
/// <summary>
75
203
/// Gets the specified certificate.
76
204
/// </summary>
@@ -121,27 +249,5 @@ private bool FindCertificateByThumbprint(string thumbprint, StoreLocation storeL
121
249
store ? . Close ( ) ;
122
250
}
123
251
}
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
- }
146
252
}
147
253
}
0 commit comments