2929
3030using System ;
3131using System . Collections . Generic ;
32+ using System . IO ;
3233using System . Management . Automation ;
3334using System . Net ;
3435using System . Net . Security ;
3536using System . Runtime . InteropServices ;
3637using System . Security ;
3738using System . Security . Cryptography ;
3839using System . Security . Cryptography . X509Certificates ;
40+ using System . Xml ;
3941using XenAPI ;
4042
4143namespace Citrix . XenServer . Commands
4244{
4345 [ Cmdlet ( "Connect" , "XenServer" ) ]
4446 public class ConnectXenServerCommand : PSCmdlet
4547 {
48+ private const string CertificatesPathVariable = "global:KnownServerCertificatesFilePath" ;
49+
4650 private readonly object _certificateValidationLock = new object ( ) ;
4751
4852 public ConnectXenServerCommand ( )
@@ -214,7 +218,10 @@ protected override void ProcessRecord()
214218 {
215219 if ( ShouldContinue ( ex . Message , ex . Caption ) )
216220 {
217- AddCertificate ( ex . Hostname , ex . Fingerprint ) ;
221+ var certPath = GetCertificatesPath ( ) ;
222+ var certificates = LoadCertificates ( certPath ) ;
223+ certificates [ ex . Hostname ] = ex . Fingerprint ;
224+ SaveCertificates ( certPath , certificates ) ;
218225 i -- ;
219226 continue ;
220227 }
@@ -254,13 +261,6 @@ protected override void ProcessRecord()
254261 WriteObject ( newSessions . Values , true ) ;
255262 }
256263
257- private void AddCertificate ( string hostname , string fingerprint )
258- {
259- var certificates = CommonCmdletFunctions . LoadCertificates ( this ) ;
260- certificates [ hostname ] = fingerprint ;
261- CommonCmdletFunctions . SaveCertificates ( this , certificates ) ;
262- }
263-
264264 private bool ValidateServerCertificate ( object sender , X509Certificate certificate , X509Chain chain , SslPolicyErrors sslPolicyErrors )
265265 {
266266 if ( sslPolicyErrors == SslPolicyErrors . None )
@@ -277,11 +277,11 @@ private bool ValidateServerCertificate(object sender, X509Certificate certificat
277277
278278 bool trusted = VerifyInAllStores ( new X509Certificate2 ( certificate ) ) ;
279279
280- var certificates = CommonCmdletFunctions . LoadCertificates ( this ) ;
280+ var certPath = GetCertificatesPath ( ) ;
281+ var certificates = LoadCertificates ( certPath ) ;
281282
282- if ( certificates . ContainsKey ( hostname ) )
283+ if ( certificates . TryGetValue ( hostname , out var fingerprintOld ) )
283284 {
284- string fingerprintOld = certificates [ hostname ] ;
285285 if ( fingerprintOld == fingerprint )
286286 return true ;
287287
@@ -295,7 +295,7 @@ private bool ValidateServerCertificate(object sender, X509Certificate certificat
295295 }
296296
297297 certificates [ hostname ] = fingerprint ;
298- CommonCmdletFunctions . SaveCertificates ( this , certificates ) ;
298+ SaveCertificates ( certPath , certificates ) ;
299299 return true ;
300300 }
301301 }
@@ -312,6 +312,65 @@ private bool VerifyInAllStores(X509Certificate2 certificate2)
312312 return false ;
313313 }
314314 }
315+
316+ private string GetCertificatesPath ( )
317+ {
318+ var certPathObject = SessionState . PSVariable . GetValue ( CertificatesPathVariable ) ;
319+
320+ return certPathObject is PSObject psObject
321+ ? psObject . BaseObject as string
322+ : certPathObject ? . ToString ( ) ?? string . Empty ;
323+ }
324+
325+ private Dictionary < string , string > LoadCertificates ( string certPath )
326+ {
327+ var certificates = new Dictionary < string , string > ( ) ;
328+
329+ if ( File . Exists ( certPath ) )
330+ {
331+ var doc = new XmlDocument ( ) ;
332+ doc . Load ( certPath ) ;
333+
334+ foreach ( XmlNode node in doc . GetElementsByTagName ( "certificate" ) )
335+ {
336+ var hostAtt = node . Attributes ? [ "hostname" ] ;
337+ var fngprtAtt = node . Attributes ? [ "fingerprint" ] ;
338+
339+ if ( hostAtt != null && fngprtAtt != null )
340+ certificates [ hostAtt . Value ] = fngprtAtt . Value ;
341+ }
342+ }
343+
344+ return certificates ;
345+ }
346+
347+ private void SaveCertificates ( string certPath , Dictionary < string , string > certificates )
348+ {
349+ string dirName = Path . GetDirectoryName ( certPath ) ;
350+
351+ if ( ! Directory . Exists ( dirName ) )
352+ Directory . CreateDirectory ( dirName ) ;
353+
354+ XmlDocument doc = new XmlDocument ( ) ;
355+ XmlDeclaration decl = doc . CreateXmlDeclaration ( "1.0" , "utf-8" , null ) ;
356+ doc . AppendChild ( decl ) ;
357+ XmlNode node = doc . CreateElement ( "certificates" ) ;
358+
359+ foreach ( KeyValuePair < string , string > cert in certificates )
360+ {
361+ XmlNode certNode = doc . CreateElement ( "certificate" ) ;
362+ XmlAttribute hostname = doc . CreateAttribute ( "hostname" ) ;
363+ XmlAttribute fingerprint = doc . CreateAttribute ( "fingerprint" ) ;
364+ hostname . Value = cert . Key ;
365+ fingerprint . Value = cert . Value ;
366+ certNode . Attributes ? . Append ( hostname ) ;
367+ certNode . Attributes ? . Append ( fingerprint ) ;
368+ node . AppendChild ( certNode ) ;
369+ }
370+
371+ doc . AppendChild ( node ) ;
372+ doc . Save ( certPath ) ;
373+ }
315374 }
316375
317376 internal abstract class CertificateValidationException : Exception
0 commit comments