SSL:tomcat server.xml配置
<!-- SSL -->
<Connector port="8443" maxHttpHeaderSize="8192"
SSLEnabled="true"
maxThreads="150"
minSpareThreads="25"
maxSpareThreads="75"
enableLookups="false"
disableUploadTimeout="true"
acceptCount="100"
scheme="https"
secure="true"
clientAuth="false"
sslProtocol="TLS"
keystoreFile="D:\tomcat6\conf\ssl\server.jks"
keystorePass="123456"
algorithm="SunX509"
/>
<!-- SSL END -->
<!-- CXF 服务端 -->
<jaxws:endpoint id="userWebService" implementor="#userServiceImpl"
address="/userservice">
<jaxws:inInterceptors>
<bean class="org.apache.cxf.interceptor.LoggingInInterceptor"></bean>
<bean class="org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor" >
<constructor-arg>
<map>
<entry key="action" value="UsernameToken Timestamp" />
<!-- MD5加密明文密码 -->
<entry key="passwordType" value="PasswordDigest" />
<entry key="user" value="admin" />
<entry key="passwordCallbackRef" >
<ref bean="serverPasswordCallback" />
</entry>
</map>
</constructor-arg>
</bean>
</jaxws:inInterceptors>
<jaxws:outInterceptors>
<bean class="org.apache.cxf.interceptor.LoggingOutInterceptor"></bean>
</jaxws:outInterceptors>
</jaxws:endpoint>
<bean id="serverPasswordCallback" class="com.cxf.webservice.callback.ServerPasswordCallback"></bean>
com.cxf.webservice.callback.ServerPasswordCallback:用于密码验证
package com.cxf.webservice.callback;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.UnsupportedCallbackException;
import org.apache.log4j.Logger;
import org.apache.ws.security.WSPasswordCallback;
public class ServerPasswordCallback implements CallbackHandler {
Logger log = Logger.getLogger(ServerPasswordCallback.class);
Map<String, String> user = new HashMap<String, String>();
{
user.put("admin", "1234");
user.put("su", "1234");
}
@Override
public void handle(Callback[] callbacks) throws IOException,
UnsupportedCallbackException {
log.debug("handler passwordcallback method....");
WSPasswordCallback wpc = (WSPasswordCallback) callbacks[0];
if (!user.containsKey(wpc.getIdentifier())) {
throw new SecurityException("No Permission!");
}
/*
* 此处特别注意::
* WSPasswordCallback 的passwordType属性和password 属性都为null,
* 你只能获得用户名(identifier),
* 一般这里的逻辑是使用这个用户名到数据库中查询其密码,
* 然后再设置到password 属性,WSS4J 会自动比较客户端传来的值和你设置的这个值。
* 你可能会问为什么这里CXF 不把客户端提交的密码传入让我们在ServerPasswordCallbackHandler 中比较呢?
* 这是因为客户端提交过来的密码在SOAP 消息中已经被加密为MD5 的字符串,
* 如果我们要在回调方法中作比较,那么第一步要做的就是把服务端准备好的密码加密为MD5 字符串,
* 由于MD5 算法参数不同结果也会有差别,另外,这样的工作CXF 替我们完成不是更简单吗?
*/
wpc.setPassword(user.get(wpc.getIdentifier()));//如果包含用户名,就设置该用户名正确密码,由CXF验证密码
String username = wpc.getIdentifier();
String password = wpc.getPassword();
log.debug("username: "+username + " password: "+password);
log.info("User : "+wpc.getIdentifier()+ " login!!!!!");
}
}
客户端:
<bean id="clientPasswordCallback" class="webservice.cxf.clientPasswordCalback.ClientPasswordCallback"></bean>
<!-- SSL -->
<!-- CXF 客户端 -->
<bean id="userServiceSSL" class="webservice.cxf.client.UserService" factory-bean="clientFactorySSL" factory-method="create" />
<bean id="clientFactorySSL" class="org.apache.cxf.jaxws.JaxWsProxyFactoryBean">
<property name="address" value="https://127.0.0.1:8443/HSQLDB/webservice/userservice"></property>
<property name="serviceClass" value="webservice.cxf.client.UserService"></property>
<property name="outInterceptors">
<list>
<bean class="org.apache.cxf.interceptor.LoggingOutInterceptor" />
<bean class="org.apache.cxf.ws.security.wss4j.WSS4JOutInterceptor">
<constructor-arg>
<map>
<entry key="action" value="UsernameToken Timestamp" />
<!-- MD5加密明文密码 -->
<entry key="passwordType" value="PasswordDigest" />
<entry key="user" value="admin" />
<entry key="passwordCallbackRef">
<ref bean="clientPasswordCallback" />
</entry>
</map>
</constructor-arg>
</bean>
</list>
</property>
</bean>
webservice.cxf.clientPasswordCalback.ClientPasswordCallback:设置密码
package webservice.cxf.clientPasswordCalback;
import java.io.IOException;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.UnsupportedCallbackException;
import org.apache.ws.security.WSPasswordCallback;
public class ClientPasswordCallback implements CallbackHandler {
@Override
public void handle(Callback[] callbacks) throws IOException,
UnsupportedCallbackException {
for (Callback callback : callbacks) {
//设置用户密码,供服务端验证
WSPasswordCallback wsc = (WSPasswordCallback)callback;
wsc.setIdentifier("su");
wsc.setPassword("1234");
}
}
}
Test:
package cxf.client.test;
import java.io.IOException;
import java.io.InputStream;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;
import java.util.List;
import javax.net.ssl.KeyManager;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import org.apache.cxf.configuration.jsse.TLSClientParameters;
import org.apache.cxf.endpoint.Client;
import org.apache.cxf.frontend.ClientProxy;
import org.apache.cxf.transport.http.HTTPConduit;
import org.junit.Before;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import webservice.cxf.client.Person;
import webservice.cxf.client.UserService;
public class Spring_Cxf_Client_Test {
ApplicationContext app ;
@Before
public void initAPP(){
app = new ClassPathXmlApplicationContext("cxf-client.xml");
}
private final static String trustStore = "truststore.jks";
private final static String keyStore = "client.jks";
private final static String trustStorePass = "123456";
private final static String keyStorePass = "123456";
@Test
public void testSSL() throws IOException{
UserService us = (UserService) app.getBean("userServiceSSL");
Client proxy = ClientProxy.getClient(us);
HTTPConduit conduit = (HTTPConduit) proxy.getConduit();
TLSClientParameters tlsParams = conduit.getTlsClientParameters();
if (tlsParams == null) {
tlsParams = new TLSClientParameters();
}
tlsParams.setSecureSocketProtocol("SSL");
tlsParams.setKeyManagers(getKeyManagers());
tlsParams.setTrustManagers(getTrustManagers());
conduit.setTlsClientParameters(tlsParams);
String response = us.sayhello("SSL");
System.out.println(response);
List<Person> ps = us.getAllUser();
for (Person person : ps) {
System.out.println("#####"+person.getId()+"#####"+person.getName()+"#####"+person.getCity()+"#####");
}
}
private static TrustManager[] getTrustManagers() throws IOException {
try {
String alg = TrustManagerFactory.getDefaultAlgorithm();
TrustManagerFactory factory = TrustManagerFactory.getInstance(alg);
InputStream fp = Spring_Cxf_Client_Test.class.getResourceAsStream(trustStore);
KeyStore ks = KeyStore.getInstance("JKS");
ks.load(fp, trustStorePass.toCharArray());
fp.close();
factory.init(ks);
TrustManager[] tms = factory.getTrustManagers();
return tms;
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (KeyStoreException e) {
e.printStackTrace();
} catch (CertificateException e) {
e.printStackTrace();
}
return null;
}
private static KeyManager[] getKeyManagers() throws IOException {
try {
String alg = KeyManagerFactory.getDefaultAlgorithm();
KeyManagerFactory factory = KeyManagerFactory.getInstance(alg);
InputStream fp = Spring_Cxf_Client_Test.class.getResourceAsStream(keyStore);
KeyStore ks = KeyStore.getInstance("JKS");
ks.load(fp, keyStorePass.toCharArray());
fp.close();
factory.init(ks, keyStorePass.toCharArray());
KeyManager[] keyms = factory.getKeyManagers();
return keyms;
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (KeyStoreException e) {
e.printStackTrace();
} catch (CertificateException e) {
e.printStackTrace();
} catch (UnrecoverableKeyException e) {
e.printStackTrace();
}
return null;
}
}