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; } }