如您从“ Metro简介 ”所了解的那样,JAXB 2.x数据绑定和JAX-WS 2.x Web服务标准的参考实现是Metro Web服务框架的核心。 但是就其本身而言,JAXB和JAX-WS仅提供基本的Web服务支持。 JAX-WS不涉及将SOAP升级到企业环境中的WS- *技术,因此需要其他软件组件来添加对这些技术的支持。
在Metro中,主要添加的组件是Web服务互操作性技术(WSIT)。 WSIT是最初称为Project Tango的当前版本,Sun致力于确保WS- *功能(包括安全性和可靠消息传递)与Microsoft .NET平台的互操作性。 WSIT为Metro提供了对WS-SecurityPolicy,WS-Trust,WS-SecureConversation,WS-ReliableMessaging等的支持。 WS-Security的实际运行时处理由另一个添加的组件XML和WebServices安全项目(XWSS)实现。
本文展示了如何使用和配置Metro上的WS-Security来作为Web应用程序独立使用(在Glassfish服务器外部)。 请参阅下载以获取本文示例的完整源代码,这些示例实现了本系列先前使用的简单库管理服务。
WSIT基础
WSIT负责配置Metro运行时以匹配服务的WS-Policy规范,包括WS-Policy扩展(例如WS-SecurityPolicy)。 除了标准的WS-Policy扩展之外,Metro还使用策略文档中的自定义扩展来配置实现安全性处理所需的用户信息(例如密钥存储位置和密码)。
WSIT从Web服务描述语言(WSDL)服务描述中获取策略信息。 在客户端,这可能会造成混淆,因为用于WSIT配置的WSDL与用于定义JAX-WS服务的WSDL是分开的。 如“ 地铁介绍 ”中所述,用于配置JAX-WS客户端的WSDL可以直接从服务获得,也可以从生成JAX-WS代码时指定的位置获得。 WSIT使用的WSDL具有固定的文件名(尽管该文件可以使用<wsdl:import>
来引用具有完整WSDL的单独文件),并且始终可以从类路径中对其进行访问。
在服务器端,WSIT要求在WEB-INF / sun-jaxws.xml配置文件(在“ Metro简介 ”中讨论)指定的位置提供WSDL。 提供的WSDL必须包括用于为WSIT配置用户信息的定制扩展,但是这些定制扩展将从响应于服务端点的HTTP GET请求而提供的WSDL版本中删除。
用于配置WSIT用户信息的定制扩展在客户端和服务器端看起来相同,但是用于扩展元素的XML名称空间不同。 在客户端上,此名称空间是http://schemas.sun.com/2006/03/wss/client
; 在服务器上,名称空间为http://schemas.sun.com/2006/03/wss/server
。
Metro中的UsernameToken
“ Axis2 WS-Security基础知识 ”以UsernameToken
的简单情况在Axis2 / Rampart中引入了WS-Security。 UsernameToken
提供了一种使用WS-Security表示用户名和密码对的标准方法。 密码信息可以纯文本形式发送(通常仅在与传输层安全性[TLS]或WS-Security加密结合使用时才在生产环境中使用,但便于测试)或散列值发送。
要在Metro上实现简单的纯文本UsernameToken
示例,您需要使用包含适当的WS-Policy / WS-SecurityPolicy配置的WSDL服务定义。 清单1显示了与“ Metro简介 ”中使用的基本WSDL服务定义相同的编辑版本,这次包含了策略信息,该信息要求在从客户端到服务器的请求上要求UsernameToken
。 <wsdl:binding>
的策略引用以粗体显示,策略本身也以粗体显示。
清单1.纯文本UsernameToken
WSDL
<?xml version="1.0" encoding="UTF-8"?>
<wsdl:definitions targetNamespace="http://ws.sosnoski.com/library/wsdl"
xmlns:wns="http://ws.sosnoski.com/library/wsdl"
xmlns:tns="http://ws.sosnoski.com/library/types"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:wsdlsoap="http://schemas.xmlsoap.org/wsdl/soap/">
<wsdl:types>
...
</wsdl:types>
<wsdl:message name="getBookRequest">
<wsdl:part element="wns:getBook" name="parameters"/>
</wsdl:message>
...
<wsdl:portType name="Library">
<wsdl:operation name="getBook">
<wsdl:input message="wns:getBookRequest" name="getBookRequest"/>
<wsdl:output message="wns:getBookResponse" name="getBookResponse"/>
</wsdl:operation>
...
</wsdl:portType>
<wsdl:binding name="LibrarySoapBinding" type="wns:Library">
<wsp:PolicyReference xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy"
URI="#UsernameToken"/>
<wsdlsoap:binding style="document"
transport="http://schemas.xmlsoap.org/soap/http"/>
<wsdl:operation name="getBook">
<wsdlsoap:operation soapAction="urn:getBook"/>
<wsdl:input name="getBookRequest">
<wsdlsoap:body use="literal"/>
</wsdl:input>
<wsdl:output name="getBookResponse">
<wsdlsoap:body use="literal"/>
</wsdl:output>
</wsdl:operation>
...
</wsdl:binding>
<wsdl:service name="MetroLibrary">
<wsdl:port binding="wns:LibrarySoapBinding" name="library">
<wsdlsoap:address location="http://localhost:8080/metro-library-username"/>
</wsdl:port>
</wsdl:service>
<!-- Policy for Username Token with plaintext password, sent from client to
server only -->
<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=".../IncludeToken/AlwaysToRecipient"/>
</wsp:Policy>
</sp:SupportingTokens>
</wsp:All>
</wsp:ExactlyOne>
</wsp:Policy>
</wsdl:definitions>
清单1的 WSDL告诉想要访问该服务的任何人在安全性方面需要做什么 。 您还需要在客户端和服务器端的策略信息上添加带有用户配置详细信息的WSIT定制扩展,以指示将如何实现安全性处理。 这些定制扩展适合WSDL的<wsp:Policy>
组件。 接下来,我将向您展示每侧这些扩展的示例。
客户端使用
在客户端,具有(固定)名称wsit-client.xml的文件用于WSIT配置。 该文件必须位于类路径上的根目录(任何软件包外部)中,或类路径中目录的META-INF子目录中。 wsit-client.xml必须是一个WSDL文档,该文档必须直接提供完整的服务WSDL或使用<wsdl:import>
引用单独的WSDL服务定义。 无论哪种方式,WSDL必须同时包含完整的WS-Policy / WS-SecurityPolicy要求和WSIT配置扩展。
清单2显示了清单1 WSDL的策略部分,其中添加了WSIT定制扩展以配置客户端UsernameToken
支持。 在这种情况下,该自定义扩展是<wssc:CallbackHandlerConfiguration>
元素和子元素,以粗体显示。 两个子元素<wssc:CallbackHandler>
定义了回调类,第一个用于用户名( name="usernameHandler"
),第二个用于密码( name="passwordHandler"
)。 指定的类必须实现javax.security.auth.callback.CallbackHandler
接口。
清单2.带有WSIT客户端扩展的UsernameToken
策略
<wsp:Policy xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy" xmlns:wsu=
"http://docs.oasis-open.org/wss/2004/01/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=".../IncludeToken/AlwaysToRecipient"/>
</wsp:Policy>
</sp:SupportingTokens>
<wssc:CallbackHandlerConfiguration wspp:visibility="private"
xmlns:wssc="http://schemas.sun.com/2006/03/wss/client"
xmlns:wspp="http://java.sun.com/xml/ns/wsit/policy">
<wssc:CallbackHandler name="usernameHandler"
classname="com.sosnoski.ws.library.metro.UserPassCallbackHandler"/>
<wssc:CallbackHandler name="passwordHandler"
classname="com.sosnoski.ws.library.metro.UserPassCallbackHandler"/>
</wssc:CallbackHandlerConfiguration>
</wsp:All>
</wsp:ExactlyOne>
</wsp:Policy>
在清单2中 ,两个回调都使用相同的类。 清单3显示了回调类代码,该代码仅检查每个回调请求的类型并设置适当的值:
清单3.客户端回调代码
public class UserPassCallbackHandler implements CallbackHandler
{
public void handle(Callback[] callbacks) throws UnsupportedCallbackException {
for (int i = 0; i < callbacks.length; i++) {
if (callbacks[i] instanceof NameCallback) {
((NameCallback)callbacks[i]).setName("libuser");
} else if (callbacks[i] instanceof PasswordCallback) {
((PasswordCallback)callbacks[i]).setPassword("books".toCharArray());
} else {
throw new UnsupportedCallbackException(callbacks[i],
"Unsupported callback type");
}
}
}
}
您不必使用回调无论是用户名或密码。 如果您使用固定值,则可以通过将classname=" xxx "
属性替换为default=" yyy "
属性来直接在相应的<wssc:CallbackHandler>
元素中进行default=" yyy "
(其中属性值为实际用户名或密码)。
服务器端使用
在服务器端,需要在WSDL服务定义中提供WSIT配置信息。 如“ 地铁介绍 ”中所述,可以将服务WSDL的位置指定为服务WAR文件中WEB-INF / sun-jaxws.xml中的参数。 如果您不使用WSIT功能,则此WSDL是可选的,在这种情况下,WSDL将在运行时自动生成。 如果使用的是WSIT功能,则WSDL是必需的,并且必须包括为服务使用的功能配置WSIT所需的任何自定义扩展元素。 清单4显示了清单1 WSDL的policy部分,这次添加了WSIT定制扩展以配置服务器端UsernameToken
支持(以粗体显示):
清单4.带有WSIT服务器端扩展的UsernameToken
策略
<wsp:Policy xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy" xmlns:wsu=
"http://docs.oasis-open.org/wss/2004/01/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=".../IncludeToken/AlwaysToRecipient"/>
</wsp:Policy>
</sp:SupportingTokens>
<wsss:ValidatorConfiguration wspp:visibility="private"
xmlns:wsss="http://schemas.sun.com/2006/03/wss/server"
xmlns:wspp="http://java.sun.com/xml/ns/wsit/policy">
<wsss:Validator name="usernameValidator"
classname="com.sosnoski.ws.library.metro.PasswordValidator"/>
</wsss:ValidatorConfiguration>
</wsp:All>
</wsp:ExactlyOne>
</wsp:Policy>
清单4中的服务器端WSIT扩展采用<wsss:ValidatorConfiguration>
元素和子<wsss:Validator>
元素的形式,指定了用作验证器回调的类。 清单5显示了该类的代码,该类必须实现com.sun.xml.wss.impl.callback.PasswordValidationCallback.PasswordValidator
接口。 在这种情况下,它仅根据固定值检查提供的用户名和密码,但是可以轻松地使用数据库查找或其他机制。
清单5.服务器回调代码
public class PasswordValidator implements PasswordValidationCallback.PasswordValidator
{
public boolean validate(Request request) throws PasswordValidationException {
PasswordValidationCallback.PlainTextPasswordRequest ptreq
= (PasswordValidationCallback.PlainTextPasswordRequest)request;
return "libuser".equals(ptreq.getUsername()) &&
"books".equals(ptreq.getPassword());
}
}
如果不提供<wsss:ValidatorConfiguration>
,Metro将使用Web应用程序容器(提供servlet支持的Web服务器)提供的授权机制。
构建并运行示例代码
在尝试示例代码之前,您需要在系统上下载并安装最新版本的Metro(该代码已经在1.5版本中进行了测试)(请参阅参考资料 )。 您还需要在解压缩的样本代码下载的根目录中编辑build.properties文件,以将metro-home
属性的值更改为Metro安装的路径。 如果要在其他系统或端口上的服务器上进行测试,则可能还需要更改host-name
和host-port
。
要使用提供的Ant build.xml构建示例应用程序,请打开控制台到下载代码的根目录,然后键入ant
。 这将首先调用JAX-WS wsimport
工具(包含在Metro发行版中),然后编译客户端和服务器,最后将服务器代码打包为WAR(在WSDL中生成包含客户端和服务器WSIT配置信息的服务WSDL的单独版本。该过程)。 请注意,Metro 1.5中包含的wsimport
版本将发出警告消息(由于该工具在处理WSDL中嵌入的架构中存在一个怪癖): src-resolve: Cannot resolve the name 'tns:BookInformation' to a(n) 'type definition' component
。
然后,您可以将生成的metro-library.war文件部署到测试服务器,最后在控制台上键入ant run
来尝试运行示例客户端。 样本客户端通过对服务器的一系列请求序列,为每个请求打印简要结果。
在Metro中签名和加密
UsernameToken
的简单性使其成为一个很好的起点,但这并不是WS-Security的典型用法。 大多数情况下,您将使用签名或加密,或同时使用两者。 清单6显示了同时使用签名和加密的WSDL的编辑示例(基于“ Axis2 WS-Security签名和加密 ”中的示例-有关一般的WS-Security签名和加密的详细讨论,请参见该文章)。 WSDL的策略部分以粗体显示。
清单6.对WSDL进行签名/加密
<?xml version="1.0" encoding="UTF-8"?>
<wsdl:definitions targetNamespace="http://ws.sosnoski.com/library/wsdl"
xmlns:wns="http://ws.sosnoski.com/library/wsdl"
xmlns:tns="http://ws.sosnoski.com/library/types"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:wsdlsoap="http://schemas.xmlsoap.org/wsdl/soap/">
<wsdl:types>
...
</wsdl:types>
<wsdl:message name="getBookRequest">
<wsdl:part element="wns:getBook" name="parameters"/>
</wsdl:message>
...
<wsdl:portType name="Library">
<wsdl:operation name="getBook">
<wsdl:input message="wns:getBookRequest" name="getBookRequest"/>
<wsdl:output message="wns:getBookResponse" name="getBookResponse"/>
</wsdl:operation>
...
</wsdl:portType>
<wsdl:binding name="LibrarySoapBinding" type="wns:Library">
<wsp:PolicyReference xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy"
URI="#SignEncr"/>
<wsdlsoap:binding style="document"
transport="http://schemas.xmlsoap.org/soap/http"/>
<wsdl:operation name="getBook">
<wsdlsoap:operation soapAction="urn:getBook"/>
<wsdl:input name="getBookRequest">
<wsdlsoap:body use="literal"/>
</wsdl:input>
<wsdl:output name="getBookResponse">
<wsdlsoap:body use="literal"/>
</wsdl:output>
</wsdl:operation>
...
</wsdl:binding>
<wsdl:service name="MetroLibrary">
<wsdl:port binding="wns:LibrarySoapBinding" name="library">
<wsdlsoap:address location="http://localhost:8080/metro-library-username"/>
</wsdl:port>
</wsdl:service>
<!-- Policy for first signing and then encrypting all messages, with the certificate
included in the message from client to server but only a thumbprint on messages from
the server to the client. -->
<wsp:Policy wsu:Id="SignEncr" 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:AsymmetricBinding
xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702">
<wsp:Policy>
<sp:InitiatorToken>
<wsp:Policy>
<sp:X509Token sp:IncludeToken=".../IncludeToken/AlwaysToRecipient">
<!-- Added this policy component so Metro would work with the same
certificates (and key stores) used in the Axis2/Rampart example. -->
<wsp:Policy>
<sp:RequireThumbprintReference/>
</wsp:Policy>
</sp:X509Token>
</wsp:Policy>
</sp:InitiatorToken>
<sp:RecipientToken>
<wsp:Policy>
<sp:X509Token sp:IncludeToken=".../IncludeToken/Never">
<wsp:Policy>
<sp:RequireThumbprintReference/>
</wsp:Policy>
</sp:X509Token>
</wsp:Policy>
</sp:RecipientToken>
<sp:AlgorithmSuite>
<wsp:Policy>
<sp:TripleDesRsa15/>
</wsp:Policy>
</sp:AlgorithmSuite>
<sp:Layout>
<wsp:Policy>
<sp:Strict/>
</wsp:Policy>
</sp:Layout>
<sp:IncludeTimestamp/>
<sp:OnlySignEntireHeadersAndBody/>
</wsp:Policy>
</sp:AsymmetricBinding>
<sp:SignedParts
xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702">
<sp:Body/>
</sp:SignedParts>
<sp:EncryptedParts
xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702">
<sp:Body/>
</sp:EncryptedParts>
</wsp:All>
</wsp:ExactlyOne>
</wsp:Policy>
</wsdl:definitions>
清单6 WSDL与早期Axis2 / Rampart示例中使用的WSDL之间的唯一显着区别是,在<sp:InitiatorToken>
组件中添加了一个策略,当X.509证书中未包含X.509证书时,要求使用指纹引用。信息。 由于在Metro和Axis2中默认处理引用的方式有所不同,因此需要此添加。
当客户端(使用WS-SecurityPolicy表示的发起方 )发送消息时,客户端的X.509证书将作为消息的一部分发送(因为sp:IncludeToken=".../IncludeToken/AlwaysToRecipient"
<sp:InitiatorToken/wsp:Policy/sp:X509Token>
元素上的属性),服务器使用它来验证签名。 当服务器回复客户端时,它需要引用来自客户端的与加密处理中相同的证书。 如果未指定其他方法,则Axis2 / Rampart默认使用指纹参考进行证书标识。 Metro / WSIT默认使用另一种方法,称为主题密钥标识符 (SKI)。 Axis2 / Rampart示例中使用的证书的格式不支持SKI,因此默认情况下它们不适用于Metro / WSIT。 将<sp:RequireThumbprintReference/>
元素添加到策略中将告诉Metro / WSIT使用指纹引用代替证书。
对策略的此更改允许在此示例中使用在早期Axis2 / Rampart示例中使用的相同证书和密钥存储。 相应地,Axis2 / Rampart客户端示例可与Metro / WSIT服务器一起使用,反之亦然,这是检查互操作性的便捷方法。 如果您尝试一下(您可以通过更改每种情况下传递给测试客户端的目标路径来完成此操作),您会发现在大多数情况下交换消息都没有困难-但操作上有所不同,请参见互操作性问题部分,如下。
与UsernameToken
示例一样,WSIT需要在客户端和服务器端对策略信息进行自定义扩展,以提供其他配置详细信息。
客户端使用
清单7显示了添加到WSDL策略中的WSIT定制扩展,以配置该示例的客户端处理。 这些自定义扩展名以粗体显示,用于配置签名和加密所需的密钥库(包含客户端的私钥和相应的证书)和信任库(包含服务器的证书)。
清单7.使用WSIT客户端扩展的签名和加密策略
<wsp:Policy xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy" xmlns:wsu=
"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"
wsu:Id="SignEncr">
<wsp:ExactlyOne>
<wsp:All>
<sp:AsymmetricBinding xmlns:sp=
"http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702">
<wsp:Policy>
...
</wsp:Policy>
</sp:AsymmetricBinding>
<sp:SignedParts
xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702">
<sp:Body/>
</sp:SignedParts>
<sp:EncryptedParts
xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702">
<sp:Body/>
</sp:EncryptedParts>
<wssc:KeyStore alias="clientkey" keypass="clientpass"
location="client.keystore" storepass="nosecret"
xmlns:wspp="http://java.sun.com/xml/ns/wsit/policy" wspp:visibility="private"
xmlns:wssc="http://schemas.sun.com/2006/03/wss/client"/>
<wssc:TrustStore location="client.keystore" peeralias="serverkey"
storepass="nosecret" xmlns:wspp="http://java.sun.com/xml/ns/wsit/policy"
wspp:visibility="private"
xmlns:wssc="http://schemas.sun.com/2006/03/wss/client"/>
</wsp:All>
</wsp:ExactlyOne>
</wsp:Policy>
清单7的 WSIT定制扩展提供了访问密钥存储区和信任存储区(在本例中是同一文件)的所有必需参数,包括访问客户端的私钥所需的密码(密钥上的keypass="clientpass"
属性)。 <wssc:KeyStore>
元素)。 如您将在下一节中看到的,也可以使用回调来获取密码信息。
命名密钥库和信任库必须位于类路径中目录的META-INF子目录中。 您还可以为这些文件使用绝对文件路径(而不仅仅是文件名),这使您可以将它们定位在文件系统上的任何固定位置。 (回想一下,对于客户端,包括WSIT自定义扩展名的WSDL必须使用固定名称wsit-client.xml,并且必须位于类路径的根目录中,或者位于根目录中META-INF子目录中。类路径。)
服务器端使用
清单8中显示了添加到WSDL的服务器端WSIT定制扩展(再次以粗体显示)。 在这种情况下, <wsss:KeyStore>
的keypass
属性给出一个类名而不是实际的密码值(如清单7的客户端示例所示)。 使用此方法时,引用的类必须实现javax.security.auth.callback.CallbackHandler
接口,并且当它需要访问密钥的密码时,它将由WSIT代码调用。 您也可以使用相同的技术为storepass
值指定类名而不是密码。
清单8.使用WSIT服务器端扩展的签名和加密策略
<wsp:Policy xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy" xmlns:wsu=
"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"
wsu:Id="SignEncr">
<wsp:ExactlyOne>
<wsp:All>
<sp:AsymmetricBinding xmlns:sp=
"http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702">
<wsp:Policy>
...
</wsp:Policy>
</sp:AsymmetricBinding>
<sp:SignedParts
xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702">
<sp:Body/>
</sp:SignedParts>
<sp:EncryptedParts
xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702">
<sp:Body/>
</sp:EncryptedParts>
<wsss:KeyStore alias="serverkey"
keypass="com.sosnoski.ws.library.metro.KeystoreAccess"
location="server.keystore" storepass="nosecret"
xmlns:wspp="http://java.sun.com/xml/ns/wsit/policy" wspp:visibility="private"
xmlns:wsss="http://schemas.sun.com/2006/03/wss/server"/>
<wsss:TrustStore location="server.keystore" storepass="nosecret"
xmlns:wspp="http://java.sun.com/xml/ns/wsit/policy" wspp:visibility="private"
xmlns:wsss="http://schemas.sun.com/2006/03/wss/server"/>
</wsp:All>
</wsp:ExactlyOne>
</wsp:Policy>
清单9显示了用于此示例的CallbackHandler
接口的实现:
清单9.服务器密钥库密码回调代码
public class KeystoreAccess implements CallbackHandler
{
public void handle(
Callback[] callbacks) throws IOException, UnsupportedCallbackException {
for (int i = 0; i < callbacks.length; i++) {
Callback callback = callbacks[i];
if (callback instanceof PasswordCallback) {
((PasswordCallback)callback).setPassword("serverpass".toCharArray());
} else {
throw new UnsupportedCallbackException(callback, "unknown callback");
}
}
}
}
构建并运行示例代码
签名和加密示例使用与UsernameToken
示例相同的构建步骤 ,除了必须将build.properties文件更改为使用variant-name=signencr
(而不是UsernameToken
示例的值username
)。
互操作性问题
如果尝试将Axis2 / Rampart客户端与Metro / WSIT服务器一起使用(反之亦然),则当客户端尝试添加具有重复的国际标准书号(ISBN)的书时,您可能会遇到问题。 在这种情况下,服务将返回错误,而不是正常的SOAP响应消息。 在这种情况下,Axis2 / Rampart 1.5.x发行版可以正确执行WSDL所需的常规签名和加密处理,但是Metro / WSIT 1.5不能,导致客户端失败。 这是WSIT代码中的错误,下一个Metro版本应予以纠正。
如果使用早期版本的Axis2 / Rampart运行该测试,则可能不会看到任何问题-因为Rampart在Rampart 1.5发行之前一直存在相同的错误。
地铁下一站
Metro的WSIT对WS-SecurityPolicy的支持允许直接配置诸如用户名和密码(包括密钥存储和私钥密码)之类的参数,并允许使用回调根据需要获取这些值。 它还允许您在servlet容器的授权处理和您自己的回调之间进行选择,以验证服务器上的用户名和密码组合。 这种灵活性使Metro可以轻松满足多种类型的应用程序的需求。 Metro还提供了WSIT / XWSS WS-Security支持作为集成组件,而不是像Axis2和Rampart那样具有单独的组件(具有自己的发布周期,并且通常在核心组件的不同版本之间不兼容)作为集成组件。
不利的一面是,有关如何单独使用Metro / WSIT并直接进行配置的信息很少(与将其与NetBeans IDE和Glassfish应用程序服务器结合使用的信息相反)。 许多必要的选项仅记录在博客文章或电子邮件交换中(请参阅参考资料 )。
Java Web服务的下一部分将继续关注Metro,这次将重点放在性能上。 在简单的消息交换和使用的WS-Security中,查看Metro性能与Axis2相比如何。
翻译自: https://www.ibm.com/developerworks/java/library/j-jws10/index.html