本文是讨论如何在企业环境中实现和应用基于Web服务安全技术的安全保护方案系列文章的第部分在本系列的第部分中回顾了现有的解决方案及其缺陷并提出开发一个新的Web服务安全工具包的方案此工具包可以解决其中部分缺陷(见第一部分)本文将进一步介绍此Web服务安全工具包的框架(下载部分源代码)并解释工具包内Web服务安全的特性与Java语言的面向对象特性之间的高层抽象映射关系
客户端
第一部分中工具包需求部分指出 开发工具包的目的之一是简化客户在当前的开发环境下处理Web服务安全的工作这些工作应该移至框架层 以便框架层最终将这些工作代理到底层基础设施——真正应该处理这些工作的地方 因此在讨论工具包的结构以及工具包内实体与WSSE相关标准之间的关系前 让我们将工具包视为一个黑盒子 从客户的角度来体验一下(如何使用工具包)
WsseHeaderToken wsseHeader = new WsseHeaderToken();
// Add Timestamp element to the WSSE Header添加时间戳元素
TsToken ts = wsseHeaderAddTimestamp();
// Sign the timestamp element with default certificate使用缺省证书对时间戳元素签名
WsToken[] sigTokens = new WsToken[] {ts};
wsseHeaderAddSignature(sigTokens);
// Encrypt the signature and body elements with default key 使用缺省的密钥加密签名及主体中元素
WsTokenRef[] encTokens = new WsTokenRef[]
{ new DSigTokenRef() new SoapBodyRef() };
wsseHeaderAddEncryption(encTokens);
wsseHeaderProcessHeader();
Element soap = wsseHeaderGetSoapEnvelope();
这个简单示例构造了一个包含时间戳子元素的Web服务安全(以下简记为WSSE)头部元素 并从配置文件中获取XML签名提供者的信息 使用相应XML签名提供者工具对时间戳元素签名 进而使用配置的XML加密提供者对安全头部中的签名元素和时间戳元素进行加密
XML文件解析具有过程化的本质 这将带来处理WSSE XML信息的困难 导致混乱复杂相互纠缠的代码 工具包中实现了复杂安全规范的代码 试图将安全领域的过程化规则映射到面向对象领域的对应部分 包中代表WSSE元素的类 隔离了XML解析过程 创建了处理XML代码的面向对象的包装器
工具包提供的WsseHeaderToken类 对一些功能进行了便于使用的封装 这样可以使得客户与框架的复杂性隔离 如果有必要 客户也可以在代码内直接创建和访问工具包内的其他类 例如 当现有帮助类未提供处理某种类型的元素的功能时 可以创建相应的处理器对象进行处理 并将处理结果添加到头部安全信息中 在下面代码中使用一个示例处理器和示例标记 演示了如何从WSSE信息头部拷贝标记元素到另一个WSSE信息头部
// Reference and read WSSE header with null actor
使用null操作器引用和读取WSSE 头部
WsseHeaderRef ref = WsseHeaderRefCreateFromFile(filename null);
WsseHeaderToken wsseHeader = refGetWsseHeader();
// Reference a sample element in the retrieved header
引用已读取头部包含的一个示例元素
SampleTokenRef sampleRef = new SampleTokenRef(wsseHeadersample);
SampleToken sample = sampleRefGetSampleToken();
// Create a new WSSE header and add the element
生成新的安全头部信息并添加元素
WsseHeaderToken wsseNew = new WsseHeaderToken();
wsseNewInsertToken(sample);
// Add sample elements processing in the new WSSE header
在生成的头部中处理示例元素
SampleProcessor sampleProcessor = new SampleProcessor();
sampleProcessorSetReplaceTokens(true);
sampleProcessorAddToken(sample);
wsseNewAddProcessor(sampleProcessor);
wsseNewProcessHeader();
Element soap = wsseNewGetSoapEnvelope();
框架
框架的结构层次很大程度上可以对应到WSSE规范描述的XML定义块上工具包包含如下类型的对象
·表示WSSE 头部的XML元素也可以由子元素合成组合元素(compiste)如果拥有用于生成标记的充足信息那么可以从头开始构建WSSE标记 又或已经从其他WSSE头部提取出(如SAML断言等)必要的XML元素 那么可以通过封装来创建 WSSE标记在工具包内的基类分别为位于wsseToolkitTokens包内的WsToken类以及WsCompisteToken类
·标记对象的指针通过它们可以对现有的安全标记进行寻址和读取操作更一般的作用是作为一种机制方便客户指向现有的XML元素并将XML元素转化为标记对象标记引用类层次的基类是位于wsseToolkitRefs包内的WsTokenRef类
·标记处理器对象表示工具包内的操作的对象可以通过它们对WSSE头部头部内任何子元素以及包含的SOAP信息进行操作现在的工具包内仅有个处理器类DsigProcessor类以及EncProcessor类 通过它们可以在WSSE头部中添加新的标记和(或者)改变已有标记实际上改动/添加标记的特性并不是处理器的必然需求非改写的处理器类型也是可能出现的这样的意图在wsseToolkitProcessors包内的处理器类型接口ITokenProcessor中得到体现它的函数签名设计可以避免引入更多的标记类型
·帮助类对象wsseToolkitUtils包内的许多帮助类可以便于客户进行配置信息处理XML处理等任务还有wsseToolkitSaml包用于支持SAML操作wsseToolkitDirectory包用于支持用户目录操作所有这些工具类本身不表示WSSE头部的任何部分仅供工具包的其它组件使用
·辅助包装器对象此类对象将标记对象和处理器对象封装起来组成WSSE安全头部的构建器同时强调标记所有权概念增强标记处理功能 现在工具包内扩展的标记类WsseHeaderToken 不仅实现了标记对象接口同时定义了一些便利方法可以实例化工具包中的类并添加这些对象到本身表示的标记对象中当然如果需要客户可以自由的直接操作工具包中的对象
需要提到的是并不是所有对象都是立即可得的它们会随着工具包实现阶段的不断展开在后续的文章中被依次介绍并添加到工具包中来(参见第一部分的结论部分)
如下图显示了工具包框架中各种对象以及客户间的关系
图 工具包的操作
为了更好的理解图需要对工具包操作的几个重点概念进行进一步的解释
·不是所有的标记元素都可以从现有XML元素生成例如重用现有时间戳元素(wsseToolkitTokensWssTsToken标记)来构建新的标记没有什么实际意义——实际上需要时应该从头构建并相应添加新标记
·可从现有XML元素创建的标记类具有唯一参数类型为orgwcdomElement的构造函数此构造函数会对输入的XML数据进行浅层次的数据有效性验证所有情况下必须正确地维护用于构建新标记XML元素的orgwcdomDocument对象不合适的文档对象会在添加元素时产生错误标记类基类WsToken类WsConpositeToken类以及帮助类WsTokenHelper具有处理XML文档的功能
·虽然标记引用类型也都是从基类wsseToolkitTokensWsToken派生的但是大多数引用类型的作用是引用现存的XML元素不是作为本身可以被添加的元素不过在下面的WSSE映射部分会提到一些特殊的标记引用类型除具有引用元素功能外本身也可以作为被添加的元素
·标记引用类型可以引用不同的安全信息头部中的标记元素——此功能有助于在新的WSSE头部中添加现有标记元素的功能的实现标记引用类型甚至可以引用在安全处理过程的初期添加的当前不存在的元素 比如前面代码示例中加密签名元素构成的元素
·标记帮助类的责任是实例化标记类型对象和标记处理器对象并将二者联系起来处理当然这需要适当的配置信息以及初始化工作标记处理器类型的责任是操作标记帮助类的处理结果比如在安全头部中添加一个新产生的数字签名元素处理器接口的要约是仅对引用标记进行适当的处理并不对此处理过程中产生的新标记进行任何操作
·处理操作可以连接起来构成处理操作链这样可以对多个安全头部的入口签名然后对签名加密 如上面客户处代码示例
工具包提供了轻量的对象层次处理每次客户调用时会实例化一些具有仅于自己上下文环境关联的对象 因此不必担心并发问题工具包中大多数类没有提供同步化锁只有wsseToolkitUtilsXmlXmlFactory 类和 wsseToolkitUtilsConfigConfigHelper类除外这两个类提供了一些可以被多个线程共享的功能对于配置的目录服务和SAML服务实现提供者来说由于工具包的所有运行客户都访问相同的提供者它们的实现必须是线程安全的
WSSE映射
现在将要讨论工具包内的组件是如何与WSSE规范规定的主要构建块的映射关系注意WSSE 规范的第部分对<wsse:Security>头部块是这样定义的<wsse:Security>头部块以SOAP行动者或角色的形式存在提供在在SOAP信息中添加针对特定接收者的安全相关信息的机制 这意味着 WSSE安全头部是可以扩展的 同时在所有可能使用此技术的应用中试图使用它是不合适的 因此工具包框架仅对规范中规定的标记类型及其关系进行映射同时可以在以后添加新的标记类型及其处理器