Skip to content

Commit 61e04ca

Browse files
Extends APIC plugins with prod Azure credentials (#661)
1 parent 5145fd1 commit 61e04ca

File tree

3 files changed

+88
-21
lines changed

3 files changed

+88
-21
lines changed

dev-proxy-plugins/RequestLogs/ApiCenterOnboardingPlugin.cs

Lines changed: 45 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,13 @@
22
// Licensed under the MIT License.
33

44
using System.Diagnostics;
5+
using System.Diagnostics.Tracing;
56
using System.Net.Http.Json;
67
using System.Text;
78
using System.Text.Json;
89
using System.Text.RegularExpressions;
910
using Azure.Core;
11+
using Azure.Core.Diagnostics;
1012
using Azure.Identity;
1113
using Microsoft.DevProxy.Abstractions;
1214
using Microsoft.DevProxy.Plugins.RequestLogs.ApiCenter;
@@ -24,19 +26,15 @@ internal class ApiCenterOnboardingPluginConfiguration
2426
public string ServiceName { get; set; } = "";
2527
public string WorkspaceName { get; set; } = "default";
2628
public bool CreateApicEntryForNewApis { get; set; } = true;
29+
public bool ExcludeDevCredentials { get; set; } = false;
30+
public bool ExcludeProdCredentials { get; set; } = true;
2731
}
2832

2933
public class ApiCenterOnboardingPlugin : BaseProxyPlugin
3034
{
3135
private ApiCenterOnboardingPluginConfiguration _configuration = new();
3236
private readonly string[] _scopes = ["https://management.azure.com/.default"];
33-
private readonly TokenCredential _credential = new ChainedTokenCredential(
34-
new VisualStudioCredential(),
35-
new VisualStudioCodeCredential(),
36-
new AzureCliCredential(),
37-
new AzurePowerShellCredential(),
38-
new AzureDeveloperCliCredential()
39-
);
37+
private TokenCredential _credential = new DefaultAzureCredential();
4038
private HttpClient? _httpClient;
4139
private JsonSerializerOptions _jsonSerializerOptions = new JsonSerializerOptions
4240
{
@@ -57,29 +55,63 @@ public override void Register(IPluginEvents pluginEvents,
5755

5856
if (string.IsNullOrEmpty(_configuration.SubscriptionId))
5957
{
60-
_logger?.LogError("Specify SubscriptionId in the ApiCenterOnboardingPlugin configuration. The ApiCenterOnboardingPlugin will not be used.");
58+
_logger?.LogError("Specify SubscriptionId in the {plugin} configuration. The {plugin} will not be used.", Name, Name);
6159
return;
6260
}
6361
if (string.IsNullOrEmpty(_configuration.ResourceGroupName))
6462
{
65-
_logger?.LogError("Specify ResourceGroupName in the ApiCenterOnboardingPlugin configuration. The ApiCenterOnboardingPlugin will not be used.");
63+
_logger?.LogError("Specify ResourceGroupName in the {plugin} configuration. The {plugin} will not be used.", Name, Name);
6664
return;
6765
}
6866
if (string.IsNullOrEmpty(_configuration.ServiceName))
6967
{
70-
_logger?.LogError("Specify ServiceName in the ApiCenterOnboardingPlugin configuration. The ApiCenterOnboardingPlugin will not be used.");
68+
_logger?.LogError("Specify ServiceName in the {plugin} configuration. The {plugin} will not be used.", Name, Name);
7169
return;
7270
}
71+
if (_configuration.ExcludeDevCredentials && _configuration.ExcludeProdCredentials)
72+
{
73+
_logger?.LogError("Both ExcludeDevCredentials and ExcludeProdCredentials are set to true. You need to use at least one set of credentials The {plugin} will not be used.", Name);
74+
return;
75+
}
76+
77+
var credentials = new List<TokenCredential>();
78+
if (!_configuration.ExcludeDevCredentials)
79+
{
80+
credentials.AddRange([
81+
new SharedTokenCacheCredential(),
82+
new VisualStudioCredential(),
83+
new VisualStudioCodeCredential(),
84+
new AzureCliCredential(),
85+
new AzurePowerShellCredential(),
86+
new AzureDeveloperCliCredential(),
87+
]);
88+
}
89+
if (!_configuration.ExcludeProdCredentials)
90+
{
91+
credentials.AddRange([
92+
new EnvironmentCredential(),
93+
new WorkloadIdentityCredential(),
94+
new ManagedIdentityCredential()
95+
]);
96+
}
97+
_credential = new ChainedTokenCredential(credentials.ToArray());
98+
99+
if (_logger?.LogLevel == LogLevel.Debug)
100+
{
101+
var consoleListener = AzureEventSourceListener.CreateConsoleLogger(EventLevel.Verbose);
102+
}
73103

104+
_logger?.LogDebug("[{now}] Plugin {plugin} checking Azure auth...", DateTime.Now, Name);
74105
try
75106
{
76107
_ = _credential.GetTokenAsync(new TokenRequestContext(_scopes), CancellationToken.None).Result;
77108
}
78109
catch (AuthenticationFailedException ex)
79110
{
80-
_logger?.LogError(ex, "Failed to authenticate with Azure. The ApiCenterOnboardingPlugin will not be used.");
111+
_logger?.LogError(ex, "Failed to authenticate with Azure. The {plugin} will not be used.", Name);
81112
return;
82113
}
114+
_logger?.LogDebug("[{now}] Plugin {plugin} auth confirmed...", DateTime.Now, Name);
83115

84116
var authenticationHandler = new AuthenticationDelegatingHandler(_credential, _scopes)
85117
{
@@ -114,7 +146,8 @@ private async Task AfterRecordingStop(object sender, RecordingArgs e)
114146
var newApis = new List<Tuple<string, string>>();
115147
var interceptedRequests = e.RequestLogs
116148
.Where(l => l.MessageType == MessageType.InterceptedRequest)
117-
.Select(request => {
149+
.Select(request =>
150+
{
118151
var methodAndUrl = request.MessageLines.First().Split(' ');
119152
return new Tuple<string, string>(methodAndUrl[0], methodAndUrl[1]);
120153
})

dev-proxy-plugins/RequestLogs/ApiCenterProductionVersionPlugin.cs

Lines changed: 40 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,10 @@
22
// Licensed under the MIT License.
33

44
using System.Diagnostics;
5+
using System.Diagnostics.Tracing;
56
using System.Text.Json;
67
using Azure.Core;
8+
using Azure.Core.Diagnostics;
79
using Azure.Identity;
810
using Microsoft.DevProxy.Abstractions;
911
using Microsoft.DevProxy.Plugins;
@@ -38,19 +40,15 @@ internal class ApiCenterProductionVersionPluginConfiguration
3840
public string ResourceGroupName { get; set; } = "";
3941
public string ServiceName { get; set; } = "";
4042
public string WorkspaceName { get; set; } = "default";
43+
public bool ExcludeDevCredentials { get; set; } = false;
44+
public bool ExcludeProdCredentials { get; set; } = true;
4145
}
4246

4347
public class ApiCenterProductionVersionPlugin : BaseProxyPlugin
4448
{
4549
private ApiCenterProductionVersionPluginConfiguration _configuration = new();
4650
private readonly string[] _scopes = ["https://management.azure.com/.default"];
47-
private readonly TokenCredential _credential = new ChainedTokenCredential(
48-
new VisualStudioCredential(),
49-
new VisualStudioCodeCredential(),
50-
new AzureCliCredential(),
51-
new AzurePowerShellCredential(),
52-
new AzureDeveloperCliCredential()
53-
);
51+
private TokenCredential _credential = new DefaultAzureCredential();
5452
private HttpClient? _httpClient;
5553
private JsonSerializerOptions _jsonSerializerOptions = new JsonSerializerOptions
5654
{
@@ -84,16 +82,50 @@ public override void Register(IPluginEvents pluginEvents,
8482
_logger?.LogError("Specify ServiceName in the ApiCenterProductionVersionPlugin configuration. The ApiCenterProductionVersionPlugin will not be used.");
8583
return;
8684
}
85+
if (_configuration.ExcludeDevCredentials && _configuration.ExcludeProdCredentials)
86+
{
87+
_logger?.LogError("Both ExcludeDevCredentials and ExcludeProdCredentials are set to true. You need to use at least one set of credentials The {plugin} will not be used.", Name);
88+
return;
89+
}
90+
91+
var credentials = new List<TokenCredential>();
92+
if (!_configuration.ExcludeDevCredentials)
93+
{
94+
credentials.AddRange([
95+
new SharedTokenCacheCredential(),
96+
new VisualStudioCredential(),
97+
new VisualStudioCodeCredential(),
98+
new AzureCliCredential(),
99+
new AzurePowerShellCredential(),
100+
new AzureDeveloperCliCredential(),
101+
]);
102+
}
103+
if (!_configuration.ExcludeProdCredentials)
104+
{
105+
credentials.AddRange([
106+
new EnvironmentCredential(),
107+
new WorkloadIdentityCredential(),
108+
new ManagedIdentityCredential()
109+
]);
110+
}
111+
_credential = new ChainedTokenCredential(credentials.ToArray());
112+
113+
if (_logger?.LogLevel == LogLevel.Debug)
114+
{
115+
var consoleListener = AzureEventSourceListener.CreateConsoleLogger(EventLevel.Verbose);
116+
}
87117

118+
_logger?.LogDebug("[{now}] Plugin {plugin} checking Azure auth...", DateTime.Now, Name);
88119
try
89120
{
90121
_ = _credential.GetTokenAsync(new TokenRequestContext(_scopes), CancellationToken.None).Result;
91122
}
92123
catch (AuthenticationFailedException ex)
93124
{
94-
_logger?.LogError(ex, "Failed to authenticate with Azure. The ApiCenterProductionVersionPlugin will not be used.");
125+
_logger?.LogError(ex, "Failed to authenticate with Azure. The {plugin} will not be used.", Name);
95126
return;
96127
}
128+
_logger?.LogDebug("[{now}] Plugin {plugin} auth confirmed...", DateTime.Now, Name);
97129

98130
var authenticationHandler = new AuthenticationDelegatingHandler(_credential, _scopes)
99131
{

dev-proxy/PluginLoader.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ public PluginLoaderResult LoadPlugins(IPluginEvents pluginEvents, IProxyContext
4242
// Load Handler Assembly if enabled
4343
string pluginLocation = Path.GetFullPath(Path.Combine(configFileDirectory, ProxyUtils.ReplacePathTokens(h.PluginPath.Replace('\\', Path.DirectorySeparatorChar))));
4444
PluginLoadContext pluginLoadContext = new PluginLoadContext(pluginLocation);
45-
_logger.LogDebug("Loading plugin {pluginName} from: {pluginLocation}", h.Name, pluginLocation);
45+
_logger?.LogDebug("Loading plugin {pluginName} from: {pluginLocation}", h.Name, pluginLocation);
4646
Assembly assembly = pluginLoadContext.LoadFromAssemblyName(new AssemblyName(Path.GetFileNameWithoutExtension(pluginLocation)));
4747
IEnumerable<UrlToWatch>? pluginUrlsList = h.UrlsToWatch?.Select(ConvertToRegex);
4848
ISet<UrlToWatch>? pluginUrls = null;
@@ -53,12 +53,14 @@ public PluginLoaderResult LoadPlugins(IPluginEvents pluginEvents, IProxyContext
5353
}
5454
// Load Plugins from assembly
5555
IProxyPlugin plugin = CreatePlugin(assembly, h);
56+
_logger?.LogDebug("Registering plugin {pluginName}...", plugin.Name);
5657
plugin.Register(
5758
pluginEvents,
5859
proxyContext,
5960
(pluginUrls != null && pluginUrls.Any()) ? pluginUrls : defaultUrlsToWatch,
6061
h.ConfigSection is null ? null : Configuration.GetSection(h.ConfigSection)
6162
);
63+
_logger?.LogDebug("Plugin {pluginName} registered.", plugin.Name);
6264
plugins.Add(plugin);
6365
}
6466
}

0 commit comments

Comments
 (0)