如何使用安全字符串密码从 C# 程序登录 XEN 会话?
How do I login to a XEN session from a C# program using a secure string password?
我正在使用 PowerShell 5.1、Visual Studio 2017、C# 和 XenServer SDK 7.1.1。
在 PowerShell 程序中使用 Get-Credentials 和 Export-CliXml,我已将 root 用户的池主服务器登录凭据保存到 XML 凭据文件 (xml_creds.xml)
现在,我想使用 C# 创建并登录会话(请参见下面的代码)。如您所见,我被迫将我的安全字符串转换为纯文本字符串以满足 Xen .NET API 的 login_with_password
方法的签名。
使用 API,如何使用安全字符串登录会话?
代码
try
{
securedPassword = new SecureString();
string unsecuredPassword = "";
Runspace rs = RunspaceFactory.CreateRunspace();
rs.Open();
Pipeline pipeline = rs.CreatePipeline(@"Import-CliXml 'C:\foo\xml_creds.xml';");
Collection<PSObject> results = pipeline.Invoke();
if (results.Count == 1)
{
PSObject psOutput = results[0];
securedPassword = ((PSCredential)psOutput.BaseObject).Password;
unsecuredPassword = new System.Net.NetworkCredential(string.Empty, securedPassword).Password;
username = ((PSCredential)psOutput.BaseObject).UserName;
rs.Close();
session = new Session(hostname, port);
session.login_with_password(username, unsecuredPassword, API_Version.API_1_3);
}
else
{
throw new System.Exception("Could not obtain pool master server credentials");
}
}
catch (Exception e1)
{
System.Console.WriteLine(e1.Message);
}
finally
{
if (securedPassword != null)
{
securedPassword.Dispose();
}
if (session != null)
{
session.logout(session);
}
}
我联系了 Citrix。
The Xen API does not provide a mechanism for logging into a session using a secure string password.
因此,我最终使用了一个 C# 程序,该程序执行两个支持安全字符串密码的 PowerShell
脚本。
查看下面的代码。
Notes:
I have the 7.1.1 XenServerPSModule installed in
%USERPROFILE%\Documents\WindowsPowerShell\Modules\XenServerPSModule. This module provides the Connect-XenServer cmdlet
I created the xml credentials file using PowerShell get-credentials
followed by using export-clixml
I loaded the requisite System.Management.Automation
reference by installing
Microsoft.PowerShell.5.ReferenceAssemblies
from NuGet
form1.cs(表单只有一个按钮)
using System;
using System.Windows.Forms;
using XenSnapshotsXenAccess;
namespace Create_XenSnapshotsUi
{
public partial class Form1 : Form
{
XenSessionAccess xenSession = null;
public Form1()
{
InitializeComponent();
}
private void Button1_Click(object sender, EventArgs e)
{
xenSession = new XenSessionAccess("https://xxx.xx.x.x", @"C:\foo\xml_credentials.xml");
xenSession.Logout();
}
}
}
XenSessionAccess class
using System;
using System.Collections.ObjectModel;
using System.Management.Automation;
using System.Management.Automation.Runspaces;
using XenAPI;
namespace XenSnapshotsXenAccess
{
public class XenSessionAccess
{
private Session xenSession = null;
public Session XenSession { get => xenSession; set => xenSession = value; }
public void Logout()
{
if (XenSession != null)
{
XenSession.logout(XenSession);
}
}
public XenSessionAccess(string poolMasterServerUrl, string xml_creds_path)
{
Collection<PSObject> results = null;
PSCredential psCredential = null;
//https://docs.microsoft.com/en-us/powershell/developer/hosting/creating-an-initialsessionstate
//Createdefault2* loads only the commands required to host Windows PowerShell (the commands from the Microsoft.PowerShell.Core module.
InitialSessionState initialSessionState = InitialSessionState.CreateDefault2();
using (Runspace runSpace = RunspaceFactory.CreateRunspace(initialSessionState))
{
runSpace.Open();
using (PowerShell powerShell = PowerShell.Create())
{
powerShell.Runspace = runSpace;
powerShell.AddCommand("Import-CliXml");
powerShell.AddArgument(xml_creds_path);
results = powerShell.Invoke();
if (results.Count == 1)
{
PSObject psOutput = results[0];
//cast the result to a PSCredential object
psCredential = (PSCredential)psOutput.BaseObject;
}
else
{
throw new System.Exception("Could not obtain pool master server credentials");
}
}
runSpace.Close();
}
initialSessionState = InitialSessionState.CreateDefault2();
initialSessionState.ImportPSModule(new string[] { "XenServerPSModule" });
initialSessionState.ExecutionPolicy = Microsoft.PowerShell.ExecutionPolicy.Unrestricted;
SessionStateVariableEntry psCredential_var = new SessionStateVariableEntry("psCredential", psCredential, "Credentials to log into pool master server");
initialSessionState.Variables.Add(psCredential_var);
SessionStateVariableEntry poolUrl_var = new SessionStateVariableEntry("poolUrl", poolMasterServerUrl, "Url of pool master server");
initialSessionState.Variables.Add(poolUrl_var);
using (Runspace runSpace = RunspaceFactory.CreateRunspace(initialSessionState))
{
runSpace.Open();
using (PowerShell powerShell = PowerShell.Create())
{
powerShell.Runspace = runSpace;
powerShell.AddScript(@"$psCredential | Connect-XenServer -url $poolUrl -SetDefaultSession -PassThru");
results = powerShell.Invoke();
}
if (results.Count == 1)
{
PSObject psOutput = results[0];
//cast the result to a XenAPI.Session object
XenSession = (Session)psOutput.BaseObject;
}
else
{
throw new System.Exception(String.Format("Could not create session for {0}", poolMasterServerUrl));
}
runSpace.Close();
}
}
}
}
我正在使用 PowerShell 5.1、Visual Studio 2017、C# 和 XenServer SDK 7.1.1。
在 PowerShell 程序中使用 Get-Credentials 和 Export-CliXml,我已将 root 用户的池主服务器登录凭据保存到 XML 凭据文件 (xml_creds.xml)
现在,我想使用 C# 创建并登录会话(请参见下面的代码)。如您所见,我被迫将我的安全字符串转换为纯文本字符串以满足 Xen .NET API 的 login_with_password
方法的签名。
使用 API,如何使用安全字符串登录会话?
代码
try
{
securedPassword = new SecureString();
string unsecuredPassword = "";
Runspace rs = RunspaceFactory.CreateRunspace();
rs.Open();
Pipeline pipeline = rs.CreatePipeline(@"Import-CliXml 'C:\foo\xml_creds.xml';");
Collection<PSObject> results = pipeline.Invoke();
if (results.Count == 1)
{
PSObject psOutput = results[0];
securedPassword = ((PSCredential)psOutput.BaseObject).Password;
unsecuredPassword = new System.Net.NetworkCredential(string.Empty, securedPassword).Password;
username = ((PSCredential)psOutput.BaseObject).UserName;
rs.Close();
session = new Session(hostname, port);
session.login_with_password(username, unsecuredPassword, API_Version.API_1_3);
}
else
{
throw new System.Exception("Could not obtain pool master server credentials");
}
}
catch (Exception e1)
{
System.Console.WriteLine(e1.Message);
}
finally
{
if (securedPassword != null)
{
securedPassword.Dispose();
}
if (session != null)
{
session.logout(session);
}
}
我联系了 Citrix。
The Xen API does not provide a mechanism for logging into a session using a secure string password.
因此,我最终使用了一个 C# 程序,该程序执行两个支持安全字符串密码的 PowerShell
脚本。
查看下面的代码。
Notes:
I have the 7.1.1 XenServerPSModule installed in %USERPROFILE%\Documents\WindowsPowerShell\Modules\XenServerPSModule. This module provides the Connect-XenServer cmdlet
I created the xml credentials file using PowerShell get-credentials followed by using export-clixml
I loaded the requisite
System.Management.Automation
reference by installingMicrosoft.PowerShell.5.ReferenceAssemblies
fromNuGet
form1.cs(表单只有一个按钮)
using System;
using System.Windows.Forms;
using XenSnapshotsXenAccess;
namespace Create_XenSnapshotsUi
{
public partial class Form1 : Form
{
XenSessionAccess xenSession = null;
public Form1()
{
InitializeComponent();
}
private void Button1_Click(object sender, EventArgs e)
{
xenSession = new XenSessionAccess("https://xxx.xx.x.x", @"C:\foo\xml_credentials.xml");
xenSession.Logout();
}
}
}
XenSessionAccess class
using System;
using System.Collections.ObjectModel;
using System.Management.Automation;
using System.Management.Automation.Runspaces;
using XenAPI;
namespace XenSnapshotsXenAccess
{
public class XenSessionAccess
{
private Session xenSession = null;
public Session XenSession { get => xenSession; set => xenSession = value; }
public void Logout()
{
if (XenSession != null)
{
XenSession.logout(XenSession);
}
}
public XenSessionAccess(string poolMasterServerUrl, string xml_creds_path)
{
Collection<PSObject> results = null;
PSCredential psCredential = null;
//https://docs.microsoft.com/en-us/powershell/developer/hosting/creating-an-initialsessionstate
//Createdefault2* loads only the commands required to host Windows PowerShell (the commands from the Microsoft.PowerShell.Core module.
InitialSessionState initialSessionState = InitialSessionState.CreateDefault2();
using (Runspace runSpace = RunspaceFactory.CreateRunspace(initialSessionState))
{
runSpace.Open();
using (PowerShell powerShell = PowerShell.Create())
{
powerShell.Runspace = runSpace;
powerShell.AddCommand("Import-CliXml");
powerShell.AddArgument(xml_creds_path);
results = powerShell.Invoke();
if (results.Count == 1)
{
PSObject psOutput = results[0];
//cast the result to a PSCredential object
psCredential = (PSCredential)psOutput.BaseObject;
}
else
{
throw new System.Exception("Could not obtain pool master server credentials");
}
}
runSpace.Close();
}
initialSessionState = InitialSessionState.CreateDefault2();
initialSessionState.ImportPSModule(new string[] { "XenServerPSModule" });
initialSessionState.ExecutionPolicy = Microsoft.PowerShell.ExecutionPolicy.Unrestricted;
SessionStateVariableEntry psCredential_var = new SessionStateVariableEntry("psCredential", psCredential, "Credentials to log into pool master server");
initialSessionState.Variables.Add(psCredential_var);
SessionStateVariableEntry poolUrl_var = new SessionStateVariableEntry("poolUrl", poolMasterServerUrl, "Url of pool master server");
initialSessionState.Variables.Add(poolUrl_var);
using (Runspace runSpace = RunspaceFactory.CreateRunspace(initialSessionState))
{
runSpace.Open();
using (PowerShell powerShell = PowerShell.Create())
{
powerShell.Runspace = runSpace;
powerShell.AddScript(@"$psCredential | Connect-XenServer -url $poolUrl -SetDefaultSession -PassThru");
results = powerShell.Invoke();
}
if (results.Count == 1)
{
PSObject psOutput = results[0];
//cast the result to a XenAPI.Session object
XenSession = (Session)psOutput.BaseObject;
}
else
{
throw new System.Exception(String.Format("Could not create session for {0}", poolMasterServerUrl));
}
runSpace.Close();
}
}
}
}