设为首页收藏本站

SAP Best Business Solution

 找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 1996|回复: 0

基于SSL验证的Apache CXF客户端设计总结

[复制链接]

20

主题

21

帖子

164

积分

注册会员

Rank: 2

积分
164
发表于 2016-9-12 17:10:54 | 显示全部楼层 |阅读模式
原文来自:http://blog.csdn.net/zhangliang605/article/details/24101051

最近在与合作方进行接口对接,合作方只提供了一个WSDL链接和一个ce.p12证书,研究了好几天终于调通了。为了与合作方对接,我自己在本地搭建了一个使用证书验证的Tomcat,在本地用自己制作的客户端证书与本地Tomcat进行SSL链接,最终终于搞清楚了使用Apache CXF框架进行SSL链接的方法。

整个过程可以分为以下几个:



  • 认证过程
  • 认识证书
  • 制作证书
  • 编写服务器端Web Service接口
  • 配置Tomcat的SSL访问
  • 编写客户端调用程序
1. 认证过程
    HTTPS认证其实是基于证书认证,一般常用的是x509认证,认证过程是这样的
  • 客户端 ==> 服务器端 : 客户端A需要使用自己的私钥进行签名,使用服务器端B的公钥进行加密,然后将请求数据传给服务器端B,服务器端B使用服务器端B的私钥进行解密,再用客户端A的公钥进行验签。
  • 服务器端 ==> 客户端 : 服务器端B使用服务器端B的私钥进行签名,使用客户端A的公钥进行加密,然后将响应数据传给客户端A,客户端A用客户端A的私钥进行解密,再用服务器端B的公钥进行验签。
    在JAVA中制作证书可以采用JDK中提供的keytool和openssl,两者的区别在于,如果证书中没有相关的证书链那么完全可以采用keytool,否则就需要用openssl工具。


2,认识证书    我们要生成的证书包括以下几个:
  • 根证书 : 根证书一般是起认证作用的,也可以称做CA,有相关的CA认证机构,不过一般需要花钱取实现CA认证,在这里根证书采用的是自签的方式。
  • 服务器端证书 : 服务器端证书由根证书签署,在服务器端配置使用。
  • 二级证书 : 二级证书由根证书签署,在服务器端配置使用。
  • 客户端证书 : 客户端证书由根证书签署,在客户端配置使用。

3,制作证书
3.1 制作根证书[html] view plain copy


  • mkdir root  
  • # 制作根证书  
  • openssl genrsa -out root/root-key.pem 1024  
  • # 创建证书请求  
  • openssl req -new -out root/root-req.csr -key root/root-key.pem -subj /C=CN/ST=BeiJing/L=BeiJing/O="Xiaomi Technologies Co. Ltd."/OU="MIUI System Safety Team"/OU="MIUI System Safety Team"/CN="localhost"/emailAddress=xxxxxx@xiaomi.com  
  • # 自签署根证书  
  • openssl x509 -req -in root/root-req.csr -out root/root-cert.pem -signkey root/root-key.pem -days 3650  
  • # 将证书导入到JKS文件中  
  • /usr/lib/jvm/java/jdk1.6.0_45/bin/keytool -import -v -trustcacerts -storepass xiaomisys -alias root -file root/root-cert.pem -keystore root/root-id.jks  
  • # 将证书导出成cer文件  
  • /usr/lib/jvm/java/jdk1.6.0_45/bin/keytool -export -alias root -keystore root/root-id.jks -file root/root-id.cer -storepass xiaomisys  


3.2 制作服务器端证书

[html] view plain copy


  • cd root  
  • #建立server文件夹  
  • mkdir server  
  • #回到root上级一目录  
  • cd ..  
  • #创建私钥  
  • openssl genrsa -out root/server/temip-key.pem 1024  
  • #创建证书请求(注意cn如果是本机应该填写localhost,如果是网站则填写域名.)  
  • openssl req -new -out root/server/temip-req.csr -key root/server/temip-key.pem -subj /C=CN/ST=BeiJing/L=BeiJing/O="Xiaomi Technologies Co. Ltd."/OU="MIUI System Safety Team"/OU="MIUI System Safety Team"/CN=localhost/emailAddress=xxxxxx@xiaomi.com  
  • #签署服务器端证书  
  • openssl x509 -req -in root/server/temip-req.csr -out root/server/temip-cert.pem -CA root/root-cert.pem -CAkey root/root-key.pem -CAcreateserial -days 3650  
  • #将服务器端证书PKCS12格式  
  • openssl pkcs12 -export -clcerts -in root/server/temip-cert.pem -inkey root/server/temip-key.pem -out root/server/temip-id.p12  


3.3 制作二级证书

[html] view plain copy


  • cd root  
  • #建立client文件夹  
  • mkdir client  
  • #回到root上一目录  
  • cd ..  
  • #创建私钥  
  • openssl genrsa -out root/client/eomsca-key.pem 1024  
  • #创建证书请求  
  • openssl req -new -out root/client/eomsca-req.csr -key root/client/eomsca-key.pem -subj /C=CN/ST=BeiJing/L=BeiJing/O="Xiaomi Technologies Co. Ltd"/OU="MIUI System Safety Team"/OU="MIUI System Safety Team"/CN="localhost"/emailAddress=xxxxxx@xiaomi.com -reqexts v3_req  
  • #自签署客户端证书  
  • openssl x509 -req -in root/client/eomsca-req.csr -out root/client/eomsca-cert.pem -signkey root/client/eomsca-key.pem -CA root/root-cert.pem -CAkey root/root-key.pem -CAcreateserial -days 3650  
  • #将客户端证书导出成浏览器可导入的PKCS12格式  
  • openssl pkcs12 -export -clcerts -in root/client/eomsca-cert.pem -inkey root/client/eomsca-key.pem -out root/client/eomsca-id.p12  


3.4 制作客户端证书

[html] view plain copy


  • #创建私钥  
  • openssl genrsa -out root/client/xm_xiaomi-key.pem 1024  
  • #创建证书请求  
  • openssl req -new -out root/client/xm_xiaomi-req.csr -key root/client/xm_xiaomi-key.pem -subj /C=CN/ST=BeiJing/L=BeiJing/O="Xiaomi Technologies Co. Ltd"/OU="MIUI System Safety Team"/OU="MIUI System Safety Team"/CN="localhost"/emailAddress=xxxxxx@xiaomi.com  
  • #自签署客户端证书  
  • openssl x509 -req -in root/client/xm_xiaomi-req.csr -out root/client/xm_xiaomi-cert.pem -signkey root/client/xm_xiaomi-key.pem -CA root/client/eomsca-cert.pem -CAkey root/client/eomsca-key.pem -CAcreateserial -days 3650  
  • #将客户端证书导出成浏览器可导入的PKCS12格式  
  • openssl pkcs12 -export -clcerts -in root/client/xm_xiaomi-cert.pem -inkey root/client/xm_xiaomi-key.pem -out root/client/xm_xiaomi-id.p12  


3.5 最终的成果

最终要用到的证书文件有3个temip-id.p12,eomsca-id.p12,xm_xiaomi-id.p12,双击它们,输入密码,可以看到证书信息,比较重要的是CN(Common Name)在本地的话一定要填写成localhost,如果是对外的可以填写成IP地址:





4,编写服务器端Web Service接口4.1 项目目录

搭建Apache CXF框架和环境的方法就忽略了,网上很多了,下面是我的服务器端demo代码结构:







4.2 Web Service接口代码[java] view plain copy


  • package com.server;  
  •   
  • import javax.jws.WebService;  
  •   
  • /**
  • * Web Service 接口声明
  • * @author liang
  • */  
  • @WebService(targetNamespace = "server.com")  
  • public interface HelloWorld {  
  •   
  •     /**
  •      * sayHi
  •      * @param text
  •      * @return
  •      */  
  •     String sayHi(String text);  
  • }  


4.3 Web Service实现类代码[java] view plain copy


  • package com.server;  
  •   
  • import javax.jws.WebService;  
  •   
  • /**
  • * Web Service接口实现
  • * @author liang
  • *
  • */  
  • @WebService(endpointInterface = "com.server.HelloWorld")  
  • public class HelloWorldImpl implements HelloWorld {  
  •   
  •     @Override  
  •     public String sayHi(String text) {  
  •         // TODO Auto-generated method stub  
  •         return "Hello, " + text;  
  •     }  
  •   
  • }  



4.4 spring-cxf.xml内容

[html] view plain copy




4.5 web.xml内容[html] view plain copy


  • <?xml version="1.0" encoding="UTF-8"?>  
  • <web-app version="3.0"   
  •     xmlns="http://java.sun.com/xml/ns/javaee"   
  •     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"   
  •     xsi:schemaLocation="http://java.sun.com/xml/ns/javaee   
  •     http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">  
  •   <display-name></display-name>  
  •   <!-- spring需要加载的配置文件 -->  
  •   <context-param>  
  •     <param-name>contextConfigLocation</param-name>  
  •     <param-value>  
  •         classpath:com/server/spring-cxf.xml  
  •     </param-value>  
  •   </context-param>      
  •   <listener>  
  •         <listener-class>  
  •             org.springframework.web.context.ContextLoaderListener  
  •         </listener-class>  
  •   </listener>  
  •   <!-- cxf服务启动servlet -->  
  •   <servlet>  
  •         <servlet-name>CXFServlet</servlet-name>  
  •         <servlet-class>  
  •             org.apache.cxf.transport.servlet.CXFServlet  
  •         </servlet-class>  
  •         <load-on-startup>1</load-on-startup>  
  •   </servlet>  
  •   <servlet-mapping>  
  •         <servlet-name>CXFServlet</servlet-name>  
  •         <url-pattern>/service/*</url-pattern>  
  •   </servlet-mapping>  
  •   <welcome-file-list>  
  •     <welcome-file>index.jsp</welcome-file>  
  •   </welcome-file-list>  
  • </web-app>  



4.5 服务器端总结

此时,我们还没有配置Tomcat的SSL访问设置,因此可以使用http来访问WSDL,启动Tomcat后可以在浏览器中输入http://localhost:8080/cxf-deom/service/HelloWorld?WSDL就可以看到Web Service的描述了。

5,Tomcat配置SSL现在,我们来配置服务器端的Tomcat,使得服务器端Tomcat支持SSL访问

5.1,配置Tomcat找到Tomcat的conf目录下的server.xml,搜索"8443"找到对应SSL的配置,该配置段默认是注释掉的,解除注释并修改成下面的样子:

[html] view plain copy


  • <Connector port="8443"  address="0.0.0.0" protocol="HTTP/1.1" SSLEnabled="true"   
  •                maxThreads="150" scheme="https" secure="true"   
  •                clientAuth="true" sslProtocol="TLS"   
  •            keystoreFile="/home/work/server/cer/temip-id.p12" keystoreType="PKCS12" keystorePass="xiaomisys"   
  •            truststoreFile="/home/work/server/cer/eomsca-id.p12" truststoreType="PKCS12" truststorePass="xiaomisys"/>   


修改完Tomcat配置后,重新启动Tomcat,在浏览器中输入https://localhost:8443/cxf-deom/service/HelloWorld?WSDL,会发现无法访问了。


5.2,chrome浏览器中导入证书打开chrome的设置页面,搜索SSL,然后点击"Mange certificates",点击"import",然后导入客户端证书xm-xiaomi-id.p12,导入时会要求输入密码。
再次访问https://localhost:8443/cxf-deom/service/HelloWorld?WSDL,chrome会弹出对话框,要求确认证书,点击"OK",接下来会提醒你说"该证书是不被信任的",选择"Process anyway",然后就能看到WSDL页面了。















如果最终看到了WSDL就说名Tomcat配置是正确的,证书也是正确的。


6,编写客户端程序
我们客户端要想通过HTTPS访问服务器端的Web Service服务,首先是要在客户端生成一个服务器Web Service服务的对象实例,其次是为给对象实例设置证书信息,然后就可以用这个对象实例直接调用Web Service声明的方法来访问了。

6.1 客户端设置信任证书信息 -- 使用代码实现[java] view plain copy


  • package com.util;  
  •   
  • import java.io.File;  
  • import java.io.FileInputStream;  
  • import java.io.IOException;  
  • import java.io.InputStream;  
  • import java.security.KeyStore;  
  •   
  • 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.jaxws.JaxWsProxyFactoryBean;  
  • import org.apache.cxf.transport.http.HTTPConduit;  
  •   
  • import com.server.HelloWorld;  
  •   
  • public class ClientUtils {  
  •   
  •     private static HelloWorld helloWorld;  
  •   
  •     public static HelloWorld getInstance(){  
  •   
  •         if(null != helloWorld){  
  •             return helloWorld;  
  •         }  
  •   
  •         try{  
  •             String addr = "https://localhost:8443/cxf-demo/service/HelloWorld";  
  •             JaxWsProxyFactoryBean factoryBean = new JaxWsProxyFactoryBean();  
  •             factoryBean.setAddress(addr);  
  •             factoryBean.setServiceClass(HelloWorld.class);  
  •             helloWorld = (HelloWorld) factoryBean.create();  
  •               Client proxy = ClientProxy.getClient(helloWorld);  
  •               HTTPConduit conduit = (HTTPConduit) proxy.getConduit();  
  •               TLSClientParameters tlsParams = conduit.getTlsClientParameters();  
  •               if (tlsParams == null) {  
  •                tlsParams = new TLSClientParameters();  
  •               }  
  •               tlsParams.setDisableCNCheck(true);  
  •               //设置keystore  
  •               tlsParams.setKeyManagers(ClientUtils.getKeyManagers());  
  •               // 设置信任证书  
  •               tlsParams.setTrustManagers(ClientUtils.getTrustManagers());  
  •               conduit.setTlsClientParameters(tlsParams);  
  •         }catch(Exception e){  
  •             e.printStackTrace();  
  •         }  
  •   
  •         return helloWorld;  
  •     }  
  •   
  •     public static KeyManager[] getKeyManagers() {  
  •           InputStream is = null;  
  •           try {  
  •            // 获取默认的 X509算法  
  •            String alg = KeyManagerFactory.getDefaultAlgorithm();  
  •            // 创建密钥管理工厂  
  •            KeyManagerFactory factory = KeyManagerFactory.getInstance(alg);  
  •            File certFile = new File("/home/liang/Documents/works/servers/tomcat/cer/xm_xiaomi-id.p12");  
  •            if (!certFile.exists() || !certFile.isFile()) {  
  •             return null;  
  •            }  
  •            is = new FileInputStream(certFile);  
  •            // 构建以证书相应格式的证书仓库  
  •            KeyStore ks = KeyStore.getInstance("pkcs12");  
  •            // 加载证书  
  •            ks.load(is, "changeit".toCharArray());  
  •            factory.init(ks, "changeit".toCharArray());  
  •            KeyManager[] keyms = factory.getKeyManagers();  
  •            return keyms;  
  •           } catch (Exception e) {  
  •            e.printStackTrace();  
  •           } finally {  
  •            if (is != null) {  
  •             try {  
  •              is.close();  
  •             } catch (IOException e) {  
  •              e.printStackTrace();  
  •             }  
  •            }  
  •   
  •           }  
  •           return null;  
  •         }  
  •   
  •     public static TrustManager[] getTrustManagers() {  
  •           // 读取证书仓库输入流  
  •           InputStream is = null;  
  •           try {  
  •            // 信任仓库的默认算法X509  
  •            String alg = TrustManagerFactory.getDefaultAlgorithm();  
  •            // 获取信任仓库工厂  
  •            TrustManagerFactory factory = TrustManagerFactory.getInstance(alg);  
  •            // 读取信任仓库  
  •            is = new FileInputStream(new File("/home/liang/Documents/works/servers/tomcat/cer/temip-id.p12"));  
  •            // 密钥类型  
  •            KeyStore ks = KeyStore.getInstance("pkcs12");  
  •            // 加载密钥  
  •            ks.load(is, "changeit".toCharArray());  
  •            factory.init(ks);  
  •            TrustManager[] tms = factory.getTrustManagers();  
  •            return tms;  
  •           } catch (Exception e) {  
  •            e.printStackTrace();  
  •   
  •           } finally {  
  •            if (is != null) {  
  •             try {  
  •              is.close();  
  •             } catch (IOException e) {  
  •              e.printStackTrace();  
  •             }  
  •            }  
  •           }  
  •           return null;  
  •         }  
  • }  


6.2 客户端置信任证书信息 -- 使用配置文件实现


[html] view plain copy


  • <?xml version="1.0" encoding="UTF-8"?>  
  • <beans xmlns="http://www.springframework.org/schema/beans"  
  • xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jaxws="http://cxf.apache.org/jaxws"  
  • xmlns:soap="http://cxf.apache.org/bindings/soap" xmlns:context="http://www.springframework.org/schema/context"  
  • xmlns:sec="http://cxf.apache.org/configuration/security" xmlns:http="http://cxf.apache.org/transports/http/configuration"  
  • xsi:schemaLocation="http://www.springframework.org/schema/beans  
  •                     http://www.springframework.org/schema/beans/spring-beans.xsd  
  •                     http://cxf.apache.org/bindings/soap  
  •                     http://cxf.apache.org/schemas/configuration/soap.xsd  
  •                     http://cxf.apache.org/jaxws  
  •                     http://cxf.apache.org/schemas/jaxws.xsd  
  •                     http://cxf.apache.org/configuration/security  
  •                     http://cxf.apache.org/schemas/configuration/security.xsd  
  •                     http://cxf.apache.org/transports/http/configuration  
  •                     http://cxf.apache.org/schemas/configuration/http-conf.xsd">  
  •   
  •     <jaxws:client id="helloClient"  
  •                   serviceClass="com.server.HelloWorld"  
  •                   address="https://localhost:8443/cxf-demo/service/HelloWorld" />  
  •   
  •         <!-- *代码所的客户端可以访问 -->  
  •     <http:conduit name="*.http-conduit">  
  •       <http:tlsClientParameters disableCNCheck="true">  
  •        <sec:trustManagers>  
  •         <sec:keyStore type="PKCS12" password="changeit" file="/home/liang/Documents/works/servers/tomcat/cer/temip-id.p12" />  
  •        </sec:trustManagers>  
  •        <!--双向认证 -->  
  •        <sec:keyManagers keyPassword="changeit">  
  •         <sec:keyStore type="PKCS12" password="changeit" file="/home/liang/Documents/works/servers/tomcat/cer/xm_xiaomi-id.p12" />  
  •        </sec:keyManagers>  
  •   
  •        <sec:cipherSuitesFilter>  
  •         <!-- these filters ensure that a ciphersuite with export-suitable or  
  •          null encryption is used, but exclude anonymous Diffie-Hellman key change  
  •          as this is vulnerable to man-in-the-middle attacks -->  
  •         <sec:include>.*_EXPORT_.*</sec:include>  
  •         <sec:include>.*_EXPORT1024_.*</sec:include>  
  •         <sec:include>.*_WITH_DES_.*</sec:include>  
  •         <sec:include>.*_WITH_NULL_.*</sec:include>  
  •         <sec:exclude>.*_DH_anon_.*</sec:exclude>  
  •        </sec:cipherSuitesFilter>  
  •       </http:tlsClientParameters>  
  •     </http:conduit>  
  • </beans>  


6.3 客户端通过HTTPS调用服务器Web Service服务


[java] view plain copy


  • package com.client;  
  •   
  • import org.springframework.context.support.ClassPathXmlApplicationContext;  
  •   
  • import com.server.HelloWorld;  
  • import com.util.ClientUtils;  
  •   
  • /**
  • * 客户端访问服务器Web Service
  • * @author liang
  • *
  • */  
  • public final class ClientTest {  
  •   
  •     public static void main(String args[]) throws Exception {  
  •   
  •         test2();  
  •   
  •     }  
  •   
  •     /**
  •      * 测试1,通过代码设置实例证书
  •      */  
  •     public static void test1(){  
  •         HelloWorld client = ClientUtils.getInstance();  
  •   
  •         String response = client.sayHi("Joe");  
  •         System.out.println("Response: " + response);  
  •         System.exit(0);  
  •     }  
  •   
  •     /**
  •      * 测试2, 通过配置文件设置实例证书
  •      */  
  •     public static void test2(){  
  •             ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(  
  •                     "beans.xml");  
  •   
  •             HelloWorld client = (HelloWorld) context.getBean("helloClient");  
  •   
  •             String response = client.sayHi("Joe");  
  •             System.out.println("Response: " + response);  
  •             System.exit(0);  
  •     }  
  •   
  • }  


以上两种方法都可以访问SSL设置的Web Service服务,然后在控制台打印输出信息。


至此,一个通过HTTPS访问Web Service的例子就搞定了。

参考 : http://liuwuhen.iteye.com/blog/1661493

回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



QQ|Archiver|手机版|小黑屋|www.sapbbs.com    

GMT+8, 2019-8-21 03:31 , Processed in 1.065519 second(s), 28 queries .

声明:本站严禁任何人以任何形式在本论坛发表与中华人民共和国法律相抵触的言论!

本站内容由网友原创或转载,如果侵犯了您的合法权益,请及时联系处理!© admin@sapbbs.com

快速回复 返回顶部 返回列表