`
omygege
  • 浏览: 1345304 次
文章分类
社区版块
存档分类
最新评论

Web Service 、WS-Security、Java和.net的互通(在路上-基于SCA规范的应用服务框架成长记之四)

 
阅读更多

Web Service WS-SecurityJava.net的互通

和第三部分同样,这部分内容其实应该在后面才对,不过当前工作既然做了,也需要写下来分享,那么就提前插队到成长记录当中吧。看了这篇文章以后,可能给人的感觉是有点偏离服务框架的内容。的却,如果纯粹从技术方面来说,这部分应该不属于服务框架范畴。拿杭州作个例子,杭州是全国唯一一个景点不但涨价,反而免门票的地方,原因何在,无非是管理者看得远,景点的门票收益看得到,但是小头,免去门票带来的商机那才是金矿。框架其实也是这样,如果客户用起来不方便,甚至都不能用,那么框架再好,也会有人笑话你是个高高在上的理论主意者,这种框架适合于教学,而非实用。现在也是在迈出平台服务框架兼容性的第一步,那天和同事们开玩笑说,以前联通移动的wap业务,好在大家的开发语言都相似,isp只需要兼容各种手机客户端,我们现在要做的就是兼容各种不同开发语言,平台,以后甚至浏览器,我们这种全部都搞通的人出去,那就真的是抢手货了。

周一测试部ISV support小组的日报反映,.net的客户端对于复杂对象数组返回有问题,紧接着就是.net客户端对于web servicewsse无法调试通过。我以前没有接触过.net,没办法,硬着个头皮装了个vs2005WSE 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中使用非对称密钥的方法恰恰相反。

在当前的安全策略上很多时候会使用到SSLVPN,他们的好处和缺点网上都有评论,但作为和传输层无关的安全策略,WS-Security规范无疑是最具广泛的应用。IBMBEA,Microsoft共同制定了WS-Security规范,解决了安全的三个基本问题:机密性、完整性、身份鉴别,在Web Services使用SOAPXML 格式)作为消息封装协议的背景下,标准化组织分别制定了XML EncryptionXML Digital Signature、与SAML(XML格式的Security Token)三套规范,WS-Security则是规定了如何将以上规范组合起来以满足Web Services安全需求的一套规范。

XML Signature规范是将数字签名和XML组合而成的产物,不要以为XML Signature仅仅是将数字签名技术应用于XML文件。

XML Signature包括以下的功能:

1XML Signature可以对任何能够以URI形式(uniform resource identifier)定位的资源做签名。既包括与签名同在一个XML文件中的元素,也包括其他XML文件中的元素,甚至可以是非XML形式的资源(比如一个图形文件),只要能被URI定位到的资源都可以应用XML Signature. 这也代表了XML签名的对象可以是动态的变化。

2XML Signature可以对XML文件中的任一元素做签名,也可以对整个文件做签名。

3XML Signature 既可以用非对称密钥做签名(Digital Signature),也可以用对称密钥做签名(HMAC)

具体的标签以及含义就不做解释了,不过如果要做签名策略配置,需要熟悉这些标签,这也会影响到后续开发中遇到的各种问题。另外两个规范这边就不做说明了,因为现在服务框架暂时只是提供了Signature的要求,如果内容需要加密,那么对于应用来说性能可能是不可接受的,因此需要的是利用SSL和签名结合的策略来实现完整的安全机制。

对于WSSE的支持

ASF这部分是改造了TusncayWeb Service子项目,Tuscany子项目内部集成的web service的开源框架是axis2,虽然很多朋友评价xfire好于axis2,不过个人在使用过程中感觉其实两者各有所长,只是说如何在适当的场合使用,如果需要和Spring很好的集成,那么xfire当然是最好的选择,如果需要能够有很好的wsse以及其他开源支持,那么axis2应该是个很不错的选择,毕竟apache组织下的开源项目众多,自家人集成起来更是得心应手,特别是wss4jaxis2的集成,axis2addressrampart两个子插件模块使用起来十分方便,同时在框架的可插入性和模块化上,觉得axis2要好过xfire。不过axis2的客户端比xfire要麻烦得多,xfire封装的好多了,这也是很多人喜欢xfire的缘故了(不过再傻瓜也抵不过.net客户端的傻瓜,不过这个傻瓜模式无法让人测试,那么就真的被当成傻瓜了),毕竟易用性往往是吸引到第一批客户的重要特质,这也是后续做ASF所需要考虑的问题。

使用Axis2的框架结合Jetty这个轻量级内嵌容器作为Web Service发布框架(不得不提的是,在作web service的性能测试的过程中,公司的测试资深人员对于ASFweb service性能作了肯定,其实这和使用Jetty也有一定的关系,现在越来越多的开源框架都使用了Jetty作为内置web轻量级容器,很灵活,同时也可以达到很好的性能要求,在后面工作中对于hessian集成到服务框架中来,也是采用了Hessian+Jetty),并且通过Axis2rampart集成了wss4j,提供了WSSE的增强功能。

对于认证模式场景需求问题的解决

ASF对于Web Service Security这部分只是要求了Signature,而对于Signature需要提供两种方式,UserNameTokenX.509证书。前者提供给内部的一些应用使用,后者提供给外部ISV使用,两者主要差别也就是在性能上,后者经过测试,在CPU的使用上,是6-8倍于不带SignatureWeb Service

UserNameToken这种模式很简单,就很类似于我们平常的用户认证,用户名和密码作为明文或者加密,嵌入在Soap Header中即可,客户端根据本地保存的受信用户记录来交验是否是合法用户。

X.509就比较特殊一些,所谓的证书,其中包括了公对(作为签名和认证使用),证书颁发者的信息(可能是一些CA机构或者是用本地的证书生成工具自己生成),证书拥有者的身份信息,以及一些导入的受信第三方的公证书。当前的证书方式的签名认证主要有两种模式,一种是双方证书都是由第三方CA认证,同时双方都将对方的CA作为可信的CA,那么请求发起方将会把自己的证书放入到Soap Header中,接受方接受到请求以后,获取证书,发现是受信的CA,那么就认为请求发起方身份可信,同时在作完整性摘要校对。另一种模式就是双方的证书可以没有任何权威的CA作保证,但是双方首先就需要将附带自己公的证书发送给对方,对方将这附带有公的证书分别导入到证书管理库中(java是某个JKS.netwindows的当前用户或者本机的证书管理文件)。双方交互的时候不需要将证书置入Soap Header中,但是需要将证书的引用标示(序列号或者是X.509 SubjectKeyIdentifier)传递给服务端,服务端根据标示在本地的证书库中查找并且校验,这种模式的好处就是不需要CA的认证(省钱)同时传递的时候不需要将证书带入到Header中,节省了传递报文的大小,缺点就是双方需要互相保存对方的公证书到本地的证书库中,同时这种模式也为跨平台带来了很多问题,后续的互通中就会提到。

ASF的证书认证模式中采用了后者,因为要求每个ISV去有一个第三方CA作为授权不是很可行,但是问题就是如果ISV需要导入我们的公证书比较方便,但是我们需要管理那么多ISV的证书,同时又需要动态上传修改保存证书那么就不能用原有的手动导入的模式,同时由于到时候部署的服务器集群不可能都维护一份本地的证书库,因此需要用数据库手段来维护,但是在应用启动以后再要新增或者修改证书,将会比较麻烦,因此采取了扩展wss4j的策略读取方式来适应新的应用场景。

<shapetype id="_x0000_t75" coordsize="21600,21600" o:preferrelative="t" o:spt="75" filled="f" stroked="f" path=" m@4@5 l@4@11@9@11@9@5 xe"><stroke joinstyle="miter"></stroke><formulas><f eqn="if lineDrawn pixelLineWidth 0 "></f><f eqn="sum @0 1 0 "></f><f eqn="sum 0 0 @1 "></f><f eqn="prod @2 1 2 "></f><f eqn="prod @3 21600 pixelWidth "></f><f eqn="prod @3 21600 pixelHeight "></f><f eqn="sum @0 0 1 "></f><f eqn="prod @6 1 2 "></f><f eqn="prod @7 21600 pixelWidth "></f><f eqn="sum @8 21600 0 "></f><f eqn="prod @7 21600 pixelHeight "></f><f eqn="sum @10 21600 0 "></f></formulas><path o:extrusionok="f" gradientshapeok="t" o:connecttype="rect"></path><lock aspectratio="t" v:ext="edit"></lock></shapetype><shape id="_x0000_i1025" style="WIDTH: 415.5pt; HEIGHT: 213pt" coordsize="21600,21600" type="#_x0000_t75"><imagedata o:title="" src="%E5%9B%9B.files/image001.emz"></imagedata></shape>

扩展的CrytoProvider类图

<shape id="_x0000_i1026" style="WIDTH: 414.75pt; HEIGHT: 522pt" coordsize="21600,21600" type="#_x0000_t75"><imagedata o:title="" src="%E5%9B%9B.files/image003.emz"></imagedata></shape>

扩展后的keystore 初始化以及signature部分流程图

这部分设计主要是扩展了WSS4JCrytoProvider,扩展后的CrytoProvider重载了获取X509证书的几个方法,这里类似于AOP,通过提供ICertsLoaderHandler接口来回调获取其它存储内的certs 构建 visual keystore,同时在作signature的时候,如果发现ISVcert不存在于当前的visual keystore 中根据CrytoProvider的接口实现,来决定是全部刷新还是部分获取刷新当前的visual keystore中的certs。这样就可以达到了动态装载和刷新certs的要求,同时根据性能要求选择配置和实现不同的CrytoProvider

.NetJava的互通

Java 的客户端和服务端Security互通很快就搞定了,只是对于一些应用场景做证书管理的扩展。然而,在经历了.net客户端调用Java发布的ws返回数组对象类型的问题以后,又一个大难题摆在了我的面前,ISV support小组和测试部的日报上把.net客户端无法在wsse的模式下调用Java 发布的 Web Service作为了重点问题,需要我支持,那么当然当仁不让的接下来尽快搞定了,虽然对.net来说,我算是新手中的新手,不过经过两天的测试,让我总结出了.net调试的技巧,那就是截包分析(感觉又回到我前几年在通信行业干活时的状况,对于对方协议不了解,又没有源码可看,那么就截报文来分析么)。开始挺乐观的,想着WS-Security微软也是参与者么,应该会严格遵守的,估计一天搞定,结果活活的折腾了两天,下面所描述的如何互通可能总的看起来应该不是很复杂,不过摸索的过程可真是很费事,google的每一条老外的信息都被我看过了,但是QuestionAnswer少。废话不多说,进入正题。

首先不管是什么客户端调用什么服务端,都需要先做一件事情,准备key pairs。在Java中证书管理库可以通过Jdk提供的key tools这个工具生成jks格式的Java Key Store,可以将公导出,或者将公导入,同时可以生成秘对保存在证书中。在.net中可以通过makecert的工具来生成符合Public Key Cryptography Standards #12PKCS#12标准定义,包含了公私钥的二进制格式的证书形式,以pfx作为证书文件后缀,同时可以通过mmcwindows的证书存储区进行管理,导入或者导出证书。其实.netjava的互通关键问题就是出在证书格式不同以及获取证书的算法上。下面就具体的描述一下如何从Java的开发者来做好Java WebService.net互通的工作。

一.准备双方的证书和公

首先通过Javakeytools 生成了两个jks,一个叫做alisoft.jks,另一个叫做myisvdemo.jks,这里需要注意,在使用keytools生成证书的时候会提示需要输入两个密码,一个是keystore的密码(每次对keystore作操作的时候都需要输入密码来验证),另一个是私保护密码(使用私作签名或者加密的时候需要输入),这两个密码可以设置为不同的值,不过为了后面转换为.netpfx格式的证书需要,两者需要设置为相同,同时在早期的tomcat中使用证书也有这种限制。然后将两个证书都自签名并将公导出,分别叫做alisoft.rsamyisvdemo.rsa(因为我这里用的是rsa算法,所以用了这个后缀,其实可以直接命名为.cer后缀,因为它们的类型其实就是base64编码后的没有私的证书,可以直接导入到windows中)。

准备好了这四份文件以后,将myisvdemo.rsa导入到alisoft.jks中(由于测试不采用上面提到的数据库存储的方式,因此直接导入作测试)。然后,通过一个叫做jks2pfx的工具包,将myisvdemo.jks转成为myisvdemo.pfx文件,通过mmc导入到本地计算机的证书管理中。

<shape id="_x0000_i1027" style="WIDTH: 415.5pt; HEIGHT: 299.25pt" coordsize="21600,21600" type="#_x0000_t75"><imagedata o:title="import" src="%E5%9B%9B.files/image005.jpg"></imagedata></shape>

这时候,双击这两个证书都会显示当前的Ca根证书不受信任,可以直接拖动复制增加到受信任的根证书颁发机构的证书中,就不会再显示这样的提示了。最后分别将这两个证书在复制到受信任人的证书中。至此,客户端和服务端的证书都已经准备好了,接下去就是如何配置使用.net的客户端来调用已经发布成为带有WSSEJava Web Service了。

二.配置.net的客户端

首先,作为测试就建立了一个C#Windows Application,然后在默认的form上面加了一个button作为激发调用服务端的事件控制载体。用.net来调用web service通常情况使用增加一个web reference来注入这个远程服务,不过这边要特别特别强调,如果你要使用WSSE的话,不要急于先建立一个Web Reference,首先要将你的安全策略配置好,然后再建立web reference,不然自己手动的要去修改后台客户端代码。那么接着来说.netWSE

.net提供的WSEWeb Services Enhancements)是用来增强对于Web Service的支持配置(包括了WS-Security等规范)。当前.netWSE最新版本是3.0的,可以很方便的集成到VS2005中,而它的2.0版本主要是针对过去的VS2003版本,不过两者都是可以用的,但是在配置上面有一些差异,同时使用的方便程度也有些差距,2.0使用起来相对3要复杂一些。不过我们这里介绍的都是通过设置WS-Policy来应用WS-Security,这样比较方便,同时代码简洁,业务逻辑和具体的WS配置分开,是一种较好的使用模式,.net也支持代码内嵌WS-Security逻辑来实现WS-Security的使用。

先来说一下3如何使用。安装好3以后,可以在我们的项目右键菜单中最下面看到WSE 3.0 setting,直接选择这项,弹出类似的设置页,第一页最顶上的一项选中。

<shape id="_x0000_i1028" style="WIDTH: 222.75pt; HEIGHT: 240.75pt" coordsize="21600,21600" type="#_x0000_t75"><imagedata o:title="import4" src="%E5%9B%9B.files/image007.jpg"></imagedata></shape>

然后选择Policy Tab页面设置,首先选中Enable Policy,然后选择Add,输入一个Policy的名称,后面就是一个向导配置页面,第一页的选择如下图

<shape id="_x0000_i1029" style="WIDTH: 324pt; HEIGHT: 225pt" coordsize="21600,21600" type="#_x0000_t75"><imagedata o:title="import5" src="%E5%9B%9B.files/image009.jpg"></imagedata></shape>

后面第一个要选择的x.509证书是本地的密码对存在的证书,也就是用来签名并向服务端发起请求的证书所在位置,选择了LocalMachine,然后再选择证书,也就是上面我导入到系统中的myisvdemo证书。然后出现如下图

<shape id="_x0000_i1030" style="WIDTH: 314.25pt; HEIGHT: 219pt" coordsize="21600,21600" type="#_x0000_t75"><imagedata o:title="" src="%E5%9B%9B.files/image011.png"></imagedata></shape>

将配置修改成图中所示,首先不要选择支持1.1扩展,因为.netjava1.1扩展的支持实现有所差异,特别是签名回执上,连域名都不一致,所以使用起来有问题。然后我们现在只是要用sign-only的功能,因此就选择这项。

下一页是选择服务端响应时使用什么证书作为解析的证书,这里就选择local Machinealisoft证书。至此Policy全部配置完成,关闭配置文件。在我们的工程里面会新增加一些文件,如下图所示:

<shape id="_x0000_i1031" style="WIDTH: 414.75pt; HEIGHT: 311.25pt" coordsize="21600,21600" type="#_x0000_t75"><imagedata o:title="import6" src="%E5%9B%9B.files/image013.jpg"></imagedata></shape>

其中在references中的是引入的第三方包,主要是为了将普通的web Service的代理类转变成为支持WSSE的代理类(这也是为什么我说不要先急着建立web reference的缘故,如果先建立web reference的话),打开Reference.map中的reference.cs文件,可以看到服务代理类是继承System.Web.Services.Protocols.SoapHttpClientProtocol,而如果在配置好策略以后服务代理类就会自动继承 Microsoft.Web.Services3.WebServicesClientProtocol,此时的服务代理类才可以支持WSSE的功能,因此如果先建立reference就要手动的去修改这些客户端文件。

然后打开wse3policyCache.config文件,这个文件就是刚才配置的Policy文件,修改establishSecurityContext="false",这个参数如果为true的话,会连续两次发送请求,后一次的请求内将不带有Policy中配置的信息(这个具体的我还不是很清楚,只是看到一个国外的人询问微软工程师的时候,认为这个是个缺陷,但是微软工程师则认为这是一个让用户集成自己配置的扩展点,不过个人认为,所谓扩展点应该是在默认没有扩展的时候不影响原有的配置)。第二需要在我们的axis2中除了配置signature还需要配置timestamp,默认每一次请求.net都会自动将timestamp作为action执行。

打开app.config文件,这里面指定了web servicepolicy配置文件,这里没有什么需要修改的,只需要按照他生成的内容即可。然后建立好web Reference,这个十分简单,就是输入wsdlURI,然后填入服务的名称即可。最后一部就是写测试代码,重新打开Form1.cs,在buttononclick事件中写入下面的测试代码:

private void button1_Click(object sender, EventArgs e)

{

// AccountServiceWse是你的客户段代理类,有WSSE的增强功能,参看reference.cs文件

AccountServiceWse service = new AccountServiceWse();

//这个客户端代理类需要指定刚才配置的策略名称

service.SetPolicy("clientPolicy");

//简单的测试代码

accountService.ArrayOfAccountBean result = service.getUserAccountArr("test");

}

噩梦开始了,到此为止,.netweb Service开发者带来的便利真的是无话可说,绝对的傻瓜级,但是就是这短短的几段代码,最后一句话执行的时候总是出现错误,那个黄色的小框让我看得快崩溃了。

<shape id="_x0000_i1032" style="WIDTH: 414.75pt; HEIGHT: 315.75pt" coordsize="21600,21600" type="#_x0000_t75"><imagedata o:title="import7" src="%E5%9B%9B.files/image015.jpg"></imagedata></shape>

根据上图的提示,错误应该在客户端这边,Java服务端也看过,已经接收到请求并且认证签名通过,并且反签发送回客户端,同时从ResponseInnerXml中拷贝出来可以看到返回的结果Soap包都是正确的,客户端的错误就是Referenced security token could not be retrieved,这个就表明了客户端的alisoft的公钥没有找到,导致检查返回结果的时候出现了问题,那么就去找是否是因为格式不同导致公钥没有导入或者导入错误(错误的查错方向)。

最后发现原因出在了获取key的标示上,前面说到如果不是第三方权威的CA认证模式下,需要双方互相导入对方的公钥到本地的证书管理库中,我们是将Jks中的公钥导出,然后导入到了本机的证书管理模块中。公钥证书的引用在WS-Security中分成两种:SKIKeyIdentifier IssuerSerial,由于我们前面提到的扩展ISV证书动态载入的需要,我们一直使用的是IssuerSerical。但是微软的工具生成的是x.509v3版本,而java keytools生成的是x.509v1版本,如果使用IssuerSerical会有问题。那么只能使用SKIKeyIdentifier,但是使用SKIKeyIdentifier.net默认使用的是自身的window的序列化方式,不过可以设置其为javaRFC3280协议方式,但是.net wse 2wse 3RFC3280方式都不一样,wse 2的可以和java互通,wse 3就不可以,也就是说23本身在RFC3280的序列化方式上都有差别,自己也不能互通,因此没有办法,只能够安装2版本,重新来生成。下面将描述一下如何用wse 2来订制web service WSSE客户端。

WSE2客户端的操作流程(使用的是WSE 2 sp3):

首先还是要设置WSEPolicy到新建项目中去,不过这而WSE 2没有像WSE3那么好的集成到VS2005中,新建好工程以后,建立Web Reference(这和WSE3不太一样,这里先建Web Reference,然后手动的去设置)。同样去选择project菜单的show all files。这时候通过外部打开WSE 2的配置工具,配置工具选择打开新建的这个项目的app.config文件,然后开始配置策略。配置如下列图:

<shape id="_x0000_i1033" style="WIDTH: 251.25pt; HEIGHT: 282.75pt" coordsize="21600,21600" type="#_x0000_t75"><imagedata o:title="import8" src="%E5%9B%9B.files/image017.jpg"></imagedata></shape>

<shape id="_x0000_i1034" style="WIDTH: 249.75pt; HEIGHT: 281.25pt" coordsize="21600,21600" type="#_x0000_t75"><imagedata o:title="import9" src="%E5%9B%9B.files/image019.jpg"></imagedata></shape>

红色部分很重要,需要选择这种协议来序列化获得key reference

<shape id="_x0000_i1035" style="WIDTH: 414.75pt; HEIGHT: 311.25pt" coordsize="21600,21600" type="#_x0000_t75"><imagedata o:title="import10" src="%E5%9B%9B.files/image021.jpg"></imagedata></shape>

这里配置策略文件有所不同,这里首先会让你输入这个Policy所属的URI,和3不同,3中是在代码中配置进去的,在配置中只是申明,而没有对应配置到具体的哪一个请求,这边可以填入某一个URI,那么你对那个URIWebService做任何请求的时候都会采取该策略,同时如果你就不填任何内容,直接用他默认的<DefaultEndpoint>,那么所有不在指定URI对应策略中出现的URI请求和响应,都将采取这种策略,我就默认采用这种模式,因为如果不采用这种模式,相应回来的请求就找不到可以使用的策略了(这个出错信息也困扰我不少时间)。继续配置下面的内容:

<shape id="_x0000_i1036" style="WIDTH: 339pt; HEIGHT: 235.5pt" coordsize="21600,21600" type="#_x0000_t75"><imagedata o:title="import11" src="%E5%9B%9B.files/image023.jpg"></imagedata></shape>

<shape id="_x0000_i1037" style="WIDTH: 312pt; HEIGHT: 216.75pt" coordsize="21600,21600" type="#_x0000_t75"><imagedata o:title="import12" src="%E5%9B%9B.files/image025.jpg"></imagedata></shape>

这里我们只需要做signature,所以只配置了签名。

<shape id="_x0000_i1038" style="WIDTH: 315pt; HEIGHT: 219pt" coordsize="21600,21600" type="#_x0000_t75"><imagedata o:title="import13" src="%E5%9B%9B.files/image027.jpg"></imagedata></shape>

<shape id="_x0000_i1039" style="WIDTH: 312pt; HEIGHT: 216.75pt" coordsize="21600,21600" type="#_x0000_t75"><imagedata o:title="import14" src="%E5%9B%9B.files/image029.jpg"></imagedata></shape>

这里选择证书根据前面页面中配置的存储位置相关,第一个证书是用来签名的带有私钥的证书。第二个是受信的返回的签名交验证书。

<shape id="_x0000_i1040" style="WIDTH: 321pt; HEIGHT: 222.75pt" coordsize="21600,21600" type="#_x0000_t75"><imagedata o:title="import15" src="%E5%9B%9B.files/image031.jpg"></imagedata></shape>

配置完成,并保存。接下去就是要做一些wse3自动作的事情,而在wse2中需要手动修改的内容。首先把project菜单的show all files去掉,然后再选上,就会发现项目中多了一个文件:policyCache.config,选中这个文件然后右键选择Include in project,不然的话每次调试都不会被拷贝到项目执行目录下面(类似于eclipsesrc目录中文件在调试中会被拷贝到bin目录下),然后将这个文件的属性Copy to Output Directory设置为Copy always,这样每次修改以后都会被同步过去。然后选择项目右击add reference,加入Microsoft.Web.Services2这个类库,修改Web References下定义的服务的Reference.cs,将服务继承类修改一下,例如我的项目中的服务自动生成以后这么继承:

AccountService : System.Web.Services.Protocols.SoapHttpClientProtocol

修改成为:

AccountService : Microsoft.Web.Services2.WebServicesClientProtocol

这样定义的代理类就可以有WSSE服务增强功能了,不过注意的是如果UpdateWeb Reference的话,自动会从新生成新的客户端代理,那么又要手动去修改了。(发现如果再次通过wse 2 的配置工具打开app.config文件,选中General下面的框就可以类似于3自动生成了)

然后双击打开policyCache.config文件,做部分的修改:

首先在文件头部有这么一段描述:

<defaultEndpoint>

<defaultOperation>

<request policy="#Sign-X.509" />

<response policy="#Sign-X.509-1" />

<fault policy="" />

</defaultOperation>

</defaultEndpoint>

这就是刚才配置中提到的默认没有配置固定策略的URI请求采用的策略。去查找文件中response对应的策略配置,修改其中的内容,这儿就是修改Sign-x.509-1的配置。

将:

<wsp:MessagePredicate wsp:Usage="wsp:Required" Dialect="http://schemas.xmlsoap.org/2002/12/wsse#part">wsp:Body() wsp:Header(wsa:To) wsp:Header(wsa:Action) wsp:Header(wsa:MessageID) wse:Timestamp()</wsp:MessagePredicate>

修改成为:

<wsp:MessagePredicate wsp:Usage="wsp:Required" Dialect="http://schemas.xmlsoap.org/2002/12/wsse#part">wsp:Body()</wsp:MessagePredicate>

因为我们回签的时候并没有设置address部分,也没有timestamp的签名,因此都需要去掉,不然就会出错。

再将<wssp:Integrity wsp:Usage="wsp:Required">中的:

<wssp:MessageParts Dialect="http://schemas.xmlsoap.org/2002/12/wsse#part">wsp:Body() wsp:Header(wsa:Action) wsp:Header(wsa:FaultTo) wsp:Header(wsa:From) wsp:Header(wsa:MessageID) wsp:Header(wsa:RelatesTo) wsp:Header(wsa:ReplyTo) wsp:Header(wsa:To) wse:Timestamp()</wssp:MessageParts>

修改成为:

<wssp:MessageParts Dialect="http://schemas.xmlsoap.org/2002/12/wsse#part">wsp:Body()</wssp:MessageParts>

打开app.config文件,增加如下一句(据说会有缺陷,关于超时判断的bug,因此还是加上为好):

<security>

<x509 storeLocation="CurrentUser" allowUrlRetrieval="true" useRFC3280="true" />

<timeToleranceInSeconds>86400</timeToleranceInSeconds>

</security>

最后在Form1.cs添加测试代码运行测试看看,不过这里的代码如下:

private void button1_Click(object sender, EventArgs e)

{

AccountService service = new AccountService();

accountService.ArrayOfAccountBean result = service.getUserAccountArr("test");

}

不在类似于WSE 3需要配置对应的策略,因为在配置文件中已经包含了配置策略的信息。

运行通过,艰难的历程告一段落,一句话,平台跨得不容易啊。

结束语:

这次的WSSE跨平台问题的查找真的花费了很多精力,也证明了我早先所担心的,那就是对于跨平台客户端的兼容性测试可能问题会很多,现在才是开始,当ISV上线调试以后,可能问题会暴露的更多,其实SAAS模式几大技术问题中,有一项就是如何让SOAISV和平台之间以及ISV之间搭起桥梁,这个问题不仅框架结构上需要设计好,同时细节上也有多需要去实践的,细节决定成败啊,记得我在上次CSDN的采访中谈了自己对于SCA的了解,有一位朋友给我留了言,说还是要一些实际的开发者来说这些为好,架构师之类的人只会玩虚的,我想我记录着一路的历程也就是让大家知道,其实走好每一小步,才能够让系统性的架构发挥其更大的作用。

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics