- 浏览: 12503 次
- 性别:
- 来自: 北京
文章分类
最新评论
-
jackyrong:
您好 能否给我提供一下源码 谢谢?1809772@qq.com ...
CXF使用X509证书的WS-Security进行验证 -
wangyudong:
由CXF实现的微服务需要有比较好的工具去测试RESTful A ...
CXF使用X509证书的WS-Security进行验证 -
jiangsong12374:
您好 能否给我提供一下源码 谢谢?js-java@163.co ...
CXF使用X509证书的WS-Security进行验证 -
ljz0898:
你好 我按照你的说法来实现的 出现以下的问题 希望得到你的解 ...
CXF使用X509证书的WS-Security进行验证 -
ljz0898:
您好 能否给我提供一下源码 谢谢?ljz0898@126.co ...
CXF使用X509证书的WS-Security进行验证
一、相关概念
提到x509,就不得不提到几个相关概念。
1、Private key
2、Public key
3、KeyStore
4、TrustStore
Private key和Public key很简单,字面意思就可以理解,就是常说的私钥和公钥。
KeyStore和TrustStore简单的说就是存储私钥和密钥的容器。二者从存储结构上面都是一样的,只不过对其概念上做个区分,KeyStore主要用来存储私钥(也可能是Chain),TrustStore是用来存储公钥的。
更详细的可以看另外一篇文章:http://lukejin.iteye.com/blog/605634
在CXF中,使用加密签名的方式作为安全策略,配置上还有些麻烦。
先来看个图:
简单解释一下
1、客户端发送soap到服务端
首先A(客户端)需要使用自己的私钥进行签名,使用B(服务端)的公钥进行加密,然后将soap传给B,B用私钥进行解密,用A的公钥进行验签。
2、服务端返回数据到客户端
首先B用自己的私钥进行签名,用A的公钥进行加密,然后将soap传回给A,A用私钥进行解密,用B的公钥进行验签。
只要搞清楚这个过程,再使用CXF就显得比较容易了。
二、搭建环境
下面我们就可以搭建CXF的环境了
首先用maven创建一个简单的java工程,可以先创建好包com.tongtech.ti.cxf.demo.security
然后上pom文件,将下面的pom文件覆盖你自己工程中的pom文件。
然后在上WSDL:
Security.wsdl
wsdl文件放在com.tongtech.ti.cxf.demo.security包下面。
下面执行mvn eclipse:myeclipse/eclipse:eclipse/idea:idea,maven会自动根据wsdl创建相关代码。代码生成后拷贝到com.tongtech.ti.cxf.demo.security.service下面。
三、编写代码
(一)生成证书
生成证书还是比较麻烦的,要用到jdk的一个工具——keytool
首先,创建客户端KeyStore和公钥
在命令行运行:
1、创建私钥和KeyStore:
创建KeyStore,文件名字为Client_KeyStore.jks,里面有个名为clientprivatekey的私钥。
2、给私钥进行自签名:
签名成功,无任何提示。
3、导出私钥
作用是导出的证书将作为公钥保存到TrustStore中。
如果成功,可以看到提示:
保存在文件中的认证 <Client_PublicCert.cer>
然后创建服务端KeyStore
1、创建私钥和KeyStore
2、给私钥进行自签名
3、导出私钥
接下来,将客户端公钥导入到服务端TrustStore中,将服务端公钥导入到客户端TrustStore中。
在命令行中输入:
回车后会提示
打y即可,然后提示
同理,将服务端公钥导入到客户端TrustStore中
同样会出现提示,打y回车,提示成功就可以了。
到这里会有个疑问,为什么都叫keystore?在最上面已经提到,KeyStore和TrustStore是概念上的区分。
(二)编写代码
将上面生成好的maven工程导入到eclipse中,在src/main/java下建立新的包,起名叫cert,将刚刚生成好的KeyStore和TrustStore拷到cert包下。
1、创建配置文件
建立客户端加密/解密配置:Client_Encrypt.properties
建立客户端验签/签名配置:Client_Sign.properties
建立服务端加密/解密配置:Server_Decrypt.properties
建立服务端验签/签名配置:Server_SignVerf.properties
整理一下:
可能说这里名字起的有些怪异,这些文件是我从cxf的example中拷贝过来,我想原意应该是客户端进行签名加密,服务器进行验签解密,并没有对返回数据进行签名加密的意图,所以名字起成这样,不过没关系,整理一下,思路会更清楚。
Client_Encrypt.properties————Client_TrustStore.jks————serverpublickey
Client_Sign.properties————Client_KeyStore.jks————clientprivatekey
Server_Decrypt.properties————Server_KeyStore.jks————serverprivatekey
Server_SignVerf.properties————Server_TrustStore.jks————clientpublickey
2、编写客户端、服务端以及各自的Callback
首先先将target/generate中将代码拷贝到com.tongtech.ti.cxf.demo.security.service中,然后在security目录下面建立X509.client和X509.server,分别把ISecuriyDemo_ISecuriyServicePort_Client.java和ISecuriyDemo_ISecuriyServicePort_Server.java改名成Client和Server并移动到X509.client和X509.server包下,然后在client包下建立UTPasswordClientCallBack.java类。
UTPasswordClientCallBack.java代码如下:
在server包下建立UTPasswordServerCallBack.java
UTPasswordServerCallBack.java代码如下:
这两个类中,pc.setPassword方法参数都是keypass,因为我们生成的所有密钥的密码均是keypass,如果密钥密码不同,在这里需要对密钥的Identifier(等同于alias)进行判断,从而设置不同的密码。
接下来将要编写客户端和服务端了。
首先打开Client.java类,将如下代码完整复制,覆盖进去
打开Server.java,同理将下面代码完整复制并完整覆盖:
复制完成后,运行服务端和客户端进行测试即可。没有出以外的话,客户端能够顺利收到返回信息。
如果要看soap内容,打开service包下的ISecuriyDemo.java,加入如下标注代码:
最后以客户端为例,简单讲解一下出入站配置:
客户端包括:
第一行,使用CXF的Client代理(ClientProxy)来获得Endpoint,然后将WSS4J的Intercepter加入到Endpoint中。
需要加入两个WSS4J的Intercepter,WSS4JOutInterceptor和WSS4JInInterceptor,outIntercepter是客户端向服务端请求时,作为客户端出站(OutBound)的Intercepter,需要配置WSS4J相关属性:
WSHandlerConstants.ACTION,WSHandlerConstants.USER,WSHandlerConstants.ENCRYPTION_USER,WSHandlerConstants.PW_CALLBACK_CLASS,WSHandlerConstants.SIG_PROP_FILE,WSHandlerConstants.ENC_PROP_FILE,将这些属性放入map中,传入WSS4JOutInterceptor中。
对于客户端出站来说,签名需要客户端私钥(Client_Sign.properties)进行签名,加密需要服务端公钥(Client_Encrypt.properties)进行加密,属性中WSHandlerConstants.SIG_PROP_FILE为签名配置文件,WSHandlerConstants.ENC_PROP_FILE为加密配置文件。
入站则相反,验签需要服务端公钥(Client_Encrypt.properties),解密需要客户端私钥(Client_Sign.properties)。
服务器端与客户端相反,意思和客户端相同。
提到x509,就不得不提到几个相关概念。
1、Private key
2、Public key
3、KeyStore
4、TrustStore
Private key和Public key很简单,字面意思就可以理解,就是常说的私钥和公钥。
KeyStore和TrustStore简单的说就是存储私钥和密钥的容器。二者从存储结构上面都是一样的,只不过对其概念上做个区分,KeyStore主要用来存储私钥(也可能是Chain),TrustStore是用来存储公钥的。
更详细的可以看另外一篇文章:http://lukejin.iteye.com/blog/605634
在CXF中,使用加密签名的方式作为安全策略,配置上还有些麻烦。
先来看个图:
简单解释一下
1、客户端发送soap到服务端
首先A(客户端)需要使用自己的私钥进行签名,使用B(服务端)的公钥进行加密,然后将soap传给B,B用私钥进行解密,用A的公钥进行验签。
2、服务端返回数据到客户端
首先B用自己的私钥进行签名,用A的公钥进行加密,然后将soap传回给A,A用私钥进行解密,用B的公钥进行验签。
只要搞清楚这个过程,再使用CXF就显得比较容易了。
二、搭建环境
下面我们就可以搭建CXF的环境了
首先用maven创建一个简单的java工程,可以先创建好包com.tongtech.ti.cxf.demo.security
然后上pom文件,将下面的pom文件覆盖你自己工程中的pom文件。
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>ti-cxf</groupId> <artifactId>ti-cxf-security</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>jar</packaging> <name>Tongtech Demo for CXF Security with wss4j</name> <properties> <cxf.version>2.4.0-SNAPSHOT</cxf.version> </properties> <dependencies> <dependency> <groupId>org.apache.cxf</groupId> <artifactId>cxf-rt-frontend-jaxws</artifactId> <version>${cxf.version}</version> </dependency> <dependency> <groupId>org.apache.cxf</groupId> <artifactId>cxf-rt-transports-http</artifactId> <version>${cxf.version}</version> </dependency> <dependency> <groupId>org.apache.cxf</groupId> <artifactId>cxf-rt-ws-security</artifactId> <version>${cxf.version}</version> </dependency> <dependency> <groupId>org.apache.cxf</groupId> <artifactId>cxf-rt-transports-http-jetty</artifactId> <version>${cxf.version}</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <configuration> <source>1.6</source> <target>1.6</target> </configuration> </plugin> <plugin> <groupId>org.apache.cxf</groupId> <artifactId>cxf-codegen-plugin</artifactId> <version>${cxf.version}</version> <executions> <execution> <id>generate-sources-static</id> <phase>generate-sources</phase> <configuration> <sourceRoot>${basedir}/target/generate</sourceRoot> <wsdlOptions> <wsdlOption> <wsdl>${basedir}/src/main/java/com/tongtech/ti/cxf/demo/security/security.wsdl</wsdl> <extraargs> <extraarg>-db</extraarg> <extraarg>jaxb</extraarg> <extraarg>-p</extraarg> <extraarg>com.tongtech.ti.cxf.demo.security.service</extraarg> <extraarg>-all</extraarg> </extraargs> </wsdlOption> </wsdlOptions> </configuration> <goals> <goal>wsdl2java</goal> </goals> </execution> </executions> </plugin> </plugins> </build> </project>
然后在上WSDL:
Security.wsdl
<?xml version="1.0" encoding="UTF-8"?> <wsdl:definitions name="security" targetNamespace="http://demo.ti.tongtech.com/security/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:tns="http://demo.ti.tongtech.com/security/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"> <wsdl:types> <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" targetNamespace="http://demo.ti.tongtech.com/security/"> <xsd:element name="input"> <xsd:complexType> <xsd:sequence> <xsd:element name="in" type="xsd:string"></xsd:element> </xsd:sequence> </xsd:complexType> </xsd:element> <xsd:element name="inputResponse"> <xsd:complexType> <xsd:sequence> <xsd:element name="out" type="xsd:string"></xsd:element> </xsd:sequence> </xsd:complexType> </xsd:element> </xsd:schema> </wsdl:types> <wsdl:message name="inputRequest"> <wsdl:part name="parameters" element="tns:input"></wsdl:part> </wsdl:message> <wsdl:message name="inputResponse"> <wsdl:part name="parameters" element="tns:inputResponse"></wsdl:part> </wsdl:message> <wsdl:portType name="ISecuriyDemo"> <wsdl:operation name="input"> <wsdl:input message="tns:inputRequest"></wsdl:input> <wsdl:output message="tns:inputResponse"></wsdl:output> </wsdl:operation> </wsdl:portType> <wsdl:binding name="ISecurityBinding" type="tns:ISecuriyDemo"> <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http" /> <wsdl:operation name="input"> <soap:operation soapAction="http://demo.ti.tongtech.com/security/input" /> <wsdl:input> <soap:body use="literal" /> </wsdl:input> <wsdl:output> <soap:body use="literal" /> </wsdl:output> </wsdl:operation> </wsdl:binding> <wsdl:service name="ISecuriyService"> <wsdl:port name="ISecuriyServicePort" binding="tns:ISecurityBinding"> <soap:address location="http://localhost:8080/sec" /> </wsdl:port> </wsdl:service> </wsdl:definitions>
wsdl文件放在com.tongtech.ti.cxf.demo.security包下面。
下面执行mvn eclipse:myeclipse/eclipse:eclipse/idea:idea,maven会自动根据wsdl创建相关代码。代码生成后拷贝到com.tongtech.ti.cxf.demo.security.service下面。
三、编写代码
(一)生成证书
生成证书还是比较麻烦的,要用到jdk的一个工具——keytool
首先,创建客户端KeyStore和公钥
在命令行运行:
1、创建私钥和KeyStore:
keytool -genkey -alias clientprivatekey -keypass keypass -keystore Client_KeyStore.jks -storepass storepass -dname "CN=tongtech.com,C=CN" -keyalg RSA
创建KeyStore,文件名字为Client_KeyStore.jks,里面有个名为clientprivatekey的私钥。
2、给私钥进行自签名:
keytool -selfcert -keystore Client_KeyStore.jks -storepass storepass -alias clientprivatekey -keypass keypass
签名成功,无任何提示。
3、导出私钥
作用是导出的证书将作为公钥保存到TrustStore中。
keytool -export -alias clientprivatekey -file Client_PublicCert.cer -keystore Client_KeyStore.jks -storepass storepass
如果成功,可以看到提示:
保存在文件中的认证 <Client_PublicCert.cer>
然后创建服务端KeyStore
1、创建私钥和KeyStore
keytool -genkey -alias serverprivatekey -keypass keypass -keystore Server_KeyStore.jks -storepass storepass -dname "CN=tongtech.com,C=CN" -keyalg RSA
2、给私钥进行自签名
keytool -selfcert -keystore Server_KeyStore.jks -storepass storepass -alias serverprivatekey -keypass keypass
3、导出私钥
keytool -export -alias serverprivatekey -file Server_PublicCert.cer -keystore Server_KeyStore.jks -storepass storepass
接下来,将客户端公钥导入到服务端TrustStore中,将服务端公钥导入到客户端TrustStore中。
在命令行中输入:
keytool -import -alias clientpublickey -file Client_PublicCert.cer -keystore Server_TrustStore.jks -storepass storepass
回车后会提示
引用
所有者:CN=tongtech.com, C=CN
签发人:CN=tongtech.com, C=CN
序列号:4cc7e86c
有效期: Wed Oct 27 16:53:00 CST 2010 至Tue Jan 25 16:53:00 CST 2011
证书指纹:
MD5:FB:AB:71:9F:56:F3:CB:65:16:DC:52:E0:2D:27:FF:F6
SHA1:06:A8:B1:B4:E2:42:9D:B2:F7:99:E7:70:34:08:96:52:E1:CD:4A:76
签名算法名称:SHA1withRSA
版本: 3
信任这个认证? [否]:
签发人:CN=tongtech.com, C=CN
序列号:4cc7e86c
有效期: Wed Oct 27 16:53:00 CST 2010 至Tue Jan 25 16:53:00 CST 2011
证书指纹:
MD5:FB:AB:71:9F:56:F3:CB:65:16:DC:52:E0:2D:27:FF:F6
SHA1:06:A8:B1:B4:E2:42:9D:B2:F7:99:E7:70:34:08:96:52:E1:CD:4A:76
签名算法名称:SHA1withRSA
版本: 3
信任这个认证? [否]:
打y即可,然后提示
引用
认证已添加至keystore中
同理,将服务端公钥导入到客户端TrustStore中
keytool -import -alias serverpublickey -file Server_PublicCert.cer -keystore Client_TrustStore.jks -storepass storepass
同样会出现提示,打y回车,提示成功就可以了。
到这里会有个疑问,为什么都叫keystore?在最上面已经提到,KeyStore和TrustStore是概念上的区分。
(二)编写代码
将上面生成好的maven工程导入到eclipse中,在src/main/java下建立新的包,起名叫cert,将刚刚生成好的KeyStore和TrustStore拷到cert包下。
1、创建配置文件
建立客户端加密/解密配置:Client_Encrypt.properties
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=storepass org.apache.ws.security.crypto.merlin.keystore.alias=serverpublickey org.apache.ws.security.crypto.merlin.file=cert/Client_TrustStore.jks
建立客户端验签/签名配置:Client_Sign.properties
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=storepass org.apache.ws.security.crypto.merlin.keystore.alias=clientprivatekey org.apache.ws.security.crypto.merlin.file=cert/Client_KeyStore.jks
建立服务端加密/解密配置:Server_Decrypt.properties
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=storepass org.apache.ws.security.crypto.merlin.keystore.alias=serverprivatekey org.apache.ws.security.crypto.merlin.file=cert/Server_KeyStore.jks
建立服务端验签/签名配置:Server_SignVerf.properties
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=storepass org.apache.ws.security.crypto.merlin.keystore.alias=clientpublickey org.apache.ws.security.crypto.merlin.file=cert/Server_TrustStore.jks
整理一下:
引用
可能说这里名字起的有些怪异,这些文件是我从cxf的example中拷贝过来,我想原意应该是客户端进行签名加密,服务器进行验签解密,并没有对返回数据进行签名加密的意图,所以名字起成这样,不过没关系,整理一下,思路会更清楚。
Client_Encrypt.properties————Client_TrustStore.jks————serverpublickey
Client_Sign.properties————Client_KeyStore.jks————clientprivatekey
Server_Decrypt.properties————Server_KeyStore.jks————serverprivatekey
Server_SignVerf.properties————Server_TrustStore.jks————clientpublickey
2、编写客户端、服务端以及各自的Callback
首先先将target/generate中将代码拷贝到com.tongtech.ti.cxf.demo.security.service中,然后在security目录下面建立X509.client和X509.server,分别把ISecuriyDemo_ISecuriyServicePort_Client.java和ISecuriyDemo_ISecuriyServicePort_Server.java改名成Client和Server并移动到X509.client和X509.server包下,然后在client包下建立UTPasswordClientCallBack.java类。
UTPasswordClientCallBack.java代码如下:
package com.tongtech.ti.cxf.demo.security.X509.client; 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 UTPasswordClientCallBack implements CallbackHandler { public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException { WSPasswordCallback pc = (WSPasswordCallback) callbacks[0]; pc.setPassword("keypass"); System.out.println("Client Identifier=" + pc.getIdentifier()); System.out.println("Client Password=" + pc.getPassword()); } }
在server包下建立UTPasswordServerCallBack.java
UTPasswordServerCallBack.java代码如下:
package com.tongtech.ti.cxf.demo.security.X509.server; 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 UTPasswordServerCallBack implements CallbackHandler { public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException { WSPasswordCallback pc = (WSPasswordCallback) callbacks[0]; pc.setPassword("keypass"); System.out.println("Server Identifier=" + pc.getIdentifier()); System.out.println("Server Password=" + pc.getPassword()); } }
这两个类中,pc.setPassword方法参数都是keypass,因为我们生成的所有密钥的密码均是keypass,如果密钥密码不同,在这里需要对密钥的Identifier(等同于alias)进行判断,从而设置不同的密码。
接下来将要编写客户端和服务端了。
首先打开Client.java类,将如下代码完整复制,覆盖进去
package com.tongtech.ti.cxf.demo.security.X509.client; /** * Please modify this class to meet your needs * This class is not complete */ import java.net.URL; import java.util.HashMap; import java.util.Map; import javax.xml.namespace.QName; import org.apache.cxf.endpoint.Endpoint; 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.tongtech.ti.cxf.demo.security.service.ISecuriyDemo; import com.tongtech.ti.cxf.demo.security.service.ISecuriyService; /** * This class was generated by Apache CXF 2.4.0-SNAPSHOT Tue Oct 26 16:45:43 CST * 2010 Generated source version: 2.4.0-SNAPSHOT * */ public final class Client { private static final QName SERVICE_NAME = new QName( "http://demo.ti.tongtech.com/security/", "ISecuriyService"); private Client() { } public static void main(String args[]) throws Exception { URL wsdlURL = ISecuriyService.WSDL_LOCATION; ISecuriyService ss = new ISecuriyService(wsdlURL, SERVICE_NAME); ISecuriyDemo port = ss.getISecuriyServicePort(); org.apache.cxf.endpoint.Client client = ClientProxy.getClient(port); Endpoint cxfEp = client.getEndpoint(); // Clint Out Map<String, Object> outProp = new HashMap<String, Object>(); outProp.put(WSHandlerConstants.ACTION, WSHandlerConstants.TIMESTAMP + " " + WSHandlerConstants.SIGNATURE + " " + WSHandlerConstants.ENCRYPT); outProp.put(WSHandlerConstants.USER, "clientprivatekey"); outProp.put(WSHandlerConstants.ENCRYPTION_USER, "serverpublickey"); outProp.put(WSHandlerConstants.PW_CALLBACK_CLASS, UTPasswordClientCallBack.class.getName()); outProp.put(WSHandlerConstants.SIG_PROP_FILE, "cert/Client_Sign.properties"); outProp.put(WSHandlerConstants.ENC_PROP_FILE, "cert/Client_Encrypt.properties"); cxfEp.getOutInterceptors().add(new WSS4JOutInterceptor(outProp)); // Client In(Return) Map<String, Object> inProp = new HashMap<String, Object>(); inProp.put(WSHandlerConstants.ACTION, WSHandlerConstants.TIMESTAMP + " " + WSHandlerConstants.SIGNATURE + " " + WSHandlerConstants.ENCRYPT); inProp.put(WSHandlerConstants.PW_CALLBACK_CLASS, UTPasswordClientCallBack.class.getName()); inProp.put(WSHandlerConstants.DEC_PROP_FILE, "cert/Client_Sign.properties"); inProp.put(WSHandlerConstants.SIG_PROP_FILE, "cert/Client_Encrypt.properties"); cxfEp.getInInterceptors().add(new WSS4JInInterceptor(inProp)); { System.out.println("Invoking input..."); java.lang.String _input_in = "Input Value!"; java.lang.String _input__return = port.input(_input_in); System.out.println("input.result=" + _input__return); } System.exit(0); } }
打开Server.java,同理将下面代码完整复制并完整覆盖:
package com.tongtech.ti.cxf.demo.security.X509.server; import java.util.HashMap; import java.util.Map; import javax.xml.ws.Endpoint; import org.apache.cxf.jaxws.EndpointImpl; 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.tongtech.ti.cxf.demo.security.service.ISecuriyDemoImpl; /** * This class was generated by Apache CXF 2.4.0-SNAPSHOT Tue Oct 26 16:45:43 CST * 2010 Generated source version: 2.4.0-SNAPSHOT * */ public class Server { protected Server() throws Exception { System.out.println("Starting Server"); Object implementor = new ISecuriyDemoImpl(); String address = "http://localhost:8080/sec"; EndpointImpl ep = (EndpointImpl) Endpoint.publish(address, implementor); org.apache.cxf.endpoint.Endpoint cxfEp = ep.getServer().getEndpoint(); // /////////////////////////////////////////////////////////////// Map<String, Object> inProp = new HashMap<String, Object>(); inProp.put(WSHandlerConstants.ACTION, WSHandlerConstants.TIMESTAMP + " " + WSHandlerConstants.SIGNATURE + " " + WSHandlerConstants.ENCRYPT); inProp.put(WSHandlerConstants.PW_CALLBACK_CLASS, UTPasswordServerCallBack.class.getName()); inProp.put(WSHandlerConstants.SIG_PROP_FILE, "cert/Server_SignVerf.properties"); inProp.put(WSHandlerConstants.DEC_PROP_FILE, "cert/Server_Decrypt.properties"); cxfEp.getInInterceptors().add(new WSS4JInInterceptor(inProp)); // ///////////////////////////////////////////////////////////////// Map<String, Object> outProp = new HashMap<String, Object>(); outProp.put(WSHandlerConstants.ACTION, WSHandlerConstants.TIMESTAMP + " " + WSHandlerConstants.SIGNATURE + " " + WSHandlerConstants.ENCRYPT); outProp.put(WSHandlerConstants.USER, "serverprivatekey"); outProp.put(WSHandlerConstants.PW_CALLBACK_CLASS, UTPasswordServerCallBack.class.getName()); outProp.put(WSHandlerConstants.ENCRYPTION_USER, "clientpublickey"); outProp.put(WSHandlerConstants.SIG_PROP_FILE, "cert/Server_Decrypt.properties");// 私钥 outProp.put(WSHandlerConstants.ENC_PROP_FILE, "cert/Server_SignVerf.properties");// 公钥 cxfEp.getOutInterceptors().add(new WSS4JOutInterceptor(outProp)); } public static void main(String args[]) throws Exception { new Server(); System.out.println("Server ready..."); Thread.sleep(60 * 60 * 1000); System.out.println("Server exiting"); System.exit(0); } }
复制完成后,运行服务端和客户端进行测试即可。没有出以外的话,客户端能够顺利收到返回信息。
如果要看soap内容,打开service包下的ISecuriyDemo.java,加入如下标注代码:
@WebService(targetNamespace = "http://demo.ti.tongtech.com/security/", name = "ISecuriyDemo") @XmlSeeAlso({ObjectFactory.class}) //====加入如下代码==== @InInterceptors(interceptors = { "org.apache.cxf.interceptor.LoggingInInterceptor" }) @OutInterceptors(interceptors = { "org.apache.cxf.interceptor.LoggingOutInterceptor" }) //====加入代码结束==== public interface ISecuriyDemo { @WebResult(name = "out", targetNamespace = "") @RequestWrapper(localName = "input", targetNamespace = "http://demo.ti.tongtech.com/security/", className = "com.tongtech.ti.cxf.demo.security.service.Input") @WebMethod(action = "http://demo.ti.tongtech.com/security/input") @ResponseWrapper(localName = "inputResponse", targetNamespace = "http://demo.ti.tongtech.com/security/", className = "com.tongtech.ti.cxf.demo.security.service.InputResponse") public java.lang.String input( @WebParam(name = "in", targetNamespace = "") java.lang.String in ); }
最后以客户端为例,简单讲解一下出入站配置:
客户端包括:
org.apache.cxf.endpoint.Client client = ClientProxy.getClient(port); Endpoint cxfEp = client.getEndpoint(); // Clint Out Map<String, Object> outProp = new HashMap<String, Object>(); outProp.put(WSHandlerConstants.ACTION, WSHandlerConstants.TIMESTAMP + " " + WSHandlerConstants.SIGNATURE + " " + WSHandlerConstants.ENCRYPT); outProp.put(WSHandlerConstants.USER, "clientprivatekey"); outProp.put(WSHandlerConstants.ENCRYPTION_USER, "serverpublickey"); outProp.put(WSHandlerConstants.PW_CALLBACK_CLASS, UTPasswordClientCallBack.class.getName()); outProp.put(WSHandlerConstants.SIG_PROP_FILE, "cert/Client_Sign.properties"); outProp.put(WSHandlerConstants.ENC_PROP_FILE, "cert/Client_Encrypt.properties"); cxfEp.getOutInterceptors().add(new WSS4JOutInterceptor(outProp)); // Client In(Return) Map<String, Object> inProp = new HashMap<String, Object>(); inProp.put(WSHandlerConstants.ACTION, WSHandlerConstants.TIMESTAMP + " " + WSHandlerConstants.SIGNATURE + " " + WSHandlerConstants.ENCRYPT); inProp.put(WSHandlerConstants.PW_CALLBACK_CLASS, UTPasswordClientCallBack.class.getName()); inProp.put(WSHandlerConstants.DEC_PROP_FILE, "cert/Client_Sign.properties"); inProp.put(WSHandlerConstants.SIG_PROP_FILE, "cert/Client_Encrypt.properties"); cxfEp.getInInterceptors().add(new WSS4JInInterceptor(inProp));
第一行,使用CXF的Client代理(ClientProxy)来获得Endpoint,然后将WSS4J的Intercepter加入到Endpoint中。
需要加入两个WSS4J的Intercepter,WSS4JOutInterceptor和WSS4JInInterceptor,outIntercepter是客户端向服务端请求时,作为客户端出站(OutBound)的Intercepter,需要配置WSS4J相关属性:
WSHandlerConstants.ACTION,WSHandlerConstants.USER,WSHandlerConstants.ENCRYPTION_USER,WSHandlerConstants.PW_CALLBACK_CLASS,WSHandlerConstants.SIG_PROP_FILE,WSHandlerConstants.ENC_PROP_FILE,将这些属性放入map中,传入WSS4JOutInterceptor中。
对于客户端出站来说,签名需要客户端私钥(Client_Sign.properties)进行签名,加密需要服务端公钥(Client_Encrypt.properties)进行加密,属性中WSHandlerConstants.SIG_PROP_FILE为签名配置文件,WSHandlerConstants.ENC_PROP_FILE为加密配置文件。
入站则相反,验签需要服务端公钥(Client_Encrypt.properties),解密需要客户端私钥(Client_Sign.properties)。
服务器端与客户端相反,意思和客户端相同。
评论
5 楼
jackyrong
2018-06-20
您好 能否给我提供一下源码 谢谢?1809772@qq.com
4 楼
wangyudong
2017-11-27
由CXF实现的微服务需要有比较好的工具去测试RESTful API,很多REST Client是不支持自动化测试RESTful API,也不支持自动生成API文档.
之前习惯用一款名字为 WisdomTool REST Client,支持自动化测试RESTful API,输出精美的测试报告,并且自动生成精美的RESTful API文档。
轻量级的工具,功能却很精悍哦!
https://github.com/wisdomtool/rest-client
Most of REST Client tools do not support automated testing.
Once used a tool called WisdomTool REST Client supports automated testing, output exquisite report, and automatically generating RESTful API document.
Lightweight tool with very powerful features!
https://github.com/wisdomtool/rest-client
之前习惯用一款名字为 WisdomTool REST Client,支持自动化测试RESTful API,输出精美的测试报告,并且自动生成精美的RESTful API文档。
轻量级的工具,功能却很精悍哦!
https://github.com/wisdomtool/rest-client
Most of REST Client tools do not support automated testing.
Once used a tool called WisdomTool REST Client supports automated testing, output exquisite report, and automatically generating RESTful API document.
Lightweight tool with very powerful features!
https://github.com/wisdomtool/rest-client
3 楼
jiangsong12374
2012-01-04
您好 能否给我提供一下源码 谢谢?js-java@163.com
2 楼
ljz0898
2011-07-13
你好 我按照你的说法来实现的 出现以下的问题 希望得到你的解答 谢谢
证书我已经点击安装了 是不是还需要规定放在什么目录下面???
2011-7-13 9:25:39 org.apache.cxf.service.factory.ReflectionServiceFactoryBean buildServiceFromWSDL
信息: Creating Service {http://copy.com/}HellowordService from WSDL: http://localhost:9090/hello?wsdl
Invoking input...
Client Identifier=clientprivatekey
Client Password=keypass
2011-7-13 9:25:40 org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor handleMessage
警告: Request does not contain Security header, but it's a fault.
Exception in thread "main" javax.xml.ws.soap.SOAPFaultException: General security error (No certificates were found for decryption (KeyId))
at org.apache.cxf.jaxws.JaxWsClientProxy.invoke(JaxWsClientProxy.java:146)
at $Proxy25.sayHi(Unknown Source)
at com.client.copy.Client.main(Client.java:74)
Caused by: org.apache.cxf.binding.soap.SoapFault: General security error (No certificates were found for decryption (KeyId))
at org.apache.cxf.binding.soap.interceptor.Soap11FaultInInterceptor.unmarshalFault(Soap11FaultInInterceptor.java:75)
at org.apache.cxf.binding.soap.interceptor.Soap11FaultInInterceptor.handleMessage(Soap11FaultInInterceptor.java:46)
at org.apache.cxf.binding.soap.interceptor.Soap11FaultInInterceptor.handleMessage(Soap11FaultInInterceptor.java:35)
at org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:263)
at org.apache.cxf.interceptor.AbstractFaultChainInitiatorObserver.onMessage(AbstractFaultChainInitiatorObserver.java:104)
at org.apache.cxf.binding.soap.interceptor.CheckFaultInterceptor.handleMessage(CheckFaultInterceptor.java:69)
at org.apache.cxf.binding.soap.interceptor.CheckFaultInterceptor.handleMessage(CheckFaultInterceptor.java:34)
at org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:263)
at org.apache.cxf.endpoint.ClientImpl.onMessage(ClientImpl.java:762)
at org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.handleResponseInternal(HTTPConduit.java:1582)
at org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.handleResponse(HTTPConduit.java:1467)
at org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.close(HTTPConduit.java:1375)
at org.apache.cxf.transport.AbstractConduit.close(AbstractConduit.java:56)
at org.apache.cxf.transport.http.HTTPConduit.close(HTTPConduit.java:623)
at org.apache.cxf.interceptor.MessageSenderInterceptor$MessageSenderEndingInterceptor.handleMessage(MessageSenderInterceptor.java:62)
at org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:263)
at org.apache.cxf.endpoint.ClientImpl.doInvoke(ClientImpl.java:510)
at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:440)
at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:343)
at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:295)
at org.apache.cxf.frontend.ClientProxy.invokeSync(ClientProxy.java:73)
at org.apache.cxf.jaxws.JaxWsClientProxy.invoke(JaxWsClientProxy.java:124)
... 2 more
证书我已经点击安装了 是不是还需要规定放在什么目录下面???
2011-7-13 9:25:39 org.apache.cxf.service.factory.ReflectionServiceFactoryBean buildServiceFromWSDL
信息: Creating Service {http://copy.com/}HellowordService from WSDL: http://localhost:9090/hello?wsdl
Invoking input...
Client Identifier=clientprivatekey
Client Password=keypass
2011-7-13 9:25:40 org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor handleMessage
警告: Request does not contain Security header, but it's a fault.
Exception in thread "main" javax.xml.ws.soap.SOAPFaultException: General security error (No certificates were found for decryption (KeyId))
at org.apache.cxf.jaxws.JaxWsClientProxy.invoke(JaxWsClientProxy.java:146)
at $Proxy25.sayHi(Unknown Source)
at com.client.copy.Client.main(Client.java:74)
Caused by: org.apache.cxf.binding.soap.SoapFault: General security error (No certificates were found for decryption (KeyId))
at org.apache.cxf.binding.soap.interceptor.Soap11FaultInInterceptor.unmarshalFault(Soap11FaultInInterceptor.java:75)
at org.apache.cxf.binding.soap.interceptor.Soap11FaultInInterceptor.handleMessage(Soap11FaultInInterceptor.java:46)
at org.apache.cxf.binding.soap.interceptor.Soap11FaultInInterceptor.handleMessage(Soap11FaultInInterceptor.java:35)
at org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:263)
at org.apache.cxf.interceptor.AbstractFaultChainInitiatorObserver.onMessage(AbstractFaultChainInitiatorObserver.java:104)
at org.apache.cxf.binding.soap.interceptor.CheckFaultInterceptor.handleMessage(CheckFaultInterceptor.java:69)
at org.apache.cxf.binding.soap.interceptor.CheckFaultInterceptor.handleMessage(CheckFaultInterceptor.java:34)
at org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:263)
at org.apache.cxf.endpoint.ClientImpl.onMessage(ClientImpl.java:762)
at org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.handleResponseInternal(HTTPConduit.java:1582)
at org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.handleResponse(HTTPConduit.java:1467)
at org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.close(HTTPConduit.java:1375)
at org.apache.cxf.transport.AbstractConduit.close(AbstractConduit.java:56)
at org.apache.cxf.transport.http.HTTPConduit.close(HTTPConduit.java:623)
at org.apache.cxf.interceptor.MessageSenderInterceptor$MessageSenderEndingInterceptor.handleMessage(MessageSenderInterceptor.java:62)
at org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:263)
at org.apache.cxf.endpoint.ClientImpl.doInvoke(ClientImpl.java:510)
at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:440)
at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:343)
at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:295)
at org.apache.cxf.frontend.ClientProxy.invokeSync(ClientProxy.java:73)
at org.apache.cxf.jaxws.JaxWsClientProxy.invoke(JaxWsClientProxy.java:124)
... 2 more
1 楼
ljz0898
2011-07-06
您好 能否给我提供一下源码 谢谢?ljz0898@126.com
相关推荐
1)参考: ...2)CXFWS工程是基于WS-Security规范,实现X.509身份验证的,同时实现签名和加密 keytool 工具的使用参考 http://hi.baidu.com/qianshuifanchuan/blog/item/6291b8510009ad3c42a75b8e.html ...
本文将深入探讨如何使用CXF框架结合ws-security标准来实现对Java客户端调用Web服务的安全接口。CXF是一个开源的服务框架,它允许开发人员创建和消费各种Web服务,而ws-security(Web Services Security)则是用于...
CXF支持使用X.509证书进行签名。 3. **消息加密(Message Encryption)**:保护数据在传输过程中的隐私,防止数据被窃取。加密通常基于公钥基础设施(PKI)。 4. **WS-SecureConversation**:用于建立长期的安全上...
而Apache WSS4J(Web Services Secure Utilities for Java)则是Apache软件基金会开发的一个实现WS-Security标准的开源库,它为Java开发者提供了处理和验证Web服务消息安全性的工具。 首先,我们来看一下标题提到的...
1. **身份验证**:通过用户名令牌、X.509证书或SAML令牌进行服务消费者的认证。 2. **消息完整性**:使用消息摘要(如MD5或SHA-1)和数字签名来防止消息被篡改。 3. **消息保密性**:通过加密机制确保消息内容不被...
【标题】"我的cxf与ws-security"涉及的是在Java Web服务开发中使用Apache CXF框架集成WS-Security(Web Service Security)的安全机制。Apache CXF是一个开源的、功能丰富的Web服务框架,它允许开发者创建和消费各种...
证书加密是WS-Security中的一个重要组成部分,它通常使用X.509数字证书来验证服务提供者和服务消费者的标识,并对消息进行加密。X.509证书包含公钥和私钥,公钥用于加密数据,私钥用于解密数据。在CXF中,我们可以...
这些可能包括X.509证书处理、XML数字签名、XML加密、SOAP头的处理以及其他与WS-Security相关的功能。 在Web服务中使用这些库,开发者可以实现以下功能: 1. 用户身份验证:通过用户名令牌、X.509证书或其他安全令牌...
本示例是关于如何在CXF中使用WS-Security和WSS4J进行安全配置和实践的实例。运行此例子时,你需要关注以下几个核心知识点: 1. **WS-Security**:这是OASIS制定的一套标准,定义了Web服务安全的各种模式,包括消息...
1. **身份验证**:WS-Security允许服务提供商和消费者进行身份验证。通过在SOAP消息中添加安全令牌,如X.509证书或用户名/密码对,可以验证服务请求者的身份。 2. **消息完整性**:通过数字签名确保消息在传输过程...
例如,`ws-security` 可以通过X.509证书进行公钥基础设施(PKI)的认证,也可以使用UsernameToken或 Kerberos Token进行用户身份验证。 在Xfire中实现`ws-security`,意味着开发者正在为基于Xfire的Web服务添加安全...
3. **CXF**:一个开源框架,支持多种Web服务标准,包括WS-Security。 #### 六、总结 WS-Security规范为Web服务的安全性提供了一个强大的框架,它不仅解决了传统安全机制的局限性,还通过消息完整性和加密等功能...
- CXF支持SOAP 1.1和1.2版本,提供了完整的SOAP处理能力,包括消息编码、处理WS-Security等。 - 使用CXF,开发者可以通过JAX-WS(Java API for XML Web Services)来创建SOAP服务。JAX-WS是Java中定义Web服务的...
这些信息构成了 X.509 标准中的 Distinguished Name (DN)。 ### 步骤二:配置 Tomcat 服务器 完成密钥库的创建后,下一步是在 Tomcat 服务器上启用 HTTPS。这可以通过修改 Tomcat 的 `server.xml` 文件来实现。在 ...
【CXF WSSCEURITRY 身份认证demo】是一个关于在WEB服务中使用Apache CXF框架实现WS-Security(Web Services Security)标准的身份验证的示例项目。该示例着重展示了如何在CXF中配置和使用WS-SecureConversation(WS-...
3. **证书认证**:除了用户名和密码,也可以使用X.509证书进行双向认证,提供更高级别的安全性。 4. **安全协议**:使用HTTPS等安全协议,确保数据在传输过程中的安全。 总结,"CXF 通过用户名和密码进行验证"涉及...
例如,可以使用X.509证书进行客户端和服务器端的身份验证,或者使用UsernameToken来传递用户名和密码。此外,还可以使用加密和签名策略来保护消息内容。 为了实现这些功能,我们需要进行以下步骤: 1. **服务器端...
8. **cxf-rt-ws-security.jar**: 包含了WS-Security和其他安全相关的实现,用于Web服务的安全认证和加密。 9. **cxf-tools-common.jar** 和 **cxf-tools-wsdlto-core.jar** 等工具类库,用于生成服务端和客户端代码...
6. **安全特性**:CXF支持WS-Security和其他安全标准,以确保Web服务的安全性。 7. **集成性**:CXF可以很好地与其他Java企业级框架集成,如Spring,允许灵活的配置和服务部署。 8. **测试工具**:CXF提供了诸如...
例如,使用X.509证书进行签名和加密。 5. **角色基授权**:通过在SOAP消息中添加WS-政策或WS-SecurityPolicy声明,可以实现基于角色的访问控制。 6. **令牌认证**:如SAML令牌,可以实现单点登录(SSO)功能。 ...