Skip to content

Commit d7f9eb9

Browse files
authored
Fix format of ClientCertificate[Key]Data from auth plugins (#480)
* Fix format of ClientCertificate[Key]Data from auth plugins * Add external certificate tests to AuthTests * format
1 parent 34eb9d0 commit d7f9eb9

File tree

2 files changed

+77
-8
lines changed

2 files changed

+77
-8
lines changed

src/KubernetesClient/KubernetesClientConfiguration.ConfigFile.cs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -391,8 +391,11 @@ private void SetUserDetails(K8SConfiguration k8SConfig, Context activeContext)
391391

392392
var (accessToken, clientCertificateData, clientCertificateKeyData) = ExecuteExternalCommand(userDetails.UserCredentials.ExternalExecution);
393393
AccessToken = accessToken;
394-
ClientCertificateData = clientCertificateData;
395-
ClientCertificateKeyData = clientCertificateKeyData;
394+
// When reading ClientCertificateData from a config file it will be base64 encoded, and code later in the system (see CertUtils.GeneratePfx)
395+
// expects ClientCertificateData and ClientCertificateKeyData to be base64 encoded because of this. However the string returned by external
396+
// auth providers is the raw certificate and key PEM text, so we need to take that and base64 encoded it here so it can be decoded later.
397+
ClientCertificateData = clientCertificateData == null ? null : Convert.ToBase64String(System.Text.Encoding.ASCII.GetBytes(clientCertificateData));
398+
ClientCertificateKeyData = clientCertificateKeyData == null ? null : Convert.ToBase64String(System.Text.Encoding.ASCII.GetBytes(clientCertificateKeyData));
396399

397400
userCredentialsFound = true;
398401
}

tests/KubernetesClient.Tests/AuthTests.cs

Lines changed: 72 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,71 @@ public void Cert()
268268
}
269269
}
270270

271+
[OperatingSystemDependentFact(Exclude = OperatingSystem.OSX | OperatingSystem.Windows)]
272+
public void ExternalCertificate()
273+
{
274+
const string name = "testing_irrelevant";
275+
276+
var serverCertificateData = Convert.FromBase64String(File.ReadAllText("assets/apiserver-pfx-data.txt"));
277+
278+
var clientCertificateKeyData = Convert.FromBase64String(File.ReadAllText("assets/client-key-data.txt"));
279+
var clientCertificateData = Convert.FromBase64String(File.ReadAllText("assets/client-certificate-data.txt"));
280+
281+
X509Certificate2 serverCertificate = null;
282+
283+
if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
284+
{
285+
using (MemoryStream serverCertificateStream = new MemoryStream(serverCertificateData))
286+
{
287+
serverCertificate = OpenCertificateStore(serverCertificateStream);
288+
}
289+
}
290+
else
291+
{
292+
serverCertificate = new X509Certificate2(serverCertificateData, "");
293+
}
294+
295+
var clientCertificate = new X509Certificate2(clientCertificateData, "");
296+
297+
var clientCertificateValidationCalled = false;
298+
299+
using (var server = new MockKubeApiServer(testOutput, listenConfigure: options =>
300+
{
301+
options.UseHttps(new HttpsConnectionAdapterOptions
302+
{
303+
ServerCertificate = serverCertificate,
304+
ClientCertificateMode = ClientCertificateMode.RequireCertificate,
305+
ClientCertificateValidation = (certificate, chain, valid) =>
306+
{
307+
clientCertificateValidationCalled = true;
308+
return clientCertificate.Equals(certificate);
309+
},
310+
});
311+
}))
312+
{
313+
{
314+
var clientCertificateText = Encoding.ASCII.GetString(clientCertificateData).Replace("\n", "\\n");
315+
var clientCertificateKeyText = Encoding.ASCII.GetString(clientCertificateKeyData).Replace("\n", "\\n");
316+
var responseJson = $"{{\"apiVersion\":\"testingversion\",\"status\":{{\"clientCertificateData\":\"{clientCertificateText}\",\"clientKeyData\":\"{clientCertificateKeyText}\"}}}}";
317+
var kubernetesConfig = GetK8SConfiguration(server.Uri.ToString(), responseJson, name);
318+
var clientConfig = KubernetesClientConfiguration.BuildConfigFromConfigObject(kubernetesConfig, name);
319+
var client = new Kubernetes(clientConfig);
320+
var listTask = ExecuteListPods(client);
321+
Assert.True(listTask.Response.IsSuccessStatusCode);
322+
Assert.Equal(1, listTask.Body.Items.Count);
323+
}
324+
{
325+
var clientCertificateText = File.ReadAllText("assets/client.crt").Replace("\n", "\\n");
326+
var clientCertificateKeyText = File.ReadAllText("assets/client.key").Replace("\n", "\\n");
327+
var responseJson = $"{{\"apiVersion\":\"testingversion\",\"status\":{{\"clientCertificateData\":\"{clientCertificateText}\",\"clientKeyData\":\"{clientCertificateKeyText}\"}}}}";
328+
var kubernetesConfig = GetK8SConfiguration(server.Uri.ToString(), responseJson, name);
329+
var clientConfig = KubernetesClientConfiguration.BuildConfigFromConfigObject(kubernetesConfig, name);
330+
var client = new Kubernetes(clientConfig);
331+
Assert.ThrowsAny<Exception>(() => ExecuteListPods(client));
332+
Assert.True(clientCertificateValidationCalled);
333+
}
334+
}
335+
}
271336
#endif // NETCOREAPP2_1
272337

273338
[Fact]
@@ -292,15 +357,18 @@ public void ExternalToken()
292357
}))
293358
{
294359
{
295-
var kubernetesConfig = GetK8SConfiguration(server.Uri.ToString(), token, name);
360+
361+
var responseJson = $"{{\"apiVersion\":\"testingversion\",\"status\":{{\"token\":\"{token}\"}}}}";
362+
var kubernetesConfig = GetK8SConfiguration(server.Uri.ToString(), responseJson, name);
296363
var clientConfig = KubernetesClientConfiguration.BuildConfigFromConfigObject(kubernetesConfig, name);
297364
var client = new Kubernetes(clientConfig);
298365
var listTask = ExecuteListPods(client);
299366
Assert.True(listTask.Response.IsSuccessStatusCode);
300367
Assert.Equal(1, listTask.Body.Items.Count);
301368
}
302369
{
303-
var kubernetesConfig = GetK8SConfiguration(server.Uri.ToString(), "wrong token", name);
370+
var responseJson = "{\"apiVersion\":\"testingversion\",\"status\":{\"token\":\"wrong_token\"}}";
371+
var kubernetesConfig = GetK8SConfiguration(server.Uri.ToString(), responseJson, name);
304372
var clientConfig = KubernetesClientConfiguration.BuildConfigFromConfigObject(kubernetesConfig, name);
305373
var client = new Kubernetes(clientConfig);
306374
var listTask = ExecuteListPods(client);
@@ -398,7 +466,7 @@ private X509Certificate2 OpenCertificateStore(Stream stream)
398466
return certificate;
399467
}
400468

401-
private K8SConfiguration GetK8SConfiguration(string serverUri, string token, string name)
469+
private K8SConfiguration GetK8SConfiguration(string serverUri, string responseJson, string name)
402470
{
403471
const string username = "testinguser";
404472

@@ -407,8 +475,6 @@ private K8SConfiguration GetK8SConfiguration(string serverUri, string token, str
407475
new Context {Name = name, ContextDetails = new ContextDetails {Cluster = name, User = username } },
408476
};
409477

410-
var responseJson = $"{{\"apiVersion\": \"testingversion\", \"status\": {{\"token\": \"{token}\"}}}}";
411-
412478
{
413479
var clusters = new List<Cluster>
414480
{
@@ -428,7 +494,7 @@ private K8SConfiguration GetK8SConfiguration(string serverUri, string token, str
428494
var arguments = new string[] { };
429495
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
430496
{
431-
arguments = ($"/c echo {responseJson}").Split(" ");
497+
arguments = new[] { "/c", "echo", responseJson };
432498
}
433499

434500
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))

0 commit comments

Comments
 (0)