diff --git a/src/Authentication.Abstractions/AuthenticationTelemetry.cs b/src/Authentication.Abstractions/AuthenticationTelemetry.cs index 4778eeb278..b042303d87 100644 --- a/src/Authentication.Abstractions/AuthenticationTelemetry.cs +++ b/src/Authentication.Abstractions/AuthenticationTelemetry.cs @@ -4,12 +4,6 @@ namespace Microsoft.Azure.Commands.Common.Authentication.Abstractions { public class AuthenticationTelemetry: IAzureTelemetry { - //public delegate string RequestIdAccquirer(); - - //public static RequestIdAccquirer GetRequestId; - - //private static string requestId; - public AuthenticationTelemetryData GetTelemetryRecord(ICmdletContext cmdletContext) { var records = PopTelemetryRecord(cmdletContext); diff --git a/src/Authentication.Abstractions/Extensions/CmdletContextExtension.cs b/src/Authentication.Abstractions/Extensions/CmdletContextExtension.cs new file mode 100644 index 0000000000..8d9c3e70c3 --- /dev/null +++ b/src/Authentication.Abstractions/Extensions/CmdletContextExtension.cs @@ -0,0 +1,32 @@ +// ---------------------------------------------------------------------------------- +// +// 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 Microsoft.Azure.Commands.Common.Authentication.Abstractions.Interfaces; + +using System.Collections.Generic; + +namespace Microsoft.Azure.Commands.Common.Authentication.Abstractions.Extensions +{ + public static class CmdletContextExtension + { + public static IDictionary ToExtensibleParameters(this ICmdletContext cmdletContext) + { + if (cmdletContext != null) + { + return new Dictionary { { nameof(ICmdletContext), cmdletContext } }; + } + return null; + } + } +} diff --git a/src/Authentication.Abstractions/Interfaces/IAuthenticationFactory.cs b/src/Authentication.Abstractions/Interfaces/IAuthenticationFactory.cs index dfe39f7d62..e5bcfa1772 100644 --- a/src/Authentication.Abstractions/Interfaces/IAuthenticationFactory.cs +++ b/src/Authentication.Abstractions/Interfaces/IAuthenticationFactory.cs @@ -16,6 +16,7 @@ using System; using System.Security; using Microsoft.Azure.Commands.Common.Authentication.Abstractions.Interfaces; +using System.Collections.Generic; namespace Microsoft.Azure.Commands.Common.Authentication.Abstractions { @@ -24,6 +25,27 @@ namespace Microsoft.Azure.Commands.Common.Authentication.Abstractions /// public interface IAuthenticationFactory : IHyakAuthenticationFactory { + + /// + /// Returns IAccessToken if authentication succeeds or throws an exception if authentication fails. + /// + /// The azure account object + /// The azure environment object + /// The AD tenant in most cases should be 'common' + /// The AD account password + /// The prompt behavior + /// The prompt action used in DeviceFlow authentication + /// The optional parameters, may include TokenCache, ResourceId and CmdletContext + /// + IAccessToken Authenticate( + IAzureAccount account, + IAzureEnvironment environment, + string tenant, + SecureString password, + string promptBehavior, + Action promptAction, + IDictionary optionalParameters); + /// /// Returns IAccessToken if authentication succeeds or throws an exception if authentication fails. /// @@ -44,7 +66,6 @@ IAccessToken Authenticate( string promptBehavior, Action promptAction, IAzureTokenCache tokenCache, - ICmdletContext cmdletContext, string resourceId = AzureEnvironment.Endpoint.ActiveDirectoryServiceEndpointResourceId); /// @@ -65,9 +86,15 @@ IAccessToken Authenticate( SecureString password, string promptBehavior, Action promptAction, - ICmdletContext cmdletContext, string resourceId = AzureEnvironment.Endpoint.ActiveDirectoryServiceEndpointResourceId); + /// + /// Get AutoRest credentials for the given context + /// + /// The target azure context + /// AutoRest client credentials targeting the given context + ServiceClientCredentials GetServiceClientCredentials(IAzureContext context); + /// /// Get AutoRest credentials for the given context /// @@ -80,9 +107,17 @@ IAccessToken Authenticate( /// Get AutoRest credebntials using the given context and named endpoint /// /// The context to use for authentication - /// The caller cmdlet context /// The named endpoint the AutoRest client will target /// AutoRest client crentials targeting the given context and endpoint + ServiceClientCredentials GetServiceClientCredentials(IAzureContext context, string targetEndpoint); + + /// + /// Get AutoRest credebntials using the given context and named endpoint + /// + /// The context to use for authentication + /// The named endpoint the AutoRest client will target + /// The caller cmdlet context + /// AutoRest client crentials targeting the given context and endpoint ServiceClientCredentials GetServiceClientCredentials(IAzureContext context, string targetEndpoint, ICmdletContext cmdletContext); /// diff --git a/src/Authentication.Abstractions/Interfaces/IAzureTelemetry.cs b/src/Authentication.Abstractions/Interfaces/IAzureTelemetry.cs index 0cf63cf8b3..853b346cf4 100644 --- a/src/Authentication.Abstractions/Interfaces/IAzureTelemetry.cs +++ b/src/Authentication.Abstractions/Interfaces/IAzureTelemetry.cs @@ -1,4 +1,6 @@ -using System.Collections.Concurrent; +using Newtonsoft.Json.Linq; +using System.Threading; +using System.Collections.Concurrent; using System.Collections.Generic; namespace Microsoft.Azure.Commands.Common.Authentication.Abstractions.Interfaces @@ -6,7 +8,19 @@ namespace Microsoft.Azure.Commands.Common.Authentication.Abstractions.Interfaces public abstract class IAzureTelemetry { private ConcurrentDictionary> telemetryDataAccquirer = new ConcurrentDictionary>(); - + + protected int historyKeyCount = 0; + public int KeysAllCount { get => historyKeyCount; } + + protected int currentKeyCount = 0; + public int KeysCurrentCount { get => currentKeyCount; } + + protected int nullCmdletContextCount = 0; + public int EmptyCmdletContextCount { get => nullCmdletContextCount; } + + protected int keyNotFoundCount = 0; + public int KeyNotFoundCount { get => keyNotFoundCount; } + public bool PushTelemetryRecord(ICmdletContext cmdletContext, T record) { if (cmdletContext != null && cmdletContext.IsValid && record != null) @@ -14,19 +28,34 @@ public bool PushTelemetryRecord(ICmdletContext cmdletContext, T record) if (!telemetryDataAccquirer.ContainsKey(cmdletContext.CmdletId)) { telemetryDataAccquirer[cmdletContext.CmdletId] = new List(); + Interlocked.Increment(ref historyKeyCount); + Interlocked.Increment(ref currentKeyCount); } telemetryDataAccquirer[cmdletContext.CmdletId].Add(record); return true; } + Interlocked.Increment(ref nullCmdletContextCount); return false; } public IList PopTelemetryRecord(ICmdletContext cmdletContext) { - if (cmdletContext != null && cmdletContext.IsValid && telemetryDataAccquirer.ContainsKey(cmdletContext.CmdletId)) + if (cmdletContext != null && cmdletContext.IsValid) + { + if (telemetryDataAccquirer.ContainsKey(cmdletContext.CmdletId)) + { + telemetryDataAccquirer.TryRemove(cmdletContext.CmdletId, out IList records); + Interlocked.Decrement(ref currentKeyCount); + return records; + } + else + { + Interlocked.Increment(ref keyNotFoundCount); + } + } + else { - telemetryDataAccquirer.TryRemove(cmdletContext.CmdletId, out IList records); - return records; + Interlocked.Increment(ref nullCmdletContextCount); } return null; } diff --git a/src/Common/AzurePSCmdlet.cs b/src/Common/AzurePSCmdlet.cs index 4394883131..9349b72da7 100644 --- a/src/Common/AzurePSCmdlet.cs +++ b/src/Common/AzurePSCmdlet.cs @@ -852,6 +852,7 @@ protected void LogQosEvent() throw new NullReferenceException("AuthenticationTelemetry not registered"); } _qosEvent.AuthTelemetry = authenticationTelemetry.GetTelemetryRecord(_cmdletContext); + WriteDebugWithTimestamp($"TotalKeyCount={authenticationTelemetry.KeysAllCount}; CurrentKeyCount={authenticationTelemetry.KeysCurrentCount}; EmptyCmdletContextCount={authenticationTelemetry.EmptyCmdletContextCount}; KeysNotFoundCount={authenticationTelemetry.KeyNotFoundCount}"); if (!IsUsageMetricEnabled && (!IsErrorMetricEnabled || _qosEvent.IsSuccess)) { diff --git a/src/Graph.Rbac/Version1_6.20190326/ActiveDirectory/ActiveDirectoryBaseCmdlet.cs b/src/Graph.Rbac/Version1_6.20190326/ActiveDirectory/ActiveDirectoryBaseCmdlet.cs index 9120d25e0a..30ba6424df 100644 --- a/src/Graph.Rbac/Version1_6.20190326/ActiveDirectory/ActiveDirectoryBaseCmdlet.cs +++ b/src/Graph.Rbac/Version1_6.20190326/ActiveDirectory/ActiveDirectoryBaseCmdlet.cs @@ -31,7 +31,7 @@ public ActiveDirectoryClient ActiveDirectoryClient { if (activeDirectoryClient == null) { - activeDirectoryClient = new ActiveDirectoryClient(DefaultProfile.DefaultContext); + activeDirectoryClient = new ActiveDirectoryClient(DefaultProfile.DefaultContext, _cmdletContext); } return activeDirectoryClient; diff --git a/src/Graph.Rbac/Version1_6.20190326/ActiveDirectory/ActiveDirectoryClient.cs b/src/Graph.Rbac/Version1_6.20190326/ActiveDirectory/ActiveDirectoryClient.cs index 13302d790d..f4d32f39b7 100644 --- a/src/Graph.Rbac/Version1_6.20190326/ActiveDirectory/ActiveDirectoryClient.cs +++ b/src/Graph.Rbac/Version1_6.20190326/ActiveDirectory/ActiveDirectoryClient.cs @@ -33,10 +33,21 @@ namespace Microsoft.Azure.Graph.RBAC.Version1_6_20190326.ActiveDirectory { public class ActiveDirectoryClient { - public ICmdletContext CmdletContext { get; set; } - public GraphRbacManagementClient GraphClient { get; private set; } + /// + /// Creates new ActiveDirectoryClient using WindowsAzureSubscription. + /// + /// + /// The cmdlet context + public ActiveDirectoryClient(IAzureContext context, ICmdletContext cmdletContext) + { + GraphClient = AzureSession.Instance.ClientFactory.CreateArmClient( + context, AzureEnvironment.Endpoint.Graph, cmdletContext); + + GraphClient.TenantID = context.Tenant.Id.ToString(); + } + /// /// Creates new ActiveDirectoryClient using WindowsAzureSubscription. /// @@ -44,7 +55,7 @@ public class ActiveDirectoryClient public ActiveDirectoryClient(IAzureContext context) { GraphClient = AzureSession.Instance.ClientFactory.CreateArmClient( - context, AzureEnvironment.Endpoint.Graph, CmdletContext); + context, AzureEnvironment.Endpoint.Graph); GraphClient.TenantID = context.Tenant.Id.ToString(); } diff --git a/src/Graph.Rbac/Version1_6/ActiveDirectory/ActiveDirectoryBaseCmdlet.cs b/src/Graph.Rbac/Version1_6/ActiveDirectory/ActiveDirectoryBaseCmdlet.cs index 8ef6b3a117..ee5eab1c44 100644 --- a/src/Graph.Rbac/Version1_6/ActiveDirectory/ActiveDirectoryBaseCmdlet.cs +++ b/src/Graph.Rbac/Version1_6/ActiveDirectory/ActiveDirectoryBaseCmdlet.cs @@ -31,7 +31,7 @@ public ActiveDirectoryClient ActiveDirectoryClient { if (activeDirectoryClient == null) { - activeDirectoryClient = new ActiveDirectoryClient(DefaultProfile.DefaultContext); + activeDirectoryClient = new ActiveDirectoryClient(DefaultProfile.DefaultContext, _cmdletContext); } return activeDirectoryClient; diff --git a/src/Graph.Rbac/Version1_6/ActiveDirectory/ActiveDirectoryClient.cs b/src/Graph.Rbac/Version1_6/ActiveDirectory/ActiveDirectoryClient.cs index eec3692952..d939a21da5 100644 --- a/src/Graph.Rbac/Version1_6/ActiveDirectory/ActiveDirectoryClient.cs +++ b/src/Graph.Rbac/Version1_6/ActiveDirectory/ActiveDirectoryClient.cs @@ -33,18 +33,17 @@ namespace Microsoft.Azure.Graph.RBAC.Version1_6.ActiveDirectory { public class ActiveDirectoryClient { - public ICmdletContext CmdletContext { get; set; } - public GraphRbacManagementClient GraphClient { get; private set; } /// /// Creates new ActiveDirectoryClient using WindowsAzureSubscription. /// /// - public ActiveDirectoryClient(IAzureContext context) + /// The cmdlet context + public ActiveDirectoryClient(IAzureContext context, ICmdletContext cmdletContext) { GraphClient = AzureSession.Instance.ClientFactory.CreateArmClient( - context, AzureEnvironment.Endpoint.Graph, CmdletContext); + context, AzureEnvironment.Endpoint.Graph, cmdletContext); GraphClient.TenantID = context.Tenant.Id.ToString(); } diff --git a/src/Network/Common/NetworkClient.cs b/src/Network/Common/NetworkClient.cs index ce32765875..bee3fc3cec 100644 --- a/src/Network/Common/NetworkClient.cs +++ b/src/Network/Common/NetworkClient.cs @@ -43,7 +43,11 @@ public partial class NetworkClient public Action WarningLogger { get; set; } - public NetworkClient(IAzureContext context): this(AzureSession.Instance.ClientFactory.CreateArmClient(context, AzureEnvironment.Endpoint.ResourceManager, AzureCmdletContext.CmdletNone)) + public NetworkClient(IAzureContext context): this(AzureSession.Instance.ClientFactory.CreateArmClient(context, AzureEnvironment.Endpoint.ResourceManager)) + { + } + + public NetworkClient(IAzureContext context, ICmdletContext cmdletContext) : this(AzureSession.Instance.ClientFactory.CreateArmClient(context, AzureEnvironment.Endpoint.ResourceManager, cmdletContext)) { } diff --git a/src/ResourceManager/Version2016_09_01/ArgumentCompleters/LocationCompleter.cs b/src/ResourceManager/Version2016_09_01/ArgumentCompleters/LocationCompleter.cs index 098128ec1b..842d5225a6 100644 --- a/src/ResourceManager/Version2016_09_01/ArgumentCompleters/LocationCompleter.cs +++ b/src/ResourceManager/Version2016_09_01/ArgumentCompleters/LocationCompleter.cs @@ -50,7 +50,7 @@ protected static IDictionary> ResourceTypeLocationDi { try { - IResourceManagementClient client = AzureSession.Instance.ClientFactory.CreateArmClient(context, AzureEnvironment.Endpoint.ResourceManager, AzureCmdletContext.CmdletNone); + IResourceManagementClient client = AzureSession.Instance.ClientFactory.CreateArmClient(context, AzureEnvironment.Endpoint.ResourceManager); var allProviders = client.Providers.ListAsync(); if (_timeout == -1) { diff --git a/src/ResourceManager/Version2016_09_01/ArgumentCompleters/ResourceGroupCompleter.cs b/src/ResourceManager/Version2016_09_01/ArgumentCompleters/ResourceGroupCompleter.cs index 98c1725d65..5e4997468c 100644 --- a/src/ResourceManager/Version2016_09_01/ArgumentCompleters/ResourceGroupCompleter.cs +++ b/src/ResourceManager/Version2016_09_01/ArgumentCompleters/ResourceGroupCompleter.cs @@ -48,7 +48,7 @@ protected static IList ResourceGroupNames var tempResourceGroupList = new List(); try { - var client = AzureSession.Instance.ClientFactory.CreateArmClient(context, AzureEnvironment.Endpoint.ResourceManager, AzureCmdletContext.CmdletNone); + var client = AzureSession.Instance.ClientFactory.CreateArmClient(context, AzureEnvironment.Endpoint.ResourceManager); // Retrieve only the first page of ResourceGroups to display to the user var resourceGroups = client.ResourceGroups.ListAsync(); diff --git a/src/ResourceManager/Version2016_09_01/ArgumentCompleters/ResourceIdCompleter.cs b/src/ResourceManager/Version2016_09_01/ArgumentCompleters/ResourceIdCompleter.cs index 790f38ab53..64d85d4145 100644 --- a/src/ResourceManager/Version2016_09_01/ArgumentCompleters/ResourceIdCompleter.cs +++ b/src/ResourceManager/Version2016_09_01/ArgumentCompleters/ResourceIdCompleter.cs @@ -59,7 +59,7 @@ public static IEnumerable GetResourceIds(string resourceType) return Cache[contextHash].ResourceInfoList; } - var client = AzureSession.Instance.ClientFactory.CreateArmClient(context, AzureEnvironment.Endpoint.ResourceManager, AzureCmdletContext.CmdletNone); + var client = AzureSession.Instance.ClientFactory.CreateArmClient(context, AzureEnvironment.Endpoint.ResourceManager); var odata = new ODataQuery(r => r.ResourceType == resourceType); diff --git a/src/ResourceManager/Version2016_09_01/ArgumentCompleters/ResourceNameCompleter.cs b/src/ResourceManager/Version2016_09_01/ArgumentCompleters/ResourceNameCompleter.cs index 4c07f19a81..28c7eecb0b 100644 --- a/src/ResourceManager/Version2016_09_01/ArgumentCompleters/ResourceNameCompleter.cs +++ b/src/ResourceManager/Version2016_09_01/ArgumentCompleters/ResourceNameCompleter.cs @@ -121,7 +121,7 @@ public static string CreateFilter( public static List GetResourceIdsFromClient(string resourceType, string resourceGroupName) { IAzureContext context = AzureRmProfileProvider.Instance?.Profile?.DefaultContext; - IResourceManagementClient client = AzureSession.Instance.ClientFactory.CreateArmClient(context, AzureEnvironment.Endpoint.ResourceManager, AzureCmdletContext.CmdletNone); + IResourceManagementClient client = AzureSession.Instance.ClientFactory.CreateArmClient(context, AzureEnvironment.Endpoint.ResourceManager); var odataQuery = new ODataQuery(r => r.ResourceType == resourceType); var allProviders = string.IsNullOrWhiteSpace(resourceGroupName) diff --git a/src/ResourceManager/Version2016_09_01/ArgumentCompleters/ResourceTypeCompleter.cs b/src/ResourceManager/Version2016_09_01/ArgumentCompleters/ResourceTypeCompleter.cs index 137202c340..74ec1f59c1 100644 --- a/src/ResourceManager/Version2016_09_01/ArgumentCompleters/ResourceTypeCompleter.cs +++ b/src/ResourceManager/Version2016_09_01/ArgumentCompleters/ResourceTypeCompleter.cs @@ -48,7 +48,7 @@ protected static IList ResourceTypes var tempResourceTypeList = new List(); try { - var client = AzureSession.Instance.ClientFactory.CreateArmClient(context, AzureEnvironment.Endpoint.ResourceManager, AzureCmdletContext.CmdletNone); + var client = AzureSession.Instance.ClientFactory.CreateArmClient(context, AzureEnvironment.Endpoint.ResourceManager); var resourceTypes = new List(); var task = client.Providers.ListAsync(); if (task.Wait(TimeSpan.FromSeconds(_timeout))) diff --git a/src/ResourceManager/Version2016_09_01/ArgumentCompleters/ScopeCompleter.cs b/src/ResourceManager/Version2016_09_01/ArgumentCompleters/ScopeCompleter.cs index 5e1838ce01..624964fae2 100644 --- a/src/ResourceManager/Version2016_09_01/ArgumentCompleters/ScopeCompleter.cs +++ b/src/ResourceManager/Version2016_09_01/ArgumentCompleters/ScopeCompleter.cs @@ -45,7 +45,7 @@ protected static IList Scopes var tempScopeList = new List(); try { - var client = AzureSession.Instance.ClientFactory.CreateArmClient(context, AzureEnvironment.Endpoint.ResourceManager, AzureCmdletContext.CmdletNone); + var client = AzureSession.Instance.ClientFactory.CreateArmClient(context, AzureEnvironment.Endpoint.ResourceManager); // Retrieve only the first page of ResourceGroups to use for scopes var resourceGroups = client.ResourceGroups.ListAsync(); diff --git a/src/ResourceManager/Version2016_09_01/Tags/TagsClient.cs b/src/ResourceManager/Version2016_09_01/Tags/TagsClient.cs index 7c2d87afe9..50d8066b99 100644 --- a/src/ResourceManager/Version2016_09_01/Tags/TagsClient.cs +++ b/src/ResourceManager/Version2016_09_01/Tags/TagsClient.cs @@ -38,7 +38,16 @@ public class TagsClient /// Creates new tags client instance. /// /// The Azure context instance - public TagsClient(IAzureContext context): this(AzureSession.Instance.ClientFactory.CreateArmClient(context, AzureEnvironment.Endpoint.ResourceManager, AzureCmdletContext.CmdletNone)) + public TagsClient(IAzureContext context): this(AzureSession.Instance.ClientFactory.CreateArmClient(context, AzureEnvironment.Endpoint.ResourceManager)) + { + } + + /// + /// Creates new tags client instance. + /// + /// The Azure context instance + /// The cmdlet context + public TagsClient(IAzureContext context, ICmdletContext cmdletContext) : this(AzureSession.Instance.ClientFactory.CreateArmClient(context, AzureEnvironment.Endpoint.ResourceManager, cmdletContext)) { } diff --git a/src/ResourceManager/Version2016_09_01/Utilities/SubscriptionAndTenantHelper.cs b/src/ResourceManager/Version2016_09_01/Utilities/SubscriptionAndTenantHelper.cs index 0ca01533fb..bd7cd78e91 100644 --- a/src/ResourceManager/Version2016_09_01/Utilities/SubscriptionAndTenantHelper.cs +++ b/src/ResourceManager/Version2016_09_01/Utilities/SubscriptionAndTenantHelper.cs @@ -14,6 +14,7 @@ using Microsoft.Azure.Commands.Common.Authentication; using Microsoft.Azure.Commands.Common.Authentication.Abstractions; +using Microsoft.Azure.Commands.Common.Authentication.Abstractions.Extensions; using Microsoft.Azure.Commands.Common.Authentication.Abstractions.Interfaces; using Microsoft.Azure.Internal.Subscriptions; using Microsoft.Azure.Internal.Subscriptions.Models; @@ -36,7 +37,7 @@ internal static IAccessToken AcquireAccessToken(IAzureAccount account, IAzureEnv null, ShowDialog.Never, null, - cmdletContext); + cmdletContext.ToExtensibleParameters()); } internal static Dictionary GetTenantsForSubscriptions(List subscriptionIds, IAzureContext defaultContext, ICmdletContext cmdletContext)