Skip to content

Commit f150c73

Browse files
committed
Merge pull request #235 from Azure/clu
Clu
2 parents 95795de + 89fd694 commit f150c73

File tree

29 files changed

+386
-171
lines changed

29 files changed

+386
-171
lines changed

src/CLU/Commands.Common.Authentication/Authentication/AdalTokenProvider.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,17 +35,17 @@ public AdalTokenProvider()
3535

3636
public IAccessToken GetAccessToken(
3737
AdalConfiguration config,
38-
ShowDialog promptBehavior,
38+
AuthenticationBehavior behavior,
3939
string userId,
4040
string password,
4141
AzureAccount.AccountType credentialType)
4242
{
4343
switch (credentialType)
4444
{
4545
case AzureAccount.AccountType.User:
46-
return userTokenProvider.GetAccessToken(config, promptBehavior, userId, password, credentialType);
46+
return userTokenProvider.GetAccessToken(config, behavior, userId, password, credentialType);
4747
case AzureAccount.AccountType.ServicePrincipal:
48-
return servicePrincipalTokenProvider.GetAccessToken(config, promptBehavior, userId, password, credentialType);
48+
return servicePrincipalTokenProvider.GetAccessToken(config, behavior, userId, password, credentialType);
4949
default:
5050
throw new ArgumentException(Resources.UnknownCredentialType, "credentialType");
5151
}

src/CLU/Commands.Common.Authentication/Authentication/ShowDialog.cs renamed to src/CLU/Commands.Common.Authentication/Authentication/AuthenticationBehavior.cs

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,21 @@
1212
// limitations under the License.
1313
// ----------------------------------------------------------------------------------
1414

15+
using Microsoft.IdentityModel.Clients.ActiveDirectory;
16+
using System;
17+
1518
namespace Microsoft.Azure.Commands.Common.Authentication
1619
{
17-
public enum ShowDialog
20+
public enum AuthenticationType
1821
{
19-
Auto,
20-
Always,
21-
Never
22+
DeviceCode,
23+
Silent
24+
}
25+
26+
public class AuthenticationBehavior
27+
{
28+
public Func<DeviceCodeResult, bool> DeviceCodeHandler { get; set; }
29+
30+
public AuthenticationType Type { get; set; }
2231
}
2332
}

src/CLU/Commands.Common.Authentication/Authentication/ITokenProvider.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,14 +28,14 @@ public interface ITokenProvider
2828
/// and credential type.
2929
/// </summary>
3030
/// <param name="config">Configuration.</param>
31-
/// <param name="promptBehavior">Prompt behavior.</param>
31+
/// <param name="behavior">Prompt behavior.</param>
3232
/// <param name="userId">User ID/Service principal to get the token for.</param>
3333
/// <param name="password">Secure strings with password/service principal key.</param>
3434
/// <param name="credentialType">Credential type.</param>
3535
/// <returns>An access token.</returns>
3636
IAccessToken GetAccessToken(
3737
AdalConfiguration config,
38-
ShowDialog promptBehavior,
38+
AuthenticationBehavior behavior,
3939
string userId,
4040
string password,
4141
AzureAccount.AccountType credentialType);

src/CLU/Commands.Common.Authentication/Authentication/KeyStoreApplicationCredentialProvider.cs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,6 @@ public KeyStoreApplicationCredentialProvider(string tenant, string password)
4646
/// <returns></returns>
4747
public async Task<AuthenticationResult> AuthenticateAsync(string clientId, string audience, AuthenticationContext context)
4848
{
49-
50-
5149
return await context.AcquireTokenAsync(audience, new ClientCredential(clientId, _password));
5250
}
5351
}

src/CLU/Commands.Common.Authentication/Authentication/ServicePrincipalTokenProvider.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ public ServicePrincipalTokenProvider(Func<String, byte[]> certificateFinder)
3737
{
3838
_getCertificate = certificateFinder;
3939
}
40-
public IAccessToken GetAccessToken(AdalConfiguration config, ShowDialog promptBehavior, string userId, string password,
40+
public IAccessToken GetAccessToken(AdalConfiguration config, AuthenticationBehavior behavior, string userId, string password,
4141
AzureAccount.AccountType credentialType)
4242
{
4343
if (credentialType == AzureAccount.AccountType.User)

src/CLU/Commands.Common.Authentication/Authentication/UserTokenProvider.cs

Lines changed: 56 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
using System.Runtime.InteropServices;
2020
using Commands.Common.Authentication.Properties;
2121
using Microsoft.Rest.Azure.Authentication;
22+
using System.Management.Automation;
2223

2324
namespace Microsoft.Azure.Commands.Common.Authentication
2425
{
@@ -29,10 +30,9 @@ namespace Microsoft.Azure.Commands.Common.Authentication
2930
/// </summary>
3031
internal class UserTokenProvider : ITokenProvider
3132
{
32-
3333
public IAccessToken GetAccessToken(
3434
AdalConfiguration config,
35-
ShowDialog promptBehavior,
35+
AuthenticationBehavior behavior,
3636
string userId,
3737
string password,
3838
AzureAccount.AccountType credentialType)
@@ -42,7 +42,7 @@ public IAccessToken GetAccessToken(
4242
throw new ArgumentException(string.Format(Resources.InvalidCredentialType, "User"), "credentialType");
4343
}
4444

45-
return new AdalAccessToken(AcquireToken(config, promptBehavior, userId, password), this, config);
45+
return new AdalAccessToken(AcquireToken(config, behavior, userId, password), this, config);
4646
}
4747

4848
private readonly static TimeSpan expirationThreshold = TimeSpan.FromMinutes(5);
@@ -81,7 +81,7 @@ private void Renew(AdalAccessToken token)
8181
if (IsExpired(token))
8282
{
8383
ServiceClientTracing.Information(Resources.UPNExpiredTokenTrace);
84-
AuthenticationResult result = AcquireToken(token.Configuration, ShowDialog.Never, token.UserId, null);
84+
AuthenticationResult result = AcquireToken(token.Configuration, new AuthenticationBehavior { Type = AuthenticationType.Silent }, token.UserId, null);
8585

8686
if (result == null)
8787
{
@@ -104,7 +104,7 @@ private AuthenticationContext CreateContext(AdalConfiguration config)
104104

105105
// We have to run this in a separate thread to guarantee that it's STA. This method
106106
// handles the threading details.
107-
private AuthenticationResult AcquireToken(AdalConfiguration config, ShowDialog promptBehavior, string userId,
107+
private AuthenticationResult AcquireToken(AdalConfiguration config, AuthenticationBehavior behavior, string userId,
108108
string password)
109109
{
110110
AuthenticationResult result = null;
@@ -121,31 +121,64 @@ private AuthenticationResult AcquireToken(AdalConfiguration config, ShowDialog p
121121
config.AdEndpoint,
122122
config.ClientId,
123123
config.ClientRedirectUri);
124-
if (promptBehavior != ShowDialog.Never)
124+
if (behavior.Type == AuthenticationType.DeviceCode)
125125
{
126-
throw new NotImplementedException("Device based authencation is not implemented.");
127-
}
126+
if(behavior.DeviceCodeHandler == null)
127+
{
128+
throw new PSArgumentException("deviceCodeHandler");
129+
}
128130

129-
try
130-
{
131-
UserCredential credential = new UserCredential(userId, password);
132-
result = context.AcquireTokenAsync(
133-
config.ResourceClientUri,
134-
config.ClientId,
135-
credential)
136-
.ConfigureAwait(false).GetAwaiter().GetResult();
137-
return result;
131+
try
132+
{
133+
DeviceCodeResult codeResult = context.AcquireDeviceCodeAsync(
134+
config.ResourceClientUri,
135+
config.ClientId)
136+
.ConfigureAwait(false).GetAwaiter().GetResult();
137+
138+
if (behavior.DeviceCodeHandler(codeResult))
139+
{
140+
return context.AcquireTokenByDeviceCodeAsync(codeResult)
141+
.ConfigureAwait(false).GetAwaiter().GetResult();
142+
}
143+
144+
throw new AadAuthenticationCanceledException("Authentication cancelled.", null);
145+
}
146+
catch (AdalException adalException)
147+
{
148+
if (adalException.ErrorCode == AdalError.AuthenticationCanceled)
149+
{
150+
throw new AadAuthenticationCanceledException(adalException.Message, adalException);
151+
}
152+
153+
throw new AadAuthenticationFailedException(adalException.Message, adalException);
154+
}
138155
}
139-
catch (AdalException adalException)
156+
else if(behavior.Type == AuthenticationType.Silent)
140157
{
141-
if (adalException.ErrorCode == AdalError.AuthenticationCanceled)
158+
try
142159
{
143-
throw new AadAuthenticationCanceledException(adalException.Message, adalException);
160+
UserCredential credential = new UserCredential(userId, password);
161+
return context.AcquireTokenAsync(
162+
config.ResourceClientUri,
163+
config.ClientId,
164+
credential)
165+
.ConfigureAwait(false).GetAwaiter().GetResult();
144166
}
167+
catch (AdalException adalException)
168+
{
169+
if (adalException.ErrorCode == AdalError.AuthenticationCanceled)
170+
{
171+
throw new AadAuthenticationCanceledException(adalException.Message, adalException);
172+
}
145173

146-
throw new AadAuthenticationFailedException(adalException.Message, adalException);
174+
throw new AadAuthenticationFailedException(adalException.Message, adalException);
175+
}
176+
}
177+
else
178+
{
179+
throw new NotImplementedException(
180+
string.Format("'{0}' authentication is not implemented.", behavior.Type));
147181
}
148-
149182
}
150183

151184
/// <summary>
@@ -187,8 +220,7 @@ public LoginType LoginType
187220
}
188221
}
189222
}
190-
191-
223+
192224
private void ClearCookies()
193225
{
194226
NativeMethods.InternetSetOption(IntPtr.Zero, NativeMethods.INTERNET_OPTION_END_BROWSER_SESSION, IntPtr.Zero, 0);

src/CLU/Commands.Common.Authentication/AuthenticationFactory.cs

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,8 @@ public IAccessToken Authenticate(
4646
AzureAccount account,
4747
AzureEnvironment environment,
4848
string tenant,
49-
string password,
49+
string password,
50+
AuthenticationBehavior behavior,
5051
TokenCache tokenCache,
5152
AzureEnvironment.Endpoint resourceId = AzureEnvironment.Endpoint.ActiveDirectoryServiceEndpointResourceId)
5253
{
@@ -64,8 +65,7 @@ public IAccessToken Authenticate(
6465
}
6566
else
6667
{
67-
68-
token = TokenProvider.GetAccessToken(configuration, ShowDialog.Never, account.Id, password, account.Type);
68+
token = TokenProvider.GetAccessToken(configuration, behavior, account.Id, password, account.Type);
6969
}
7070

7171
account.Id = token.UserId;
@@ -79,7 +79,14 @@ public IAccessToken Authenticate(
7979
string password,
8080
AzureEnvironment.Endpoint resourceId = AzureEnvironment.Endpoint.ActiveDirectoryServiceEndpointResourceId)
8181
{
82-
return Authenticate(account, environment, tenant, password, TokenCache.DefaultShared, resourceId);
82+
return Authenticate(
83+
account,
84+
environment,
85+
tenant,
86+
password,
87+
new AuthenticationBehavior { Type = AuthenticationType.Silent },
88+
TokenCache.DefaultShared,
89+
resourceId);
8390
}
8491

8592
public ServiceClientCredentials GetSubscriptionCloudCredentials(AzureContext context)
@@ -151,8 +158,12 @@ public ServiceClientCredentials GetSubscriptionCloudCredentials(
151158
tokenCache = new TokenCache(context.TokenCache);
152159
}
153160

154-
var token = Authenticate(context.Account, context.Environment,
155-
tenant, null, tokenCache);
161+
var token = Authenticate(
162+
context.Account,
163+
context.Environment,
164+
tenant, null,
165+
new AuthenticationBehavior { Type = AuthenticationType.Silent },
166+
tokenCache);
156167

157168
if (context.TokenCache != null && context.TokenCache.Length > 0)
158169
{

src/CLU/Commands.Common.Authentication/IAuthenticationFactory.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,14 +28,16 @@ public interface IAuthenticationFactory
2828
/// <param name="environment">The azure environment object</param>
2929
/// <param name="tenant">The AD tenant in most cases should be 'common'</param>
3030
/// <param name="password">The AD account password</param>
31+
/// <param name="behavior">The authentication behavior</param>
3132
/// <param name="tokenCache">Token Cache</param>
3233
/// <param name="resourceId">Optional, the AD resource id</param>
3334
/// <returns></returns>
3435
IAccessToken Authenticate(
3536
AzureAccount account,
3637
AzureEnvironment environment,
3738
string tenant,
38-
string password,
39+
string password,
40+
AuthenticationBehavior behavior,
3941
TokenCache tokenCache,
4042
AzureEnvironment.Endpoint resourceId = AzureEnvironment.Endpoint.ActiveDirectoryServiceEndpointResourceId);
4143

@@ -56,6 +58,7 @@ IAccessToken Authenticate(
5658
AzureEnvironment.Endpoint resourceId = AzureEnvironment.Endpoint.ActiveDirectoryServiceEndpointResourceId);
5759

5860
ServiceClientCredentials GetSubscriptionCloudCredentials(AzureContext context);
61+
5962
ServiceClientCredentials GetSubscriptionCloudCredentials(AzureContext context, AzureEnvironment.Endpoint targetEndpoint);
6063

6164
ServiceClientCredentials GetServiceClientCredentials(AzureContext context);

src/CLU/Commands.Common.Authentication/project.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
"System.Linq": "4.0.1-beta-23516",
1919
"Microsoft.CLU": "1.0.0",
2020
"Microsoft.IdentityModel.Clients.ActiveDirectory": "3.6.210231457-alpha",
21-
"Microsoft.Rest.ClientRuntime": "1.4.1",
21+
"Microsoft.Rest.ClientRuntime": "1.5.0",
2222
"Microsoft.Rest.ClientRuntime.Azure.Authentication": "1.0.0-preview",
2323
"Newtonsoft.Json": "7.0.1",
2424
"System.Collections": "4.0.11-beta-23516",

src/CLU/Commands.Common.Storage/project.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
"Commands.Common": "",
2121
"Commands.Common.Authentication": "",
2222
"Microsoft.IdentityModel.Clients.ActiveDirectory": "3.6.210231457-alpha",
23-
"Microsoft.Rest.ClientRuntime": "1.4.1",
23+
"Microsoft.Rest.ClientRuntime": "1.5.0",
2424
"Newtonsoft.Json": "7.0.1",
2525
"System.Collections": "4.0.11-beta-23516",
2626
"System.Collections.Concurrent": "4.0.11-beta-23516",

src/CLU/Commands.Common/AzurePSCmdlet.cs

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,16 @@ protected virtual T GetSessionVariableValue<T>(string name, T defaultValue) wher
107107
{
108108
try
109109
{
110-
returnValue = SessionState.PSVariable.Get<T>(name)?? defaultValue ;
110+
returnValue = SessionState.PSVariable.Get<T>(name) ?? defaultValue;
111+
}
112+
catch
113+
{
114+
}
115+
}
116+
else
117+
{
118+
try
119+
{
111120
var variablePath = GetPath(name);
112121
var fileText = DataStore.ReadFileAsText(variablePath);
113122
if (!string.IsNullOrEmpty(fileText))
@@ -117,6 +126,7 @@ protected virtual T GetSessionVariableValue<T>(string name, T defaultValue) wher
117126
}
118127
catch
119128
{
129+
120130
}
121131
}
122132

@@ -127,11 +137,15 @@ protected virtual string GetPath(string variableName)
127137
{
128138
return Path.Combine(Directory.GetCurrentDirectory(), "sessions", variableName);
129139
}
140+
130141
protected virtual void SetSessionVariable<T>(string name, T value) where T : class
131142
{
132143
if (SessionState != null)
133144
{
134145
SessionState.PSVariable.Set(name, value);
146+
}
147+
else
148+
{
135149
var variablePath = GetPath(name);
136150
DataStore.WriteFile(variablePath, JsonConvert.SerializeObject(value));
137151
}
@@ -152,12 +166,12 @@ protected static void InitializeDataCollectionProfile()
152166
{
153167
if (string.Equals(value, bool.FalseString, StringComparison.OrdinalIgnoreCase))
154168
{
155-
// Disable data collection only if it is explictly set to 'false'.
169+
// Disable data collection only if it is explicitly set to 'false'.
156170
_dataCollectionProfile = new AzurePSDataCollectionProfile(true);
157171
}
158172
else if (string.Equals(value, bool.TrueString, StringComparison.OrdinalIgnoreCase))
159173
{
160-
// Enable data collection only if it is explictly set to 'true'.
174+
// Enable data collection only if it is explicitly set to 'true'.
161175
_dataCollectionProfile = new AzurePSDataCollectionProfile(false);
162176
}
163177
}
@@ -270,7 +284,7 @@ protected override void BeginProcessing()
270284
WriteDebugWithTimestamp(string.Format("using account id '{0}'...", DefaultContext.Account.Id));
271285
}
272286

273-
DataStore = GetSessionVariableValue<IDataStore>(AzurePowerShell.DataStoreVariable, new DiskDataStore());
287+
DataStore = DataStore?? GetSessionVariableValue<IDataStore>(AzurePowerShell.DataStoreVariable, new DiskDataStore());
274288
_adalListener = _adalListener ?? new DebugStreamTraceListener(_debugMessages);
275289
DebugStreamTraceListener.AddAdalTracing(_adalListener);
276290

@@ -339,11 +353,7 @@ protected bool IsVerbose()
339353
protected new void WriteObject(object sendToPipeline)
340354
{
341355
FlushDebugMessages();
342-
#if DEBUG
343-
CommandRuntime.WriteObject(sendToPipeline);
344-
#else
345356
base.WriteObject(sendToPipeline);
346-
#endif
347357
}
348358

349359
protected new void WriteObject(object sendToPipeline, bool enumerateCollection)

0 commit comments

Comments
 (0)