239 lines
8.2 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Security.Cryptography;
using System.Net;
using System.Net.Sockets;
using System.IO;
using System.Xml;
using System.Security.Cryptography.X509Certificates;
using System.Security;
namespace Intel.Management.Wsman
{
class ClientRequest : IDisposable
{
private readonly HttpTransport _transport; //message transport
public ClientRequest(Uri address, AddressFamily addressType)
{
_transport = string.Compare(address.Scheme, "https", true) == 0
? new TlsTransport(addressType, address)
: new PlainTextTransport(addressType, address);
}
public Uri Address => _transport.Address;
/// <summary>
/// Sends the XML to Amt and returns the response XML
/// </summary>
/// <param name="reqDoc">The XML to send</param>
/// <param name="soapCmd">Optional Soap Action to send</param>
/// <returns></returns>
public ServerResponse Send(XmlDocument reqDoc, string soapCmd)
{
ServerResponse result = null;
string proxyToken = null;
string authToken = null;
// make sure there is authorization
GetAuthorization();
int retry = _transport.Authorization.MaxAttempts;
// _transport.Proxy = new HttpProxy("http://localhost:8080","randy","P@ssw0rd");
while (retry >0)
{
if (authToken == null)
{
switch (_transport.Authorization.State)
{
case HandshakeState.CredentialsAquired:
// get the initial token (this message will be sent with it)
authToken = _transport.Authorization.GetInitialToken();
break;
case HandshakeState.ResponseNeeded:
// get the next token (this message will be sent with it)
authToken = _transport.Authorization.GetNextToken();
break;
case HandshakeState.Failed:
break; // result may null
}
}
int contentLength = -1;
if (reqDoc != null)
{
byte[] data = Encoding.UTF8.GetBytes(reqDoc.OuterXml);
contentLength = data.Length;
}
using (StringWriter writer = new StringWriter())
{
writer.Write("POST ");
writer.Write(_transport.GetRequestUri());
writer.Write(" HTTP/1.1");
writer.WriteLine();
writer.Write("Host: ");
writer.Write(_transport.Address.Authority);
writer.WriteLine();
writer.Write("User-Agent: AmtClient/1.0");
writer.WriteLine();
writer.Write("Content-Type: text/xml; charset=utf-8");
writer.WriteLine();
writer.Write("Content-Length: ");
writer.Write(contentLength.ToString());
writer.WriteLine();
writer.Write("Connection: keep-alive");
writer.WriteLine();
if (authToken != null && !authToken.Equals(string.Empty))
{
writer.Write("Authorization: ");
writer.Write(authToken);
writer.WriteLine();
}
if (proxyToken != null)
{
writer.Write("Proxy-Authorization: ");
writer.Write(proxyToken);
writer.WriteLine();
}
// add optional SoapAction
if (soapCmd != null)
{
writer.Write("SOAPAction: ");
if (!soapCmd.StartsWith("\""))
writer.Write("\"");
writer.Write(soapCmd);
if (!soapCmd.StartsWith("\""))
writer.Write("\"");
writer.WriteLine();
}
writer.WriteLine();
_transport.InitializeRequest();
//send headers first
_transport.SendMessageHeaders(writer.ToString());
}
//next send body (if any)
if (reqDoc != null)
_transport.SendMessageBody(reqDoc.OuterXml);
result=_transport.GetResponse("POST");
proxyToken = null;
if (result.StatusCode == 401 || result.StatusCode==407 )
{
if (result.StatusCode == 401)
{
if (_transport.Authorization.State != HandshakeState.ResponseNeeded)
retry = 0;
retry--;
if (retry > 0)
_transport.Authorization.SetReturnToken(result.Challange);
}
// if we have a proxy challange then get the proxy authorization
if (!string.IsNullOrEmpty(result.ProxyChallange))
{
proxyToken = _transport.GetProxyAuthorization("POST", _transport.Address.LocalPath, result);
retry = 3;
}
else
{
authToken = null; // only keep the authToken if we have a proxy challenge
}
}
else
{
retry = 0;
authToken = null;
}
}
return result;
}
/// <summary>
/// Sends the XML to Amt and returns the response XML
/// </summary>
/// <param name="reqDoc">The XML to send</param>
/// <returns></returns>
public ServerResponse Send(XmlDocument reqDoc)
{
return Send(reqDoc, null);
}
public ISecurityHandshake GetAuthorization()
{
if (_transport.Authorization == null)
_transport.Authorization = new AnonymousAuthorization();
return _transport.Authorization;
}
public void SetProxy(HttpProxy proxy)
{
_transport.Proxy = proxy;
}
public void SetWindowsAuthorization(string user, string domain, SecureString password, string spn)
{
if (string.IsNullOrEmpty(spn))
spn = "HTTP/" + Address?.Authority.ToUpper();
_transport.Authorization = new WindowsAuthorization(user, domain, password, spn);
}
public void SetDigestAuthorization(string user, SecureString password)
{
_transport.Authorization = new DigestAuthorization(user, password, _transport.Address.LocalPath, "POST");
}
public void SetAnonymousAuthorization()
{
_transport.Authorization = new AnonymousAuthorization();
}
public void SetCertificate(X509Certificate2 cert)
{
_transport.SetCredentials(cert);
}
public void SetCertificateOptions(bool verifyCa,bool verifyCN, bool sendRoot)
{
_transport.SetCertificateValidationOptions(verifyCa, verifyCN, sendRoot);
}
#region IDisposable Members
private bool _disposed = false;
protected virtual void Dispose(bool disposing)
{
if (_disposed)
return;
if (disposing)
{
_transport?.Dispose();
}
_disposed = true;
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
#endregion
}
}//end namespace