Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SDK fixes including CP-53003 #6210

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 8 additions & 31 deletions ocaml/sdk-gen/csharp/autogen/src/Session.cs
Original file line number Diff line number Diff line change
Expand Up @@ -65,29 +65,15 @@ public Session(JsonRpcClient client)
client.KeepAlive = true;
client.UserAgent = UserAgent;
client.WebProxy = Proxy;
client.JsonRpcVersion = JsonRpcVersion.v2;
client.AllowAutoRedirect = true;
JsonRpcClient = client;
}

[Obsolete("Use Session(string url) { Timeout = ... }; instead.")]
public Session(int timeout, string url)
: this(new JsonRpcClient(url))
{
JsonRpcClient.Timeout = timeout;
}

public Session(string url) :
this(new JsonRpcClient(url))
{
}

[Obsolete("Use Session(string host, int port) { Timeout = ... }; instead.")]
public Session(int timeout, string host, int port)
: this(timeout, GetUrl(host, port))
{
}

public Session(string host, int port)
: this(GetUrl(host, port))
{
Expand All @@ -100,23 +86,6 @@ public Session(string url, string opaqueRef)
SetupSessionDetails();
}

/// <summary>
/// Create a new Session instance, using the given instance and timeout. The connection details and Xen-API session handle will be
/// copied from the given instance, but a new connection will be created. Use this if you want a duplicate connection to a host,
/// for example when you need to cancel an operation that is blocking the primary connection.
/// </summary>
/// <param name="session"></param>
/// <param name="timeout"></param>
[Obsolete("Use Session(Session session) { Timeout = ... }; instead.")]
public Session(Session session, int timeout)
: this(session)
{
if (JsonRpcClient != null)
{
JsonRpcClient.Timeout = timeout;
}
}

/// <summary>
/// Create a new Session instance, using the given instance. The connection details
/// and Xen-API session handle will be copied from the given instance, but a new
Expand Down Expand Up @@ -175,6 +144,14 @@ private void SetAPIVersion()
Host host = Host.get_record(this, pool.master);
APIVersion = Helper.GetAPIVersion(host.API_version_major, host.API_version_minor);
}

if (JsonRpcClient != null)
{
if (APIVersion == API_Version.API_2_6)
JsonRpcClient.JsonRpcVersion = JsonRpcVersion.v1;
else if (APIVersion >= API_Version.API_2_8)
JsonRpcClient.JsonRpcVersion = JsonRpcVersion.v2;
}
}

private void CopyADFromSession(Session session)
Expand Down
28 changes: 4 additions & 24 deletions ocaml/sdk-gen/csharp/templates/ApiVersion.mustache
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,6 @@
*/

using System;
using System.Collections;
using System.Collections.Generic;


namespace XenAPI
{
Expand Down Expand Up @@ -63,8 +60,7 @@ namespace XenAPI
{
try
{
return (API_Version)Enum.Parse(typeof(API_Version),
string.Format("API_{0}_{1}", major, minor));
return (API_Version)Enum.Parse(typeof(API_Version), $"API_{major}_{minor}");
}
catch (ArgumentException)
{
Expand All @@ -82,30 +78,14 @@ namespace XenAPI
{
string[] tokens = version.Split('.');
int major, minor;
if (tokens.Length == 2 && int.TryParse(tokens[0], out major) && int.TryParse(tokens[1], out minor))
if (tokens.Length == 2 &&
int.TryParse(tokens[0], out major) &&
int.TryParse(tokens[1], out minor))
{
return GetAPIVersion(major, minor);
}
}
return API_Version.UNKNOWN;
}

/// <summary>
/// Return a positive number if the given session's API version is greater than the given
/// API_version, negative if it is less, and 0 if they are equal.
/// </summary>
internal static int APIVersionCompare(Session session, API_Version v)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why remove those functions?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These methods are not visible outside the library because they are internal. Inside the library they are not used, which means they are not needed.
Now, if someone has implemented the SDK in the way XenCenter has, the methods might be in use, however, XC's design is not ideal and should not be encouraged because it leads to complicated code.

{
return (int)session.APIVersion - (int)v;
}

/// <summary>
/// Return true if the given session's API version is greater than or equal to the given
/// API_version.
/// </summary>
internal static bool APIVersionMeets(Session session, API_Version v)
{
return APIVersionCompare(session, v) >= 0;
}
}
}
73 changes: 5 additions & 68 deletions ocaml/sdk-gen/powershell/autogen/src/CommonCmdletFunctions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,14 +39,11 @@

namespace Citrix.XenServer
{
class CommonCmdletFunctions
internal class CommonCmdletFunctions
{
private const string SessionsVariable = "global:Citrix.XenServer.Sessions";

private const string DefaultSessionVariable = "global:XenServer_Default_Session";

private const string KnownServerCertificatesFilePathVariable = "global:KnownServerCertificatesFilePath";

static CommonCmdletFunctions()
{
Session.UserAgent = string.Format("XenServerPSModule/{0}", Assembly.GetExecutingAssembly().GetName().Version);
Expand Down Expand Up @@ -78,72 +75,12 @@ internal static void SetDefaultXenSession(PSCmdlet cmdlet, Session session)
cmdlet.SessionState.PSVariable.Set(DefaultSessionVariable, session);
}

internal static string GetKnownServerCertificatesFilePathVariable(PSCmdlet cmdlet)
{
var knownCertificatesFilePathObject = cmdlet.SessionState.PSVariable.GetValue(KnownServerCertificatesFilePathVariable);
if (knownCertificatesFilePathObject is PSObject psObject)
return psObject.BaseObject as string;
return knownCertificatesFilePathObject?.ToString() ?? string.Empty;
}

internal static string GetUrl(string hostname, int port)
{
return string.Format("{0}://{1}:{2}", port == 80 ? "http" : "https", hostname, port);
}

public static Dictionary<string, string> LoadCertificates(PSCmdlet cmdlet)
{
Dictionary<string, string> certificates = new Dictionary<string, string>();
var knownServerCertificatesFilePath = GetKnownServerCertificatesFilePathVariable(cmdlet);

if (File.Exists(knownServerCertificatesFilePath))
{
XmlDocument doc = new XmlDocument();
doc.Load(knownServerCertificatesFilePath);

foreach (XmlNode node in doc.GetElementsByTagName("certificate"))
{
XmlAttribute hostAtt = node.Attributes?["hostname"];
XmlAttribute fngprtAtt = node.Attributes?["fingerprint"];

if (hostAtt != null && fngprtAtt != null)
certificates[hostAtt.Value] = fngprtAtt.Value;
}
}

return certificates;
}

public static void SaveCertificates(PSCmdlet cmdlet, Dictionary<string, string> certificates)
{
var knownServerCertificatesFilePath = GetKnownServerCertificatesFilePathVariable(cmdlet);
string dirName = Path.GetDirectoryName(knownServerCertificatesFilePath);

if (!Directory.Exists(dirName))
Directory.CreateDirectory(dirName);

XmlDocument doc = new XmlDocument();
XmlDeclaration decl = doc.CreateXmlDeclaration("1.0", "utf-8", null);
doc.AppendChild(decl);
XmlNode node = doc.CreateElement("certificates");

foreach (KeyValuePair<string, string> cert in certificates)
{
XmlNode certNode = doc.CreateElement("certificate");
XmlAttribute hostname = doc.CreateAttribute("hostname");
XmlAttribute fingerprint = doc.CreateAttribute("fingerprint");
hostname.Value = cert.Key;
fingerprint.Value = cert.Value;
certNode.Attributes?.Append(hostname);
certNode.Attributes?.Append(fingerprint);
node.AppendChild(certNode);
}

doc.AppendChild(node);
doc.Save(knownServerCertificatesFilePath);
return $"{(port == 80 ? "http" : "https")}://{hostname}:{port}";
}

public static string FingerprintPrettyString(string fingerprint)
internal static string FingerprintPrettyString(string fingerprint)
{
List<string> pairs = new List<string>();
while (fingerprint.Length > 1)
Expand All @@ -157,7 +94,7 @@ public static string FingerprintPrettyString(string fingerprint)
return string.Join(":", pairs.ToArray());
}

public static Dictionary<T, S> ConvertHashTableToDictionary<T, S>(Hashtable tbl)
internal static Dictionary<T, S> ConvertHashTableToDictionary<T, S>(Hashtable tbl)
{
if (tbl == null)
return null;
Expand All @@ -169,7 +106,7 @@ public static Dictionary<T, S> ConvertHashTableToDictionary<T, S>(Hashtable tbl)
return dict;
}

public static Hashtable ConvertDictionaryToHashtable<T, S>(Dictionary<T, S> dict)
internal static Hashtable ConvertDictionaryToHashtable<T, S>(Dictionary<T, S> dict)
{
if (dict == null)
return null;
Expand Down
83 changes: 71 additions & 12 deletions ocaml/sdk-gen/powershell/autogen/src/Connect-XenServer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,20 +29,24 @@

using System;
using System.Collections.Generic;
using System.IO;
using System.Management.Automation;
using System.Net;
using System.Net.Security;
using System.Runtime.InteropServices;
using System.Security;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using System.Xml;
using XenAPI;

namespace Citrix.XenServer.Commands
{
[Cmdlet("Connect", "XenServer")]
public class ConnectXenServerCommand : PSCmdlet
{
private const string CertificatesPathVariable = "global:KnownServerCertificatesFilePath";

private readonly object _certificateValidationLock = new object();

public ConnectXenServerCommand()
Expand Down Expand Up @@ -214,7 +218,10 @@ protected override void ProcessRecord()
{
if (ShouldContinue(ex.Message, ex.Caption))
{
AddCertificate(ex.Hostname, ex.Fingerprint);
var certPath = GetCertificatesPath();
var certificates = LoadCertificates(certPath);
certificates[ex.Hostname] = ex.Fingerprint;
SaveCertificates(certPath, certificates);
i--;
continue;
}
Expand Down Expand Up @@ -254,13 +261,6 @@ protected override void ProcessRecord()
WriteObject(newSessions.Values, true);
}

private void AddCertificate(string hostname, string fingerprint)
{
var certificates = CommonCmdletFunctions.LoadCertificates(this);
certificates[hostname] = fingerprint;
CommonCmdletFunctions.SaveCertificates(this, certificates);
}

private bool ValidateServerCertificate(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
{
if (sslPolicyErrors == SslPolicyErrors.None)
Expand All @@ -277,11 +277,11 @@ private bool ValidateServerCertificate(object sender, X509Certificate certificat

bool trusted = VerifyInAllStores(new X509Certificate2(certificate));

var certificates = CommonCmdletFunctions.LoadCertificates(this);
var certPath = GetCertificatesPath();
var certificates = LoadCertificates(certPath);

if (certificates.ContainsKey(hostname))
if (certificates.TryGetValue(hostname, out var fingerprintOld))
{
string fingerprintOld = certificates[hostname];
if (fingerprintOld == fingerprint)
return true;

Expand All @@ -295,7 +295,7 @@ private bool ValidateServerCertificate(object sender, X509Certificate certificat
}

certificates[hostname] = fingerprint;
CommonCmdletFunctions.SaveCertificates(this, certificates);
SaveCertificates(certPath, certificates);
return true;
}
}
Expand All @@ -312,6 +312,65 @@ private bool VerifyInAllStores(X509Certificate2 certificate2)
return false;
}
}

private string GetCertificatesPath()
{
var certPathObject = SessionState.PSVariable.GetValue(CertificatesPathVariable);

return certPathObject is PSObject psObject
? psObject.BaseObject as string
: certPathObject?.ToString() ?? string.Empty;
}

private Dictionary<string, string> LoadCertificates(string certPath)
{
var certificates = new Dictionary<string, string>();

if (File.Exists(certPath))
{
var doc = new XmlDocument();
doc.Load(certPath);

foreach (XmlNode node in doc.GetElementsByTagName("certificate"))
{
var hostAtt = node.Attributes?["hostname"];
var fngprtAtt = node.Attributes?["fingerprint"];

if (hostAtt != null && fngprtAtt != null)
certificates[hostAtt.Value] = fngprtAtt.Value;
}
}

return certificates;
}

private void SaveCertificates(string certPath, Dictionary<string, string> certificates)
{
string dirName = Path.GetDirectoryName(certPath);

if (!Directory.Exists(dirName))
Directory.CreateDirectory(dirName);

XmlDocument doc = new XmlDocument();
XmlDeclaration decl = doc.CreateXmlDeclaration("1.0", "utf-8", null);
doc.AppendChild(decl);
XmlNode node = doc.CreateElement("certificates");

foreach (KeyValuePair<string, string> cert in certificates)
{
XmlNode certNode = doc.CreateElement("certificate");
XmlAttribute hostname = doc.CreateAttribute("hostname");
XmlAttribute fingerprint = doc.CreateAttribute("fingerprint");
hostname.Value = cert.Key;
fingerprint.Value = cert.Value;
certNode.Attributes?.Append(hostname);
certNode.Attributes?.Append(fingerprint);
node.AppendChild(certNode);
}

doc.AppendChild(node);
doc.Save(certPath);
}
}

internal abstract class CertificateValidationException : Exception
Expand Down
Loading