Tomcat 配置设置https访问(单向验证)


注1:以下内容SSL链路加密(对来往数据进行加密)或单向验证(只验证服务端)的步骤,也是tomcat配置https双向验证的一部分。双向验证需要使用两对证书,客户端与服务端互相交换公钥,发送消息时A使用自己的私钥加密数据,B使用A的公钥解密。 
注2:分析IE实现实现SSL连接的中的证书双向认证过程: 
在地址栏中输入https://localhost:8443 
客户端向服务器发送hello消息,tomcat服务器侦听8443端口,收到SSL连接的hello消息,服务器发送server certificate,并且发送client certificate request.客户端IE收到server certificate后取出issuer项,和IE受信任的根证书库中证书的subject比对,找到合适的根证书认证server certificate。并且同时向服务器发送client certificate,服务器收到client certificate后,tomcat服务器查找根证书库cacerts中的根证书的suject,找到合适的根证书认证client certificate.在认证的同时完成密钥协商。客户端认证结束后,IE会弹出"安全警报"对话框,用户可以查看服务器证书,以及服务器证书是否受信任,可以选择是否继续SSL连接。 

参考链接: 
1. Java+Https+Tomcat双向验证实例: http://blog.csdn.net/zhongming_software/article/details/8592331 
2. Tomcat+Axis2 WebService配置SSL单向验证: http://blog.csdn.net/honglei915/article/details/6073290 
3. Tomcat配置HTTPS方式(单向): http://www.blogjava.net/stevenjohn/archive/2012/09/26/388600.html 

1. 服务端创建KeyStore命令:
Java代码   收藏代码
  1. keytool -genkey -alias server_jks_testws -keyalg RSA -keypass changeit -storepass changeit -keystore server_jks_testws.jks -validity 3650.  

引用
keytool命令如下: 
-genkey             在用户主目录中创建一个默认文件".jks",还会产生一个server_jks_cennavi的别名,server_jks_cennavi中包含用户的公钥、私钥和证书 
-alias             产生别名server_jks_testws 
-keystore      指定密钥库的名称(产生的各类信息将不在.jks文件中 
-keyalg          指定密钥的算法    
-validity          指定创建的证书有效期多少天 
-keysize        指定密钥长度 
-storepass   指定密钥库的密码 
-keypass      指定别名条目的密码 
-dname        指定证书拥有者信息


 

引用
注:上图中的名字和姓氏代表客户端访问的域名或ip地址(即服务端的对外地址,比如www.sina.com.cn或127.0.0.1),上图设置localhost代表服务端运行在本机,客户端访问本机服务。这个地方名字若和服务端实际运行地址不一样,则浏览器访问https链接会出现证书不匹配错误!

在C:\Users\Administrator\目录下生成server_jks_testws.jks文件,此文件包含服务端的公钥、私钥和证书。 
2. 发布http非加密服务,查看soap包数据 
2.1 在服务端发布webservice接口,接口代码如下:
 
  
Java代码   收藏代码
  1. public int sum(int num1, int num2) throws AxisFault {  
  2.         LoginCheck.checkUserPwd();   
  3. // 当客户端调用getPrice方法是,在此处先进行用户名和密码校验,如果校验通过则继续后续逻辑处理,如果不通过则抛出异常。  
  4.         return num1 + num2;  
  5.   }  
  6.   LoginCheck进行用户验证,代码如下:  
  7.   public class LoginCheck {  
  8.   public static void checkUserPwd() throws AxisFault {  
  9.         MessageContext msgContext = MessageContext.getCurrentMessageContext();  
  10.         Iterator list = (Iterator) msgContext.getEnvelope().getHeader().getFirstElement().getChildren();  
  11.         String Username = "";  
  12.         String Password = "";  
  13.         while (list.hasNext()) {  
  14.             OMElement element = (OMElement) list.next();  
  15.             if (element.getLocalName().equals("Username")) {  
  16.                 Username = element.getText();  
  17.             }  
  18.             if (element.getLocalName().equals("Password")) {  
  19.                 Password = element.getText();  
  20.             }  
  21.         }  
  22.         if (!Username.equals("toone") || !Password.equals("111")) {  
  23.             throw new AxisFault(" Authentication Fail! Check username/password ");  
  24.         }else{  
  25.             System.out.println("use:"+Username+"验证通过");  
  26.         }  
  27.   }  
  28.   }  

2.2 客户端访问代码 
Java代码   收藏代码
  1. public class TestClient {  
  2.     public static void main(String[] args) {  
  3.         try {  
  4. //          WSStub stub = new WSStub("https://localhost:8553/TestWS/services/WS");  
  5.             WSStub stub = new WSStub("http://localhost:8080/TestWS/services/WS");                               ServiceClient sc = stub._getServiceClient();  
  6.             sc.addHeader(HeaderOMElement.createHeaderOMElement());  
  7.             stub._setServiceClient(sc);  
  8.               
  9.             WSStub.Sum sums = new WSStub.Sum();  
  10.             sums.setNum1(2);  
  11.             sums.setNum2(3);  
  12.             WSStub.SumResponse sr = stub.sum(sums);  
  13.             System.out.println(sr.get_return());  
  14.               
  15. //          WSStub.GetPrice gp = new WSStub.GetPrice();  
  16. //          gp.setSymbol("sino");  
  17. //          WSStub.GetPriceResponse gpr = stub.getPrice(gp);  
  18. //          System.out.println(gp.getSymbol()+" : "+gpr.get_return());  
  19.   
  20.         }  catch (AxisFault e) {  
  21.             System.out.println("验证失败:"+e.getMessage());  
  22.             e.printStackTrace();  
  23.         }catch (RemoteException e) {  
  24.             System.out.println("远程连接失败:"+e.getMessage());  
  25.             e.printStackTrace();  
  26.         }  
  27.     }  
  28. }  

其中HeaderOMElement.createHeaderOMElement()指的是将用户信息添加到soap header中,用于服务端验证。 
代码如下: 
Java代码   收藏代码
  1. public class HeaderOMElement {  
  2.     public static OMElement createHeaderOMElement() {  
  3.         OMFactory factory = OMAbstractFactory.getOMFactory();  
  4.         OMNamespace SecurityElementNamespace = factory.createOMNamespace("http://handler.com""wsse");  
  5.         OMElement authenticationOM = factory.createOMElement("Authentication",SecurityElementNamespace);  
  6.         OMElement usernameOM = factory.createOMElement("Username",SecurityElementNamespace);  
  7.         OMElement passwordOM = factory.createOMElement("Password",SecurityElementNamespace);  
  8.         usernameOM.setText("toone");  
  9.         passwordOM.setText("111");  
  10.         authenticationOM.addChild(usernameOM);  
  11.         authenticationOM.addChild(passwordOM);  
  12.         return authenticationOM;  
  13.     }  
  14. }  
2.3 抓包显示,通过TcpTrace抓包显示截图如下: 

上图中用户信息和接口参数的双向传递都是明文。 
3. 设置tomcat https访问 
服务端 
3.1 修改%TOMCAT_HOME%/conf/server.xml文件
  将原server.xml文件中对应部分代码去掉注释,并添加相应代码,如下: 
  
Java代码   收藏代码
  1. <Connector port="8443" protocol="HTTP/1.1" SSLEnabled="true"  
  2.                maxThreads="150" scheme="https" secure="true"  
  3.                clientAuth="false" sslProtocol="TLS"   
  4.                keystoreFile="C:\Users\Administrator\server_jks_testws.jks" keystorePass="changeit"/>  
  5.     <!-- clientAuth="false" 代表ssl单向验证,即只验证服务端-->  
注:keystorePass="changeit",对应第一部分申请证书时的密码设置。 
3.2 修改%TOMCAT_HOME%/conf/web.xml文件 
  屏蔽http链接,所有http访问都重定向为https访问,在文件结尾添加代码: 
   
Java代码   收藏代码
  1. <login-config>  
  2.           <auth-method>CLIENT-CERT</auth-method>  
  3.           <realm-name>Client Cert Users-only Area</realm-name>  
  4.       </login-config>  
  5.       <security-constraint>  
  6.           <web-resource-collection >  
  7.               <web-resource-name >SSL</web-resource-name>  
  8.               <url-pattern>/*</url-pattern>  
  9.           </web-resource-collection>  
  10.           <user-data-constraint>  
  11.               <transport-guarantee>CONFIDENTIAL</transport-guarantee>  
  12.           </user-data-constraint>  
  13.       </security-constraint>  

客户端 
3.3 将服务端证书*.jks文件复制到客户端特定目录下,并在客户端添加灰色背景代码
Java代码   收藏代码
  1. public class TestClient {  
  2.     private static String trustKeyStore = "D:/Workspace/TestWSClient/jks/server_jks_testws.jks";  
  3.     public static void main(String[] args) {  
  4.         //添加服务器信任证书  
  5.         System.setProperty("javax.net.ssl.trustStore", trustKeyStore);  
  6.         System.setProperty("javax.net.ssl.trustStorePassword""changeit");  
  7.         try {  
  8.             WSStub stub = new WSStub("https://localhost:8443/TestWS/services/WS");  
  9. //          WSStub stub = new WSStub("http://localhost:8080/TestWS/services/WS");                               ServiceClient sc = stub._getServiceClient();  
  10.             sc.addHeader(HeaderOMElement.createHeaderOMElement());  
  11.             stub._setServiceClient(sc);  
  12.               
  13.             WSStub.Sum sums = new WSStub.Sum();  
  14.             sums.setNum1(2);  
  15.             sums.setNum2(3);  
  16.             WSStub.SumResponse sr = stub.sum(sums);  
  17.             System.out.println(sr.get_return());  
  18.               
  19. //          WSStub.GetPrice gp = new WSStub.GetPrice();  
  20. //          gp.setSymbol("sino");  
  21. //          WSStub.GetPriceResponse gpr = stub.getPrice(gp);  
  22. //          System.out.println(gp.getSymbol()+" : "+gpr.get_return());  
  23.   
  24.         }  catch (AxisFault e) {  
  25.             System.out.println("验证失败:"+e.getMessage());  
  26.             e.printStackTrace();  
  27.         }catch (RemoteException e) {  
  28.             System.out.println("远程连接失败:"+e.getMessage());  
  29.             e.printStackTrace();  
  30.         }  
  31.     }  
  32. }  

3.4 抓包显示,通过TcpTrace抓包显示截图如下: 




4. 配置特定资源访问使用https某些情况下,某些特定资源需要走https协议,如登录请求。这时,我们可以在web.xml中配置约束。 
  
Java代码   收藏代码
  1. <security-constraint>  
  2.          <web-resource-collection>  
  3.              <web-resource-name>SSL Resource</web-resource-name>  
  4.              <url-pattern>/index.jsp</url-pattern>  
  5.          </web-resource-collection>  
  6.          <user-data-constraint>  
  7.               <transport-guarantee>CONFIDENTIAL</transport-guarantee>  
  8.          </user-data-constraint>  
  9.   </security-constraint>  

这样当使用如下请求访问登录页面时,则服务器将该请求建立在https连接上。 
  http://localhost:8080/TestWS/index.jsp 


备注: 
TcpTrace设置:监听8888,目的地地址:localhost,转发8443 
客户端访问:http://localhost:8888/TestWS/,则是指将数据包发往8888,TcpTrace接收到数据包转发给8443 

问题1:org.apache.axis2.AxisFault: Transport error: 302 Error: Moved Temporarily 
若在tomcat中配置http(端口8080)访问自动转到https(端口8443),使用TcpTrace进行端口转发抓包时会报错: 
org.apache.axis2.AxisFault: Transport error: 302 Error: Moved Temporarily 
at org.apache.axis2.transport.http.HTTPSender.handleResponse(HTTPSender.java:296) 
at org.apache.axis2.transport.http.HTTPSender.sendViaPost(HTTPSender.java:190) 
at org.apache.axis2.transport.http.HTTPSender.send(HTTPSender.java:75) 
at org.apache.axis2.transport.http.CommonsHTTPTransportSender.writeMessageWithCommons(CommonsHTTPTransportSender.java:371)
at org.apache.axis2.transport.http.CommonsHTTPTransportSender.invoke(CommonsHTTPTransportSender.java:209)
at org.apache.axis2.engine.AxisEngine.send(AxisEngine.java:448) 
at org.apache.axis2.description.OutInAxisOperationClient.send(OutInAxisOperation.java:401) 
at org.apache.axis2.description.OutInAxisOperationClient.executeImpl(OutInAxisOperation.java:228) 
at org.apache.axis2.client.OperationClient.execute(OperationClient.java:163) 
at com.*.webservice.WSStub.sum(WSStub.java:210) 
at com.*.testws.TestClient.main(TestClient.java:28) 
验证失败:Transport error: 302 Error: Moved Temporarily 
问题2:java.security.UnrecoverableKeyException: Password verification failed 
由于keytool设置证书的默认密码是changeit,若改为其他密码,则会导致在客户端调用时出现错误: 
java.security.UnrecoverableKeyException: Password verification failed 
暂时解决方法是将证书的密码设置为changeit,参考链接:http://www.wirelust.com/ 
其他解决方法还需要继续研究。 

问题3: 
如果AC主机不能通过域名查找,必须使用IP,但是这个IP只有在配置后才能确定,这样证书就必须在AC确定IP地址后才能生成。 
问题4: 
证书文件只能绑定一个IP地址,假设有10.1.25.250 和 192.168.1.250 两个IP地址,在证书生成文件时,如使用了10.1.25.250,通过IE就只能使用10.1.25.250 来访问AC-WEB,192.168.1.250是无法访问AC-WEB的。
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值