1、 重写transport Sender类并重定义axis2的配置文件。
参考http://www.cnblogs.com/SoYoung/archive/2012/04/08/Custom_SSL_in_Axis2.html
主要目的是需要实现一个SSLcontext(注:主要是实现自己的SSLProtocolSocketFactory,在getSSLContext方法里面使用下面方式构造一个SSLContent并返回,下面这段代码是写到了createSocket里面了,可以分开来)
SSLContext ctx = SSLContext.getInstance("SSL");
KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
KeyStore ks = KeyStore.getInstance("JKS");
KeyStore tks = KeyStore.getInstance("JKS");
ks.load(new FileInputStream("data/kclient.keystore"), CLIENT_KEY_STORE_PASSWORD.toCharArray());
tks.load(new FileInputStream("data/tclient.keystore"), CLIENT_TRUST_KEY_STORE_PASSWORD.toCharArray());
kmf.init(ks, CLIENT_KEY_STORE_PASSWORD.toCharArray());
tmf.init(tks);
ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
return (SSLSocket) ctx.getSocketFactory().createSocket(DEFAULT_HOST, DEFAULT_PORT);
有了SSLContext后
可以按如下方式使用HttpClient
Protocol myhttps =new Protocol("https", new MySecureProtocolSocketFactory (), 443);
Protocol.registerProtocol("https", myhttps);
HttpClient httpclient=new HttpClient();
自定义transport Sender类(关键步骤)
<transportSender name="https" class="com.**.**.common.MyHTTPTransport">
<parametername="PROTOCOL">HTTP/1.0</parameter>
<parametername="Transfer-Encoding">chunked</parameter>
</transportSender>
创建java类MyHTTPTransport直接继承TransportSender,并且复制其中的方法。
在其中的writeMessageWithCommons方法中会使用到AbstractHTTPSender和HttpSender,同样的方法,继承并复制其中的方法创建MyAbstractHTTPSender和MyHttpSender类。
配置了自定义的处理类后,剩下的是如何传入定制的SSLcontext和如何在httpsender中使用它
在HttpSender中的getHostConfiguration方法中会看到这么一段话:(Axis2的开发人员很幽默)
// I assume the 90% case, or even 99% case will be no protocolhandler case.
if (protocolHandler ==null) {
config.setHost(targetURL.getHost(), port, targetURL.getProtocol());
} else {
config.setHost(targetURL.getHost(), port, protocolHandler);
}
如此则可以将上面自定的protocol(包含配置好的sslcontext)传进来即可,通过configContext传入(注:下面这段代码写在构建stub时,可以把keystore文件路径的设置也提前到这里来)
String path =FileUtil.getWebInfPath();
ConfigurationContext configContext = ConfigurationContextFactory
.createConfigurationContextFromFileSystem(path, path +"conf/axis2.xml");
AuthSSLProtocolSocketFactory sslProtocalFactory = newAuthSSLProtocolSocketFactory(vdiConfig.getCertStream(),vdiConfig.getPk());
ProtocolSocketFactory socketFactory = (ProtocolSocketFactory)sslProtocalFactory;
Protocol authhttps = new Protocol("https",socketFactory,443);
configContext.setProperty("httpsProtocol", authhttps);
vdistub = new VdsServiceStub(configContext,ItaURL);
然后在HttpSender中的getHostConfiguration方法中加入设置代码
Protocol authhttps =(Protocol)msgCtx.getConfigurationContext().getProperty("httpsProtocol");
protocolHandler = authhttps;
2、 直接使用rampart的配置方式
参考:http://blog.csdn.net/lifetragedy/article/details/7844589
下面是实际项目中使用的(当然隐藏了敏感字)
<!-- 对此服务启用rampart模块 -->
<module ref="rampart" />
<parametername="OutflowSecurity">
<action>
<items>TimestampSignature</items>
<timeToLive>60000</timeToLive>
<!-- user要跟证书上别名一致 -->
<user>gsdfsdf</user>
<signaturePropFile>conf/client.properties</signaturePropFile>
<passwordCallbackClass>***.PWCBHandler</passwordCallbackClass>
<signatureKeyIdentifier>X509KeyIdentifier</signatureKeyIdentifier>
</action>
</parameter>
org.apache.ws.security.crypto.provider=org.apache.ws.security.components.crypto.Merlin
org.apache.ws.security.crypto.merlin.keystore.type=pkcs12
org.apache.ws.security.crypto.merlin.keystore.password=888888
org.apache.ws.security.crypto.merlin.file=conf/client.p12
在代码中只需要指定axis2.xml配置文件,其他什么都不用动了:
String path = FileUtil.getWebInfPath();
ConfigurationContextconfigContext = ConfigurationContextFactory
.createConfigurationContextFromFileSystem(path,path + "conf/axis2.xml");
configContext.setProperty(HTTPConstants.REUSE_HTTP_CLIENT, Boolean.TRUE);
3、 重写org.apache.ws.security.crypto.provider的方式。
这种方式是第2种的变种版本,某些特殊的情况如将priKey和证书存到数据库中的情况可以使用。
publicclass CustomizableCrypto implements Crypto
{
/**
* 构造X509格式证书的工厂变量
*/
private CertificateFactory certFact;
/**
* 获取构造X509格式证书的工厂变量(单例模式)
*
* @return证书工厂变量
*/
publicsynchronizedCertificateFactory getCertificateFactory()
{
if (certFact == null)
{
try
{
certFact =CertificateFactory.getInstance("X.509");
}
catch(CertificateException e)
{
if (logger.isErrorEnable())
{
logger.error("Fail to get CertificateFactory");
}
}
returncertFact;
}
returncertFact;
}
public PrivateKeygetPrivateKey(String keyName, String passwrod)
{
PEMReader pemIn;
ByteArrayInputStreampemByteIn = new ByteArrayInputStream(getprivatekey(keyName));
pemIn = new PEMReader(newInputStreamReader(pemByteIn));
return ((KeyPair) pemIn.readObject()).getPrivate();
}
public X509Certificate[]getCertificates(String keyName)
{
X509Certificate[] certList= new X509Certificate[1];
// 从psql中取出证书并转换为X509格式证书
CertificateFactory cf = null;
X509Certificate cert = null;
cf = getCertificateFactory();
ByteArrayInputStream bais =new ByteArrayInputStream(getCertificate(keyName));
cert = (X509Certificate)cf.generateCertificate(bais);
certList[0] = cert;
return certList;
}
其他方法空实现....
}