技术开发 频道

Java Web 服务: Axis2 WS-Security 基础

  如果对 清单 4 中的内嵌策略与 清单 3 中的基本策略进行比较,会发现多了一项内容 — 一个 元素。该元素为策略信息提供了特定于 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>
0
相关文章