欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

CXF Message Level Security

程序员文章站 2022-07-13 13:58:10
...
The firsts:Environment

1.Operating System Version :Fedora14
2.Eclipse Version:J2ee版3.5
3.jdk Version:jdk1.6
4.maven local repository:/var/javaproject/repo
5.tomcat Version:1.6
6.tomcat Port:9080
7.The Web service server and client use CXF can work already. refer to CXF用户认证

The second step:Create X509 certificate store
Window batch scriptt file
create a dos batch execute file name generateKeyPair.bat and input the following content
rem ************** generateKeyPair.bat ********** start
rem @echo off
echo alias %1
echo keypass %2
echo keystoreName %3
echo KeyStorePass %4
echo keyName %5
echo keyName %5
keytool -genkey -alias %1 -keypass %2 -keystore %3 -storepass %4 -dname "cn=%1" -keyalg RSA
keytool -selfcert -alias %1 -keystore %3 -storepass %4 -keypass %2
keytool -export -alias %1 -file %5 -keystore %3 -storepass %4
rem ************** generateKeyPair.bat ********** end
create a dos batch execute file name generateServerKey.bat and input the following content:
rem ************** generateServerKey.bat ********** start
call generateKeyPair.bat apmserver apmserverpass serverStore.jks keystorePass serverKey.rsa
call generateKeyPair.bat apmclient apmclientpass clientStore.jks keystorePass clientKey.rsa
keytool -import -alias apmserver -file serverKey.rsa -keystore clientStore.jks -storepass keystorePass -noprompt
keytool -import -alias apmclient -file clientKey.rsa -keystore serverStore.jks -storepass keystorePass -noprompt
rem ************** generateServerKey.bat ********** end

Linux shell scriptt :
create a Linux shell scriptt file name generateKeyPair.sh and input the following content:
# ******************* generateKeyPair.sh start ***********
#!/bin/bash
echo alias $1
echo keypass $2
echo keystoreName $3
echo KeyStorePass $4
echo keyName $5
echo keyName $5
keytool -genkey -alias $1 -keypass $2 -keystore $3 -storepass $4 -dname "cn=$1" -keyalg RSA
keytool -selfcert -alias $1 -keystore $3 -storepass $4 -keypass $2
keytool -export -alias $1 -file $5 -keystore $3 -storepass $4
# ******************* generateKeyPair.sh end ***********

create a Linux shell scriptt file name generateServerKey.sh then input the following content:
# ******************* generateServerKey.sh start ***********
#!/bin/bash
./generateKeyPair.sh apmserver apmserverpass serverStore.jks keystorePass serverKey.rsa
./generateKeyPair.sh apmclient apmclientpass clientStore.jks keystorePass clientKey.rsa
keytool -import -alias apmserver -file serverKey.rsa -keystore clientStore.jks -storepass keystorePass -noprompt
keytool -import -alias apmclient -file clientKey.rsa -keystore serverStore.jks -storepass keystorePass -noprompt
# ******************* generateServerKey.sh end ***********

3.execute the generateServerKey.sh on Linux(generateServerKey.bat on windows) then you will get two key store file clientStore.jks and serverStore.jks. As show on the shell scriptt the user name and password is:
Server:apmserver / apmserverpass
Client:apmclient / apmclientpass

The third step:Configure Server
Copy the serverStore.jks to the resource fold of the web project, The root fold of resource fold, That is the same fold as the file applicationContext-server.xml.
Create a properties file named server_insecurity_enc.properties in the same fold for server encryption then input the following content:
#-- server_insecurity_enc.properties start
org.apache.ws.security.crypto.provider=org.apache.ws.security.components.crypto.Merlin
org.apache.ws.security.crypto.merlin.keystore.type=jks
org.apache.ws.security.crypto.merlin.keystore.password=keystorePass
org.apache.ws.security.crypto.merlin.alias.password=apmserverpass
org.apache.ws.security.crypto.merlin.keystore.alias=apmserver
org.apache.ws.security.crypto.merlin.file=serverStore.jks
#-- server_insecurity_enc.properties end

Create a properties file named server_insecurity_sign.properties in the same fold for server signature then input the following content:
#-- server_insecurity_enc.properties start
org.apache.ws.security.crypto.provider=org.apache.ws.security.components.crypto.Merlin
org.apache.ws.security.crypto.merlin.keystore.type=jks
org.apache.ws.security.crypto.merlin.keystore.password=keystorePass
org.apache.ws.security.crypto.merlin.keystore.alias=apmserver
org.apache.ws.security.crypto.merlin.file=serverStore.jks
#-- server_insecurity_enc.properties end

Create a properties file named sserver_outsecurity_enc.properties in the same fold for server out encryption then input the following content:
#-- server_outsecurity_enc.properties start
org.apache.ws.security.crypto.provider=org.apache.ws.security.components.crypto.Merlin
org.apache.ws.security.crypto.merlin.keystore.type=jks
org.apache.ws.security.crypto.merlin.keystore.password=keystorePass
org.apache.ws.security.crypto.merlin.file=serverStore.jks
#-- server_outsecurity_enc.properties end

alter the service definition file applicationContext-server.xml.
<!-- applicationContext-server.xml start -->
<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:jaxws="http://cxf.apache.org/jaxws" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd">

<import resource="classpath:META-INF/cxf/cxf.xml" />
<import resource="classpath:META-INF/cxf/cxf-extension-soap.xml" />
<import resource="classpath:META-INF/cxf/cxf-servlet.xml" />

<bean id="addressBookServiceImpl" class="com.bruce.cxftest.service.AddressBookServiceImpl" />

<bean id="passwordCallback" class="com.bruce.cxftest.security.ServerPasswordCallback" />

<bean id="saajInInterceptor" class="org.apache.cxf.binding.soap.saaj.SAAJInInterceptor" />
<bean id="saajOutInterceptor" class="org.apache.cxf.binding.soap.saaj.SAAJOutInterceptor" />

<bean id="logInInterceptor" class="org.apache.cxf.interceptor.LoggingInInterceptor" />
<bean id="logOutInterceptor" class="org.apache.cxf.interceptor.LoggingOutInterceptor" />

<bean id="wss4jInConfiguration" class="org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor">
<property name="properties">
<map>
<entry key="action" value="UsernameToken Timestamp Encrypt Signature" />
<entry key="decryptionPropFile" value="server_insecurity_enc.properties" />
<entry key="signaturePropFile" value="server_insecurity_sign.properties" />
<entry>
<key>
<value>passwordCallbackRef</value>
</key>
<ref bean="passwordCallback" />
</entry>
</map>
</property>
</bean>


<bean id="wss4jOutConfiguration" class="org.apache.cxf.ws.security.wss4j.WSS4JOutInterceptor">
<property name="properties">
<map>
<entry key="action" value="Timestamp Encrypt Signature" />
<entry key="user" value="apmserver" />
<entry key="encryptionUser" value="apmclient" />
<entry key="encryptionPropFile" value="server_outsecurity_enc.properties" />
<entry key="signaturePropFile" value="server_insecurity_sign.properties" />
<entry>
<key>
<value>passwordCallbackRef</value>
</key>
<ref bean="passwordCallback" />
</entry>
</map>
</property>
</bean>

<jaxws:endpoint id="addressBookService" implementor="#addressBookServiceImpl"
address="/AddressBookService" >

<jaxws:inInterceptors>
<ref bean="logInInterceptor" />
<ref bean="saajInInterceptor" />
<ref bean="wss4jInConfiguration" />
</jaxws:inInterceptors>

<jaxws:outInterceptors>
<ref bean="logOutInterceptor" />
<ref bean="saajOutInterceptor" />
<ref bean="wss4jOutConfiguration" />
</jaxws:outInterceptors>
</jaxws:endpoint>
</beans>
<!-- applicationContext-server.xml end -->

6.alter the user name and password call back class:

//---- ServerPasswordCallback.java start
package com.bruce.cxftest.security;
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.ws.security.WSPasswordCallback;
public class ServerPasswordCallback implements CallbackHandler {
Map<String,String> userMap = new HashMap<String,String>();
public ServerPasswordCallback(){
userMap.put("apmserver", "apmserverpass");
userMap.put("apmclient", "apmclientpass");
}
public void handle(Callback[] callbacks) throws IOException,
UnsupportedCallbackException {
WSPasswordCallback pc = (WSPasswordCallback) callbacks[0];
if (userMap.containsKey(pc.getIdentifier())) {
pc.setPassword(userMap.get(pc.getIdentifier()));
}
}
}
//---- ServerPasswordCallback.java end

The fourth step :configure client
Copy the clientStore.jks to the resource fold of the client project, The root fold of resource fold, That is the same fole as the file applicationContext-client.xml.
Create a properties file named insecurity_enc.properties in the same fold for server encryption then input the following content:
#-- insecurity_enc.properties start
org.apache.ws.security.crypto.provider=org.apache.ws.security.components.crypto.Merlin
org.apache.ws.security.crypto.merlin.keystore.type=jks
org.apache.ws.security.crypto.merlin.keystore.password=keystorePass
org.apache.ws.security.crypto.merlin.alias.password=apmclientpass
org.apache.ws.security.crypto.merlin.keystore.alias=apmclient
org.apache.ws.security.crypto.merlin.file=clientStore.jks
#-- insecurity_enc.properties end

Create a properties file named outsecurity_enc.properties in the same fold for server signature then input the following content:
#-- outsecurity_enc.properties start
org.apache.ws.security.crypto.provider=org.apache.ws.security.components.crypto.Merlin
org.apache.ws.security.crypto.merlin.keystore.type=jks
org.apache.ws.security.crypto.merlin.keystore.password=keystorePass
org.apache.ws.security.crypto.merlin.alias.password=apmclientpass
org.apache.ws.security.crypto.merlin.keystore.alias=apmclient
org.apache.ws.security.crypto.merlin.file=clientStore.jks
#-- outsecurity_enc.properties end

Create a properties file named outsecurity_sign.properties in the same fold for server out encryption then input the following content:
#-- outsecurity_sign.properties start
org.apache.ws.security.crypto.provider=org.apache.ws.security.components.crypto.Merlin
org.apache.ws.security.crypto.merlin.keystore.type=jks
org.apache.ws.security.crypto.merlin.keystore.password=keystorePass
org.apache.ws.security.crypto.merlin.alias.password=apmclientpass
org.apache.ws.security.crypto.merlin.keystore.alias=apmclient
org.apache.ws.security.crypto.merlin.file=clientStore.jks
#-- outsecurity_sign.properties end

alter the client definition file applicationContext-client.xml.
<!-- applicationContext-client.xml start -->
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:jaxws="http://cxf.apache.org/jaxws" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://cxf.apache.org/jaxws
http://cxf.apache.org/schemas/jaxws.xsd">
<bean id="passwordCallback" class="com.bruce.cxftest.security.ServerPasswordCallback" />
<bean id="saajInInterceptor" class="org.apache.cxf.binding.soap.saaj.SAAJInInterceptor" />
<bean id="saajOutInterceptor" class="org.apache.cxf.binding.soap.saaj.SAAJOutInterceptor" />
<bean id="wss4jOutConfiguration" class="org.apache.cxf.ws.security.wss4j.WSS4JOutInterceptor">
<property name="properties">
<map>
<entry key="action" value="UsernameToken Timestamp Encrypt Signature" />
<entry key="user" value="apmclient" />
<entry key="encryptionUser" value="apmserver" />
<entry key="signaturePropFile" value="outsecurity_sign.properties" />
<entry key="signatureKeyIdentifier" value="IssuerSerial" />
<entry key="encryptionPropFile" value="outsecurity_enc.properties" />
<entry>
<key>
<value>passwordCallbackRef</value>
</key>
<ref bean="passwordCallback" />
</entry>
</map>
</property>
</bean>
<bean id="wss4jInConfiguration" class="org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor">
<property name="properties">
<map>
<entry key="action" value="Timestamp Encrypt Signature" />
<entry key="user" value="apmclient" />
<entry key="decryptionPropFile" value="insecurity_enc.properties" />
<entry key="enableSignatureConfirmation" value="true" />
<entry key="signaturePropFile" value="outsecurity_sign.properties" />
<entry key="signatureKeyIdentifier" value="IssuerSerial" />
<entry>
<key>
<value>passwordCallbackRef</value>
</key>
<ref bean="passwordCallback" />
</entry>
</map>
</property>
</bean>
<jaxws:client id="addressBookClient"
serviceClass="com.bruce.cxftest.service.AddressBookService"
address="http://127.0.0.1:9080/cxftest/service/AddressBookService">
<jaxws:outInterceptors>
<ref bean="saajOutInterceptor" />
<ref bean="wss4jOutConfiguration" />
</jaxws:outInterceptors>
<jaxws:inInterceptors>
<ref bean="saajInInterceptor" />
<ref bean="wss4jInConfiguration" />
</jaxws:inInterceptors>
</jaxws:client>
</beans>
<!-- applicationContext-client.xml end -->

6.alter the user name and password call back class:

//---- ServerPasswordCallback.java start
package com.bruce.cxftest.security;
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.ws.security.WSPasswordCallback;
public class ServerPasswordCallback implements CallbackHandler {
Map<String,String> userMap = new HashMap<String,String>();
public ServerPasswordCallback(){
userMap.put("apmserver", "apmserverpass");
userMap.put("apmclient", "apmclientpass");
}
public void handle(Callback[] callbacks) throws IOException,
UnsupportedCallbackException {
WSPasswordCallback pc = (WSPasswordCallback) callbacks[0];
if (userMap.containsKey(pc.getIdentifier())) {
pc.setPassword(userMap.get(pc.getIdentifier()));
}
}
}
//---- ServerPasswordCallback.java end

7. create a client class not use spring.
//--- CxfWsTestClient.java start
package com.bruce.cxftest.client;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import javax.xml.namespace.QName;
import javax.xml.ws.BindingProvider;
import org.apache.cxf.binding.soap.saaj.SAAJInInterceptor;
import org.apache.cxf.binding.soap.saaj.SAAJOutInterceptor;
import org.apache.cxf.frontend.ClientProxy;
import org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor;
import org.apache.cxf.ws.security.wss4j.WSS4JOutInterceptor;
import org.apache.ws.security.handler.WSHandlerConstants;
import com.bruce.cxftest.dto.Phone;
import com.bruce.cxftest.security.ServerPasswordCallback;
import com.bruce.cxftest.service.AddressBookService;
import com.bruce.cxftest.service.AddressBookService_Service;
public class CxfWsTestClient {
public static void main(String[] args) {
try {
URL wsdlAdd = new URL("http://127.0.0.1:9080/cxftest/service/AddressBookService?wsdl");
QName SERVICE = new QName("http://www.bruce.com/cxftest/service", "AddressBookService");
AddressBookService_Service gs = new AddressBookService_Service(wsdlAdd,SERVICE);
AddressBookService greeter = gs.getAddressBookService();
org.apache.cxf.endpoint.Client client = ClientProxy.getClient(greeter);
org.apache.cxf.endpoint.Endpoint cxfEndpoint = client.getEndpoint();
SAAJInInterceptor saajInInterceptor = new SAAJInInterceptor();
cxfEndpoint.getInInterceptors().add(saajInInterceptor);
Map<String, Object> inProps = new HashMap<String, Object>();
inProps.put(WSHandlerConstants.ACTION, WSHandlerConstants.TIMESTAMP + " " + WSHandlerConstants.ENCRYPT + " " + WSHandlerConstants.SIGNATURE);
inProps.put(WSHandlerConstants.USER, "apmclient");
inProps.put(WSHandlerConstants.DEC_PROP_FILE, "insecurity_enc.properties");
inProps.put(WSHandlerConstants.ENABLE_SIGNATURE_CONFIRMATION, "true");
inProps.put(WSHandlerConstants.SIG_PROP_FILE, "outsecurity_sign.properties");
inProps.put(WSHandlerConstants.SIG_KEY_ID, "IssuerSerial");
inProps.put(WSHandlerConstants.PW_CALLBACK_CLASS, ServerPasswordCallback.class.getName());
WSS4JInInterceptor wssIn = new WSS4JInInterceptor(inProps);
cxfEndpoint.getInInterceptors().add(wssIn);
SAAJOutInterceptor saajOutInterceptor = new SAAJOutInterceptor();
cxfEndpoint.getOutInterceptors().add(saajOutInterceptor);
Map<String, Object> outProps = new HashMap<String, Object>();
outProps.put(WSHandlerConstants.ACTION,WSHandlerConstants.USERNAME_TOKEN
+ " " + WSHandlerConstants.TIMESTAMP
+ " " + WSHandlerConstants.ENCRYPT
+ " " + WSHandlerConstants.SIGNATURE);
outProps.put(WSHandlerConstants.USER, "apmclient");
outProps.put(WSHandlerConstants.ENCRYPTION_USER, "apmserver");
outProps.put(WSHandlerConstants.SIG_PROP_FILE, "outsecurity_sign.properties");
outProps.put(WSHandlerConstants.SIG_KEY_ID, "IssuerSerial");
outProps.put(WSHandlerConstants.ENC_PROP_FILE, "insecurity_enc.properties");
outProps.put(WSHandlerConstants.PW_CALLBACK_CLASS, ServerPasswordCallback.class.getName());
WSS4JOutInterceptor wssOut = new WSS4JOutInterceptor(outProps);
cxfEndpoint.getOutInterceptors().add(wssOut);
AddressBookService service =(AddressBookService) greeter;
System.out.println("#############Client getPhone##############");
Phone phone = service.getPhone("zph");
System.out.println("AreaCode:" + phone.getAreaCode());
System.out.println("Exchange:" + phone.getExchange());
System.out.println("Number:" + phone.getNumber());
} catch (Exception e) {
e.printStackTrace();
}
}
}
//--- CxfWsTestClient.java end

The fifth step: run and debug
1.ope a Console and change directory to cxftest_build,Run the following maven command:
$mvn clean install
2.Deploy the wea package to Tomcat webapps fold' subfold cxftest.
3.start Tomcat
4.start class SpringUsersWsClient or CxfWsTestClient in the project cxftest_client and you will see the below out put information:
AreaCode:120
Exchange:10
Number:10
That means you have successful!