程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> 關於JAVA >> Java Web 服務: Axis2 WS-Security基礎

Java Web 服務: Axis2 WS-Security基礎

編輯:關於JAVA

簡介:了解如何將 Rampart 安全模塊添加到 Apache Axis2 並開始在 Web 服務中使用 WS-Security 特性。

安全性對於眾多企業服務來說都是一個重要需求。並且,嘗試實現自己的安全性也頗具風險,因為任 何微小的疏忽都會導致嚴重的安全漏洞。這些特征引起了人們對安全處理標准化的興趣,許多專家為標准 作出貢獻並避免出現任何個人的疏漏。基於 SOAP 的 Web 服務可以使用廣泛支持的 WS-Security 和相關 標准來滿足它們的安全需求,允許針對每種服務相應地配置安全性。

Apache Axis2 通過 Rampart 模塊支持這些安全標准(見 參考資料)。在本文中,您將看到如何為 Axis2 安裝、配置和使用 Rampart 以實現基本的安全功能,即在一個服務請求中發送用戶名和密碼。在 本系列的後續文章中,您將理解如何使用 Rampart 實現更加復雜的安全性。

WS-Security

WS-Security 是向 SOAP Web 服務消息交換添加安全性的一種標准(見 參考資料)。它使用一個 SOAP 消息頭部元素將安全信息附加到消息中,使用令牌(token)的形式傳遞不同類型的聲明(包括名稱 、身份、密匙、組、特權、功能等等)以及加密和數字簽名信息。WS-Security 支持多種形式的令牌、多 個可信任域、多種簽名格式和多種加密技術,因此大多數情況下頭部信息需要針對每種內容包含特定的格 式和算法識別。附加的信息會導致頭部信息產生復雜的結構,如 清單 1 所示(進行了大量編輯)— 包 含簽名和加密的樣例消息:

清單 1. 包含簽名和加密的樣例消息

<soap:Envelope  xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" ...>
 <soap:Header>
 <wsse:Security soap:mustUnderstand="1">
  <wsu:Timestamp  wsu:Id="Timestamp-d2e3c4aa-da82-4138-973d-66b596d66b2f">
  <wsu:Created>2006- 07-11T21:59:32Z</wsu:Created>
  <wsu:Expires>2006-07- 12T06:19:32Z</wsu:Expires>
  </wsu:Timestamp>
   <wsse:BinarySecurityToken ValueType="...-x509-token-profile-1.0#X509v3"
    EncodingType="...-wss-soap-message-security-1.0#Base64Binary"
   xmlns:wsu="...oasis- 200401-wss-wssecurity-utility-1.0.xsd"
   wsu:Id="SecurityToken- faa295...">MIIEC56MQswCQY...</wsse:BinarySecurityToken>
   <xenc:EncryptedKey xmlns:xenc="http://www.w3.org/2001/04/xmlenc#">
   <xenc:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#rsa-1_5" />
   <KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
    <wsse:SecurityTokenReference>
   <wsse:KeyIdentifier ValueType=
     "...#X509SubjectKeyIdentifier">LlYsHyhNnOVA9Aj7...</wsse:KeyIdentifier>
    </wsse:SecurityTokenReference>
  </KeyInfo>
   <xenc:CipherData>
    <xenc:CipherValue>g+A2WJhsoGBKUydZ9Za...</xenc:CipherValue>
   </xenc:CipherData>
  <xenc:ReferenceList>
   <xenc:DataReference  URI="#EncryptedContent-ba0556c3-d443-4f34-bcd1-14cbc32cd689" />
   </xenc:ReferenceList>
  </xenc:EncryptedKey>
  <Signature  xmlns="http://www.w3.org/2000/09/xmldsig#">
  <SignedInfo>
    <ds:CanonicalizationMethod
    Algorithm="http://www.w3.org/2001/10/xml-exc- c14n#"
    xmlns:ds="http://www.w3.org/2000/09/xmldsig#" />
    <SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1" />
    <Reference URI="#Id-c80f735c-62e9-4001-8094-702a4605e429">
    <Transforms>
    <Transform Algorithm="http://www.w3.org/2001/10/xml-exc- c14n#" />
   </Transforms>
   <DigestMethod  Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" />
    <DigestValue>lKjc5nyLQDZAIu/hZb4B6mLquow=</DigestValue>
    </Reference>
   ...
  </SignedInfo>
   <SignatureValue>TiLmWvlz3mswinLVQn58BgYS0368...</SignatureValue>
   <KeyInfo>
   <wsse:SecurityTokenReference>
   <wsse:Reference  URI="#SecurityToken-faa295..."
    ValueType="...-x509-token-profile- 1.0#X509v3" />
   </wsse:SecurityTokenReference>
  </KeyInfo>
  </Signature>
 </wsse:Security>
 </soap:Header>
  <soap:Body wsu:Id="Id-8db9ff44-7bef-4737-8091-cdac51a34db8">
  <xenc:EncryptedData Id="EncryptedContent-ba05..."
   Type="http://www.w3.org/2001/04/xmlenc#Content"
   xmlns:xenc="http://www.w3.org/2001/04/xmlenc#">
  <xenc:EncryptionMethod  Algorithm="http://www.w3.org/2001/04/xmlenc#aes128-cbc"/>
   <xenc:CipherData>
   <xenc:CipherValue>mirmi0KuFEEI56eu2U3cICz...</xenc:CipherValue>
   </xenc:CipherData>
 </xenc:EncryptedData>
  </soap:Body>
</soap:Envelope>

在本文中,您將看到一些 WS-Security 頭部示例,並且只包含單個令牌。本系列下一篇文章將更進一 步,探討 清單 1 所示的復雜結構類型。

WS-Security 應用於實際的 SOAP 消息交換。服務實現可以檢驗 WS-Security 是否恰當應用於傳入的 消息,但是客戶機需要提前知道它們必須實現什麼才能使用服務。由於 WS-Security 的復雜性以及所支 持的選項有限,因此僅使用文本描述很難實現這個目的,而手動配置 WS-Security 處理極容易出現錯誤 。WS-Policy 是一個用於為 Web 服務指定擴展需求的通用結構,而 WS-SecurityPolicy 是一個專門針對 WS-Security 支持的 WS-Policy 擴展。這兩者合起來可以以機器可讀的方式描述 WS-Security 需求。 WS-Policy 和 WS-SecurityPolicy 信息可以單獨使用,也可以直接嵌入到 Web Services Description Language (WSDL) 文檔內部,這樣 Web 服務框架就可以將它們自動配置為服務的需求。

Rampart 簡介

Rampart 是 Axis2 的安全模塊,支持 WS-Security、WS-SecurityPolicy、WS-SecureConversation 和 WS-Trust。在本文中,您將只查看 Rampart 的 WS-Security 和 WS-SecurityPolicy 功能;後續文章 將討論其他特性。

由於 Rampart 是以模塊形式實現(實際上是一對模塊 — rampart.mar 和 rahas.mar),它將插入到 Axis2 處理框架中並在出站和入站處理的特定點攔截消息,檢查對消息的修改或根據需要對消息作出修改 ,從而完成工作。

安裝 Rampart

Rampart 附帶了一些 .jar 文件(在發行版的 lib 目錄中),以及一對 .mar 模塊文件(位於 dist 目錄中)。您必須將 .jar 文件添加到類路徑中才能對 Axis2 使用 Rampart,並且必須將 .mar 文件添 加到類路徑或 Axis2 庫結構中。

處理 Rampart .jar 和 .mar 文件的最簡單方法是將它們添加到 Axis2 安裝中。可以從 Rampart lib 目錄中直接將 .jar 文件復制到 Axis2 lib 目錄,從 Rampart dist 目錄中直接將 .mar 文件復制到 Axis2 庫/模塊目錄中。(還可以使用 Ant build.xml 在 Rampart 樣例目錄中將文件復制給 Axis2 安裝 。只需要將 AXIS2_HOME 環境變量設置為 Axis2 安裝目錄並從打開 Rampart 樣例目錄的控制台運行 ant )。

對於眾多 WS-Security 特性,您還需要向 JVM 安全配置添加 Bouncy Castle 安全提供程序,向 Axis2 安裝添加 Bouncy Castle .jar。本系列後續文章中涉及的其他安全特性(不包括本文將介紹的 UsernameToken)需要使用這一步驟。由於某些安全算法涉及專利問題,Bouncy Castle .jar 可以從 Rampart 獨立下載(見 參考資料)。為您的 Java 運行時下載合適的 .jar 版本,並向 Axis2 lib 目錄 添加 .jar。您隨後需要修改 Java 安裝的安全策略來使用 Bouncy Castle 代碼,需要向 Java 運行時的 lib/security 目錄中的 java.security 文件添加一行代碼。查找文件中具有不同 security.provider 行的部分,然後添加以下代碼行:

security.provider.99=org.bouncycastle.jce.provider.BouncyCastleProvider

security.provider 行在文件中的順序並不重要,但是最好將其添加到實現預定義安全提供程序的代 碼行的後面。

要在 Axis2 服務器安裝中使用 Rampart 代碼,需要創建一個新的 axis2.war 文件,其中包括新添加 的 Rampart .jar 和 .mar 文件。可以使用 webapp 目錄中提供的 Ant build.xml 來創建 axis2.war, 假設您做了一處修改:刪除文件末尾的 <exclude name="axis2-codegen*.jar"/> 行。然後在控制 台中打開 Axis2 webapp 目錄並運行 ant。運行完 build.xml 後,會發現創建的 axis2.war Web 應用程 序出現在 Axis2 安裝的 dist 目錄中。

樣例應用程序

示例代碼中提供的應用程序(見 下載)基於我在 “Axis2 數據綁定” 中用於演示 Axis2 數據綁定 方法的示例。對於本文以及有關 Axis2 WS-Security 支持的後續文章,我將這個示例精簡到三個操作: getBook、addBook 和 getBooksByType。為了保持簡單性,只提供了 Axis Data Binding (ADB) 版本的 代碼,但是這並不是在 Axis2 中使用 WS-Security 的必需要求 — Rampart 可以獨立於代碼使用的數據 綁定技術實現 WS-Security,因此它可以處理 Axis2 支持的所有形式的數據綁定。

示例代碼的根目錄為 jws04code。在該目錄內部,將找到 Ant build.xml 和 build.properties 文件 ,以及為示例應用程序提供服務定義的 library.wsdl 文件,用於配置客戶端登錄的 log4j.properties 文件,以及一些屬性定義 XML 文件(全部命名為 XXX-policy-client.xml 或 XXX-policy-server.xml) 。build.properties 文件配置示例應用程序的操作。清單 2 展示了這個屬性文件的附帶版本:

清單 2. 附帶的 build.properties 文件

# set axis-home to your Axis2 installation directory
axis- home=PATH_TO_AXIS2_INSTALLATION
# set the connection protocol to be used to  access services (http or https)
protocol=http
# set the name of the service  host
host-name=localhost
# set the port for accessing the services (change  this for monitoring)
host-port=8080
# set the base path for accessing all  services on the host
base-path=/axis2/services/
# set the name of the policy  file to be used by the client
client-policy=plain-policy-client.xml
# set  the name of the policy file to be used by the server
server-policy=plain- policy-server.xml

在嘗試使用示例應用程序前,需要編輯 build.properties 文件並將實際路徑設置為 Axis2 安裝(添 加了 Rampart,如前一小節所述)。如果對服務器使用了不同的主機或端口號,還需要修改 host-name 和 host-port 值。我將在本文後面討論其余的值。

嘗試使用 WS-Security

WS-Security 定義了一些不同的安全令牌類型(包括構成核心規范的令牌以及在配置文件 中定義為規 范的插件擴展的令牌),並定義了多種方法來構建和使用令牌。本文的目的就是使用 Axis2 配置和 Rampart,因此我將使用最簡單的令牌作為示例:由 UsernameToken 配置文件定義的 UsernameToken。

UsernameToken WS-SecurityPolicy

UsernameToken 的功能僅僅是將用戶名和密碼信息作為 WS-Security 頭部的一部分進行傳遞。 UsernameToken 的最基本形式就是以明文的方式發送用戶名和密碼。從安全角度來看這並不合適(但是在 安全連接之上使用這種方法並不會出問題),但是很容易看到發送的內容,因此是一個非常好的起點。

將 UsernameToken 以文本形式發送的 WS-SecurityPolicy 配置非常簡單,如 清單 3 所示。該策略 (在這裡將一行代碼顯示為兩行以匹配頁面寬度 — 實際使用時這樣做是無效的)包含了一個標准 WS- Policy 包裝器(使用 wsp 前綴的元素),用來封裝一個 WS-SecurityPolicy UsernameToken 斷言。

清單 3. 用於明文形式的 UsernameToken 的 WS-SecurityPolicy

<wsp:Policy wsu:Id="UsernameToken" xmlns:wsu=
  "http://docs.oasis- open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"
   xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy">
 <wsp:ExactlyOne>
  <wsp:All>
   <sp:SupportingTokens
      xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702">
     <wsp:Policy>
     <sp:UsernameToken sp:IncludeToken="http://docs.oasis- open.org/
        ws-sx/ws- securitypolicy/200702/IncludeToken/AlwaysToRecipient"/>
     </wsp:Policy>
   </sp:SupportingTokens>
  </wsp:All>
  </wsp:ExactlyOne>
</wsp:Policy>

清單 3 中的 UsernameToken 使用一個 IncludeToken 屬性指定將包含到令牌中的消息流的類型 — 在本例中,所有消息流從請求發起者(即客戶機)流向請求接收者(即服務器)。還可以為 IncludeToken 屬性定義其他值來指定不同的令牌用途,但是對於 UsernameToken,這通常是惟一有效的 值。

應用策略

WS-Policy 和 WS-SecurityPolicy 旨在支持 WSDL 服務定義中的內嵌功能。使用引用將一個策略關聯 到一個或多個 <wsdl:binding>、<wsdl:binding>/<wsdl:operation> 或 <wsdl:message> 定義。Axis2 1.4.X 為 WSDL 中內嵌的策略實現了初步處理,但是直到 Axis2 1.4.1,實現仍然不夠健壯。本文將把策略直接連接到客戶機和服務器,從而實現與 1.4.1 代碼的兼容性 。

服務器端策略處理

在服務器端,應用策略的方式是將其添加到每個 Axis2 .aar 服務歸檔中的 services.xml 配置文件 。策略可以作為 <service> 元素的子元素直接添加,以應用於服務定義的所有操作。還需要向 services.xml 添加一個 <module> 元素,這是為了告訴 Axis2 Rampart 模塊必須包含在服務的配 置中。清單 4 是示例應用程序使用的經過編輯的 services.xml,其中粗體顯示的是添加的模塊引用和策 略信息:

清單 4. 包含內嵌策略的 services.xml

<serviceGroup>
 <service name="library-username">
   <messageReceivers>
   <messageReceiver
      class="com.sosnoski.ws.library.adb.LibraryUsernameMessageReceiverInOut"
      mep="http://www.w3.org/ns/wsdl/in-out"/>
  </messageReceivers>
   <parameter
     name="ServiceClass">com.sosnoski.ws.library.adb.LibraryUsernameImpl</parameter>
  <parameter name="useOriginalwsdl">true</parameter>
  <parameter  name="modifyUserWSDLPortAddress">true</parameter>
  <operation  mep="http://www.w3.org/ns/wsdl/in-out" name="getBook"
     namespace="http://ws.sosnoski.com/library/wsdl">
    <actionMapping>urn:getBook</actionMapping>
    <outputActionMapping>http://.../getBookResponse</outputActionMapping>
   </operation>
  ...

  <module ref="rampart"/>
   <wsp:Policy xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy"
     xmlns:wsu="http://.../oasis-200401-wss-wssecurity-utility-1.0.xsd"
     wsu:Id="UsernameToken">
   <wsp:ExactlyOne>
    <wsp:All>
      <sp:SupportingTokens
       xmlns:sp="http://docs.oasis-open.org/ws- sx/ws-securitypolicy/200702">
      <wsp:Policy>
        <sp:UsernameToken
          sp:IncludeToken="http://.../IncludeToken/AlwaysToRecipient">
         <wsp:Policy>
         <sp:HashPassword/>
         </wsp:Policy>
       </sp:UsernameToken>
       </wsp:Policy>
     </sp:SupportingTokens>

      <ramp:RampartConfig xmlns:ramp="http://ws.apache.org/rampart/policy">
       <ramp:passwordCallbackClass>...PWCBHandler</ramp:passwordCallbackClass>
      </ramp:RampartConfig>

    </wsp:All>
    </wsp:ExactlyOne>
  </wsp:Policy>
  </service>
</serviceGroup>

如果對 清單 4 中的內嵌策略與 清單 3 中的基本策略進行比較,會發現多了一項內容 — 一個 <ramp:RampartConfig> 元素。該元素為策略信息提供了特定於 Rampart 的擴展,在本例中,給出 了將用於處理密碼回調的類的名稱。服務器代碼使用回調檢驗客戶機在請求中提供的用戶名和密碼組合。

清單 5 展示了回調類的實際實現,用於明文形式的密碼。在本例中,用戶名和密碼都被提供給回調, 並且所有回調只需要檢驗用戶名和密碼組合。如果用戶名和密碼匹配預期值,那麼返回即可;否則,將拋 出一個異常表示出錯。

清單 5. 密碼回調代碼

import org.apache.ws.security.WSPasswordCallback;

public class  PWCBHandler implements CallbackHandler
{
 public void handle(Callback[]  callbacks)
  throws IOException, UnsupportedCallbackException {
   for (int  i = 0; i < callbacks.length; i++) {
    WSPasswordCallback pwcb =  (WSPasswordCallback)callbacks[i];
     String id = pwcb.getIdentifer();
       if (pwcb.getUsage() == WSPasswordCallback.USERNAME_TOKEN_UNKNOWN) {

        // used when plain-text password in message
        if  (!"libuser".equals(id) || !"books".equals(pwcb.getPassword())) {
          throw new UnsupportedCallbackException(callbacks[i], "check failed");
         }
      }
    }
  }
}

對於一個真正的應用程序,您肯定希望使用其他一些機制(比如數據庫或外部安全機制)來檢驗用戶 名和密碼組合。回調技術可以讓您使用任何檢查技巧來擴展 Rampart 安全處理。

客戶端配置

要對客戶機代碼使用 Rampart,首先需要對 Axis2 使用模塊。方法就是針對客戶機配置一個 Axis2 庫結構,但是更簡單的方法是在您的類路徑中包含 rampart.mar 模塊文件(以及需要使用的其他模塊) 。提供的示例使用了類路徑方法。

然後需要為客戶機配置安全模塊和其他相關參數。處理此配置的最簡單方法就是直接在服務 stub 上 設置值。清單 6 展示了示例代碼中的配置過程:

清單 6. 客戶機配置

  /**
   * Load policy file from classpath.
   */
  private  static Policy loadPolicy(String name) throws XMLStreamException {
     ClassLoader loader = WebServiceClient.class.getClassLoader();
    InputStream  resource = loader.getResourceAsStream(name);
    StAXOMBuilder builder = new  StAXOMBuilder(resource);
    return PolicyEngine.getPolicy (builder.getDocumentElement());
  }

  public static void main(String[]  args) throws IOException, XMLStreamException {

    // check for required  command line parameters
    if (args.length < 4) {
       System.out.println("Usage:\n java " +
         "com.sosnoski.ws.library.adb.WebServiceClient protocol host port path");
       System.exit(1);
    }

    // create the client stub
     String target = args[0] + "://" + args[1] + ":" + args[2] + args[3];
     System.out.println("Connecting to " + target);
    LibraryUsernameStub stub =  new LibraryUsernameStub(target);

    // configure and engage Rampart
     ServiceClient client = stub._getServiceClient();
    Options options =  client.getOptions();
    options.setProperty (RampartMessageData.KEY_RAMPART_POLICY,
      loadPolicy("policy.xml"));
     options.setUserName("libuser");
    options.setPassword("books");
     client.engageModule("rampart");

配置內容包含在清單 6 中的最後一個代碼塊。包括從創建的 stub 中獲得 org.apache.axis2.client.ServiceClient 實例並在客戶機選項中設置策略信息(從類路徑加載)和用戶 名/密碼。隨後在客戶機使用的 Axis2 配置中加入 Rampart 模塊。完成這些操作後,可以使用 stub 訪 問服務,就像不存在 WS-Security 一樣,而 Rampart 將 UsernameToken 自動添加到每個請求。

確認結果

安裝 Ant 後,可以從打開了示例代碼目錄的控制台運行 ant,以構建客戶機和服務器代碼。隨後可以 將創建的 library-username.aar 文件部署到 Axis2 服務器安裝(當然,包含 Rampart .jars 和 .mars ),並通過在控制台輸入 ant run 來運行客戶機。如果一切順利的話,應當看到如 圖 1 所示的輸出:

圖 1. 運行應用程序時的控制台輸出

當然,僅僅用服務器運行客戶機並不能向您表明發生的操作。可以使用 TCPMon 等工具充當客戶機和 服務器之間的中間層,從而捕獲消息交換以查看 WS-Security UsernameToken 的行為(見 參考資料)。 為此,首先需要設置 TCPMon 並在一個端口上接受來自客戶機的連接,這個端口隨後將連接轉發給運行在 不同端口(或不同主機)上的服務器。然後可以編輯 build.properties 文件並將 host-port 的值修改 為偵聽 TCPMon 的端口。如果再一次在控制台中輸入 ant run,應當會看到消息發生了交換。清單 7 展 示了一個樣例客戶機消息捕捉:

清單 7. 使用 UsernameToken 的客戶機消息

<?xml version='1.0' encoding='UTF-8'?>
<soapenv:Envelope  xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
  <soapenv:Header>
  <wsse:Security xmlns:wsse="...wss-wssecurity-secext- 1.0.xsd"
    soapenv:mustUnderstand="1">
   <wsse:UsernameToken  xmlns:wsu="...wss-wssecurity-utility-1.0.xsd"
     wsu:Id="UsernameToken- 1815911473">
    <wsse:Username>libuser</wsse:Username>
     <wsse:Password Type="...wss-username-token-profile-1.0#PasswordText"
       >books</wsse:Password>
   </wsse:UsernameToken>
   </wsse:Security>
 </soapenv:Header>
 <soapenv:Body>
   <ns2:getBooksByType xmlns:ns2="http://ws.sosnoski.com/library/wsdl">
    <ns2:type>scifi</ns2:type>
  </ns2:getBooksByType>
  </soapenv:Body>
</soapenv:Envelope>

保護 UsernameToken

一個基本的明文形式的 UsernameToken 並不能直接提供很強的安全性,因為用戶名和相應的密碼對於 任何能夠監視消息的人來說都是可見的。如果使用加密的通信通道,那麼就可以解決這個問題 — 只要通 道加密非常可靠,外部無法監視消息。WS-SecurityPolicy 方便地定義了一種方法來使用加密過的通道, 如 清單 8 所示(同樣,將一行代碼分解為兩行以匹配頁面寬度 — 查看示例代碼包的 secure-policy- server.xml 文件獲得真實的策略):

清單 8. 要求 HTTPS 連接的策略

<wsp:Policy wsu:Id="UsernameToken" xmlns:wsu=
"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility- 1.0.xsd"
xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy">
<wsp:ExactlyOne>
<wsp:All>
<sp:TransportBinding xmlns:sp="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy">
<wsp:Policy>
<sp:TransportToken>
<wsp:Policy>
<sp:HttpsToken RequireClientCertificate="false"/>
</wsp:Policy>
</sp:TransportToken>
</wsp:Policy>
</sp:TransportBinding>
<sp:SupportingTokens
xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702">
<wsp:Policy>
<sp:UsernameToken sp:IncludeToken="http://docs.oasis-open.org/
ws-sx/ws-securitypolicy/200702/IncludeToken/AlwaysToRecipient"/>
</wsp:Policy>
</sp:SupportingTokens>
</wsp:All>
</wsp:ExactlyOne>
</wsp:Policy>

清單 8 中使用粗體顯示的代碼是新增的部分,由 <sp:TransportBinding> 元素和嵌套的 <sp:HttpsToken> 元素組成。<sp:HttpsToken> 元素表示一個安全的 HTTPS 連接必須用於 與服務的通信。如果嘗試使用此策略構建 service .aar(通過將 build.properties 中的 server- policy 值修改為 secure-policy-server.xml,然後運行 ant build-server)並部署它,將看到 Rampart 實施這項策略需求,拒絕任何普通的 HTTP 連接。

如果希望對服務使用一個 HTTPS 連接,這樣做是可行的,但是首先需要配置您的 Web 服務器以支持 HTTPS。(Tomcat 提供了非常好的說明,可以從 /tomcat-docs/ssl-howto.html 訪問)。還需要在 build.properties 中將 protocol 值修改為 https,並且如果對 Web 服務器使用的是自簽名的證書,在 運行 Ant test 目標時需要向客戶機發送一個證書存儲庫(trust store)。提供的 build.xml 有一個注 釋掉的行可以實現這點,因此只需去掉此行的注釋符號,並設置相應的證書存儲庫文件在系統中的位置。

另一種增強 UsernameToken 安全性的方法甚至可以處理未加密的鏈接。這種方法使用對一個字符串計 算得到的摘要(digest)值,該字符串由兩個文本值和密碼組成。其中一個文本值為 nonce,是由發送者 對每個請求生成的隨機值。另一個文本值是一個生成的時間戳,表示發送者創建 UsernameToken 的時間 。這兩個值都以明文形式包含在 UsernameToken 中。如果恰當地應用於客戶機和服務器,組合這些值和 摘要中的密碼使服務器能夠驗證在生成摘要時使用的是正確的密碼,同時使得外部很難偽造有效的密碼。 清單 9 給出了一個使用摘要密碼的策略示例,其後是實際捕獲的使用摘要密碼的消息(全部重新格式化 以適合頁面寬度 — 查找 hash-policy-client.xml 文件獲得真實的策略),粗體顯示的是與初始策略不 同的地方。

清單 9. 使用密碼摘要的策略和樣例消息

<wsp:Policy wsu:Id="UsernameToken" xmlns:wsu=
    "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-

1.0.xsd"
    xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy">
  <wsp:ExactlyOne>
    <wsp:All>
      <sp:SupportingTokens
          xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702">
        <wsp:Policy>
          <sp:UsernameToken sp:IncludeToken="http://docs.oasis-open.org/
ws-sx/ws-securitypolicy/200702/IncludeToken/AlwaysToRecipient">
            <wsp:Policy>
              <sp:HashPassword/>
            </wsp:Policy>
          </sp:UsernameToken>
        </wsp:Policy>
      </sp:SupportingTokens>
    </wsp:All>
  </wsp:ExactlyOne>
</wsp:Policy>
<?xml version='1.0' encoding='UTF-8'?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
  <soapenv:Header>
    <wsse:Security xmlns:wsse=".../oasis-200401-wss-wssecurity-secext-1.0.xsd"
        soapenv:mustUnderstand="1">
      <wsse:UsernameToken xmlns:wsu="...wss-wssecurity-utility-1.0.xsd"
          wsu:Id="UsernameToken-1421876889">
        <wsse:Username>libuser</wsse:Username>
        <wsse:Password Type="...wss-username-token-profile-1.0#PasswordDigest"
          >/Wt/2yDdZwa8a5qd7U70hrp29/w=</wsse:Password>
        <wsse:Nonce>4ZQz5ytME/RXfChuKJ03iA==</wsse:Nonce>
        <wsu:Created>2009-03-17T11:20:57.467Z</wsu:Created>
      </wsse:UsernameToken>
    </wsse:Security>
  </soapenv:Header>
  <soapenv:Body>
    <ns2:getBooksByType xmlns:ns2="http://ws.sosnoski.com/library/wsdl">
      <ns2:type>scifi</ns2:type>
    </ns2:getBooksByType>
  </soapenv:Body>
</soapenv:Envelope>

結束語

在本文中,您了解了如何使用 Axis2 和 Rampart 實現基本的基於策略的 WS-Security 處理。在下一 期 Java Web 服務 中,將了解 WS-Security 的兩個強大特性:XML 加密和簽名。使用 XML 加密可以使 您在操作任何類型的連接時保持消息內容的私密性,即使在處理過程中涉及到不可信的代理。使用 XML 簽名可以確保消息確實來自聲稱的發起者,並且消息內容在傳輸過程中沒有被篡改。加密和簽名是大多數 企業安全實現的基礎,回顧一下這些特性,看看如何在您自己的 Web 服務中應用它們。

隨文源碼:http://www.bianceng.net/java/201212/690.htm

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved