0

我希望能够动态更改/设置每个在 cxf 中发送肥皂消息的 ws-security 信息。怎样才能做到最好。

详细信息:我想在运行时更改密钥库名称、密钥库别名、密码、主机名等设置,最好在每次发送消息时更改。目前我正在使用:带有 WSS4JOutInterceptor 和 WSS4JInInterceptor 拦截器的 jaxws 客户端进行签名。我正在使用带有 tls 客户端参数的 http 管道进行 SSL/TLS 通信。jaxws 客户端和 http 管道都在 spring 中配置,并且在 Spring 配置中设置了它们的配置,如密钥库名称、别名和密码。

我看到了选项:1)我在运行时通过全局属性更改这些设置。2)我更改每个发送消息的这些设置(最好)。

2)我认为是可取的,但最困难的。我该怎么做?

我在考虑: a) jaxws 客户端:制作我自己的进出拦截器来拦截消息,并根据该消息所需的安全设置使用正确的(缓存的)WSS4JOutInterceptor 拦截器。如果缓存中不存在 WSS4JOutInterceptor 拦截器,则会创建它(我可能缓存了最多 5 个 WSS4JOutInterceptor 实例)。但是,当与@Webservice 代理交谈以创建和发送soap 请求/消息时,我如何确定我的拦截器中需要哪些设置,因为这在应用程序的其他部分中是已知的......也许我可以添加通过 JaxWsClientProxy 将某种 securityInfo 对象传递给 soap 消息,但是如何......

b)http管道:使用ConduitSelector(从未使用过,但会发现),这样我就可以选择正确的http管道,但我遇到与(a)中相同的问题:“如何确定我应该使用哪些设置使用”,因为它们在创建/发送肥皂消息时已知,并且拦截器稍后设置......可能我必须为每个发送消息设置一个管道选择器..

最后上面成为一个大故事;),但我希望很清楚你可以给一些建议吗?

4

2 回答 2

0

这个问题的公认答案似乎是(来自http://www.mail-archive.com/users@cxf.apache.org/msg29804.html):

嗨,埃德,

正如我已经写过的,您甚至不需要拦截器来更改属性。您可以通过发送消息在客户端中执行此操作:

AddNumbers 端口 = (AddNumbers)service.getPort(portName, AddNumbers.class); ((BindingProvider)port).getRequestContext().put(SecurityConstants.ENCRYPT_PROPERTIES, )。

虽然,如果您想在拦截器中执行此操作,您可以使用相同的技术传递带有消息属性的必要信息。

在 CXF 中控制安全性的最标准和推荐的方法是使用 WS-Policy。您还可以在运行时动态应用它。如果您对这种方式感兴趣,我可以提供更多关于如何动态设置 WS-Policy 的信息。

干杯,安德烈。

(来自http://www.mail-archive.com/users@cxf.apache.org/msg29809.html):

如果你这样做: ((BindingProvider)port).getRequestContext().put("thread.local.request.context", "true");

以后对 getRequestContext() 的调用将使用线程本地请求上下文。这允许请求上下文是线程安全的。(注意:响应上下文在 CXF 中始终是线程本地的)。

http://cxf.apache.org/faq.html#FAQ-AreJAXWSclientproxiesthreadsafe%3F中的详细信息

干杯,安德烈。

于 2013-10-25T21:43:18.870 回答
0

我发现这些org.apache.cxf包非常有助于让我不必编写自定义类并且能够坚持使用基本界面。

对于您的实例,该方法可能如下所示:

  • 使用JAX-WSorwsimport客户端
  • 使用cxf WSS4JOutInterceptor具有动态属性的
  • 使用动态CallbackHandler类访问密钥库

典型的 ( wsimport'd) 客户端公共 API 可能如下所示:

public class SomeServiceClient
{

  public SomeService getSomeService( URL url )
  {

    SomeService_Service svc = new SomeService_Service();

    SomeService someService = svc.getSomeServicePort();

    Client client = ClientProxy.getClient( someService );
    Endpoint cxfEP = client.getEndpoint();

    Map<String, Object> outProps = new HashMap<String, Object>();
    outProps.put( WSHandlerConstants.ACTION, "Signature" );
    outProps.put( WSHandlerConstants.USER, "foo" );
    outProps.put( WSHandlerConstants.PW_CALLBACK_CLASS, SomeClientCallbackHandler.class.getName() );
    outProps.put( WSHandlerConstants.SIG_PROP_FILE, "client-sign.properties" );

    WSS4JOutInterceptor wssOut = new WSS4JOutInterceptor( outProps );

    cxfEP.getOutInterceptors().add( wssOut );

    return someService;
  }
}

您可以提供一些逻辑来确定WSHandlerConstants.USER要传递的值、PW_CALLBACK_CLASS使用的值以及SIG_PROP_FILE使用的值。

属性文件可能如下所示。您可以简单地选择多个文件,或者您可以在类中动态添加这些属性:

# properties for accessing the java keystore using Merlin
org.apache.ws.security.crypto.provider=org.apache.ws.security.components.crypto.Merlin
org.apache.ws.security.crypto.merlin.keystore.type=jks
org.apache.ws.security.crypto.merlin.keystore.password=bar
org.apache.ws.security.crypto.merlin.keystore.alias=foo
org.apache.ws.security.crypto.merlin.keystore.file=foobar.keystore

最后,您CallbackHandler需要提供您在密钥库中标识的证书别名的密码。这也可能包含一些动态逻辑。

public class SomeClientCallbackHandler implements CallbackHandler
{

    @Override
    public void handle( Callback[] callbacks ) throws IOException, UnsupportedCallbackException
    {
        for( Callback thisCallback : callbacks )
        {
            WSPasswordCallback pwcb = (WSPasswordCallback)thisCallback;
            String user = pwcb.getIdentifier();
            int usage = pwcb.getUsage();

            if( usage == WSPasswordCallback.SIGNATURE )
            {
                if( "foo".equals( user ) ) pwcb.setPassword( "bar" );
            }
        }        
    }
}

最后,与只做一次所需的工作相比,没有太多工作可以让这一切都“动态”地处理多个密钥库。它可能比编写自己的“输入”或“输出”拦截器更可取。

于 2013-04-11T16:47:42.240 回答