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/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)