|
1 | 1 | using System; |
2 | | -using System.Collections.Generic; |
3 | 2 | using System.Reflection; |
4 | 3 | using System.IO; |
5 | 4 | using System.Net; |
6 | 5 | using System.Net.Http; |
7 | | -using System.Runtime.ConstrainedExecution; |
| 6 | +using System.Text; |
| 7 | +using System.Xml; |
| 8 | + |
8 | 9 | using Microsoft.Extensions.Logging; |
9 | | -using System.Threading; |
10 | | -using System.Threading.Tasks; |
11 | | -using Keyfactor.Logging; |
12 | | -using Keyfactor.Orchestrators.Extensions; |
13 | | -using Keyfactor.Extensions.Orchestrator.AxisIPCamera.Model; |
14 | 10 | using Newtonsoft.Json; |
15 | 11 | using RestSharp; |
16 | 12 | using RestSharp.Authenticators; |
17 | | -using System.Xml; |
| 13 | + |
| 14 | +using Keyfactor.Logging; |
| 15 | +using Keyfactor.Orchestrators.Extensions; |
| 16 | +using Keyfactor.Extensions.Orchestrator.AxisIPCamera.Model; |
| 17 | +using Keyfactor.Orchestrators.Extensions.Interfaces; |
| 18 | +using Keyfactor.Extensions.Orchestrator.AxisIPCamera.Helpers; |
18 | 19 |
|
19 | 20 | /* AxisHttpClient.cs |
20 | 21 | * --------------------------------------------------------------------------------------------------- |
@@ -53,112 +54,76 @@ public class AxisHttpClient |
53 | 54 | private readonly RestClient _httpClient; |
54 | 55 | private ILogger Logger { get; } |
55 | 56 |
|
56 | | - public AxisHttpClient(JobConfiguration config, CertificateStore store) |
| 57 | + public AxisHttpClient(JobConfiguration config, CertificateStore store, IPAMSecretResolver resolver) |
57 | 58 | { |
58 | 59 | try |
59 | 60 | { |
| 61 | + var errorContext = new CertificateErrorContext(); |
| 62 | + |
60 | 63 | Logger = LogHandler.GetClassLogger<AxisHttpClient>(); |
61 | | - Logger.MethodEntry(); |
62 | | - |
63 | | - // TODO REMOVE |
64 | | - bool vetDevice = true; |
65 | | - |
| 64 | + Logger.LogTrace("Entered AxisHttpClient constructor."); |
66 | 65 | Logger.LogTrace("Initializing Axis IP Camera HTTP Client"); |
67 | 66 |
|
68 | | - var baseRestClientUrl = |
69 | | - (config.UseSSL) ? $"https://{store.ClientMachine}" : $"http://{store.ClientMachine}"; |
70 | | - |
71 | | - // TODO: Need to consider onboarding of camera |
| 67 | + //TODO; REMOVE var baseRestClientUrl = |
| 68 | + //(config.UseSSL) ? $"https://{store.ClientMachine}" : $"http://{store.ClientMachine}"; |
| 69 | + // NOTE: Ignoring the default config.UseSSL custom field --- we will always connect to the device via HTTPS |
| 70 | + var baseRestClientUrl = $"https://{store.ClientMachine}"; |
| 71 | + |
72 | 72 | Logger.LogDebug($"Base HTTP Client URL: {baseRestClientUrl}"); |
73 | 73 |
|
74 | | - // If vetting the device, initialize custom HTTP handler for onboarding of device |
| 74 | + // Initialize custom HTTP handler to validate device identity |
75 | 75 | RestClientOptions options = null; |
76 | | - if (vetDevice) |
| 76 | + Logger.LogTrace($"Adding custom SSL cert validator to the HTTP client options..."); |
| 77 | + var handler = new HttpClientHandler |
77 | 78 | { |
78 | | - Logger.LogInformation($"Vet device: {vetDevice} --- Looking at custom cert validator"); |
79 | | - var handler = new HttpClientHandler |
80 | | - { |
81 | | - ServerCertificateCustomValidationCallback = |
82 | | - DeviceCertValidator.GetValidator(store.StorePath, Logger) |
83 | | - }; |
| 79 | + ServerCertificateCustomValidationCallback = |
| 80 | + DeviceCertValidator.GetValidator(store.StorePath, errorContext, Logger) |
| 81 | + }; |
84 | 82 |
|
85 | | - // Initialize HTTP client options with the base URL and custom cert validator |
86 | | - options = new RestClientOptions(baseRestClientUrl) |
87 | | - { |
88 | | - ConfigureMessageHandler = _ => handler |
89 | | - }; |
90 | | - } |
91 | | - else |
| 83 | + // Initialize HTTP client options with the base URL and custom SSL cert validator |
| 84 | + options = new RestClientOptions(baseRestClientUrl) |
92 | 85 | { |
93 | | - // Initialize HTTP client options with the base URL |
94 | | - options = new RestClientOptions(baseRestClientUrl); |
95 | | - options.RemoteCertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) => true; |
96 | | - } |
| 86 | + ConfigureMessageHandler = _ => handler |
| 87 | + }; |
97 | 88 |
|
98 | 89 | // Add Basic Auth username and password credentials |
99 | 90 | Logger.LogTrace("Adding Basic Auth Credentials to the HTTP client options..."); |
100 | 91 |
|
| 92 | + string username = PAMUtilities.ResolvePAMField(resolver, Logger, "API Username", config.ServerUsername); |
| 93 | + string password = PAMUtilities.ResolvePAMField(resolver, Logger, "API Password", config.ServerPassword); |
| 94 | + |
101 | 95 | // TODO: Do we want to remove this log statement in PRODUCTION? |
102 | | - Logger.LogDebug($"Username: {config.ServerUsername}, Password: {config.ServerPassword}"); |
| 96 | + Logger.LogDebug($"Username: {username}, Password: {password}"); |
103 | 97 | options.Authenticator = new HttpBasicAuthenticator(config.ServerUsername, config.ServerPassword); |
104 | 98 |
|
105 | 99 | // Add SSL validation |
106 | | - Logger.LogTrace("Checking for SSL validation..."); |
107 | | - Logger.LogDebug($"Use SSL: {config.UseSSL}"); |
108 | | - |
109 | | - Logger.LogTrace("Turning off SSL validation --- FOR TESTING ONLY"); |
110 | | - |
111 | | - // TODO: Enable this flag in PRODUCTION |
112 | | - //if (config.UseSSL) |
113 | | - //{ |
114 | | - // TODO FOR TESTING: options.RemoteCertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) => true; |
115 | | - //} |
| 100 | + Logger.LogTrace("Validating connection to the device..."); |
116 | 101 |
|
117 | 102 | _httpClient = new RestClient(options); |
| 103 | + var request = new RestRequest("/"); // Initiates the TLS handshake to retrieve the server cert |
| 104 | + var response = _httpClient.Execute(request); |
118 | 105 |
|
119 | | - // TODO FOR TESTING |
120 | | - if (vetDevice) |
| 106 | + // Build the list of errors to log to the console |
| 107 | + StringBuilder errorSb = new StringBuilder(); |
| 108 | + if (errorContext.HasErrors) |
121 | 109 | { |
122 | | - var request = new RestRequest("/"); // Initiates the TLS handshake to retrieve the server cert |
123 | | - var response = _httpClient.Execute(request); |
124 | | - Logger.LogTrace($"Response status: {response.StatusCode}"); |
125 | | - |
126 | | - /*if (!response.IsSuccessful) |
| 110 | + foreach (var error in errorContext.Errors) |
127 | 111 | { |
128 | | - if (response.StatusCode == 0 && response.ErrorException != null) |
129 | | - { |
130 | | - // Likely caused by TLS/Cert validation failure |
131 | | - Logger.LogError(response.ErrorException, "TLS handshake or certificate validation failed."); |
132 | | - throw new Exception("INVALID DEVICE --- Cert chain validation failed.", |
133 | | - response.ErrorException); |
134 | | - } |
135 | | -
|
136 | | - Logger.LogError("Request failed. Status: {Status}, Message: {Message}", |
137 | | - response.StatusCode, response.ErrorMessage); |
138 | | -
|
139 | | - throw new Exception("Request failed: " + response.ErrorMessage); |
140 | | - }*/ |
| 112 | + errorSb.AppendLine(error); |
| 113 | + } |
| 114 | + throw new Exception(errorSb.ToString()); |
141 | 115 | } |
142 | | - |
| 116 | + |
| 117 | + Logger.LogTrace($"Connection to the device response status code: {response.StatusCode}"); |
143 | 118 |
|
144 | 119 | Logger.LogTrace("Completed Initialization of Axis IP Camera HTTP Client"); |
145 | 120 |
|
146 | | - Logger.MethodExit(); |
147 | | - } |
148 | | - catch (CertificateSslException e1) |
149 | | - { |
150 | | - Logger.LogError("Certificate SSL validation failed: " + LogHandler.FlattenException(e1)); |
151 | | - throw; |
152 | | - } |
153 | | - catch (CertificateSubjectValidationException e2) |
154 | | - { |
155 | | - Logger.LogError("Subject validation failed: " + LogHandler.FlattenException(e2)); |
156 | | - throw; |
| 121 | + Logger.LogTrace("Leaving AxisHttpClient constructor."); |
157 | 122 | } |
158 | 123 | catch (Exception e) |
159 | 124 | { |
160 | | - Logger.LogError("Error in Constructor AxisRestClient(): " + LogHandler.FlattenException(e)); |
161 | | - throw; |
| 125 | + Logger.LogError("Error initializing Axis IP Camera HTTP Client: " + LogHandler.FlattenException(e)); |
| 126 | + throw new Exception($"Device identity could not be verified successfully --- {e.Message}"); |
162 | 127 | } |
163 | 128 | } |
164 | 129 |
|
@@ -988,7 +953,7 @@ public string GetCertUsageBinding(Constants.CertificateUsage certUsage) |
988 | 953 | break; |
989 | 954 | } |
990 | 955 |
|
991 | | - Logger.LogDebug($"Bound Certificate Alias: {boundCertAlias}"); |
| 956 | + Logger.LogDebug($"Bound certificate alias for '{certUsageString}': {boundCertAlias}"); |
992 | 957 |
|
993 | 958 | Logger.MethodExit(); |
994 | 959 | } |
|
0 commit comments