Skip to content

Commit e86316c

Browse files
authored
Merge pull request #4063 from allanbomsft/feature/allanbo/appgwclassicfixlistcert
Application Gateway classic, fixed list cert to work with cert collec…
2 parents a01e161 + 48b0cfb commit e86316c

File tree

4 files changed

+191
-26
lines changed

4 files changed

+191
-26
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
// ----------------------------------------------------------------------------------
2+
//
3+
// Copyright Microsoft Corporation
4+
// Licensed under the Apache License, Version 2.0 (the "License");
5+
// you may not use this file except in compliance with the License.
6+
// You may obtain a copy of the License at
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
// Unless required by applicable law or agreed to in writing, software
9+
// distributed under the License is distributed on an "AS IS" BASIS,
10+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
// See the License for the specific language governing permissions and
12+
// limitations under the License.
13+
// ----------------------------------------------------------------------------------
14+
15+
using Microsoft.WindowsAzure.Commands.Common.Test.Mocks;
16+
using Microsoft.WindowsAzure.Commands.ScenarioTest;
17+
using Microsoft.WindowsAzure.Commands.ServiceManagement.Network.ApplicationGateway;
18+
using Microsoft.WindowsAzure.Management;
19+
using Microsoft.WindowsAzure.Management.Compute;
20+
using Microsoft.WindowsAzure.Management.Network;
21+
using Microsoft.WindowsAzure.Management.Network.Models;
22+
using Moq;
23+
using System.Collections.Generic;
24+
using System.Threading;
25+
using System.Threading.Tasks;
26+
using Xunit;
27+
using PowerShellAppGwModel = Microsoft.WindowsAzure.Commands.ServiceManagement.Network.ApplicationGateway.Model;
28+
29+
namespace Microsoft.WindowsAzure.Commands.ServiceManagement.Network.Test.ApplicationGateway
30+
{
31+
public class GetApplicationGatewayCertificateTests
32+
{
33+
private const string CertWithCAChain = "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";
34+
private const string SelfSignedCert = "MIIDWgYJKoZIhvcNAQcCoIIDSzCCA0cCAQExADALBgkqhkiG9w0BBwGgggMvMIIDKzCCAhOgAwIBAgIQRX3qiBwWP7xCrNLmDrkk0zANBgkqhkiG9w0BAQsFADAdMRswGQYDVQQDExJteXNlbGZzaWduZWRzZXJ2ZXIwHhcNMTcwNjAyMDQxOTAzWhcNMzkxMjMxMjM1OTU5WjAdMRswGQYDVQQDExJteXNlbGZzaWduZWRzZXJ2ZXIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCqUUNsYjVD/Gly67Y46Xgi5oNJH0aXWC/y04oLrmT8nugeeM1BdlLuqFdRZ223Q54N1XS1BJKwWmeo+/2FeWlenWoJHvxTYVTPCen4CpX34EXyLwkW0sk7xefoN6ykfpR/URf+53A3gQt0B2OPjNSQV/z0KLq0HZ7oWp8XRwPEIkSioEUdI5dSfqjQ8eL1HV962LK7x3nCaCc/MCyfc/Ork3Rfo8ZQiOuE8Ei3IlJw/b2mUeZ9IuKRwTGKQ8z8weXVjfSQ0o7P5nSrQcYS6f2vXhugov8bSKxw5SGAzvAaoRedj4hvUcIrH4Bmpbdju1ykZYU1CmfBNIfytVQUVamfAgMBAAGjZzBlMBMGA1UdJQQMMAoGCCsGAQUFBwMBME4GA1UdAQRHMEWAEIbgiHZ2FJOsHlc3iheady2hHzAdMRswGQYDVQQDExJteXNlbGZzaWduZWRzZXJ2ZXKCEEV96ogcFj+8QqzS5g65JNMwDQYJKoZIhvcNAQELBQADggEBAJM9BHtyyX9EXXNO8XwWC6MAPJwiR6m3xN7/qUJsSr9PcTBgsn10l3qP7l4g/XAPt2Ot8WFxe/VSyLM+TQ1WxYKxUIE3QbILH1orn+6pKjr40dLBodQdTQFtg8x0Z1bCPn3kne1WlLeaOlrLDMUlfgQgg6/ompYu0W4gKF3e3t3inoLb5ETpQ4Pa+8XIzKRNwen3twt2us4CG2RU5cwQdzLwIvgcAkok3U3zo5Tz4GIJ9n7x1zVjJdz1VSDMilqWr57e3jfT7cGmGXE3m34oT36rSxF2HsF5jTJHT1QVnPBu7VRmC85vBcZAGh9VTdL01oCk2VvAgaXw78wHJquHPOUxAA==";
35+
36+
private MockCommandRuntime mockCommandRuntime;
37+
38+
private GetApplicationGatewayCertificateCommand cmdlet;
39+
40+
private NetworkClient client;
41+
private Mock<INetworkManagementClient> networkingClientMock;
42+
43+
public GetApplicationGatewayCertificateTests()
44+
{
45+
this.networkingClientMock = new Mock<INetworkManagementClient>();
46+
var computeClientMock = new Mock<IComputeManagementClient>();
47+
var managementClientMock = new Mock<IManagementClient>();
48+
this.mockCommandRuntime = new MockCommandRuntime();
49+
this.client = new NetworkClient(
50+
this.networkingClientMock.Object,
51+
computeClientMock.Object,
52+
managementClientMock.Object,
53+
mockCommandRuntime);
54+
55+
this.networkingClientMock
56+
.Setup(n => n.ApplicationGateways.GetCertificateAsync(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<CancellationToken>()))
57+
.Returns(Task.Factory.StartNew(() => new ApplicationGatewayGetCertificate()
58+
{
59+
Name = "cert1",
60+
Data = CertWithCAChain,
61+
}));
62+
63+
64+
this.networkingClientMock
65+
.Setup(n => n.ApplicationGateways.ListCertificateAsync(It.IsAny<string>(), It.IsAny<CancellationToken>()))
66+
.Returns(Task.Factory.StartNew(() => new ApplicationGatewayListCertificate()
67+
{
68+
ApplicationGatewayCertificates = new List<ApplicationGatewayGetCertificate>()
69+
{
70+
new ApplicationGatewayGetCertificate()
71+
{
72+
Name = "cert1",
73+
Data = CertWithCAChain
74+
},
75+
new ApplicationGatewayGetCertificate()
76+
{
77+
Name = "cert2",
78+
Data = SelfSignedCert,
79+
}
80+
}
81+
}));
82+
}
83+
84+
[Fact]
85+
[Trait(Category.Service, Category.Network)]
86+
[Trait(Category.AcceptanceType, Category.CheckIn)]
87+
public void GetCertByName()
88+
{
89+
// Setup
90+
cmdlet = new GetApplicationGatewayCertificateCommand
91+
{
92+
Name = "appgw1",
93+
CertificateName = "cert1",
94+
CommandRuntime = mockCommandRuntime,
95+
Client = this.client
96+
};
97+
98+
// Action
99+
cmdlet.ExecuteCmdlet();
100+
101+
// Assert
102+
this.networkingClientMock.Verify(
103+
n => n.ApplicationGateways.ListCertificateAsync(It.IsAny<string>(), It.IsAny<CancellationToken>()),
104+
Times.Never());
105+
106+
this.networkingClientMock.Verify(
107+
n => n.ApplicationGateways.GetCertificateAsync(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<CancellationToken>()),
108+
Times.Once());
109+
110+
Assert.Equal(1, mockCommandRuntime.OutputPipeline.Count);
111+
112+
var returnedPsObj = (PowerShellAppGwModel.ApplicationGatewayCertificate)mockCommandRuntime.OutputPipeline[0];
113+
Assert.Equal("cert1", returnedPsObj.Name);
114+
Assert.Equal("4D0431E9C2DAEB10BEFE50CAD7FD43539EC410B1", returnedPsObj.Thumbprint);
115+
Assert.Equal("sha1RSA", returnedPsObj.ThumbprintAlgo);
116+
}
117+
118+
[Fact]
119+
[Trait(Category.Service, Category.Network)]
120+
[Trait(Category.AcceptanceType, Category.CheckIn)]
121+
public void ListCerts()
122+
{
123+
// Setup
124+
cmdlet = new GetApplicationGatewayCertificateCommand
125+
{
126+
Name = "appgw1",
127+
CommandRuntime = mockCommandRuntime,
128+
Client = this.client
129+
};
130+
131+
// Action
132+
cmdlet.ExecuteCmdlet();
133+
134+
// Assert
135+
this.networkingClientMock.Verify(
136+
n => n.ApplicationGateways.ListCertificateAsync(It.IsAny<string>(), It.IsAny<CancellationToken>()),
137+
Times.Once());
138+
139+
this.networkingClientMock.Verify(
140+
n => n.ApplicationGateways.GetCertificateAsync(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<CancellationToken>()),
141+
Times.Never());
142+
143+
Assert.Equal(2, mockCommandRuntime.OutputPipeline.Count);
144+
145+
var returnedPsObj1 = (PowerShellAppGwModel.ApplicationGatewayCertificate)mockCommandRuntime.OutputPipeline[0];
146+
Assert.Equal("cert1", returnedPsObj1.Name);
147+
Assert.Equal("4D0431E9C2DAEB10BEFE50CAD7FD43539EC410B1", returnedPsObj1.Thumbprint);
148+
Assert.Equal("sha1RSA", returnedPsObj1.ThumbprintAlgo);
149+
150+
var returnedPsObj2 = (PowerShellAppGwModel.ApplicationGatewayCertificate)mockCommandRuntime.OutputPipeline[1];
151+
Assert.Equal("cert2", returnedPsObj2.Name);
152+
Assert.Equal("89A6A0B7FDC249488ED9B23BAE674121CD9B036F", returnedPsObj2.Thumbprint);
153+
Assert.Equal("sha256RSA", returnedPsObj2.ThumbprintAlgo);
154+
}
155+
}
156+
}

src/ServiceManagement/Network/Commands.Network.Test/Commands.ServiceManagement.Network.Test.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,7 @@
166166
</Reference>
167167
</ItemGroup>
168168
<ItemGroup>
169+
<Compile Include="ApplicationGateway\GetApplicationGatewayCertificateTests.cs" />
169170
<Compile Include="IPForwarding\GetIPForwardingTests.cs" />
170171
<Compile Include="IPForwarding\SetIPForwardingTests.cs" />
171172
<Compile Include="Multivip\MultivipTests.cs" />

src/ServiceManagement/Network/Commands.Network/NetworkClient.cs

Lines changed: 32 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -202,27 +202,7 @@ public ApplicationGatewayOperationResponse AddApplicationGatewayCertificate(stri
202202
public PowerShellAppGwModel.ApplicationGatewayCertificate GetApplicationGatewayCertificate(string gatewayName, string certificateName)
203203
{
204204
ApplicationGatewayGetCertificate certificate = client.ApplicationGateways.GetCertificate(gatewayName, certificateName);
205-
X509Certificate2Collection certCollection = new X509Certificate2Collection();
206-
certCollection.Import(Convert.FromBase64String(certificate.Data));
207-
208-
X509Certificate2 certToReturn = null;
209-
// We need to return the first non-CA cert.
210-
// If there is no non-CA cert, return the first cert in the collection.
211-
foreach (var certObject in certCollection)
212-
{
213-
// Remember first cert in collection
214-
if (certToReturn == null)
215-
{
216-
certToReturn = certObject;
217-
}
218-
// Non-CA cert, so this is the one we want
219-
if (!IsCACert(certObject))
220-
{
221-
certToReturn = certObject;
222-
break;
223-
}
224-
}
225-
205+
var certToReturn = ExtractLeafCert(certificate);
226206
return (new PowerShellAppGwModel.ApplicationGatewayCertificate
227207
{
228208
Name = certificate.Name,
@@ -248,23 +228,50 @@ private static bool IsCACert(X509Certificate2 cert)
248228
return false;
249229
}
250230

231+
private static X509Certificate2 ExtractLeafCert(ApplicationGatewayGetCertificate certificate)
232+
{
233+
X509Certificate2Collection certCollection = new X509Certificate2Collection();
234+
certCollection.Import(Convert.FromBase64String(certificate.Data));
235+
236+
X509Certificate2 certToReturn = null;
237+
// We need to return the first non-CA cert.
238+
// If there is no non-CA cert, return the first cert in the collection.
239+
foreach (var certObject in certCollection)
240+
{
241+
// Remember first cert in collection
242+
if (certToReturn == null)
243+
{
244+
certToReturn = certObject;
245+
}
246+
// Non-CA cert, so this is the one we want
247+
if (!IsCACert(certObject))
248+
{
249+
certToReturn = certObject;
250+
break;
251+
}
252+
}
253+
254+
return certToReturn;
255+
}
256+
251257
public List<PowerShellAppGwModel.ApplicationGatewayCertificate> ListApplicationGatewayCertificate(string gatewayName)
252258
{
253259
ApplicationGatewayListCertificate hydraCertList = client.ApplicationGateways.ListCertificate(gatewayName);
254260

255261
List<PowerShellAppGwModel.ApplicationGatewayCertificate> psCertList = new List<PowerShellAppGwModel.ApplicationGatewayCertificate>();
256262
foreach (ApplicationGatewayGetCertificate certificate in hydraCertList.ApplicationGatewayCertificates)
257263
{
258-
X509Certificate2 certObject = new X509Certificate2(Convert.FromBase64String(certificate.Data));
264+
var certToReturn = ExtractLeafCert(certificate);
259265
psCertList.Add(new PowerShellAppGwModel.ApplicationGatewayCertificate
260266
{
261267
Name = certificate.Name,
262-
SubjectName = certObject.SubjectName.Name,
263-
Thumbprint = certObject.Thumbprint,
264-
ThumbprintAlgo = certObject.SignatureAlgorithm.FriendlyName,
268+
SubjectName = certToReturn.SubjectName.Name,
269+
Thumbprint = certToReturn.Thumbprint,
270+
ThumbprintAlgo = certToReturn.SignatureAlgorithm.FriendlyName,
265271
State = certificate.State
266272
});
267273
}
274+
268275
return psCertList;
269276
}
270277

src/ServiceManagement/Services/Commands.Utilities/ChangeLog.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121

2222
## Version 4.1.0
2323
* Add-AzureVhd: The size limit on vhd is increased to 4TB.
24+
* Application Gateway classic, fixed certificate list to work with certificate collections
2425
* New-AzureBGPPeering: Support LegacyMode
2526

2627
## Version 4.0.2
@@ -91,4 +92,4 @@
9192
- Set-AzureManagedCacheNamedCache
9293
* For more information about Managed Cache service deprecation, see http://go.microsoft.com/fwlink/?LinkID=717458
9394

94-
## Version 3.1.0
95+
## Version 3.1.0

0 commit comments

Comments
 (0)