`
wangwengcn
  • 浏览: 175817 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

3.CXF安全访问之SIGN_ENC(二)

    博客分类:
  • CXF
阅读更多

上一篇讲了如何使用UsernameToken的方式来安全访问CXF,这篇将讲解使用证书的签名和加密技术来达到安全访问的目的。

 

1.证书的签名和加密的原理

在CXF官网关于WS-SECURITY的章节中首先介绍了,签名和加密的原理,图和文字很形象,就不再多说了。

下面附上本文中使用的生成证书的代码:

 

1. 生成别名和密码为 "serverkey"/"myPassword"的服务端证书,别名都使用小写(在keystore中存储的别名都是小写字符), 并保存在server-keystore.jks中(改证书用来服务端解密)
keytool -genkey -alias serverkey -validity 365 -keypass myPassword -keystore server-keystore.jks -storepass myPassword -dname "cn=serverkey" -keyalg RSA

2. 自签名我们的生成的证书(正式环境应该由正式的公司来做这个步骤,比如Verisign)
keytool -selfcert -alias serverkey -validity 365 -keystore server-keystore.jks -storepass myPassword -keypass myPassword

3. 从服务端keystore中导出公钥并且命名为 key.cer
keytool -export -alias serverkey -file serverkey.cer -keystore server-keystore.jks -storepass myPassword

4. 将步骤3导出的证书导入到客户端的client-truststore.jks(用来做客户端加密)

keytool -import -alias serverkey -file serverkey.cer -keystore client-truststore.jks -storepass myPassword

5. 生成别名和密码为 "clientkey"/"myPassword"的客户端证书, 并保存在client-keystore.jks中(改证书用来服务端解密)
keytool -genkey -alias clientkey -validity 365 -keypass myPassword -keystore client-keystore.jks -storepass myPassword -dname "cn=clientkey" -keyalg RSA

6. 自签名我们的生成的证书(正式环境应该由正式的公司来做这个步骤,比如Verisign)
keytool -selfcert -alias clientkey -validity 365 -keystore client-keystore.jks -storepass myPassword -keypass myPassword

7. 从客户端keystore中导出公钥并且命名为 key.cer
keytool -export -alias clientkey -file clientkey.cer -keystore client-keystore.jks -storepass myPassword

8. 将步骤3导出的证书导入到服务端的server-truststore.jks(用来做客户端加密)

keytool -import -alias clientkey -file clientkey.cer -keystore server-truststore.jks -storepass myPassword

 

执行完,你可以在%JDK_HOME%/bin目录得到4个jks文件(数字证书库),这就是我们即将用来加密和签名的证书文件了。

 

 2.添加四个证书配置文件

  • Client_Encrypt.properties
  • Client_Sign.properties
  • Server_Decrypt.properties
  • Server_SignVerf.properties

四个文件格式都一样,里面配置的keystore的类型、地址、密码以及做相应操作的证书别名。

内容如下:

 

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=myPassword
org.apache.ws.security.crypto.merlin.keystore.alias=clientKey
org.apache.ws.security.crypto.merlin.keystore.file=resource/keystore/server-truststore.jks
 

 

 3.修改客户端和服务端spring配置文件

各个配置文件中的内容相应做了注释,请看下面的详细文件

 

服务端配置:

 

<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jaxws="http://cxf.apache.org/jaxws"
	xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.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-servlet.xml" />

	<jaxws:endpoint id="helloWorld"
		implementor="com.demo.cxf.helloword.impl.HelloWordImpl" address="/HelloWorld">
		<jaxws:inInterceptors>
			<ref bean="serverWSS4JInInterceptor" />
			<bean class="com.demo.cxf.helloword.ClientIpInInterceptor" />
			<bean class="org.apache.cxf.interceptor.LoggingInInterceptor" />
		</jaxws:inInterceptors>
		<jaxws:outInterceptors>
			<ref bean="serverWSS4JOutInterceptor" />
			<bean class="org.apache.cxf.interceptor.LoggingOutInterceptor" />
		</jaxws:outInterceptors>
	</jaxws:endpoint>
	
	<bean id="passwordCallback" class="com.demo.cxf.callbacks.PasswordCallback"></bean>
	<bean id="serverWSS4JInInterceptor" class="org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor">
		<property name="properties">
			<map>
				<entry key="action" value="Timestamp Encrypt Signature" />
				<!-- 
					服务器会自动在SOAP中拿到解码(私钥)的用户名,并在 PasswordCallback中取到密码。
					公钥不需要密码。
				-->
				<entry key="passwordCallbackRef">
					<ref bean="passwordCallback" />
				</entry>
				<entry key="decryptionPropFile" value="resource/properties/Server_Decrypt.properties" />
				<entry key="signaturePropFile" value="resource/properties/Server_SignVerf.properties" />
			</map>
		</property>
	</bean>
	<bean id="serverWSS4JOutInterceptor" class="org.apache.cxf.ws.security.wss4j.WSS4JOutInterceptor">
		<property name="properties">
			<map>
				<!-- 
					此处配置需注意,当指定Signature时就必须像UsernameToken那样指定user和passwordCallbackRef。
					因为假如我们没指定signatureUser或者encryptionUser,CXF将会使用user来替代之,而signatureUser的
					密码必须通过passwordCallbackRef赋值。所以哪怕定义了signatureUser也必须同时定义user,
					且不能为空。
					公钥不需要密码。
				 -->
				<entry key="action" value="Timestamp Encrypt Signature" />
				<!-- MD5加密明文密码 -->
				<entry key="passwordType" value="PasswordDigest" />
				<!-- 该用户名只能在激活了UsernameToken时才能拿到并使用 -->
				<entry key="user" value="admin" />
				<entry key="passwordCallbackRef">
					<ref bean="passwordCallback" />
				</entry>
				<entry key="encryptionPropFile" value="resource/properties/Server_SignVerf.properties" />
				<entry key="encryptionUser" value="clientkey" />
				<entry key="signaturePropFile" value="resource/properties/Server_Decrypt.properties" />
				<entry key="signatureUser" value="serverkey" />
			</map>
		</property>
	</bean>

</beans>
 

 

 

客户端配置:

 

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	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.xsd
		http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd">

	<jaxws:client id="helloClient" serviceClass="com.demo.cxf.helloword.HelloWord"
		address="http://10.248.157.51:8080/web_service/services/HelloWorld">
		<jaxws:inInterceptors>
			<ref bean="clientWSS4JInInterceptor"/>
		</jaxws:inInterceptors>
		<jaxws:outInterceptors>
			<ref bean="clientWSS4JOutInterceptor" />
		</jaxws:outInterceptors>
	</jaxws:client>
	
	<bean id="passwordCallback" class="com.demo.cxf.callbacks.PasswordCallback"></bean>
	<bean id="clientWSS4JInInterceptor" class="org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor">
		<property name="properties">
			<map>
				<entry key="action" value="Timestamp Encrypt Signature" />
				<entry key="passwordCallbackRef">
					<ref bean="passwordCallback" />
				</entry>
				<entry key="decryptionPropFile" value="resource/properties/Client_Sign.properties" />
				<entry key="signaturePropFile" value="resource/properties/Client_Encrypt.properties" />
			</map>
		</property>
	</bean>
	<bean id="clientWSS4JOutInterceptor" class="org.apache.cxf.ws.security.wss4j.WSS4JOutInterceptor">
		<property name="properties">
			<map>
				<entry key="action" value="Timestamp Encrypt Signature" />
				<entry key="passwordType" value="PasswordDigest" />
				<entry key="user" value="admin" />
				<entry key="passwordCallbackRef">
					<ref bean="passwordCallback" />
				</entry>
				<entry key="encryptionPropFile" value="resource/properties/Client_Encrypt.properties" />
				<entry key="encryptionUser" value="serverkey" />
				<entry key="signaturePropFile" value="resource/properties/Client_Sign.properties" />
				<entry key="signatureUser" value="clientkey" />
			</map>
		</property>
	</bean>
</beans>

 

 

  • 客户端发送数据前:使用服务端的公钥进行加密,同时使用客户端的私钥进行签名
  • 服务端收到请求:使用服务端的私钥解密,并使用客户端的公钥进行签名验证
  • 服务端响应前:使用客户端的公钥进行加密,同时使用服务端的私钥进行签名
  • 客户端收到响应:使用客户端的私钥解密,并使用服务端的公钥进行签名验证

这两个配置文件的大致内容如上。

 

4.添加PasswordCallback

UsernameToken中就使用过,不多做解释,只是需要注意下面代码中的证书密码部分,证书密码在客户端和服务端分别只需要保存己方的私钥密码,公钥是不需要密码的。

 

package com.demo.cxf.callbacks;

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 PasswordCallback implements CallbackHandler {

	Map<String, String> user = new HashMap<String, String>();
	{
		// 用户名和密码
		user.put("admin", "123");
		user.put("su", "123");
		// 证书的密码
		user.put("serverkey", "myPassword");
		user.put("clientkey", "myPassword");
	}

	@Override
	public void handle(Callback[] callbacks) throws IOException,
			UnsupportedCallbackException {
		WSPasswordCallback wpc = (WSPasswordCallback) callbacks[0];
		System.out.println(wpc.getIdentifier());
		if (!user.containsKey(wpc.getIdentifier())) {
			throw new SecurityException("权限不足!");
		}
		/*
		 * 此处特别注意:: WSPasswordCallback 的passwordType属性和password 属性都为null,
		 * 你只能获得用户名(identifier), 一般这里的逻辑是使用这个用户名到数据库中查询其密码, 然后再设置到password
		 * 属性,WSS4J 会自动比较客户端传来的值和你设置的这个值。 你可能会问为什么这里CXF
		 * 不把客户端提交的密码传入让我们在ServerPasswordCallbackHandler 中比较呢?
		 * 这是因为客户端提交过来的密码在SOAP 消息中已经被加密为MD5 的字符串,
		 * 如果我们要在回调方法中作比较,那么第一步要做的就是把服务端准备好的密码加密为MD5 字符串, 由于MD5
		 * 算法参数不同结果也会有差别,另外,这样的工作CXF 替我们完成不是更简单吗?
		 */

		// 如果包含用户名,就设置该用户名正确密码,由CXF验证密码
		wpc.setPassword(user.get(wpc.getIdentifier()));
	}

}

 

5.其他的SEI和IMPL请参考上一篇中的代码,完全一样,附上代码。

 

 

分享到:
评论

相关推荐

    2.CXF安全访问之Http Basic Auth(一)

    本文将深入探讨CXF安全访问的一个重要方面:HTTP基本认证(Http Basic Auth)。这是一种简单但有效的身份验证机制,适用于对Web服务进行安全控制。 HTTP基本认证是基于HTTP协议的,它在请求头中包含一个Base64编码...

    cxf_helloworld.rar_SOA CXF_SOA JAVA _cxf_cxf helloworld_hellowor

    3. **配置CXF**:通过XML配置文件(如`cxf-servlet.xml`)来告诉CXF如何发布你的服务。 4. **发布服务**:将服务绑定到一个URL,使得其他应用可以通过网络访问。 5. **生成客户端代码**:使用CXF的wsdl2java工具,...

    4.CXF安全访问之单向SSL或者双向SSL(三)

    本篇将详细探讨如何使用CXF实现单向SSL(Secure Sockets Layer)和双向SSL的安全访问。首先,我们需要理解SSL的基本概念。 SSL是一种网络安全协议,用于在客户端和服务器之间建立加密连接,确保数据传输的隐私和...

    CXF-demo.zip_cxf_cxf 2.7.11 demo_cxf demo_cxf webservice demo_we

    这不仅涵盖了基本的Web服务概念,还包括了CXF特有的特性,如WS-Security(安全)、WS-ReliableMessaging(可靠消息传递)等。 为了更好地理解CXF的使用,你需要理解以下几个关键概念: - **JAX-WS**:Java API for...

    java_webservice_JAX-RS.zip_cxf_jax_jax-rs_spring cxf

    CXF允许开发者使用JAX-RS和JAX-WS标准来编写Web服务,并提供了丰富的功能,如WSDL(Web Services Description Language)生成、客户端API生成、数据绑定、安全支持等。 **4. CXF与Spring的整合** 将CXF与Spring...

    CXF接口所有所需jar包

    CXF接口所有所需jar包 1.cxf-2.3.3.jar 2.geronimo-annotation_1.0_spec-1.1.1.jar 3.geronimo-jaxws_2.2_spec-1.0.jar 4.geronimo-stax-api_1.0_spec-1.0.1.jar 5.geronimo-ws-metadata_2.0_spec-1.1.3.jar 6...

    org.apache.cxf.spring.remoting.Jsr181HandlerMapping.jar

    org.apache.cxf.spring.remoting.Jsr181HandlerMapping.jar

    java-1.8.0-openjdk-1.8.0.232-3.b09.redhat.windows.x86_64.rar

    在 Oracle 退出和变更许可后,红帽宣布接手维护 OpenJDK 8 和 OpenJDK 11,为这两个 OpenJDK 的旧版本提供错误修复和安全补丁。

    jaxb-api.jar.jaxws-api.zip_ jaxb-api.jar_cxf_jax-ws.jar_jaxb-api

    在Java开发中,CXF框架是一个广泛使用的开源服务框架,它支持Web服务的创建和消费。CXF框架提供了丰富的功能,包括SOAP、RESTful API、JAX-RS和JAX-WS等标准的实现。然而,在某些情况下,尤其是在使用Java 6的环境中...

    android_ksoap2_cxf_wss4j_authentication

    在服务器端,你可以使用CXF和WSS4J来设置安全策略,确保只有经过验证的客户端才能访问服务。 **Android客户端的令牌认证** 在Android客户端,使用Ksoap2进行认证通常涉及以下步骤: 1. **创建SOAP请求**:首先,你...

    02.CXF功能概述_CXF发展历史和使用CXF开发WebService服务器端

    【标题】"02.CXF功能概述_CXF发展历史和使用CXF开发WebService服务器端"主要探讨了Apache CXF框架在Web服务领域的应用及其发展历程,同时也涵盖了如何利用CXF来构建一个高效的WebService服务器端。 Apache CXF是一...

    ssh-dwr.rar_cxf_dwr_dwr stru_spring dwr_ssh购物车

    它还能与其他框架如Hibernate和Struts无缝集成,提供了事务管理和数据访问抽象。 Struts作为MVC(Model-View-Controller)设计模式的实现,主要负责处理HTTP请求和响应,将用户界面与业务逻辑分离。在描述中提到的...

    CXF打印SOAP报文,记录WebService日志

    import org.apache.cxf.phase.AbstractPhaseInterceptor; import org.apache.cxf.phase.Phase; public class InInterceptor extends AbstractPhaseInterceptor&lt;Message&gt; { private int limit = 102400; public ...

    apach-cxf-api.rar_API_cxf

    CXF提供了强大的WSDL第一和WSDL第二类工具,允许从Java代码生成WSDL,或从WSDL生成Java代码。 - **Data Binding**: CXF支持多种数据绑定框架,如JAXB(Java Architecture for XML Binding)和JAX-BRI(Java API for...

    apache-cxf-3.0.16.zip_cxf index:0_webservice

    3. **JAX-WS和JAX-RS实现**:CXF实现了Java API for XML Web Services (JAX-WS) 和Java API for RESTful Web Services (JAX-RS),使得开发者可以利用这些标准API轻松创建Web服务。 4. **多种绑定和数据格式支持**:...

    apache-cxf-2.4.1.rar_apache-cxf-2.4.1_cxf_web service

    3. `samples`目录:可能包含CXF官方提供的示例代码,这些示例可以帮助学习和理解如何使用CXF。 4. `docs`目录:可能包含CXF的用户手册、API文档和其他参考资料。 5. `schema`目录:可能包含CXF支持的XML schema定义...

Global site tag (gtag.js) - Google Analytics