内容


了解 Web 服务规范,第 5 部分

WS-Policy

Comments

系列内容:

此内容是该系列 # 部分中的第 # 部分: 了解 Web 服务规范,第 5 部分

敬请期待该系列的后续内容。

此内容是该系列的一部分:了解 Web 服务规范,第 5 部分

敬请期待该系列的后续内容。

开始之前

在本教程中,我们将了解 Web 访问策略(Web Services Policy,WS-Policy)。此标准针对这样的开发人员:希望在环境中公开自己的服务,并使用定义允许这些 Web 服务如何与其他客户机和服务进行交互的策略。术语 WS-Policy 指定义治理(例如传输方法)和安全性(如加密级别)的框架。

要学习本教程的内容,您应该具有 SOAP 方面的基本知识,可以阅读本系列的第 1 部分对此进行了解(另外,还需要具备 XML 方面的基本知识)。SOAP 是独立于编程语言的。不过,本教程中的示例使用 Java™ 和 Apache Axis2 项目,但其中的概念适用于任何编程语言和环境。

关于本系列

本系列教程以假想的报社 Daily Moon 为例;为了提高在竞争激烈的环境中的生产力,其员工将使用各种 Web 服务来创建工作流系统,我们将在此过程中讲述各个 Web 服务基本概念。

第 1 部分比较简单,介绍了 Web 服务背后的基本概念,并演示如何使用 SOAP(以后要讨论的大部分内容的基础规范)来将 Classifieds Department 连接到内容管理系统。

第 2 部分进一步深入介绍了如何使用 Web 服务描述语言(Web Services Description Language,WSDL)定义 Web 服务产生的消息,从而使团队更方便地创建服务以及连接到服务的客户机。

第 3 部分中,团队希望准备一系列服务,并希望能方便地查找这些服务。与此对应,统一描述、发现和集成(Universal Description, Discovery and Integration,UDDI)提供了可用服务的可搜索注册中心,以便使自己的服务为其他人所注意。

第 4 部分中,Daily Moon 的发行人 Rudy 决定报社需要为访问其内部系统的 Web 服务制订更好的安全过程。

本文是第 5 部分,讨论 WS-Policy,我们将讨论团队为了访问这些刚提供了安全保护的服务需要进行哪些更改。

第 6 部分重点讨论互操作性,因为必须从单个系统访问来自几个不同实现的服务。第 6 部分还将讨论 WS-I 证书中涉及的要求和测试。

最后,第 7 部分将演示如何使用业务流程执行语言(Business Process Execution Language,WS-BPEL)来从各个服务创建复杂应用程序。

关于本教程

在本教程中,Daily Moon 报社团队使用 WS-Policy 规范来指定 Web 服务必须遵循的策略,以便使用公司的 Web 服务。

在本教程中,您将了解以下内容:

  • 了解创建策略文档的语法,并了解如何创建自己的策略以及如何使用其他已经存在的断言。
  • 了解可以如何使用基础 XML 构造的数学属性操作策略文档。
  • 使用 Apache Neethi,该组件是 Axis2 提供的非完整 WS-Policy 实现,允许 Axis2 用户操作和组合策略文档。
  • 了解如何将 WS-Policy 和 WSDL 一起使用,并了解如何编写要求端口符合所定义的策略的 WSDL。

开始前,您将需要一些工具。

先决条件

本教程的大部分内容都是概念性的,但为了处理通过 Apache Neethi 来使用 WS-Policy 文档的代码,您将需要安装以下软件:

Java 2 Standard Edition 的 1.4.2 或更高版本——所有这些工具都是基于 Java 的,本教程中将要构建的服务和客户机也是如此。

Apache Neethi——Apache Neethi 是 Axis2 用于创建策略文档的运行时表示形式、以及对策略文档执行规范化、合并和求交操作的工具。

概述

在为 Web 服务指定策略之前,让我们回顾一下本系列教程到目前为止的示例场景。

已完成的工作

本系列教程逐步说明了虚构的 Daily Moon 报社的员工将其日常操作更改为基于 Web 服务的系统的过程。在第 1 部分中,Classifieds Department 通过与内容管理系统交互了解了 SOAP 的相关信息,在第 2 部分中,他们创建了自己的服务,并使用 Web 服务描述语言 (WSDL) 对其进行描述。然后,在第 3 部分,他们了解了如何与 UDDI 注册中心交互,并了解了如何在其中查找数据,而这最终使他们为自己的公司创建了一个注册中心,以支持其他组织与 Daily Moon 进行交互。在第 4 部分中,由于 Rudy 坚持要求他的同事 Gene 和 Francis 提供防止系统非授权访问的方法,因此 Gene 和 Francis 必须为其 Web 服务实现 WS-Security。

现在,Rudy 认识到,访问其 Web 服务的客户机并不一定使用他所要求的新 Web 服务。因此,他需要为 Web 服务定义策略,以确定可以如何以及通过何种方式对其进行使用。也就是说,Rudy 希望强制访问 Daily Moon 的 Web 服务的客户机按照预先确定的方式进行访问,确保其中建立的安全性也可确保本系列第 4 部分的安全。他让 Gene 和 Francis 来进行此工作!

为何使用 WS-Policy

Web 服务策略框架(Web Services Policy Framework,WS-Policy)是允许 Web 服务具有一组必须满足(或使用)的规则的规范。使用 Web 服务的客户机的创建者必须了解策略信息,以确定是否能够遵守这些策略。因此,不能编写客户机来直接访问具有策略(要求对所有消息以特定方式进行加密或签名)的 Web 服务。客户机也不能在发送没有时间戳的消息的情况下访问具有要求采用时间戳的策略的 Web 服务。而这就是 WS-Policy 的目标:指定 Web 服务使用者必须遵循的策略信息。

当 Gene 坐下来实现 WS-Policy 时,他发现了一个问题。Axis2 尚不完全支持 WS-Policy。Apache Neethi 组件(该组件处理 WS-Policy)读取和解释策略,但 Axis2 尚未向服务提供获取该信息的方法。

不过这目前已经在计划中了。因此,Gene 和 Francis 决定按照已经提供了此支持的方式处理,因此他们将全面讨论此主题,以便提供此支持时就可立即使用。Rudy 考虑到 WS-Policy 对其已经有所了解的即将到来的 SOA 世界的重要性,他认为值得花这个时间。

策略是什么样子

您一定急于知道策略是什么样子!没关系,您马上就可以看到了。首先,从简单的策略文档开始,如清单 1 中所示。

清单 1. 所看到第一个策略文档
<wsp:Policy
xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy"
xmlns:sec="http://schemas.xmlsoap.org/ws/2002/12/secext" >

  <wsp:ExactlyOne>
    <wsp:All>
      <sec:SecurityToken>
        <sec:TokenType>sec:X509v3</sec:TokenType>
      </sec:SecurityToken>
    </wsp:All>
  </wsp:ExactlyOne>
</wsp:Policy>

最重要的是,使用此策略文档的 Web 服务对于与其进行事务处理的客户机有一个要求:采用 X509v3 类型的安全令牌(有关安全令牌的更多信息,请参见参考资料)。接下来,我们将了解如何使用策略或策略组对 WS-Security 进行加强。

WS-Policy 如何加强 WS-Security

WS-Policy 与 WS-Security 紧密相关。事实上,存在 WS-SecurityPolicy 规范,其中包含能包括在 WS-Policy 文档中的多个断言;因为可采用多种方法实现安全性,因此需要存在针对这些类型的策略,以便能将其包含在策略中。通过创建要求特定类型的加密、签名或要求时间戳的策略,可帮助巩固 Web 服务的安全性,因为除非客户机遵循 Web 服务给定的策略,否则任何传入消息都不能从定义了策略的安全 Web 服务获取所需的响应。Francis 非常喜欢这个想法。如果没有办法执行,所有这些工作又有什么意义呢?为 WS-Policy 欢呼!

太棒了!请跟随 Gene 和 Francis,开始了解如何创建策略文档。

构造 WS-Policy 文档

可以在清单 1 中看到,策略文档与大部分其他 Web 服务文档一样,都是采用 XML 格式,在这一部分中您将学习相关语法和已经可用的断言,从而了解如何构造自己的策略文档。

术语

以下是所有 WS-Policy 人员(包括 Francis 和 Gene)应该知道的一些术语词汇:

策略
策略备选项的列表。
策略备选项
包含策略断言。在规范形式中,策略包含一个策略备选项列表(在 wsp:All tags 中指定),表示遵循此策略的客户机可以选择遵循其中任一可用策略备选项。客户机可以选择一个备选项,但必须遵循与所选备选项相关的所有策略。稍后将了解这具体如何工作。
策略断言
表示要求或能力。例如,策略断言可以要求在加密传输的数据中使用特定类型的加密。在规范形式中,策略断言在策略备选项中列出。
策略断言类型
策略断言所属的类。例如,清单 1 中的 <sec:SecurityToken> 就是策略断言类型的例子。
策略表达式
策略的 XML 表示形式,如清单 1 中所示,可以采用规范形式,也可以采用紧凑形式。
策略主体
可以在其上应用策略的实体或对象。
策略范围
可以向其应用策略的对象集。
策略附件
策略与一个或多个策略范围关联的方式。

请参见参考资料中列出的有关 WS-Policy 的概述性文章。接下来我们将了解如何创建采用规范形式的策略文档。

规范形式

规范形式的策略表达式是在 WS-Policy 规范中定义的语法。最简单的策略文档是空文档: <wsp:Policy />

不过,这并没有什么用处。接下来,我们对其进行扩展,但同时保持内容为空(请参见清单 2)。

清单 2. 采用规范形式的空策略文档
<wsp:Policy ...>
  <wsp:ExactlyOne>
    <wsp:All>
    </wsp:All>
    <wsp:All>
    </wsp:All>
  </wsp:ExactlyOne>
</wsp:Policy>

清单 2 中的策略文档指定了一个策略,此策略具有两个不包含策略断言的策略备选项。现在回头看看清单 1,会发现其中仅包含单个策略断言。

请注意,清单 1 中的策略断言无效,此处仅是作为一个例子给出。此文档包含两个策略备选项:一个具有单个策略断言,另一个具有两个策略断言。因此,一个报社的其他调用客户机可以选择遵循包含一个策略断言 DummyAssertion1 的策略备选项,或选择遵循包含两个策略断言 DummyAssertion1DummyAssertion2 的另一个策略备选项。

接下来我们将了解如何引用 WS-SecurityPolicy 规范中定义的策略断言。

WS-SecurityPolicy

WS-SecurityPolicy 规范包含多个策略断言和策略断言类型。该规范中指定了多个断言,其中包括以下断言:

SignedParts
指定必须对消息的哪些部分(如 Header、主体等)进行签名。
SignedElements
指定必须对消息中的哪些元素进行签名。
EncryptedParts
和 SignedParts 一样,不过要求进行加密。
EncryptedElements
和 SignedElements 一样,不过要求进行加密。
Token assertions
WS-SecurityPolicy 文档(请参见参考资料)中列出了多个令牌断言,定义了在消息中包括何种类型的令牌。
Properties
另外还能对多个属性进行设置,如加密算法或时间戳要求。

现在 Gene 和 Francis 可以创建与其使用 WS-SecurityPolicy 规范的 Web 服务项目相关的策略文档了。

构建使用 WS-SecurityPolicy 规范的策略

接下来我们为 Daily Moon 构建策略。Francis 首先从一个小策略开始入手,如清单 3 中所示。

清单 3. 为报社构建策略
<wsp:Policy
xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy"
xmlns:sp="http://schemas.xmlsoap.org/ws/2002/12/secext" >

  <wsp:ExactlyOne>
    <wsp:All>
      <sp:SecurityToken>
        <sp:TokenType>sp:X509v3</sp:TokenType>
      </sp:SecurityToken>
    </wsp:All>
  </wsp:ExactlyOne>
</wsp:Policy>

此文档包含单个策略断言,该断言要求包括特定的安全令牌。如果该策略附加到 Web 服务,希望与该 Web 服务进行事务交互的客户机必须发送策略中指定类型的安全令牌(本例中为 X509v3)。Gene 希望通过指定签名、加密、时间戳和用户名令牌策略断言来添加策略(请参见清单 4)。

清单 4. 添加到报社的策略
<wsp:Policy
xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy"
xmlns:sp="http://schemas.xmlsoap.org/ws/2002/12/secext" >
...
      </sp:SecurityToken>
      <sp:UsernameToken /> 
      <sp:SignedParts />
      <sp:EncryptedParts>
        <sp:Body />
      </sp:EncryptedParts>
      <sp:TransportBinding>
        <sp:IncludeTimeStamp />
      </sp:TransportBinding>
    </wsp:All>
  </wsp:ExactlyOne>
</wsp:Policy>

包含 sp:WssUsernameToken11 的行要求使用用户名令牌。<sp:SignedParts /> 要求对整个消息进行签名。sp:EncryptedParts XML 构造包含 <sp:Body /> 标记,表示只需要对主体部分进行加密。最后,sp:TransportBinding XML 构造包含 sp:IncludeTimeStamp 标记,要求在消息中包含时间戳。

大功告成,我们现在有了一个完整的策略文件,感谢 Gene 和 Francis。接下来我们将了解如何通过引用已经存在的策略(而不是重复编写)来编写紧凑的策略。

引用策略中的策略文档

我们从清单 4 中所示的策略开始着手。现在将其转换为以下形式,如清单 5 中所示。

清单 5. 在策略中引用策略
<wsp:Policy
xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy"
xmlns:sp="http://schemas.xmlsoap.org/ws/2002/12/secext"
xmlns:wsu=http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity
-utility-1.0.xsd >

  <wsp:ExactlyOne>
    <wsp:All>
      <sp:SecurityToken>
        <sp:TokenType>sp:X509v3</sp:TokenType>
      </sp:SecurityToken>

      <wsp:Policy wsu:Id="myPolicy">
        <sp:UsernameToken /> 
        <sp:SignedParts />
        <sp:EncryptedParts>
          <sp:Body />
        </sp:EncryptedParts>
      </wsp:Policy>

      <sp:TransportBinding>
        <sp:IncludeTimeStamp />
      </sp:TransportBinding>
    </wsp:All>
    <wsp:PolicyReference URI="#myPolicy" />
  </wsp:ExactlyOne>
</wsp:Policy>

请注意,三个策略断言位于 wsp:Policy 内,并有一个 ID 与其关联 (myPolicy)。wsp:PolicyReference 语句实际上就是将策略构造复制到指定的位置。Gene 认为这非常适用于创建紧凑的策略表达式。

接下来,我们将了解策略操作符以及如何使用策略操作符的数学属性操作策略文档。

使用策略操作符

组成策略的构造(如策略断言和策略备选项)具有一些数学属性。知道了这些属性,就能够以最为紧凑的方式编写复杂的策略。在这一部分中我们将了解这些属性以及如何将其应用到策略文档。

构造概述

可用于以最紧凑的方式表示复杂策略的构造有 wsp:Policywsp:Allwsp:ExactlyOne。为了帮助编写复杂的策略,可以将这三个构造彼此进行嵌套。将紧凑表达式(表达式尽可能少)转换为规范表达式(不省略任何行;整个表达式都以最详尽的方式编写)时,应用以下规则:

  • 等价规则
  • 空规则
  • 关联规则
  • 可交换规则
  • 分配规则

这一部分剩下的部分将说明如何使用每个规则。

等价规则

等价规则指定 wsp:Policy 等价于 wsp:All。由于 wsp:All 指定策略备选项,因此 wsp:Policy 也指定策略备选项。

空规则

策略和策略备选项都可以为空。如果策略为空(如 <wsp:ExactlyOne />),则策略具有零个策略备选项。类似地,如果策略备选项为空(如 <wsp:All /><wsp:Policy />),则策略具有零个策略断言。

关联规则

操作符 wsp:ExactlyOnewsp:All 彼此关联。这意味着,使用清单 6 中所定义的 wsp:ExactlyOne(其中 <!-- assertion a --><!-- assertion b --> 为任意断言)时,该策略与清单 4 中的策略等价。

.

清单 6. 具有关联关系的 wsp:ExactlyOne
<wsp:ExactlyOne>
  <!-- assertion a -->
  <wsp:ExactlyOne> <!-- assertion b --> </wsp:ExactlyOne>
</wsp:ExactlyOne>

wsp:ExactlyOne 的等价策略如使用关联的清单 7 中所示。

清单 7. 等价策略
<wsp:ExactlyOne>
  <!-- assertion a --> <!-- assertion b -->
</wsp:ExactlyOne>

清单 8 中使用 wsp:All 的策略等价于清单 9 中的策略。

清单 8. 具有关联关系的 wsp:All
<wsp:All>
  <!-- assertion a -->
  <wsp:All> <!-- assertion b --> </wsp:All>
</wsp:All>

使用 wsp:All 的关联关系的等价策略如清单 9 中所示。

清单 9. 等价策略
<wsp:All>
  <!-- assertion a --> <!-- assertion b -->
</wsp:All>

接下来我们将了解两个操作符如何满足可交换规则。

可交换规则

操作符 wsp:ExactlyOnewsp:All 还是可交换的。这意味着,当两个或更多策略断言嵌套在其中的任一操作符中时,其顺序并不重要。例如,在清单 10 中使用 wsp:All 的语句等价于清单 11 中的语句。

清单 10. 说明可交换操作符的 <wsp:All>
<wsp:All>
  <!-- assertion a --> <!-- assertion b -->
</wsp:All>

wsp:ExactlyOne 的等价策略如使用可交换操作符的清单 11 中所示。

清单 11. 等价语句
<wsp:All>
  <!-- assertion b --> <!-- assertion a -->
</wsp: All>

清单 12 与清单 13 中所示的 wsp:ExactlyOne 操作符也是如此。

清单 12.说明可交换操作符的 wsp:ExactlyOne 操作符
<wsp:ExactlyOne>
  <!-- assertion a --> <!-- assertion b -->
</wsp:ExactlyOne>

使用 wsp:ExactlyOne 操作符的可交换操作符的等价策略如清单 13 中所示。

清单 13. 等价语句
<wsp:ExactlyOne>
  <!-- assertion b --> <!-- assertion a -->
</wsp:ExactlyOne>

接下来我们将了解操作符如何满足分配规则。

分配规则

wsp:ExactlyOnewsp:All 都是可分配的。以下的示例说明了在策略表达式空间中的这种关系(请参见清单 14)。

清单 14. wsp:Allwsp:ExactlyOne 上进行分配,第 1 部分
<wsp:All>
  <wsp:ExactlyOne>
    <!-- assertion a --> <!-- assertion b -->
  </wsp:ExactlyOne>
</wsp:All>

wsp:Allwsp:ExactlyOne 上进行分配的等价策略如清单 15 中所示。

清单 15. wsp:Allwsp:ExactlyOne 上进行分配,第 2 部分
<wsp:ExactlyOne>
  <wsp:All>
    <!-- assertion a -->
  </wsp:All>
  <wsp:All>
    <!-- assertion b -->
  </wsp:All>
</wsp:ExactlyOne>

下面给出一个更为复杂的示例。这与将 (x + a) 与 (y + z) 相乘而得到四个表达式相类似:xy + xz + ay + az(请参见清单 16)。

清单 16. wsp:Allwsp:ExactlyOne 上进行分配,第 3 部分
<wsp:All>
  <wsp:ExactlyOne>
    <!-- assertion a --> <!-- assertion b -->
  </wsp:ExactlyOne>
  <wsp:ExactlyOne>
    <!-- assertion c --> <!-- assertion d -->
  </wsp:ExactlyOne>
</wsp:All>

wsp:Allwsp:ExactlyOne 上进行分配的等价策略如清单 17 中所示。

清单 17. wsp:Allwsp:ExactlyOne 上进行分配,第 4 部分
<wsp:ExactlyOne>
  <wsp:All>
    <!-- assertion a --> <!-- assertion c -->
  </wsp:All>
  <wsp:All>
    <!-- assertion a --> <!-- assertion d -->
  </wsp:All>
  <wsp:All>
    <!-- assertion b --> <!-- assertion c -->
  </wsp:All>
  <wsp:All>	
    <!-- assertion b --> <!-- assertion d -->
  </wsp:All>
</wsp:ExactlyOne>

请注意,wsp:All 在空 wsp:ExactlyOne 上进行分配不会得到任何备选项 (<wsp:ExactlyOne />),因为这与乘以零的情况完全一样。如果清单 15 中的任一 wsp:ExactlyOne 表达式为空,得到的结果也一样:结果是没有备选项的策略。

等幂

操作符还是等幂的,即任何具有等幂属性的值乘以这个值本身,结果不会发生变化。清单 18 到清单 21 中的示例对此属性进行了说明。

清单 18. 具有等幂性的 wsp:All
<wsp:All>
  <wsp:All> <!-- assert a --> <!-- assert b --> </wsp:All>
</wsp:All>

使用 wsp:All 的等幂性的等价策略如清单 19 中所示。

清单 19. 等价清单
<wsp:All>
  <!-- assertion a --> <!-- assertion b -->
</wsp:All>

清单 20 和清单 21 表明 wsp:ExactlyOne 是等幂的。

清单 20. 具有等幂性的 wsp:ExactlyOne
<wsp:ExactlyOne>
  <wsp:ExactlyOne>
    <!-- assert a --> <!-- assert b -->
  </wsp:ExactlyOne>
</wsp:ExactlyOne>

使用 wsp:ExactlyOne 的等幂性的等价策略如清单 21 中所示。

清单 21. 等价清单
<wsp:ExactlyOne>
  <!-- assert a --> <!-- assert b --> 
</wsp:ExactlyOne>

实质上,在 wsp:All 内嵌套的 wsp:All 或在 wsp:ExactlyOne 内嵌套的 wsp:ExactlyOne 都是冗余的,这意味着可以从表达式中删除一个 wsp:Allwsp:ExactlyOne 操作符。这与将任何数乘以 1 的情况相同:值将保持不变。在下一部分中将介绍使用 Apache Neethi 操作和规范化策略文档时,了解这些操作符的数学属性的重要性。

使用 Apache Neethi 处理策略文档

Axis2 将 Apache Neethi 项目作为策略文档的运行时表示形式使用。在这一部分中,我们将安装 Apache Neethi;加载一些策略文档;对其进行规范化、合并和求交;然后查看所得到的规范化策略文档。现在请从下载部分下载示例代码。解压缩,然后阅读自述文件。

阅读策略文档

在使用 WS-Policy 进行有意义的工作前,需要能够读写策略。Francis 认为这一点非常好。她希望求两个策略文档的交集。清单 22 给出了策略阅读器代码。

清单 22. 阅读策略文档
    public static Policy readPolicy(String file){
        Policy policy = null;
        try{
            PolicyReader reader =
                PolicyFactory.getPolicyReader
                    (PolicyFactory.DOM_POLICY_READER);
            FileInputStream fis =
                new FileInputStream(file);
            policy = reader.readPolicy(fis);
        } catch(Exception e) {
            System.out.println("Exception occurred: " + e);
            e.printStackTrace();
        }
        return policy;
    }

readPolicy() 方法放在名为 PolicyUtility.java 的文件中。稍后将在 Apache Neethi 试验中使用此文件来读取策略文件。此方法仅阅读指定的策略文件,将其放入按对象命名的策略中,并将其返回。接下来介绍策略编写器。

写入策略文档

如果能写入策略文档,就可以查看策略操作的结果。清单 23 给出了策略编写器代码。

清单 23. 写入策略文档
    public static void writePolicy(Policy w, String file){
        try{
            FileOutputStream fos =
                new FileOutputStream(file);

            PolicyWriter writer =
                PolicyFactory.getPolicyWriter
                    (PolicyFactory.StAX_POLICY_WRITER);

            writer.writePolicy(w, fos);
        } catch(Exception e) {
            System.out.println("Exception occurred: " + e);
            e.printStackTrace();
        }
    }

将此放在与前面相同的类文件中:PolicyUtility.java。这个方法将给定的策略文档的内容写入到给定文件中。接下来,我们将在 Apache Neethi 试验中使用这两个实用方法。

对策略文档进行规范化

在 Apache Neethi 对文档进行规范化时,会采用规范形式对其内容进行安排(而不是紧凑方式)。在随本教程提供的示例代码中(请参见下载),可以看到三个文件:normalize1.xml、normalize2.xml 和 normalize_output_final.xml。normalize1.xml(如清单 24 所示)包含引用外部策略的策略文档。normalize2.xml(如清单 25 中所示)是 normalize1.xml 所引用的文件。

清单 24. normalize1.xml
<wsp:Policy
xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy"
xmlns:sp="http://schemas.xmlsoap.org/ws/2002/12/secext"
xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-
utility-1.0.xsd" >

  <wsp:ExactlyOne>
    <wsp:All>
      <sp:SecurityToken>
        <sp:TokenType>sp:X509v3</sp:TokenType>
      </sp:SecurityToken>

      <wsp:Policy wsu:Id="#myPolicy">
        <sp:UsernameToken /> 
        <sp:SignedParts />
        <sp:EncryptedParts>
          <sp:Body />
        </sp:EncryptedParts>
      </wsp:Policy>

      <sp:TransportBinding>
        <sp:IncludeTimeStamp />
      </sp:TransportBinding>
    </wsp:All>
    <wsp:PolicyReference URI="#myPolicy" />
  </wsp:ExactlyOne>
</wsp:Policy>

清单 25 中显示了上面所引用的策略 myPolicy。

清单 25. normalize2.xml
<wsp:Policy wsu:Id="myPolicy"
xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy"
xmlns:sp="http://schemas.xmlsoap.org/ws/2002/12/secext"
xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-
utility-1.0.xsd" >
  <wsp:ExactlyOne>
    <wsp:All>
      <sp:UsernameToken /> 
      <sp:SignedParts />
      <sp:EncryptedParts>
        <sp:Body />
      </sp:EncryptedParts>
    </wsp:All>
  </wsp:ExactlyOne>
</wsp:Policy>

清单 26 显示了用于对清单 24 的策略进行规范化的代码。

清单 26. 对策略文档进行规范化
import org.apache.ws.policy.Policy;
import org.apache.ws.policy.util.PolicyRegistry;
import org.apache.ws.policy.util.PolicyReader;
import org.apache.ws.policy.util.PolicyWriter;
import org.apache.ws.policy.util.PolicyFactory;
import java.io.FileInputStream;
import java.io.FileOutputStream;

class PolicyUtility{

    public static void main(String argsv[]){
        Policy normalize1 = readPolicy("normalize1.xml");
        Policy normalize2 = readPolicy("normalize2.xml");
        PolicyRegistry pr = new PolicyRegistry();
        pr.register("#myPolicy", normalize2);
        normalize1 = (Policy)normalize1.normalize(pr);
        writePolicy(normalize1, "normalize_output.xml");

规范化的结果在 normalize_output_final.xml 中给出(请参见清单 27)。

清单 27. 得到的 normalize_output_final.xml
<wsp:Policy xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy">
  <wsp:ExactlyOne>
    <wsp:All>
      <sp:SecurityToken xmlns:sp="http://schemas.xmlsoap.org/ws/2002/12/secext">
        <sp:TokenType>sp:X509v3</sp:TokenType>
      </sp:SecurityToken>
      <sp:UsernameToken>
      </sp:UsernameToken>
      <sp:SignedParts>
      </sp:SignedParts>
      <sp:EncryptedParts>
        <sp:Body>
        </sp:Body>
      </sp:EncryptedParts>
      <sp:TransportBinding>
        <sp:IncludeTimeStamp>
        </sp:IncludeTimeStamp>
      </sp:TransportBinding>
    </wsp:All>
    <wsp:All>
      <sp:UsernameToken xmlns:sp="http://schemas.xmlsoap.org/ws/2002/12/secext">
      </sp:UsernameToken>
      <sp:SignedParts>
      </sp:SignedParts>
      <sp:EncryptedParts>
        <sp:Body>
        </sp:Body>
      </sp:EncryptedParts>
    </wsp:All>
  </wsp:ExactlyOne>
</wsp:Policy>

如果按自述文件中的说明运行程序,会将结果写入 normalize_output.xml。请注意 normalize1.xml 中的 PolicyReference 如何替换为 normalize2.xml 中的策略备选项。可在再次运行规范化过程时随意修改这两个文件,看看得到了什么结果。接下来我们将对两个策略文档进行合并。

合并两个策略文档

通过进行合并,可让两个策略文档将所有策略备选项从两个独立的文件合并到一起。例如,如果有两个文件,每个都包含两个策略备选项,最终就得到了拥有四个策略备选项的一个文件。如果一个文件包含有两个策略备选项,而另一个文件有一个策略备选项,最终将得到两个策略备选项。请看清单 28 和清单 29 中可以进行合并的两个文件。

清单 28. merge1.xml
<wsp:Policy
xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy"
xmlns:sp="http://schemas.xmlsoap.org/ws/2002/12/secext" >

  <wsp:ExactlyOne>
    <wsp:All>
      <sp:SecurityToken>
        <sp:TokenType>sp:X509v3</sp:TokenType>
      </sp:SecurityToken>
      <sp:UsernameToken /> 
      <sp:EncryptedParts>
        <sp:Body />
      </sp:EncryptedParts>
      <sp:TransportBinding>
        <sp:IncludeTimeStamp />
      </sp:TransportBinding>
    </wsp:All>
  </wsp:ExactlyOne>
</wsp:Policy>

可以将上面 merge1.xml 中的策略与清单 29 中的策略 merge2.xml 合并。

清单 29. merge2.xml
<wsp:Policy
xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy"
xmlns:sp="http://schemas.xmlsoap.org/ws/2002/12/secext" >

  <wsp:ExactlyOne>
    <wsp:All>
      <sp:SecurityToken>
        <sp:TokenType>sp:X509v3</sp:TokenType>
      </sp:SecurityToken>
      <sp:SignedParts />
      <sp:EncryptedParts />
    </wsp:All>
  </wsp:ExactlyOne>
</wsp:Policy>

实践是学习此概念的最佳方法。因此清单 30 继续前面的 PolicyUtility.java 类,实现了用于合并清单 28 和清单 29 中的两个策略文档的代码。

清单 30. 合并两个策略文档
...
        normalize1 = (Policy)normalize1.normalize(pr);
        writePolicy(normalize1, "normalize_output.xml");

        Policy merge1 = readPolicy("merge1.xml");
        Policy merge2 = readPolicy("merge2.xml");
        merge1 = (Policy)merge1.merge(merge2);
        writePolicy(merge1, "merge_output.xml");
...

将读取两个策略文档并对其进行合并,然后将合并的输出写入一个文件中(请参见清单 31)。

清单 31. 得到的 merge_output_final.xml
<wsp:Policy xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy">
  <wsp:ExactlyOne>
    <wsp:All>
      <sp:SecurityToken xmlns:sp="http://schemas.xmlsoap.org/ws/2002/12/secext">
        <sp:TokenType>sp:X509v3</sp:TokenType>
      </sp:SecurityToken>
      <sp:UsernameToken>
      </sp:UsernameToken>
      <sp:EncryptedParts>
        <sp:Body>
        </sp:Body>
      </sp:EncryptedParts>
      <sp:TransportBinding>
        <sp:IncludeTimeStamp>
        </sp:IncludeTimeStamp>
      </sp:TransportBinding>
      <sp:SecurityToken>
        <sp:TokenType>sp:X509v3</sp:TokenType>
      </sp:SecurityToken>
      <sp:SignedParts>
      </sp:SignedParts>
      <sp:EncryptedParts>
      </sp:EncryptedParts>
    </wsp:All>
  </wsp:ExactlyOne>
</wsp:Policy>

回到清单 28 和清单 29。这二者均包含一个策略备选项,因此所得到的文档包含一个策略备选项,其中包含从原来的策略备选项中复制过来的所有策略断言。所得到的 merge_output_final.xml 中的结果如清单 31 中所示。请注意,merge1.xml 中的单个策略备选项的所有策略断言和 merge2.xml 中的单个策略备选项的所有策略断言组合到 merge_output_final.xml 中,形成了单个合并策略备选项。

对两个策略文档求交

求交是一个更为重要的概念。一般来说,如果两个 Web 服务要进行交互,则需要使用二者均支持的策略备选项进行此工作。Web 服务需要对彼此的策略文档求交。所得到的将是一个匹配的策略备选项合并结果。Francis 对这个做法很感兴趣,因为这样的话,在使用客户机调用嵌套 Web 服务时,就可以将 Daily Moon 的可用策略与希望与其进行交互的 Web 服务的策略求交(请参见清单 32)。

清单 32. intersect1.xml
<wsp:Policy
xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy"
xmlns:sp="http://schemas.xmlsoap.org/ws/2002/12/secext" >

  <wsp:ExactlyOne>
    <wsp:All>
      <sp:SecurityToken>
        <sp:TokenType>sp:X509v3</sp:TokenType>
      </sp:SecurityToken>
      <sp:UsernameToken /> 
      <sp:SignedParts />
      <sp:EncryptedParts>
        <sp:Body />
      </sp:EncryptedParts>
      <sp:TransportBinding>
        <sp:IncludeTimeStamp />
      </sp:TransportBinding>
    </wsp:All>
    <wsp:All>
      <sp:SecurityToken>
        <sp:TokenType>sp:X509v3</sp:TokenType>
      </sp:SecurityToken>
      <sp:UsernameToken /> 
    </wsp:All>
  </wsp:ExactlyOne>
</wsp:Policy>

可对上面的策略 intersect1.xml 与清单 33 中所示的策略 intersect2.xml 求交。

清单 33. intersect2.xml
<wsp:Policy
xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy"
xmlns:sp="http://schemas.xmlsoap.org/ws/2002/12/secext" >

  <wsp:ExactlyOne>
    <wsp:All>
      <sp:SecurityToken>
        <sp:TokenType>sp:X509v3</sp:TokenType>
      </sp:SecurityToken>
      <sp:SignedParts />
      <sp:EncryptedParts />
    </wsp:All>
    <wsp:All>
      <sp:SecurityToken>
        <sp:TokenType>sp:X509v3</sp:TokenType>
      </sp:SecurityToken>
      <sp:UsernameToken /> 
    </wsp:All>
  </wsp:ExactlyOne>
</wsp:Policy>

请看清单 34 中的代码,可使用此代码对 intersect1.xml 和 intersect2.xml 进行求交。

清单 34. 对两个策略文档求交
...
        merge1 = (Policy)merge1.merge(merge2).normalize();
        writePolicy(merge1, "merge_output.xml");

        Policy intersect1 = readPolicy("intersect1.xml");
        Policy intersect2 = readPolicy("intersect2.xml");
        intersect1 = (Policy)intersect1.merge(intersect2);
        writePolicy(intersect1, "intersect_output.xml");
...

将读取两个策略文档并对其求交,然后将求交输出写入一个文件中。请看清单 32 和清单 33 中的两个文件。它们均包含两个策略备选项,但均只有一个与另一个文件中的备选项匹配。将删除不匹配的策略备选项,而将匹配的策略备选项合并到一起(在本例中就有一个匹配)。现在请看 merge_output_final.xml 中的实际结果,如清单 35 中所示。

清单 35. 得到的 merge_output_final.xml
<wsp:Policy xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy">
  <wsp:ExactlyOne>
    <wsp:All>
      <sp:SecurityToken xmlns:sp="http://schemas.xmlsoap.org/ws/2002/12/secext">
        <sp:TokenType>sp:X509v3</sp:TokenType>
      </sp:SecurityToken>
      <sp:UsernameToken>
      </sp:UsernameToken>
      <sp:SecurityToken>
        <sp:TokenType>sp:X509v3</sp:TokenType>
      </sp:SecurityToken>
      <sp:UsernameToken>
      </sp:UsernameToken>
    </wsp:All>
  </wsp:ExactlyOne>
</wsp:Policy>

请注意,每个文件中的匹配策略备选项(intersect1.xml 和 intersect2.xml 中的第二个策略备选项)实际合并为了 merge_output_final.xml 中所示的单个策略备选项。我们使用 Apache Neethi 的工作就到此结束了。

接下来,我们将了解如何在 WSDL 中处理策略文档。

在 WSDL 中处理策略文档

WS-PolicyAttachment 规范详细说明了策略如何附加到绑定,实际上充当了强制 Web 服务遵循策略的粘合剂。这一部分将讨论 WS-PolicyAttachment 规范的目标以及其如何支持将策略附加到 Web 服务。

WS-PolicyAttachment

WS-PolicyAttachment 规范的目标是为开发人员定义从 WSDL 定义引用策略的方法。规范中还提供了相关详细信息,以帮助将策略与 UDDI 实体关联,不过本教程并不会对此进行讨论。请参见参考资料部分,其中提供了指向完整 WS-PolicyAttachment 规范的链接。这一部分剩下的部分将说明如何遵循 WS-PolicyAttachment 规范,以便让 WSDL 引用 Daily Moon 策略文档。Gene 对这个任务非常感兴趣,因为可以尽可能快地设置策略并在 Daily Moon Web 服务上运行。

要求使用 WS-Policy

有一个构造可用于强制 WSDL 使用和引用策略。清单 36 显示了一个示例。

清单 36. 在 WSDL 中要求使用策略
<wsdl:definitions...>

  <wsp:UsingPolicy wsdl:Required="true" />
...
</wsdl:definitions >

接下来,在 WSDL 中添加策略。

策略的位置

将策略放置在 wsp:UsingPolicy 要求代码行之后的位置。对于 Daily Moon,可以采用 Gene 的处理方式,如清单 37 中所示。

清单 37. 在 WSDL 中定义策略
<wsdl:definitions 
xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy"
xmlns:sp="http://schemas.xmlsoap.org/ws/2002/12/secext"
xmlns:wsu=http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-
utility-1.0.xsd
...
>

  <wsp:UsingPolicy wsdl:Required="true" />
  <wsp:Policy wsu:Id="myPolicy">
    <wsp:ExactlyOne>
      <wsp:All>
        <sp:SecurityToken>
          <sp:TokenType>sp:X509v3</sp:TokenType>
        </sp:SecurityToken>
        <sp:UsernameToken /> 
        <sp:SignedParts />
        <sp:EncryptedParts>
          <sp:Body />
        </sp:EncryptedParts>
        <sp:TransportBinding>
          <sp:IncludeTimeStamp />
        </sp:TransportBinding>
      </wsp:All>
    </wsp:ExactlyOne>
  </wsp:Policy>
...
</wsdl:definitions >

这就好了!策略位于 WSDL 内部。现在只需要将其与绑定关联即可,我们接下来就要进行此工作。

将策略附加到绑定

现在已经编写了策略,不过在将其与绑定关联前,它都没有什么用处。如果定义了绑定,清单 38 显示了如何将 Daily Moon 策略附加到绑定。

清单 38. 将策略与绑定关联:执行策略
<wsdl:definitions 
...
>

  <wsp:UsingPolicy wsdl:Required="true" />
  <wsp:Policy wsu:Id="myPolicy">
...
  </wsp:Policy>
  <wsdl:binding name="myBinding"
                type="tns:myPortType">
    <soap:binding 
      transport="http://schemas.xmlsoap.org/soap/http"
      style="document" />
    <wsp:PolicyReference URI="#myPolicy"
                         wsdl:required="true" />
    <wsdl:operation name="myOperation" >
...
    </wsdl:operation>
  </wsdl:binding>

</wsdl:definitions >

请注意 Gene 编写 WSDL 的方式。请看端口绑定中引用策略 myPolicywsp:PolicyReference 标记。此标记指定绑定(使用 myBinding)到指定的 portType (myPortType) 的 Web 服务操作 (myOperation) 必须强制要求所有传入消息遵循该策略,如 wsu:Id="#myPolicy" 策略所定义的。这就是全部了!如果 Axis2 完全支持策略,除非遵循策略的备选项之一的所有断言,否则尝试与 Daily Moon Web 服务交互的客户机将无法执行成功事务。

总结

为了 Web 服务能够在企业环境中得到充分利用,需要其具有恰当的配置和安全策略。WS-Policy 通过允许将策略定义绑定到 Web 服务解决了这个问题。这些策略定义定义事务如何出现,它们需要进行大量的工作来保证更为安全的环境,以便进行事务处理。

通过执行一定级别的加密和数字签名,可以在其传输过程中保证数据安全,并将访问限制为授权的个人或组织,并随后验证信息在传输过程中没有被修改。让策略要求采用时间戳(并对其进行签名),可防止消息被捕获和重现。

在本教程中,Daily Moon 的员工为在本系列教程前面部分创建的 Web 服务强制执行了安全性,确保本系列前面几部分的安全。在第 6 部分中,他们将向 Web 服务应用 Web 服务互操作性(WS-Interoperability,WS-I)。


下载资源


相关主题


评论

添加或订阅评论,请先登录注册

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=10
Zone=SOA and web services
ArticleID=244077
ArticleTitle=了解 Web 服务规范,第 5 部分: WS-Policy
publish-date=08012007