CXF客户端安全



我正在创建一个Java soap web服务的客户端,但是我很难弄清楚如何正确地传递密码。以下是我的"硬编码"密码示例:

@Test
public void exploratorySecurityTest() {
     String username = "user";
     String password = "pwd";
    UserStoryService service = new UserStoryService();
    UserStoryServiceSoap port = service.getUserStoryServiceSoap();
    //initialize security
    org.apache.cxf.endpoint.Client client = ClientProxy.getClient(port); 
    org.apache.cxf.endpoint.Endpoint cxfEndpoint = client.getEndpoint();
    Map<String, Object> outProps = new HashMap<String, Object>();
    outProps.put(WSHandlerConstants.ACTION, WSHandlerConstants.USERNAME_TOKEN);
    outProps.put(WSHandlerConstants.USER, username);
    outProps.put(WSHandlerConstants.PASSWORD_TYPE, WSConstants.PW_TEXT);
    outProps.put(WSHandlerConstants.PW_CALLBACK_CLASS, ClientPasswordCallback.class.getName());
    WSS4JOutInterceptor wssOut = new WSS4JOutInterceptor(outProps);
    cxfEndpoint.getOutInterceptors().add(wssOut);
    int storyId = 33401;
    UserStoryDTO userStoryDTO = port.getByID(storyId);
    //success if no error
}
public class ClientPasswordCallback implements CallbackHandler {
@Override
public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
    WSPasswordCallback pc = (WSPasswordCallback) callbacks[0];
    pc.setPassword("pwd");
}}

我真正想做的是将密码传递给回调处理程序。我在CXF文档中看到的示例实现了"硬编码"的回调(就像我在这个示例中所做的那样),或者作为用户名的函数:

if (pc.getIdentifier().equals("user"))
   pc.setPassword("pwd");

这些都不符合我的需要。有没有一种方法可以让我做如下的事情:

@Test
public void exploratorySecurityTest() {
     String username = "user";
     String password = "pwd";
    UserStoryService service = new UserStoryService();
    UserStoryServiceSoap port = service.getUserStoryServiceSoap();
    //initialize security
    org.apache.cxf.endpoint.Client client = ClientProxy.getClient(port); 
    org.apache.cxf.endpoint.Endpoint cxfEndpoint = client.getEndpoint();
    Map<String, Object> outProps = new HashMap<String, Object>();
    outProps.put(WSHandlerConstants.ACTION, WSHandlerConstants.USERNAME_TOKEN);
    outProps.put(WSHandlerConstants.USER, username);
            //pass the password here?
            outProps.put("password", password);
    outProps.put(WSHandlerConstants.PASSWORD_TYPE, WSConstants.PW_TEXT);
    outProps.put(WSHandlerConstants.PW_CALLBACK_CLASS, ClientPasswordCallback.class.getName());
    WSS4JOutInterceptor wssOut = new WSS4JOutInterceptor(outProps);
    cxfEndpoint.getOutInterceptors().add(wssOut);
            // ...
}

使用PW_CALLBACK_REF代替PW_CALLBACK_CLASS,并传递一个实例化的对象,而不是静态类。您可以在该对象中注入密码。

类似:

    outProps.put(WSHandlerConstants.PASSWORD_TYPE, WSConstants.PW_TEXT);
    CXFClientPasswordHandler handler = new CXFClientPasswordHandler();
    handler.setPassword(password);
    outProps.put(WSHandlerConstants.PW_CALLBACK_REF, handler);

我还可以做以下事情:

    org.apache.cxf.endpoint.Client client = ClientProxy.getClient(obj);
    org.apache.cxf.endpoint.Endpoint cxfEndpoint = client.getEndpoint();
    Map<String, Object> outProps = new HashMap<String, Object>();
    outProps.put(WSHandlerConstants.ACTION, WSHandlerConstants.USERNAME_TOKEN);
    System.out.println("initialize security for user " + this.username);
    outProps.put(WSHandlerConstants.USER, this.username);
    outProps.put(WSHandlerConstants.PASSWORD_TYPE, WSConstants.PW_TEXT);
    Map<String, Object> ctx = ((BindingProvider) obj).getRequestContext();
    ctx.put("password", this.password);
    WSS4JOutInterceptor wssOut = new WSS4JOutInterceptor(outProps);
    cxfEndpoint.getOutInterceptors().add(wssOut);

您的ClientPasswordCallback类可能是这样的,具有自己的pwd字段和相关的setter:

class ClientPasswordCallback implements CallbackHandler {
    private String pwd;
    public void setPassword(String pwd) {
        passwd = pwd;
    }
    @Override
    public void handle(Callback[] callbacks) {
        WSPasswordCallback pc = (WSPasswordCallback) callbacks[0];
        pc.setPassword(pwd);
    }
}

然后您可以在您的测试中实例化它,设置其密码并使用PW_CALLBACK_REF密钥将其添加到outProps映射中:

@Test
public void exploratorySecurityTest() {
    String username = "user";
    String password = "pwd";
    // ...
    outProps.put(PASSWORD_TYPE, WSConstants.PW_TEXT);
    ClientPasswordCallback handler = new ClientPasswordCallback();
    handler.setPassword(passwd);
    outProps.put(PW_CALLBACK_REF, handler);
    WSS4JOutInterceptor wssOut = new WSS4JOutInterceptor(outProps);
    // ...
}

我一直使用以下方式添加属性来请求http级别认证的上下文,以及添加消息级别用户名令牌的CallbackHandler。

org.apache.cxf.endpoint.Client client = ClientProxy.getClient(obj);
org.apache.cxf.endpoint.Endpoint cxfEndpoint = client.getEndpoint();

System.out.println("initialize security for user " + this.username);
outProps.put(WSHandlerConstants.USER, this.username);
outProps.put(WSHandlerConstants.PASSWORD_TYPE, WSConstants.PW_TEXT);
Map<String, Object> requestContext = ((BindingProvider) obj).getRequestContext();

//For message level authentication
requestContext.put("ws-security.username", "Ron");
requestContext.put("ws-security.callback-handler", "com.ws.cxf.client.callback.UTPasswordCallback");
//For endpoint level authentication, HTTP Basic/Digest
requestContext.put(BindingProvider.USERNAME_PROPERTY, username);
requestContext.put(BindingProvider.PASSWORD_PROPERTY, password);


class UTPasswordCallback implements CallbackHandler {
@Override
public void handle(Callback[] callbacks) throws IOException,
        UnsupportedCallbackException {

    for(Callback cb:callbacks){
        WSPasswordCallback pcallback = (WSPasswordCallback)cb;
         if(pcallback.getUsage()==WSPasswordCallback.USERNAME_TOKEN)
        {
            if(pcallback.getIdentifier().equals("Ron"))
                pcallback.setPassword("noR");
        }
        }

    }
}

相关内容

  • 没有找到相关文章

最新更新