天天看點

讓Apache CXF支援WS-Security規範

接上例:http://blog.csdn.net/kunshan_shenbin/archive/2008/12/26/3613918.aspx

建立2個批處理檔案用以生成服務端及用戶端密鑰檔案。

generateKeyPair.bat

  1. rem @echo off
  2. echo alias %1
  3. echo keypass %2
  4. echo keystoreName %3
  5. echo KeyStorePass %4
  6. echo keyName %5
  7. echo keyName %5
  8. keytool -genkey -alias %1 -keypass %2 -keystore %3 -storepass %4  -dname "cn=%1" -keyalg RSA
  9. keytool -selfcert -alias %1 -keystore %3 -storepass %4 -keypass %2
  10. keytool -export -alias %1 -file %5 -keystore %3 -storepass %4

generateServerKey.bat

  1. call generateKeyPair.bat serverAlias aliaspass serverStore.jks keystorePass serverKey.rsa
  2. call generateKeyPair.bat client-344-839  client344Password  clientStore.jks keystorePass clientKey.rsa
  3. keytool -import -alias serverAlias -file serverKey.rsa -keystore clientStore.jks -storepass keystorePass -noprompt
  4. keytool -import -alias client-344-839 -file clientKey.rsa -keystore serverStore.jks -storepass keystorePass -noprompt

注意:

生成的密鑰檔案中包含的資訊:

服務端 賬戶:serverAlias / aliaspass

用戶端 賬戶:client-344-839 / client344Password

依次運作後生成serverStore.jks和clientStore.jks這2個檔案待用。

如下圖所示建立工程:

讓Apache CXF支援WS-Security規範

所需lib包一覽:

XmlSchema-1.4.2.jar

commons-logging-1.1.1.jar

cxf-2.0.9.jar

jaxb-impl-2.0.5.jar

jaxws-api-2.0.jar

neethi-2.0.4.jar

opensaml-1.1.jar

saaj-api-1.3.jar

saaj-impl-1.3.jar

serializer-2.7.1.jar

spring-beans-2.0.8.jar

spring-context-2.0.8.jar

spring-core-2.0.8.jar

spring-web-2.0.8.jar

wsdl4j-1.6.2.jar

wss4j-1.5.4.jar

xalan-2.7.1.jar

xml-resolver-1.2.jar

xmlsec-1.4.0.jar

代碼如下:

TestServiceClient.java

  1. package jp.co.apm.client;
  2. import jp.co.apm.service.TestService;
  3. import org.springframework.context.ApplicationContext;
  4. import org.springframework.context.support.ClassPathXmlApplicationContext;
  5. public class TestServiceClient {
  6.     public static void main(String[] args) {
  7.         ApplicationContext context = new ClassPathXmlApplicationContext(
  8.                 new String[] { "jp/co/apm/client/clientApplicationContext.xml" });
  9.         TestService service = (TestService) context.getBean("client");
  10.         System.out.println(service.sayHello());
  11.     }
  12. }

clientApplicationContext.xml

  1. <beans xmlns="http://www.springframework.org/schema/beans"
  2.     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  3.     xmlns:jaxws="http://cxf.apache.org/jaxws"
  4.     xsi:schemaLocation="
  5.     http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
  6.     http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd">
  7.     <bean id="client" class="jp.co.apm.service.impl.TestServiceImpl" factory-bean="clientFactory" factory-method="create"/>
  8.     <bean id="clientFactory" class="org.apache.cxf.jaxws.JaxWsProxyFactoryBean">
  9.         <property name="serviceClass" value="jp.co.apm.service.TestService">
  10.         </property>
  11.         <property name="address"
  12.             value="http://localhost:8080/APM_CXF/services/test">
  13.         </property>
  14.         <property name="outInterceptors">
  15.             <list>
  16.                 <bean class="org.apache.cxf.binding.soap.saaj.SAAJOutInterceptor" />
  17.                 <ref bean="wss4jOutConfiguration" />
  18.             </list>
  19.         </property> 
  20.     </bean>
  21.     <bean id="wss4jOutConfiguration" class="org.apache.cxf.ws.security.wss4j.WSS4JOutInterceptor">
  22.         <property name="properties">
  23.             <map>
  24.                 <entry key="action" value="Signature" />
  25.                 <entry key="user" value="client-344-839" />
  26.                 <entry key="passwordType" value="PasswordDigest" />
  27.                 <entry key="signatureKeyIdentifier" value="IssuerSerial" />
  28.                 <entry key="signaturePropFile" value="jp/co/apm/client/outsecurity_sign.properties" />
  29.                 <entry>
  30.                     <key>
  31.                         <value>passwordCallbackRef</value>
  32.                     </key>
  33.                     <ref bean="passwordCallback" />
  34.                 </entry>
  35.             </map>
  36.         </property>
  37.     </bean>
  38.     <bean id="passwordCallback" class="jp.co.apm.security.PasswordCallbackHandler"/>
  39. </beans>

outsecurity_sign.properties

  1. org.apache.ws.security.crypto.provider=org.apache.ws.security.components.crypto.Merlin
  2. org.apache.ws.security.crypto.merlin.keystore.type=jks
  3. org.apache.ws.security.crypto.merlin.keystore.password=keystorePass
  4. org.apache.ws.security.crypto.merlin.alias.password=client344Password
  5. org.apache.ws.security.crypto.merlin.keystore.alias=client-344-839
  6. org.apache.ws.security.crypto.merlin.file=jp/co/apm/client/clientStore.jks

以下是服務端代碼:

PasswordCallbackHandler.java

  1. package jp.co.apm.security;
  2. import java.io.IOException;
  3. import java.util.HashMap;
  4. import java.util.Map;
  5. import javax.security.auth.callback.Callback;
  6. import javax.security.auth.callback.CallbackHandler;
  7. import javax.security.auth.callback.UnsupportedCallbackException;
  8. import org.apache.ws.security.WSPasswordCallback;
  9. public class PasswordCallbackHandler implements CallbackHandler {
  10.     private Map<String, String> passwords = new HashMap<String, String>();
  11.     public PasswordCallbackHandler() {
  12.         passwords.put("serveralias", "aliaspass");
  13.         passwords.put("client-344-839", "client344Password");
  14.     }
  15.     public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
  16.         WSPasswordCallback pc = (WSPasswordCallback) callbacks[0];
  17.         String id = pc.getIdentifer();
  18.         pc.setPassword((String) passwords.get(id));
  19.     }
  20. }

TestServiceImpl.java

  1. package jp.co.apm.service.impl;
  2. import javax.jws.WebService;
  3. import jp.co.apm.service.TestService;
  4. @WebService
  5. public class TestServiceImpl implements TestService {
  6.     public String sayHello() {
  7.         return "Hello, Shen Bin";
  8.     }
  9. }

TestService.java

  1. package jp.co.apm.service;
  2. import javax.jws.WebService;
  3. @WebService
  4. public interface TestService {
  5.     public String sayHello();
  6. }

server_insecurity_sign.properties

  1. org.apache.ws.security.crypto.provider=org.apache.ws.security.components.crypto.Merlin
  2. org.apache.ws.security.crypto.merlin.keystore.type=jks
  3. org.apache.ws.security.crypto.merlin.keystore.password=keystorePass
  4. #org.apache.ws.security.crypto.merlin.alias.password=aliaspass
  5. org.apache.ws.security.crypto.merlin.keystore.alias=serveralias
  6. org.apache.ws.security.crypto.merlin.file=serverStore.jks

cxf-servlet.xml

  1. <beans xmlns="http://www.springframework.org/schema/beans"
  2.     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  3.     xmlns:jaxws="http://cxf.apache.org/jaxws"
  4.     xsi:schemaLocation="
  5.     http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
  6.     http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd">
  7.     <import resource="classpath:META-INF/cxf/cxf.xml" />
  8.     <import resource="classpath:META-INF/cxf/cxf-extension-soap.xml" />
  9.     <import resource="classpath:META-INF/cxf/cxf-servlet.xml" />
  10.     <jaxws:endpoint id="testservice" implementor="jp.co.apm.service.impl.TestServiceImpl" address="/test">
  11.         <jaxws:features>
  12.             <bean class="org.apache.cxf.feature.LoggingFeature"/>
  13.         </jaxws:features>
  14.         <jaxws:inInterceptors>
  15.             <bean class="org.apache.cxf.binding.soap.saaj.SAAJInInterceptor"/>   
  16.             <ref bean="wss4jInConfiguration"/>
  17.         </jaxws:inInterceptors>
  18.     </jaxws:endpoint>
  19.     <bean id="wss4jInConfiguration" class="org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor">
  20.         <property name="properties">
  21.             <map>
  22.                 <entry key="action" value="Signature"/>
  23.                 <!--  
  24.                 <entry key="user" value="client-344-839" />
  25.                 <entry key="passwordType" value="PasswordDigest" />
  26.                 -->
  27.                 <entry key="signaturePropFile" value="server_insecurity_sign.properties"/>
  28.                 <entry>
  29.                     <key>
  30.                         <value>passwordCallbackRef</value>
  31.                     </key>
  32.                     <ref bean="passwordCallback"/>
  33.                 </entry>
  34.             </map>
  35.         </property>
  36.     </bean>
  37.     <bean id="passwordCallback" class="jp.co.apm.security.PasswordCallbackHandler"/>
  38. </beans>

web.xml

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
  3.     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4.     xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 
  5.     http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
  6.     <display-name>APM</display-name>
  7.     <description>APM</description>
  8.     <context-param>
  9.         <param-name>contextConfigLocation</param-name>
  10.         <param-value>WEB-INF/cxf-servlet.xml</param-value>
  11.     </context-param>
  12.     <listener>
  13.         <listener-class>
  14.             org.springframework.web.context.ContextLoaderListener
  15.         </listener-class>
  16.     </listener>
  17.     <servlet>
  18.         <servlet-name>APM</servlet-name>
  19.         <servlet-class>
  20.             org.apache.cxf.transport.servlet.CXFServlet
  21.         </servlet-class>
  22.         <load-on-startup>2</load-on-startup>
  23.     </servlet>
  24.     <servlet-mapping>
  25.         <servlet-name>APM</servlet-name>
  26.         <url-pattern>/services/*</url-pattern>
  27.     </servlet-mapping>
  28.     <session-config>
  29.         <session-timeout>60</session-timeout>
  30.     </session-config>
  31. </web-app>

差點忘了一個最重要的環節,就是要在java.security中追加一個解密算法的支援:

/jre/lib/security/java.security檔案中,追加類似如下語句:

.....

security.provider.5=sun.security.jgss.SunProvider

security.provider.6=com.sun.security.sasl.Provider

security.provider.7=org.bouncycastle.jce.provider.BouncyCastleProvider