我正在尝试基于rpc /编码格式与SOAP Web服务进行通信。它是外部Web服务,因此无法更改。它通过SSL进行保护,并且身份验证基于X509证书。
我已经使用openssl命令创建了未签名的证书和密钥文件:
openssl req -new -sha256 -newkey rsa:2048 -nodes -keyout keyfile.key -out unsigned.pem -subj '/O= <Company_name>/OU=WebApi/CN=<uid>'
,然后收到已签名的pem文件(将其命名为signed.pem)。我已将BEGIN CERTIFICATE / END CERTIFICATE内容与BEGIN PRIVATE KEY / END PRIVATE KEY内容合并到一个文件中。然后,我使用此文件(将其命名为final.pem)进行身份验证。
我有用PHP编写的简单示例代码,它确实有效:
$client = new SoapClient('https://www.url.to.external.web.service?wsdl',
array('local_cert' => "final.pem"));
$result = $client->Login();
现在我正在努力将此代码移植到.NET或Java,但更喜欢使用.NET。我会记下我的所作所为和取得的结果。
.NET
已安装xmlrpcnet库,因为我已经了解到.NET不支持现成的RPC /编码格式。我创建了代理界面:
[XmlRpcUrl("https://www.url.to.external.web.service?wsdl")]
[ServiceContract]
public interface WebServiceProxy : IXmlRpcProxy
{
[XmlRpcMethod("Login")]
[OperationContract(Action = "Login")]
LoginReturn Login();
}
稍后,我将从final.pem中提取X509Certificate2实例。我是这样做的:
public X509Certificate2 GetCertificate(string fileName)
{
var pem = File.ReadAllText(fileName);
byte[] certBuffer = GetBytesFromPEM(pem, "CERTIFICATE");
return new X509Certificate2(certBuffer);
}
private byte[] GetBytesFromPEM(string pemString, string section)
{
var header = String.Format("-----BEGIN {0}-----", section);
var footer = String.Format("-----END {0}-----", section);
var start = pemString.IndexOf(header, StringComparison.Ordinal);
if (start < 0)
return null;
start += header.Length;
var end = pemString.IndexOf(footer, start, StringComparison.Ordinal) - start;
if (end < 0)
return null;
return Convert.FromBase64String(pemString.Substring(start, end));
}
最后,我正在创建代理对象,附加证书并调用Login()方法:
var proxy = XmlRpcProxyGen.Create<WebServiceProxy>();
proxy.ClientCertificates.Add(_certificate);
proxy.Login();
但是我收到带有消息“无法创建ssl / tls安全通道”的WebException。
Java:
不幸的是,最新版本的轴库不支持RPC /编码格式,因此我下载了旧的(1.4)。然后使用工具WSDL2Java从WSDL文件生成代理类。后来我使用keytool将final.pem添加到密钥库中:
keytool -import -noprompt -trustcacerts -alias somealias -file final.pem -keystore final.jks -storepass password
并将其加载到Java代码中。然后创建了SSL上下文,创建了代理并调用了login()方法,但是不幸的是我收到了异常。
var certPath = "C:\path\to\final.jks"
var file = new File(certPath);
var keyStore = KeyStore.getInstance(file, "password".toCharArray());
SSLContext sslContext = SSLContext.getInstance("TLSv1.2");
KeyManagerFactory keyManagerFactory =
KeyManagerFactory.getInstance("SunX509");
keyManagerFactory.init(keyStore, "abcABC123".toCharArray());
sslContext.init(keyManagerFactory.getKeyManagers(), null, null);
Service service = new APILocator("https://www.url.to.external.web.service?wsdl", new QName("http://namespace.com/", "path"));
URL url = new URL("https://www.url.to.external.web.service?wsdl");
var proxy = new APIBindingStub(url, service);
proxy.login();
和我之前提到的错误:
javax.net.ssl.SSLHandshakeException:收到致命警报:handshake_failure
有人早些时候试图从.NET / Java访问此类Web服务吗?