和第三部分同样,这部分内容其实应该在后面才对,不过当前工作既然做了,也需要写下来分享,那么就提前插队到成长记录当中吧。看了这篇文章以后,可能给人的感觉是有点偏离服务框架的内容。的却,如果纯粹从技术方面来说,这部分应该不属于服务框架范畴。拿杭州作个例子,杭州是全国唯一一个景点不但不涨价,反而免门票的地方,原因何在,无非是管理者看得远,景点的门票收益看得到,但是是小头,免去门票带来的商机那才是金矿。框架其实也是这样,如果客户用起来不方便,甚至都不能用,那么框架再好,也会有人笑话你是个高高在上的理论主意者,这种框架适合于教学,而非实用。现在也是在迈出平台服务框架兼容性的第一步,那天和同事们开玩笑说,以前联通移动的wap业务,好在大家的开发语言都相似,isp只需要兼容各种手机客户端,我们现在要做的就是兼容各种不同开发语言,平台,以后甚至浏览器,我们这种全部都搞通的人出去,那就真的是抢手货了。
周一测试部和ISV support小组的日报反映,.net的客户端对于复杂对象数组返回有问题,紧接着就是.net客户端对于web service的wsse无法调试通过。我以前没有接触过.net,没办法,硬着个头皮装了个vs2005和WSE 3。前面一个问题就是我前面半周间断性的解决的问题,在第三篇记录中也写了。后面的问题比较紧急,也比较严重,因为如果wsse不能顺利调试通过,那么将会直接影响我们后续将wsse全面部署的计划,同时ISV已经跟在后面作测试了。看了看时间进度表,下周要进入平台搜索引擎增强的开发和WSSE性能优化(WSSE对于CPU的消耗真是厉害),因此也就只有两天,周四和周五。昨天晚上调试到了很晚(我说的很晚可能有些朋友觉得很早,不过对于我这种早睡早起的人来说,真的算晚了),虽然尽力了,但是还是卡在了最后的部分(服务端返回内容的验证解析),周五一大早到公司就开始继续调试,一直到了下午5点钟,我的神哪,让我看到那个断点不再跳出一个令我已经看到都反胃的出错提示框(顺便说一下,微软的vs出错提示框作的蛮精致,不过再好看都是出错,2天内看到了不下数百次,再好看也让人反胃了),最后在群里面大大的发泄了一把,公司一堆人觉得莫名其妙,不知道我受了什么打击,就搞通一个东西能够压抑成这样,其实这其中的苦也就自己知道,还是那句话:“在没有调试过.net的程序以前不知道开源的好啊,能看到源码是多么开心的一件事情啊,整一个在替微软作白盒测试,连google都被我翻烂了,也就只看到几个老外在Q,而没有人在那儿A”。废话说了那么多,言归正传,实践是建立在理论基础上的,那么先系统性的来介绍一下关于WSSE的内容(如果概念已经十分熟悉了,跳过即可),以及如何解决.net客户端无法调试Java发布的web service的问题。
在互连网应用中Web Service已经得到了广泛的认同,同时也是因为这种广泛的应用,使得Web Service在规范化方面越来越成熟。企业和企业之间的信息交互,很重要一点就是信息的安全性,电子商务等互连网应用这方面的需求更为突出,如果没有安全的保证,没有客户或者企业愿意将信息在网上交互,同时也不会信任任何接受到的信息。然而,作为SOA的有效技术手段,Web Service的动态性很强,服务的开发者无法预料到服务将在什么环境下被使用,因此服务的安全性变得更加复杂。
在考虑安全性方面主要有三个关键性的概念:
机密性(Confidentiality),完整性(Integrity),身份鉴别(Authentication)。
机密性:除了指定的接受者,其他人无法查看消息的内容。通常会使用密钥(对称或非对称)对消息加密,从而保证消息的机密性。
完整性:确保消息在传输的过程中没有被修改。即保证消息的接收者接收到的消息与消息发送者最初发送的消息完全一致。通常会对消息做摘要(Digest),再使用密钥(对称,非对称)加密摘要,从而保证消息的完整性。
身份鉴别:确保消息发送者的身份与消息中所声称的用户身份一致。最简单的做法就是让用户同时发送用户名和密码,服务方确认密码的有效性从而判断该用户身份是否与用户名所代表的一致。然而在实际的应用中的做法通常不会如此简单,此时往往会使用密钥对一段信息加密,服务方通过解密此信息确认用户的身份。
那么如何选择使用对称密钥还是非对称密钥?什么时候使用公钥,什么时候使用私钥?首先由于对称密钥的加密解密速度比非对称的密钥快很多(大约1000倍),所以在加密消息的时候一般都使用对称密钥。但是有一个问题就是对称密钥又如何发布呢?网络上两个没有联系的用户如何建立起一个共享的密钥?这时就需要PKI来帮助我们将这个共享的密钥建立起来,即利用非对称密钥中的公钥来加密那个共享密钥,传递到私钥的拥有方。由此可以知道:对称密钥加密普通信息,非对称密钥加密对称密钥。
在Integrity中,使用非对称密钥的私钥加密摘要,得到的东西是一个广为人知的东西—Digital Signature(数字签名). 而使用对称密钥加密摘要得到的是HMAC(Hash message authentication codes)。他们在保证消息完整性的同时,都具有身份鉴别的功能,不过前者还有一个功能---抗否认性。值得注意的是在Confidentiality中,使用非对称密钥方法是用公钥加密,私钥解密,而在Integrity中使用非对称密钥的方法恰恰相反。
在当前的安全策略上很多时候会使用到SSL和VPN,他们的好处和缺点网上都有评论,但作为和传输层无关的安全策略,WS-Security规范无疑是最具广泛的应用。IBM,BEA,Microsoft共同制定了WS-Security规范,解决了安全的三个基本问题:机密性、完整性、身份鉴别,在Web Services使用SOAP(XML 格式)作为消息封装协议的背景下,标准化组织分别制定了XML Encryption、XML Digital Signature、与SAML(XML格式的Security Token)三套规范,WS-Security则是规定了如何将以上规范组合起来以满足Web Services安全需求的一套规范。
XML Signature规范是将数字签名和XML组合而成的产物,不要以为XML Signature仅仅是将数字签名技术应用于XML文件。
XML Signature包括以下的功能:
1.XML Signature可以对任何能够以URI形式(uniform resource identifier)定位的资源做签名。既包括与签名同在一个XML文件中的元素,也包括其他XML文件中的元素,甚至可以是非XML形式的资源(比如一个图形文件),只要能被URI定位到的资源都可以应用XML Signature. 这也代表了XML签名的对象可以是动态的变化。
2.XML Signature可以对XML文件中的任一元素做签名,也可以对整个文件做签名。
3.XML Signature 既可以用非对称密钥做签名(Digital Signature),也可以用对称密钥做签名(HMAC)。
具体的标签以及含义就不做解释了,不过如果要做签名策略配置,需要熟悉这些标签,这也会影响到后续开发中遇到的各种问题。另外两个规范这边就不做说明了,因为现在服务框架暂时只是提供了Signature的要求,如果内容需要加密,那么对于应用来说性能可能是不可接受的,因此需要的是利用SSL和签名结合的策略来实现完整的安全机制。
对于WSSE的支持
ASF这部分是改造了Tusncay的Web Service子项目,Tuscany子项目内部集成的web service的开源框架是axis2,虽然很多朋友评价xfire好于axis2,不过个人在使用过程中感觉其实两者各有所长,只是说如何在适当的场合使用,如果需要和Spring很好的集成,那么xfire当然是最好的选择,如果需要能够有很好的wsse以及其他开源支持,那么axis2应该是个很不错的选择,毕竟apache组织下的开源项目众多,自家人集成起来更是得心应手,特别是wss4j和axis2的集成,axis2的address和rampart两个子插件模块使用起来十分方便,同时在框架的可插入性和模块化上,觉得axis2要好过xfire。不过axis2的客户端比xfire要麻烦得多,xfire封装的好多了,这也是很多人喜欢xfire的缘故了(不过再傻瓜也抵不过.net客户端的傻瓜,不过这个傻瓜模式无法让人测试,那么就真的被当成傻瓜了),毕竟易用性往往是吸引到第一批客户的重要特质,这也是后续做ASF所需要考虑的问题。
使用Axis2的框架结合Jetty这个轻量级内嵌容器作为Web Service发布框架(不得不提的是,在作web service的性能测试的过程中,公司的测试资深人员对于ASF的web service性能作了肯定,其实这和使用Jetty也有一定的关系,现在越来越多的开源框架都使用了Jetty作为内置web轻量级容器,很灵活,同时也可以达到很好的性能要求,在后面工作中对于hessian集成到服务框架中来,也是采用了Hessian+Jetty),并且通过Axis2的rampart集成了wss4j,提供了WSSE的增强功能。
对于认证模式场景需求问题的解决
ASF对于Web Service Security这部分只是要求了Signature,而对于Signature需要提供两种方式,UserNameToken和X.509证书。前者提供给内部的一些应用使用,后者提供给外部ISV使用,两者主要差别也就是在性能上,后者经过测试,在CPU的使用上,是6-8倍于不带Signature的Web Service。
UserNameToken这种模式很简单,就很类似于我们平常的用户认证,用户名和密码作为明文或者加密,嵌入在Soap Header中即可,客户端根据本地保存的受信用户记录来交验是否是合法用户。
X.509就比较特殊一些,所谓的证书,其中包括了公钥私钥对(作为签名和认证使用),证书颁发者的信息(可能是一些CA机构或者是用本地的证书生成工具自己生成),证书拥有者的身份信息,以及一些导入的受信第三方的公钥证书。当前的证书方式的签名认证主要有两种模式,一种是双方证书都是由第三方CA认证,同时双方都将对方的CA作为可信的CA,那么请求发起方将会把自己的证书放入到Soap Header中,接受方接受到请求以后,获取证书,发现是受信的CA,那么就认为请求发起方身份可信,同时在作完整性摘要校对。另一种模式就是双方的证书可以没有任何权威的CA作保证,但是双方首先就需要将附带自己公钥的证书发送给对方,对方将这附带有公钥的证书分别导入到证书管理库中(java是某个JKS,.net是windows的当前用户或者本机的证书管理文件)。双方交互的时候不需要将证书置入Soap Header中,但是需要将证书的引用标示(序列号或者是X.509 SubjectKeyIdentifier)传递给服务端,服务端根据标示在本地的证书库中查找并且校验,这种模式的好处就是不需要CA的认证(省钱)同时传递的时候不需要将证书带入到Header中,节省了传递报文的大小,缺点就是双方需要互相保存对方的公钥证书到本地的证书库中,同时这种模式也为跨平台带来了很多问题,后续的互通中就会提到。
ASF的证书认证模式中采用了后者,因为要求每个ISV去有一个第三方CA作为授权不是很可行,但是问题就是如果ISV需要导入我们的公钥证书比较方便,但是我们需要管理那么多ISV的证书,同时又需要动态上传修改保存证书那么就不能用原有的手动导入的模式,同时由于到时候部署的服务器集群不可能都维护一份本地的证书库,因此需要用数据库手段来维护,但是在应用启动以后再要新增或者修改证书,将会比较麻烦,因此采取了扩展wss4j的策略读取方式来适应新的应用场景。
扩展的CrytoProvider类图
扩展后的keystore初始化以及signature部分流程图
这部分设计主要是扩展了WSS4J的CrytoProvider,扩展后的CrytoProvider重载了获取X509证书的几个方法,这里类似于AOP,通过提供ICertsLoaderHandler接口来回调获取其它存储内的certs构建 visual keystore,同时在作signature的时候,如果发现ISV的cert不存在于当前的visual keystore 中根据CrytoProvider的接口实现,来决定是全部刷新还是部分获取刷新当前的visual keystore中的certs。这样就可以达到了动态装载和刷新certs的要求,同时根据性能要求选择配置和实现不同的CrytoProvider。
.Net和Java的互通
Java 的客户端和服务端Security互通很快就搞定了,只是对于一些应用场景做证书管理的扩展。然而,在经历了.net客户端调用Java发布的ws返回数组对象类型的问题以后,又一个大难题摆在了我的面前,ISV support小组和测试部的日报上把.net客户端无法在wsse的模式下调用Java 发布的 Web Service作为了重点问题,需要我支持,那么当然当仁不让的接下来尽快搞定了,虽然对.net来说,我算是新手中的新手,不过经过两天的测试,让我总结出了.net调试的技巧,那就是截包分析(感觉又回到我前几年在通信行业干活时的状况,对于对方协议不了解,又没有源码可看,那么就截报文来分析么)。开始挺乐观的,想着WS-Security微软也是参与者么,应该会严格遵守的,估计一天搞定,结果活活的折腾了两天,下面所描述的如何互通可能总的看起来应该不是很复杂,不过摸索的过程可真是很费事,google的每一条老外的信息都被我看过了,但是Question多Answer少。废话不多说,进入正题。
首先不管是什么客户端调用什么服务端,都需要先做一件事情,准备key pairs。在Java中证书管理库可以通过Jdk提供的key tools这个工具生成jks格式的Java Key Store,可以将公钥导出,或者将公钥导入,同时可以生成秘钥对保存在证书中。在.net中可以通过makecert的工具来生成符合Public Key Cryptography Standards #12,PKCS#12标准定义,包含了公钥和私钥的二进制格式的证书形式,以pfx作为证书文件后缀,同时可以通过mmc对windows的证书存储区进行管理,导入或者导出证书。其实.net和java的互通关键问题就是出在证书格式不同以及获取证书的算法上。下面就具体的描述一下如何从Java的开发者来做好Java WebService和.net互通的工作。
更多内容请参见:
http://blog.csdn.net/cenwenchu79