diff --git a/AxisIPCamera/Client/AxisHttpClient.cs b/AxisIPCamera/Client/AxisHttpClient.cs index a135476..7f594dc 100644 --- a/AxisIPCamera/Client/AxisHttpClient.cs +++ b/AxisIPCamera/Client/AxisHttpClient.cs @@ -232,7 +232,7 @@ public CertificateData ListCertificates() /// /// Gets the default keystore configured on the device. /// - /// Keystore Enum + /// Keystore struct public Constants.Keystore GetDefaultKeystore() { try diff --git a/AxisIPCamera/Inventory.cs b/AxisIPCamera/Inventory.cs index 5b83643..ca579c9 100644 --- a/AxisIPCamera/Inventory.cs +++ b/AxisIPCamera/Inventory.cs @@ -8,6 +8,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Text.RegularExpressions; using Microsoft.Extensions.Logging; using Newtonsoft.Json; @@ -47,7 +48,8 @@ public JobResult ProcessJob(InventoryJobConfiguration config, SubmitInventoryUpd _logger.MethodEntry(); _logger.LogTrace($"Begin Inventory for Client Machine {config.CertificateStoreDetails.ClientMachine}..."); - _logger.LogDebug($"Inventory Config: {JsonConvert.SerializeObject(config)}"); + string jsonConfig = JsonConvert.SerializeObject(config); + _logger.LogDebug($"Inventory Config: {jsonConfig.Replace(config.ServerPassword,"**********")}"); _logger.LogTrace("Create HTTPS client to connect to device"); var client = new AxisHttpClient(config, config.CertificateStoreDetails, Resolver); @@ -63,7 +65,7 @@ public JobResult ProcessJob(InventoryJobConfiguration config, SubmitInventoryUpd // Get the default keystore _logger.LogTrace("Retrieve the default keystore"); Constants.Keystore defaultKeystore = client.GetDefaultKeystore(); - string defaultKeystoreString = Enum.GetName(typeof(Constants.Keystore), defaultKeystore); + string defaultKeystoreString = defaultKeystore.ToString(); _logger.LogDebug($"Inventory - Default keystore: {defaultKeystoreString}"); // Create new list of client certs that are only tied to the default keystore diff --git a/AxisIPCamera/Management.cs b/AxisIPCamera/Management.cs index d458123..357e4f3 100644 --- a/AxisIPCamera/Management.cs +++ b/AxisIPCamera/Management.cs @@ -77,7 +77,8 @@ public JobResult ProcessJob(ManagementJobConfiguration config) // to determine if job should overwrite an existing certificate in the store, for example a renewal. // Retrieve management config from Command - _logger.LogDebug($"Management Config {JsonConvert.SerializeObject(config)}"); + string jsonConfig = JsonConvert.SerializeObject(config); + _logger.LogDebug($"Management Config: {jsonConfig.Replace(config.ServerPassword,"**********")}"); _logger.LogDebug($"Client Machine: {config.CertificateStoreDetails.ClientMachine}"); // Get needed information from config diff --git a/AxisIPCamera/Model/Certificate.cs b/AxisIPCamera/Model/Certificate.cs index 1c3846e..977d8a2 100644 --- a/AxisIPCamera/Model/Certificate.cs +++ b/AxisIPCamera/Model/Certificate.cs @@ -28,7 +28,7 @@ public class Certificate { [JsonProperty("alias")] public string Alias { get; set; } [JsonProperty("certificate")] public string CertAsPem { get; set; } - [JsonProperty("keystore")] public Constants.Keystore Keystore { get; set; } + [JsonProperty("keystore")] public Constants.Keystore Keystore { get; init; } public Constants.CertificateUsage Binding { get; set; } = Constants.CertificateUsage.Other; } diff --git a/AxisIPCamera/Model/Constants.cs b/AxisIPCamera/Model/Constants.cs index fcf276e..2f182e0 100644 --- a/AxisIPCamera/Model/Constants.cs +++ b/AxisIPCamera/Model/Constants.cs @@ -7,6 +7,7 @@ using System; using System.IO; +using Newtonsoft.Json; using Org.BouncyCastle.OpenSsl; using Org.BouncyCastle.Pkcs; @@ -55,11 +56,15 @@ public enum CertificateUsage Undefined } - // ** NOTE: There may be more keystore types depending on the Axis camera model - public enum Keystore + /** NOTE: Keystore IDs are device-specific and not stable across Axis camera models. + * New camera/firmware can introduce new Keystore IDs. Cameras can also have multiple + * keystores of the same type (i.e. SE0, SE1, TPM0, TPM1, etc.) + * Therefore, treat the Keystore ID as an opaque string, not a fixed enum. + */ + [JsonConverter(typeof(KeystoreJsonConverter))] + public readonly record struct Keystore(string Value) { - TEE0, // Trusted Environment - SE0 // Secure Element + public override string ToString() => Value; } public enum ApiType @@ -212,5 +217,35 @@ public static void ValidateCsr(string csrPem) throw new Exception($"CSR Validation failed: {ex.Message}"); } } + + /// + /// Custom JSON converter to tell Newtonsoft how to parse the record struct 'Keystore' type. + /// + private sealed class KeystoreJsonConverter : JsonConverter + { + public override Keystore ReadJson( + JsonReader reader, + Type objectType, + Keystore existingValue, + bool hasExistingValue, + JsonSerializer serializer) + { + if (reader.TokenType == JsonToken.String) + { + return new Keystore(reader.Value!.ToString()!); + } + + throw new JsonSerializationException( + $"Unexpected token {reader.TokenType} when parsing Keystore"); + } + + public override void WriteJson( + JsonWriter writer, + Keystore value, + JsonSerializer serializer) + { + writer.WriteValue(value.Value); + } + } } } diff --git a/AxisIPCamera/Reenrollment.cs b/AxisIPCamera/Reenrollment.cs index 996361c..afd519b 100644 --- a/AxisIPCamera/Reenrollment.cs +++ b/AxisIPCamera/Reenrollment.cs @@ -42,7 +42,8 @@ public JobResult ProcessJob(ReenrollmentJobConfiguration config, SubmitReenrollm _logger.MethodEntry(); _logger.LogTrace($"Begin Reenrollment for Client Machine {config.CertificateStoreDetails.ClientMachine}"); - _logger.LogDebug($"Reenrollment Config: {JsonConvert.SerializeObject(config)}"); + string jsonConfig = JsonConvert.SerializeObject(config); + _logger.LogDebug($"Reenrollment Config: {jsonConfig.Replace(config.ServerPassword,"**********")}"); // Log each key-value pair in the Job Properties for debugging _logger.LogDebug("Begin Job Properties ---"); @@ -109,7 +110,7 @@ public JobResult ProcessJob(ReenrollmentJobConfiguration config, SubmitReenrollm // Get the default keystore _logger.LogTrace("Retrieve the default keystore"); Constants.Keystore defaultKeystore = client.GetDefaultKeystore(); - string defaultKeystoreString = Enum.GetName(typeof(Constants.Keystore), defaultKeystore); + string defaultKeystoreString = defaultKeystore.ToString(); _logger.LogDebug($"Reenrollment - Default keystore: {defaultKeystoreString}"); _logger.LogTrace("Generating self-signed cert with private key on device"); diff --git a/CHANGELOG.md b/CHANGELOG.md index 035dc64..12153e6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +v1.0.2 +- fix(logs): Removed logging of plaintext cert store Server Password +- fix(keystore): Updated Keystore type to be dynamic instead of a fixed Enum to allow compatibility across different cameras/firmware + v1.0.1 - chore(docs): Add screenshots to docs diff --git a/README.md b/README.md index 108bece..4e275e1 100644 --- a/README.md +++ b/README.md @@ -187,6 +187,37 @@ the Keyfactor Command Portal ![AxisIPCamera Custom Fields Tab](docsource/images/AxisIPCamera-custom-fields-store-type-dialog.png) + + ###### Server Username + Enter the username of the configured "service" user on the camera + + + > [!IMPORTANT] + > This field is created by the `Needs Server` on the Basic tab, do not create this field manually. + + + + + ###### Server Password + Enter the password of the configured "service" user on the camera + + + > [!IMPORTANT] + > This field is created by the `Needs Server` on the Basic tab, do not create this field manually. + + + + + ###### Use SSL + Select True or False depending on if SSL (HTTPS) should be used to communicate with the camera. This should always be "True" + + ![AxisIPCamera Custom Field - ServerUseSsl](docsource/images/AxisIPCamera-custom-field-ServerUseSsl-dialog.png) + ![AxisIPCamera Custom Field - ServerUseSsl](docsource/images/AxisIPCamera-custom-field-ServerUseSsl-validation-options-dialog.png) + + + + + ##### Entry Parameters Tab | Name | Display Name | Description | Type | Default Value | Entry has a private key | Adding an entry | Removing an entry | Reenrolling an entry | @@ -197,21 +228,29 @@ the Keyfactor Command Portal ![AxisIPCamera Entry Parameters Tab](docsource/images/AxisIPCamera-entry-parameters-store-type-dialog.png) + + ##### Certificate Usage + The Certificate Usage to assign to the cert after enrollment. Can be left 'Other' to be assigned later. + + ![AxisIPCamera Entry Parameter - CertUsage](docsource/images/AxisIPCamera-entry-parameters-store-type-dialog-CertUsage.png) + ![AxisIPCamera Entry Parameter - CertUsage](docsource/images/AxisIPCamera-entry-parameters-store-type-dialog-CertUsage-validation-options.png) + + + ## Installation 1. **Download the latest AXIS IP Camera Universal Orchestrator extension from GitHub.** - Navigate to the [AXIS IP Camera Universal Orchestrator extension GitHub version page](https://github.com/Keyfactor/axis-ipcamera-orchestrator/releases/latest). Refer to the compatibility matrix below to determine whether the `net6.0` or `net8.0` asset should be downloaded. Then, click the corresponding asset to download the zip archive. + Navigate to the [AXIS IP Camera Universal Orchestrator extension GitHub version page](https://github.com/Keyfactor/axis-ipcamera-orchestrator/releases/latest). Refer to the compatibility matrix below to determine the asset should be downloaded. Then, click the corresponding asset to download the zip archive. | Universal Orchestrator Version | Latest .NET version installed on the Universal Orchestrator server | `rollForward` condition in `Orchestrator.runtimeconfig.json` | `axis-ipcamera-orchestrator` .NET version to download | | --------- | ----------- | ----------- | ----------- | | Older than `11.0.0` | | | `net6.0` | | Between `11.0.0` and `11.5.1` (inclusive) | `net6.0` | | `net6.0` | - | Between `11.0.0` and `11.5.1` (inclusive) | `net8.0` | `Disable` | `net6.0` | - | Between `11.0.0` and `11.5.1` (inclusive) | `net8.0` | `LatestMajor` | `net8.0` | - | `11.6` _and_ newer | `net8.0` | | `net8.0` | + | Between `11.0.0` and `11.5.1` (inclusive) | `net8.0` | `Disable` | `net6.0` || Between `11.0.0` and `11.5.1` (inclusive) | `net8.0` | `LatestMajor` | `net8.0` | + | `11.6` _and_ newer | `net8.0` | | `net8.0` | Unzip the archive containing extension assemblies to a known location. diff --git a/integration-manifest.json b/integration-manifest.json index c5f483a..4c1144a 100644 --- a/integration-manifest.json +++ b/integration-manifest.json @@ -9,6 +9,7 @@ "update_catalog": true, "link_github": true, "description": "The Axis IP Camera Orchestrator Extension is used to inventory, manage Trust certs, and enroll for client certificates that can be bound to endpoints.", + "short_description": "The Axis IP Camera Orchestrator Extension is used to inventory, manage Trust certs, and enroll for client certificates that can be bound to endpoints.", "about": { "orchestrator": { "UOFramework": "10.1", @@ -90,3 +91,4 @@ } } } +