Skip to content
This repository was archived by the owner on Feb 23, 2024. It is now read-only.

Commit f879768

Browse files
f-alizadaFarhad Alizada
andauthored
NamedValues solve reference in parameters file (#846)
* Fetch secret values on request, solve reference named values in parameters file * Add NamedValues parameters extraction tests * Add secret values when extractSecret is true and paramNamedValues is false * Added test for extract secrets with named values Co-authored-by: Farhad Alizada <falizada@microsoft.com>
1 parent 5b43144 commit f879768

File tree

16 files changed

+477
-35
lines changed

16 files changed

+477
-35
lines changed

src/ArmTemplates/Common/API/Clients/Abstractions/INamedValuesClient.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,5 +13,7 @@ namespace Microsoft.Azure.Management.ApiManagement.ArmTemplates.Common.API.Clien
1313
public interface INamedValuesClient
1414
{
1515
Task<List<NamedValueTemplateResource>> GetAllAsync(ExtractorParameters extractorParameters);
16+
17+
Task<NamedValuesSecretValue> ListNamedValueSecretValueAsync(string namedValueId, ExtractorParameters extractorParameters);
1618
}
1719
}

src/ArmTemplates/Common/API/Clients/NamedValues/NamedValuesClient.cs

Lines changed: 40 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
using System.Net.Http;
88
using System.Threading.Tasks;
99
using Microsoft.Azure.Management.ApiManagement.ArmTemplates.Common.API.Clients.Abstractions;
10+
using Microsoft.Azure.Management.ApiManagement.ArmTemplates.Common.API.Models;
1011
using Microsoft.Azure.Management.ApiManagement.ArmTemplates.Common.Constants;
1112
using Microsoft.Azure.Management.ApiManagement.ArmTemplates.Common.Templates.NamedValues;
1213
using Microsoft.Azure.Management.ApiManagement.ArmTemplates.Extractor.Models;
@@ -17,11 +18,12 @@ namespace Microsoft.Azure.Management.ApiManagement.ArmTemplates.Common.API.Clien
1718
public class NamedValuesClient : ApiClientBase, INamedValuesClient
1819
{
1920
const string GetNamedValuesRequest = "{0}/subscriptions/{1}/resourceGroups/{2}/providers/Microsoft.ApiManagement/service/{3}/namedValues?api-version={4}";
20-
readonly ITemplateResourceDataProcessor<NamedValueTemplateResource> templateResourceDataProcessor;
21+
const string GetNamedValueSecretValueRequest = "{0}/subscriptions/{1}/resourceGroups/{2}/providers/Microsoft.ApiManagement/service/{3}/namedValues/{4}/listValue?api-version={5}";
22+
readonly INamedValuesDataProcessor namedValuesDataProcessor;
2123

22-
public NamedValuesClient(IHttpClientFactory httpClientFactory, ITemplateResourceDataProcessor<NamedValueTemplateResource> templateResourceDataProcessor) : base(httpClientFactory)
24+
public NamedValuesClient(IHttpClientFactory httpClientFactory, INamedValuesDataProcessor namedValuesDataProcessor) : base(httpClientFactory)
2325
{
24-
this.templateResourceDataProcessor = templateResourceDataProcessor;
26+
this.namedValuesDataProcessor = namedValuesDataProcessor;
2527
}
2628

2729
public async Task<List<NamedValueTemplateResource>> GetAllAsync(ExtractorParameters extractorParameters)
@@ -32,8 +34,42 @@ public async Task<List<NamedValueTemplateResource>> GetAllAsync(ExtractorParamet
3234
this.BaseUrl, azSubId, extractorParameters.ResourceGroup, extractorParameters.SourceApimName, GlobalConstants.ApiVersion);
3335

3436
var namedValuesTemplateResources = await this.GetPagedResponseAsync<NamedValueTemplateResource>(azToken, requestUrl);
35-
this.templateResourceDataProcessor.ProcessData(namedValuesTemplateResources);
37+
this.namedValuesDataProcessor.ProcessData(namedValuesTemplateResources);
38+
await this.FetchSecretsValue(namedValuesTemplateResources, extractorParameters);
3639
return namedValuesTemplateResources;
3740
}
41+
42+
public async Task<NamedValuesSecretValue> ListNamedValueSecretValueAsync(string namedValueId, ExtractorParameters extractorParameters)
43+
{
44+
var (azToken, azSubId) = await this.Auth.GetAccessToken();
45+
46+
var requestUrl = string.Format(GetNamedValueSecretValueRequest,
47+
this.BaseUrl, azSubId, extractorParameters.ResourceGroup, extractorParameters.SourceApimName, namedValueId, GlobalConstants.ApiVersion);
48+
49+
return await this.GetResponseAsync<NamedValuesSecretValue>(azToken, requestUrl, useCache: false, method: ClientHttpMethod.POST);
50+
}
51+
52+
async Task FetchSecretsValue(List<NamedValueTemplateResource> namedValues, ExtractorParameters extractorParameters)
53+
{
54+
if (namedValues == null || namedValues.Count== 0)
55+
{
56+
return ;
57+
}
58+
59+
if (!extractorParameters.ExtractSecrets)
60+
{
61+
return ;
62+
}
63+
64+
foreach(var namedValue in namedValues)
65+
{
66+
if (namedValue.Properties.Secret && namedValue.Properties.KeyVault == null)
67+
{
68+
var namaedValueSecretData = await this.ListNamedValueSecretValueAsync(namedValue.OriginalName, extractorParameters);
69+
namedValue.Properties.OriginalValue = namaedValueSecretData?.Value;
70+
namedValue.Properties.Value = namaedValueSecretData?.Value;
71+
}
72+
}
73+
}
3874
}
3975
}

src/ArmTemplates/Common/Templates/NamedValues/NamedValueProperties.cs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,26 @@
44
// --------------------------------------------------------------------------
55

66
using System.Collections.Generic;
7+
using Newtonsoft.Json;
78

89
namespace Microsoft.Azure.Management.ApiManagement.ArmTemplates.Common.Templates.NamedValues
910
{
1011
public class NamedValueProperties
1112
{
13+
[JsonIgnore]
14+
public string OriginalValue { get; set; }
15+
16+
[JsonIgnore]
17+
public string OriginalKeyVaultSecretIdentifierValue { get; set; }
18+
1219
public IList<string> Tags { get; set; }
20+
1321
public bool Secret { get; set; }
22+
1423
public string DisplayName { get; set; }
24+
1525
public string Value { get; set; }
26+
1627
public NamedValueResourceKeyVaultProperties KeyVault { get; set; }
1728
}
1829
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// --------------------------------------------------------------------------
2+
// Copyright (c) Microsoft Corporation. All rights reserved.
3+
// Licensed under the MIT License.
4+
// --------------------------------------------------------------------------
5+
6+
namespace Microsoft.Azure.Management.ApiManagement.ArmTemplates.Common.Templates.NamedValues
7+
{
8+
public class NamedValuesSecretValue
9+
{
10+
public string Value { get; set; }
11+
}
12+
}

src/ArmTemplates/Extractor/EntityExtractors/NamedValuesExtractor.cs

Lines changed: 20 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -77,21 +77,7 @@ public async Task<Template<NamedValuesResources>> GenerateNamedValuesTemplateAsy
7777
namedValueResource.ApiVersion = GlobalConstants.ApiVersion;
7878
namedValueResource.Scale = null;
7979

80-
if (extractorParameters.ParameterizeNamedValue)
81-
{
82-
namedValueResource.Properties.Value = $"[parameters('{ParameterNames.NamedValues}').{NamingHelper.GenerateValidParameterName(namedValueResource.OriginalName, ParameterPrefix.Property)}]";
83-
}
84-
85-
//Hide the value field if it is a keyvault named value
86-
if (namedValueResource.Properties.KeyVault != null)
87-
{
88-
namedValueResource.Properties.Value = null;
89-
}
90-
91-
if (namedValueResource.Properties.KeyVault != null && extractorParameters.ParamNamedValuesKeyVaultSecrets)
92-
{
93-
namedValueResource.Properties.KeyVault.SecretIdentifier = $"[parameters('{ParameterNames.NamedValueKeyVaultSecrets}').{NamingHelper.GenerateValidParameterName(namedValueResource.OriginalName, ParameterPrefix.Property)}]";
94-
}
80+
this.ModifyNamedValuesOutput(namedValueResource, extractorParameters);
9581

9682
if (string.IsNullOrEmpty(singleApiName))
9783
{
@@ -179,5 +165,24 @@ bool DoesLoggerReferenceNamedValue(
179165
}
180166
return false;
181167
}
168+
169+
void ModifyNamedValuesOutput(NamedValueTemplateResource namedValueResource, ExtractorParameters extractorParameters)
170+
{
171+
if (extractorParameters.ParameterizeNamedValue)
172+
{
173+
namedValueResource.Properties.Value = $"[parameters('{ParameterNames.NamedValues}').{NamingHelper.GenerateValidParameterName(namedValueResource.OriginalName, ParameterPrefix.Property)}]";
174+
}
175+
176+
//Hide the value field if it is a keyvault named value
177+
if (namedValueResource.Properties.KeyVault != null)
178+
{
179+
namedValueResource.Properties.Value = null;
180+
}
181+
182+
if (namedValueResource.Properties.KeyVault != null && extractorParameters.ParamNamedValuesKeyVaultSecrets)
183+
{
184+
namedValueResource.Properties.KeyVault.SecretIdentifier = $"[parameters('{ParameterNames.NamedValueKeyVaultSecrets}').{NamingHelper.GenerateValidParameterName(namedValueResource.OriginalName, ParameterPrefix.Property)}]";
185+
}
186+
}
182187
}
183188
}

src/ArmTemplates/Extractor/EntityExtractors/ParametersExtractor.cs

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -185,23 +185,30 @@ void AddNamedValuesParameters()
185185
var keyVaultNamedValues = new Dictionary<string, string>();
186186
foreach (var namedValue in namedValuesResources.NamedValues)
187187
{
188+
// secret/plain values
188189
if (extractorParameters.ParameterizeNamedValue && namedValue?.Properties.KeyVault == null)
189190
{
190-
var propertyValue = namedValue.Properties.Value;
191191
var validPName = NamingHelper.GenerateValidParameterName(namedValue.OriginalName, ParameterPrefix.Property);
192-
namedValuesParameters.Add(validPName, propertyValue);
192+
namedValuesParameters.Add(validPName, namedValue?.Properties.OriginalValue);
193193
}
194194

195+
//key vault values
195196
if (extractorParameters.ParamNamedValuesKeyVaultSecrets && namedValue?.Properties.KeyVault is not null)
196197
{
197-
var propertyValue = namedValue.Properties.KeyVault.SecretIdentifier;
198198
var validPName = NamingHelper.GenerateValidParameterName(namedValue.OriginalName, ParameterPrefix.Property);
199-
keyVaultNamedValues.Add(validPName, propertyValue);
199+
keyVaultNamedValues.Add(validPName, namedValue.Properties.OriginalKeyVaultSecretIdentifierValue);
200200
}
201201
}
202202

203-
parameters.Add(ParameterNames.NamedValues, new TemplateObjectParameterProperties() { Value = namedValuesParameters });
204-
parameters.Add(ParameterNames.NamedValueKeyVaultSecrets, new TemplateObjectParameterProperties() { Value = keyVaultNamedValues });
203+
if (extractorParameters.ParameterizeNamedValue)
204+
{
205+
parameters.Add(ParameterNames.NamedValues, new TemplateObjectParameterProperties() { Value = namedValuesParameters });
206+
}
207+
208+
if (extractorParameters.ParamNamedValuesKeyVaultSecrets)
209+
{
210+
parameters.Add(ParameterNames.NamedValueKeyVaultSecrets, new TemplateObjectParameterProperties() { Value = keyVaultNamedValues });
211+
}
205212
}
206213

207214
async Task AddSecretValuesParameters()
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// --------------------------------------------------------------------------
2+
// Copyright (c) Microsoft Corporation. All rights reserved.
3+
// Licensed under the MIT License.
4+
// --------------------------------------------------------------------------
5+
6+
using System.Collections.Generic;
7+
using Microsoft.Azure.Management.ApiManagement.ArmTemplates.Common.Templates.NamedValues;
8+
9+
namespace Microsoft.Azure.Management.ApiManagement.ArmTemplates.Extractor.Utilities.DataProcessors.Absctraction
10+
{
11+
public interface INamedValuesDataProcessor
12+
{
13+
void ProcessData(List<NamedValueTemplateResource> templateResources);
14+
void ProcessSingleData(NamedValueTemplateResource templateResource);
15+
}
16+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
// --------------------------------------------------------------------------
2+
// Copyright (c) Microsoft Corporation. All rights reserved.
3+
// Licensed under the MIT License.
4+
// --------------------------------------------------------------------------
5+
6+
using System.Collections.Generic;
7+
using Microsoft.Azure.Management.ApiManagement.ArmTemplates.Common.Extensions;
8+
using Microsoft.Azure.Management.ApiManagement.ArmTemplates.Common.Templates.NamedValues;
9+
using Microsoft.Azure.Management.ApiManagement.ArmTemplates.Extractor.Utilities.DataProcessors.Absctraction;
10+
11+
namespace Microsoft.Azure.Management.ApiManagement.ArmTemplates.Extractor.Utilities.DataProcessors
12+
{
13+
public class NamedValuesDataProcessor : INamedValuesDataProcessor
14+
{
15+
public void ProcessData(List<NamedValueTemplateResource> templateResources)
16+
{
17+
if (templateResources.IsNullOrEmpty())
18+
{
19+
return;
20+
}
21+
22+
foreach (var templateResource in templateResources)
23+
{
24+
this.ProcessSingleData(templateResource);
25+
}
26+
}
27+
28+
public void ProcessSingleData(NamedValueTemplateResource templateResource)
29+
{
30+
if (templateResource == null)
31+
{
32+
return;
33+
}
34+
35+
templateResource.OriginalName = templateResource.Name;
36+
templateResource.Properties.OriginalValue = templateResource.Properties?.Value;
37+
38+
templateResource.Properties.OriginalKeyVaultSecretIdentifierValue = templateResource.Properties.KeyVault?.SecretIdentifier;
39+
}
40+
}
41+
}

src/ArmTemplates/ServiceExtensions.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ static void SetupDataProcessors(IServiceCollection services)
7474
services.AddScoped<IProductApiDataProcessor, ProductApiDataProcessor>();
7575
services.AddScoped<IApiDataProcessor, ApiDataProcessor>();
7676
services.AddScoped<IApiOperationDataProcessor, ApiOperationDataProcessor>();
77+
services.AddScoped<INamedValuesDataProcessor, NamedValuesDataProcessor>();
7778
services.AddScoped(typeof(ITemplateResourceDataProcessor<>), typeof(TemplateResourceDataProcessor<>));
7879
}
7980

tests/ArmTemplates.Tests/Extractor/Scenarios/NamedValuesExtractorTests.cs

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,5 +98,56 @@ public async Task GenerateNamedValuesTemplates_ProperlyLaysTheInformation()
9898
namedValuesTemplate.TypedResources.NamedValues.First().Name.Should().Contain(MockNamedValuesClient.NamedValueName);
9999
namedValuesTemplate.TypedResources.NamedValues.First().Properties.DisplayName.Should().Contain(MockNamedValuesClient.NamedValueDisplayName);
100100
}
101+
102+
[Fact]
103+
public async Task GenerateNamedValuesTemplates_ProperlyLaysTheInformation_GivenExtractSecretSetToTrue()
104+
{
105+
// arrange
106+
var currentTestDirectory = Path.Combine(this.OutputDirectory, nameof(GenerateNamedValuesTemplates_ProperlyLaysTheInformation_GivenExtractSecretSetToTrue));
107+
108+
var extractorConfig = this.GetDefaultExtractorConsoleAppConfiguration(extractSecrets: "true");
109+
var extractorParameters = new ExtractorParameters(extractorConfig);
110+
111+
var fileLocationNamedValues = Path.Combine(MockClientUtils.ApiClientJsonResponsesPath, "ApiManagementListNamedValues_success_response.json");
112+
var fileLocationSecretValues = Path.Combine(MockClientUtils.ApiClientJsonResponsesPath, "ApiManagementNamedValueListValue_success_response.json");
113+
var mockedNamedValuesClient = await MockNamedValuesClient.GetMockedHttpNamedValuesClient(
114+
new MockClientConfiguration(responseFileLocation: fileLocationNamedValues, urlPath: $"/namedValues?api-version={GlobalConstants.ApiVersion}"),
115+
new MockClientConfiguration(responseFileLocation: fileLocationSecretValues, urlPath: $"/namedValues/named-value-2/listValue?api-version={GlobalConstants.ApiVersion}"));
116+
117+
var namedValuesExtractor = new NamedValuesExtractor(
118+
this.GetTestLogger<NamedValuesExtractor>(),
119+
new TemplateBuilder(),
120+
mockedNamedValuesClient,
121+
default,
122+
default);
123+
124+
var extractorExecutor = ExtractorExecutor.BuildExtractorExecutor(
125+
this.GetTestLogger<ExtractorExecutor>(),
126+
namedValuesExtractor: namedValuesExtractor);
127+
extractorExecutor.SetExtractorParameters(extractorParameters);
128+
129+
// act
130+
var namedValuesTemplate = await extractorExecutor.GenerateNamedValuesTemplateAsync(
131+
null,
132+
new List<PolicyTemplateResource>(){},
133+
It.IsAny<List<LoggerTemplateResource>>(),
134+
currentTestDirectory);
135+
136+
// assert
137+
File.Exists(Path.Combine(currentTestDirectory, extractorParameters.FileNames.NamedValues)).Should().BeTrue();
138+
139+
namedValuesTemplate.Parameters.Should().ContainKey(ParameterNames.ApimServiceName);
140+
141+
namedValuesTemplate.TypedResources.NamedValues.Should().HaveCount(2);
142+
namedValuesTemplate.Resources.Should().HaveCount(2);
143+
144+
var plainNamedValue = namedValuesTemplate.TypedResources.NamedValues.First(x => x.OriginalName.Equals("named-value-1"));
145+
plainNamedValue.Should().NotBe(null);
146+
plainNamedValue.Properties.Value.Should().Be("named-value-1-value");
147+
148+
var secretNamedValue = namedValuesTemplate.TypedResources.NamedValues.First(x => x.OriginalName.Equals("named-value-2"));
149+
secretNamedValue.Should().NotBe(null);
150+
secretNamedValue.Properties.Value.Should().Be("named-value-2");
151+
}
101152
}
102153
}

0 commit comments

Comments
 (0)