Skip to content

Commit 1cb29d2

Browse files
committed
Save local changes
1 parent 0192565 commit 1cb29d2

4 files changed

Lines changed: 103 additions & 29 deletions

File tree

AxisIPCamera/Client/AxisHttpClient.cs

Lines changed: 19 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -549,54 +549,50 @@ public void RemoveCACertificate(string alias)
549549
throw new Exception(e.Message);
550550
}
551551
}
552-
552+
553553
/// <summary>
554554
/// Removes a certificate with private key from the device.
555555
/// </summary>
556556
/// <param name="alias">Unique identifier of the CA certificate to be removed</param>
557-
public void RemoveCertificate(string alias)
557+
public HttpResult RemoveCertificate(string alias)
558558
{
559559
try
560560
{
561561
Logger.MethodEntry();
562562

563+
var context = new HttpContext();
564+
563565
var deleteCertResource = $"{Constants.RestApiEntryPoint}/certificates/{alias}";
564566
var httpResponse = ExecuteHttp(deleteCertResource, Method.Delete);
565567

566568
// Decode the HTTP response if failed
567569
if (httpResponse is { IsSuccessful: false })
568570
{
569-
Logger.LogError($"HTTP Request unsuccessful - HTTP Response: {DecodeHttpStatus(httpResponse)}");
570-
throw new Exception($"HTTP Request unsuccessful.");
571+
var decodedStatus = DecodeHttpStatus(httpResponse);
572+
573+
Logger.LogWarning($"HTTP Request unsuccessful - HTTP Response: {decodedStatus}");
574+
context.AddWarning(decodedStatus);
571575
}
572576

573-
// Decode the API response when HTTP response is successful
577+
// Decode the API response for more information
574578
if (httpResponse != null && string.IsNullOrEmpty(httpResponse.Content))
575579
{
576-
throw new Exception("No content returned from HTTP Response");
577-
}
578-
579-
RestApiResponse apiResponse = JsonConvert.DeserializeObject<RestApiResponse>(httpResponse.Content);
580-
if (apiResponse.Status == Constants.Status.Success)
581-
{
582-
Logger.MethodExit();
580+
Logger.LogError("No content returned from HTTP Response");
581+
context.AddError($"No content returned from HTTP Response for {nameof(Method.Delete)} {deleteCertResource}");
583582
}
584583
else
585584
{
586-
ErrorData error = JsonConvert.DeserializeObject<ErrorData>(httpResponse.Content);
587-
588-
// Check for error code 5 - "Validation error: Certificate is in use" or "Validation error: Certificate is not deletable" ---
589-
// This will capture all device ID certs, which we do not want to delete anyway
590-
if (error.ErrorInfo is { Code: 5, Message: "Validation error: Certificate is not deletable" or "Validation error: Certificate is in use"})
591-
{
592-
Logger.LogWarning($"API warning encountered - {error.ErrorInfo.Message} - (Code: {error.ErrorInfo.Code})");
593-
}
594-
else
585+
RestApiResponse apiResponse = JsonConvert.DeserializeObject<RestApiResponse>(httpResponse.Content);
586+
if (apiResponse.Status != Constants.Status.Success)
595587
{
596-
throw new Exception(
597-
$"API error encountered - {error.ErrorInfo.Message} - (Code: {error.ErrorInfo.Code})");
588+
ErrorData error = JsonConvert.DeserializeObject<ErrorData>(httpResponse.Content);
589+
Logger.LogWarning($"API error encountered - {error.ErrorInfo.Message} - (Code: {error.ErrorInfo.Code})");
590+
context.AddWarning($"HTTP Request {nameof(Method.Delete)} {deleteCertResource}: API error encountered - {error.ErrorInfo.Message} - (Code: {error.ErrorInfo.Code})");
598591
}
599592
}
593+
594+
Logger.MethodExit();
595+
return context.ToResult();
600596
}
601597
catch (Exception e)
602598
{

AxisIPCamera/Inventory.cs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -62,8 +62,9 @@ public JobResult ProcessJob(InventoryJobConfiguration config, SubmitInventoryUpd
6262
_logger.LogTrace("Retrieve all client certificates");
6363
CertificateData data2 = client.ListCertificates();
6464

65+
// TODO: Remove this if not using
6566
// Get the default keystore
66-
_logger.LogTrace("Retrieve the default keystore");
67+
/*_logger.LogTrace("Retrieve the default keystore");
6768
Constants.Keystore defaultKeystore = client.GetDefaultKeystore();
6869
string defaultKeystoreString = defaultKeystore.ToString();
6970
_logger.LogDebug($"Inventory - Default keystore: {defaultKeystoreString}");
@@ -78,7 +79,7 @@ public JobResult ProcessJob(InventoryJobConfiguration config, SubmitInventoryUpd
7879
foreach (var cert in data2.Certs.Where(cert => cert.Keystore == defaultKeystore))
7980
{
8081
data2DefKey.Certs.Add(cert);
81-
}
82+
}*/
8283

8384
_logger.LogTrace("Retrieve all certificate bindings for each possible certificate usage type");
8485
// Lookup the certificate used for HTTPS, MQTT, IEEE802.X
@@ -88,7 +89,7 @@ public JobResult ProcessJob(InventoryJobConfiguration config, SubmitInventoryUpd
8889

8990
// Set the binding on the client certificates object if the aliases found for each certificate usage match
9091
_logger.LogTrace("Mark each client certificate with the appropriate certificate usage type");
91-
foreach (Certificate c in data2DefKey.Certs)
92+
foreach (Certificate c in data2.Certs)
9293
{
9394
if (c.Alias.Equals(httpAlias))
9495
{
@@ -131,7 +132,7 @@ public JobResult ProcessJob(InventoryJobConfiguration config, SubmitInventoryUpd
131132
}).Where(item => item?.Certificates != null).ToList());
132133

133134
// Build the list of client certificates and add to the InventoryItems object that is sent back to Command
134-
inventoryItems.AddRange(data2DefKey.Certs.Select(
135+
inventoryItems.AddRange(data2.Certs.Select(
135136
c =>
136137
{
137138
try

AxisIPCamera/Model/HttpResponse.cs

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
// Copyright 2026 Keyfactor
2+
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.
3+
// You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
4+
// Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS,
5+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions
6+
// and limitations under the License.
7+
8+
using System;
9+
using System.Collections.Generic;
10+
using System.Linq;
11+
12+
namespace Keyfactor.Extensions.Orchestrator.AxisIPCamera.Model
13+
{
14+
public sealed class HttpContext
15+
{
16+
private readonly List<string> _warnings = new();
17+
private readonly List<string> _errors = new();
18+
19+
public IReadOnlyList<string> Warnings => _warnings;
20+
public IReadOnlyList<string> Errors => _errors;
21+
22+
public void AddWarning(string message) =>
23+
_warnings.Add(message);
24+
25+
public void AddError(string message) =>
26+
_errors.Add(message);
27+
28+
public HttpResult ToResult()
29+
{
30+
if (_errors.Any())
31+
return HttpResult.Error(FormatMessages(_errors));
32+
33+
if (_warnings.Any())
34+
return HttpResult.Warning(FormatMessages(_warnings));
35+
36+
return HttpResult.Success();
37+
}
38+
39+
private static string FormatMessages(IEnumerable<string> messages)
40+
{
41+
return string.Join(
42+
Environment.NewLine,
43+
messages.Select((message, index) =>
44+
$"({index + 1}) {message}")
45+
);
46+
}
47+
}
48+
49+
public enum HttpStatus
50+
{
51+
Success,
52+
Warning,
53+
Error
54+
}
55+
56+
public sealed record HttpResult(HttpStatus Status, string Message = null)
57+
{
58+
public static HttpResult Success()
59+
=> new(HttpStatus.Success);
60+
61+
public static HttpResult Warning(string message)
62+
=> new(HttpStatus.Warning, message);
63+
64+
public static HttpResult Error(string message)
65+
=> new(HttpStatus.Error, message);
66+
67+
}
68+
}

AxisIPCamera/Reenrollment.cs

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
using System;
99
using System.Collections.Generic;
10+
using System.Net;
1011
using System.Net.Http;
1112
using System.Text;
1213
using System.Text.RegularExpressions;
@@ -197,13 +198,21 @@ public JobResult ProcessJob(ReenrollmentJobConfiguration config, SubmitReenrollm
197198
client.SetCertUsageBinding(newAlias,certUsageEnum);
198199

199200
// Perform unused certificate cleanup ---
200-
// 1) If a bound alias exists and there is a new alias to enroll, delete the bound alias
201+
// 1) If a bound alias exists, delete the bound alias
202+
HttpResult result;
201203
if (oldCertExists)
202204
{
203205
_logger.LogTrace($"Removing certificate and private key associated with alias '{oldAlias}'");
204-
client.RemoveCertificate(oldAlias);
206+
result = client.RemoveCertificate(oldAlias);
207+
208+
if (result.Status == HttpStatus.Warning)
209+
{
210+
return new JobResult() { Result = OrchestratorJobStatusJobResult.Warning, JobHistoryId = config.JobHistoryId,
211+
FailureMessage = $"Reenrollment Job Had Warnings - Refer to logs for more detailed information." };
212+
}
205213
}
206214

215+
207216
// TESTING build chain functionality
208217
/*using var aiaClient = new HttpClient();
209218
var builder = new ChainBuilder(aiaClient);

0 commit comments

Comments
 (0)