diff --git a/src/Common/Commands.Common/AzureRmProfileProvider.cs b/src/Common/Commands.Common/AzureRmProfileProvider.cs index 16aae9bc4e24..fddf65d662a4 100644 --- a/src/Common/Commands.Common/AzureRmProfileProvider.cs +++ b/src/Common/Commands.Common/AzureRmProfileProvider.cs @@ -12,6 +12,7 @@ // limitations under the License. // ---------------------------------------------------------------------------------- +using Microsoft.Azure.Common.Authentication; using Microsoft.Azure.Common.Authentication.Models; namespace Microsoft.WindowsAzure.Commands.Common diff --git a/src/ResourceManager/Common/Commands.ResourceManager.Common/AzureRMCmdlet.cs b/src/ResourceManager/Common/Commands.ResourceManager.Common/AzureRMCmdlet.cs index cfdd74df9587..534e719037ac 100644 --- a/src/ResourceManager/Common/Commands.ResourceManager.Common/AzureRMCmdlet.cs +++ b/src/ResourceManager/Common/Commands.ResourceManager.Common/AzureRMCmdlet.cs @@ -37,10 +37,10 @@ public abstract class AzureRMCmdlet : AzurePSCmdlet /// static AzureRMCmdlet() { - if (AzureSession.DataStore == null) + if (!TestMockSupport.RunningMocked) { AzureSession.DataStore = new DiskDataStore(); - } + } } public AzureRMCmdlet() diff --git a/src/ResourceManager/Profile/Commands.Profile/Account/AddAzureRmAccount.cs b/src/ResourceManager/Profile/Commands.Profile/Account/AddAzureRmAccount.cs index 801ba1080d6c..4f9a53d31fe5 100644 --- a/src/ResourceManager/Profile/Commands.Profile/Account/AddAzureRmAccount.cs +++ b/src/ResourceManager/Profile/Commands.Profile/Account/AddAzureRmAccount.cs @@ -55,11 +55,15 @@ public class AddAzureRMAccountCommand : AzureRMCmdlet , IModuleAssemblyInitializ [ValidateNotNullOrEmpty] public string AccessToken { get; set; } - [Parameter(Mandatory = false, HelpMessage = "Subscription")] + [Parameter(ParameterSetName = "AccessToken", Mandatory = true, HelpMessage = "Account Id for access token")] + [ValidateNotNullOrEmpty] + public string AccountId { get; set; } + + [Parameter(Mandatory = false, HelpMessage = "Subscription Id")] [ValidateNotNullOrEmpty] public string SubscriptionId { get; set; } - [Parameter(Mandatory = false, HelpMessage = "Subscription")] + [Parameter(Mandatory = false, HelpMessage = "Subscription name")] [ValidateNotNullOrEmpty] public string SubscriptionName { get; set; } @@ -97,7 +101,14 @@ protected override void ProcessRecord() if (!string.IsNullOrEmpty(AccessToken)) { + if (string.IsNullOrWhiteSpace(AccountId) ) + { + throw new PSInvalidOperationException(Resources.AccountIdRequired); + } + azureAccount.Type = AzureAccount.AccountType.AccessToken; + azureAccount.Id = AccountId; + azureAccount.SetProperty(AzureAccount.Property.AccessToken, AccessToken); } else if (ServicePrincipal.IsPresent) { @@ -127,7 +138,8 @@ protected override void ProcessRecord() var profileClient = new RMProfileClient(AzureRmProfileProvider.Instance.Profile); - WriteObject((PSAzureProfile)profileClient.Login(azureAccount, Environment, Tenant, SubscriptionId, SubscriptionName, password)); + WriteObject((PSAzureProfile)profileClient.Login(azureAccount, Environment, Tenant, SubscriptionId, + SubscriptionName, password)); } /// diff --git a/src/ResourceManager/Profile/Commands.Profile/Commands.Profile.csproj b/src/ResourceManager/Profile/Commands.Profile/Commands.Profile.csproj index 0ed70994841b..deae18eb8079 100644 --- a/src/ResourceManager/Profile/Commands.Profile/Commands.Profile.csproj +++ b/src/ResourceManager/Profile/Commands.Profile/Commands.Profile.csproj @@ -146,6 +146,7 @@ + diff --git a/src/ResourceManager/Profile/Commands.Profile/Models/PSAzureProfile.cs b/src/ResourceManager/Profile/Commands.Profile/Models/PSAzureProfile.cs index 9c690a8a79f6..43e006617dac 100644 --- a/src/ResourceManager/Profile/Commands.Profile/Models/PSAzureProfile.cs +++ b/src/ResourceManager/Profile/Commands.Profile/Models/PSAzureProfile.cs @@ -34,7 +34,7 @@ public static implicit operator PSAzureProfile(AzureRMProfile profile) }; profile.Environments - .ForEach((e) => result.Environments.Add(e.Key, (PSAzureEnvironment)e.Value)); + .ForEach((e) => result.Environments[e.Key] = (PSAzureEnvironment)e.Value); return result; } @@ -54,8 +54,7 @@ public static implicit operator AzureRMProfile(PSAzureProfile profile) { Context = profile.Context }; - profile.Environments - .ForEach((e) => result.Environments.Add(e.Key, (AzureEnvironment)e.Value)); + profile.Environments.ForEach((e) => result.Environments[e.Key] = (AzureEnvironment) e.Value); return result; } diff --git a/src/ResourceManager/Profile/Commands.Profile/Models/PSAzureRmAccount.cs b/src/ResourceManager/Profile/Commands.Profile/Models/PSAzureRmAccount.cs index 8ac13163cf37..32159c3116e9 100644 --- a/src/ResourceManager/Profile/Commands.Profile/Models/PSAzureRmAccount.cs +++ b/src/ResourceManager/Profile/Commands.Profile/Models/PSAzureRmAccount.cs @@ -36,11 +36,23 @@ public static implicit operator PSAzureRmAccount(AzureAccount account) return null; } - return new PSAzureRmAccount + var result = new PSAzureRmAccount { Id = account.Id, AccountType = account.Type.ToString() }; + + if (account.IsPropertySet(AzureAccount.Property.AccessToken)) + { + result.AccessToken = account.GetProperty(AzureAccount.Property.AccessToken); + } + + if (account.IsPropertySet(AzureAccount.Property.Tenants)) + { + result.Tenants = account.GetProperty(AzureAccount.Property.Tenants); + } + + return result; } /// @@ -65,6 +77,16 @@ public static implicit operator AzureAccount(PSAzureRmAccount account) result.Type = accountType; } + if (!string.IsNullOrWhiteSpace(account.AccessToken)) + { + result.SetProperty(AzureAccount.Property.AccessToken, account.AccessToken); + } + + if (!string.IsNullOrWhiteSpace(account.Tenants)) + { + result.SetProperty(AzureAccount.Property.Tenants, account.Tenants); + } + return result; } @@ -77,6 +99,16 @@ public static implicit operator AzureAccount(PSAzureRmAccount account) /// public string AccountType { get; set; } + /// + /// The tenant ids for the account + /// + public string Tenants { get; set; } + + /// + /// The access token for the account (if any) + /// + public string AccessToken { get; set; } + public override string ToString() { return this.Id; diff --git a/src/ResourceManager/Profile/Commands.Profile/Models/RMProfileClient.cs b/src/ResourceManager/Profile/Commands.Profile/Models/RMProfileClient.cs index 8d3697d3779c..3d553a1abcb0 100644 --- a/src/ResourceManager/Profile/Commands.Profile/Models/RMProfileClient.cs +++ b/src/ResourceManager/Profile/Commands.Profile/Models/RMProfileClient.cs @@ -25,6 +25,7 @@ using System.Linq; using System.Management.Automation; using System.Security; +using Microsoft.Azure.Commands.Profile.Models; namespace Microsoft.Azure.Commands.ResourceManager.Common { @@ -44,11 +45,13 @@ public RMProfileClient(AzureRMProfile profile) } } - public AzureRMProfile Login(AzureAccount account, AzureEnvironment environment, string tenantId, string subscriptionId, string subscriptionName, SecureString password) + public AzureRMProfile Login(AzureAccount account, AzureEnvironment environment, string tenantId, string subscriptionId, + string subscriptionName, SecureString password) { AzureSubscription newSubscription = null; AzureTenant newTenant = null; - ShowDialog promptBehavior = password == null ? ShowDialog.Always : ShowDialog.Never; + ShowDialog promptBehavior = (password == null && account.Type != AzureAccount.AccountType.AccessToken) + ? ShowDialog.Always : ShowDialog.Never; // (tenant and subscription are present) OR // (tenant is present and subscription is not provided) @@ -280,6 +283,12 @@ private IAccessToken AcquireAccessToken(AzureAccount account, SecureString password, ShowDialog promptBehavior) { + if (account.Type == AzureAccount.AccountType.AccessToken) + { + tenantId = tenantId ?? "Common"; + return new SimpleAccessToken(account, tenantId); + } + return AzureSession.AuthenticationFactory.Authenticate( account, environment, diff --git a/src/ResourceManager/Profile/Commands.Profile/Models/SimpleAccessToken.cs b/src/ResourceManager/Profile/Commands.Profile/Models/SimpleAccessToken.cs new file mode 100644 index 000000000000..6872c3c0b6f7 --- /dev/null +++ b/src/ResourceManager/Profile/Commands.Profile/Models/SimpleAccessToken.cs @@ -0,0 +1,90 @@ +// ---------------------------------------------------------------------------------- +// +// Copyright Microsoft Corporation +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------------- + +using System; +using Microsoft.Azure.Commands.Profile.Properties; +using Microsoft.Azure.Common.Authentication; +using Microsoft.Azure.Common.Authentication.Models; + +namespace Microsoft.Azure.Commands.Profile.Models +{ + /// + /// Provides access token information for a bearer token + /// + public class SimpleAccessToken : IAccessToken + { + public const string _defaultTokenType = "Bearer"; + private string _tokenType; + + /// + /// Create a new access token from the given account and tenant id + /// + /// The account, containing user id, access token information + /// The tenant id for the given access token + /// The token type for the given token. + public SimpleAccessToken(AzureAccount account, string tenantId, string tokenType = _defaultTokenType) + { + if (account == null) + { + throw new ArgumentNullException("account"); + } + if (string.IsNullOrWhiteSpace(account.Id)) + { + throw new ArgumentOutOfRangeException("account", Resources.AccessTokenRequiresAccount); + } + if (account.Type != AzureAccount.AccountType.AccessToken || + !account.IsPropertySet(AzureAccount.Property.AccessToken)) + { + throw new ArgumentException(Resources.TypeNotAccessToken); + } + this.UserId = account.Id; + this._tokenType = tokenType; + this.AccessToken = account.GetProperty(AzureAccount.Property.AccessToken); + this.TenantId = tenantId; + } + + + /// + /// The access token to be applied to a request message + /// + public string AccessToken { get; private set; } + + /// + /// Authorize a request using an authorization setter function. + /// + /// The authorization token setter function. + public void AuthorizeRequest(System.Action authTokenSetter) + { + authTokenSetter(_tokenType, AccessToken); + } + + /// + /// The login type for this token + /// + public LoginType LoginType + { + get { return LoginType.OrgId; } + } + + /// + /// The tenant Id for this token. + /// + public string TenantId { get; private set; } + + /// + /// The User Id associated with this token. + /// + public string UserId { get; private set; } + } +} diff --git a/src/ResourceManager/Profile/Commands.Profile/Properties/Resources.Designer.cs b/src/ResourceManager/Profile/Commands.Profile/Properties/Resources.Designer.cs index 4d0ead958c30..4a66c728e1aa 100644 --- a/src/ResourceManager/Profile/Commands.Profile/Properties/Resources.Designer.cs +++ b/src/ResourceManager/Profile/Commands.Profile/Properties/Resources.Designer.cs @@ -60,6 +60,24 @@ internal Resources() { } } + /// + /// Looks up a localized string similar to AccountId must be provided to use an AccessToken credential.. + /// + internal static string AccessTokenRequiresAccount { + get { + return ResourceManager.GetString("AccessTokenRequiresAccount", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Access token credentials must provide the AccountId parameter.. + /// + internal static string AccountIdRequired { + get { + return ResourceManager.GetString("AccountIdRequired", resourceCulture); + } + } + /// /// Looks up a localized string similar to Selected profile must not be null.. /// @@ -131,5 +149,14 @@ internal static string TenantAuthFailed { return ResourceManager.GetString("TenantAuthFailed", resourceCulture); } } + + /// + /// Looks up a localized string similar to To create an access token credential, you must provide an access token account.. + /// + internal static string TypeNotAccessToken { + get { + return ResourceManager.GetString("TypeNotAccessToken", resourceCulture); + } + } } } diff --git a/src/ResourceManager/Profile/Commands.Profile/Properties/Resources.resx b/src/ResourceManager/Profile/Commands.Profile/Properties/Resources.resx index 0e92efc9cc35..9e39364a5eff 100644 --- a/src/ResourceManager/Profile/Commands.Profile/Properties/Resources.resx +++ b/src/ResourceManager/Profile/Commands.Profile/Properties/Resources.resx @@ -117,6 +117,12 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + AccountId must be provided to use an AccessToken credential. + + + Access token credentials must provide the AccountId parameter. + Selected profile must not be null. @@ -141,4 +147,7 @@ Could not authenticate with tenant {0}. Please ensure that your account has access to this tenant and log in with Login-AzureRmAccount + + To create an access token credential, you must provide an access token account. + \ No newline at end of file