【问题标题】:how to add security header in jax-ws request如何在 jax-ws 请求中添加安全标头
【发布时间】:2016-09-29 17:50:33
【问题描述】:

我正在使用 apache cxf 创建一个 jax-ws 客户端。 我正在为 spring cotext 配置而苦苦挣扎。 我只需要将此标头添加到我的肥皂请求中:

<soapenv:Header>
  <wsse:Security  xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
     <wsse:UsernameToken wsu:Id="usernametoken">
        <wsse:Username>login</wsse:Username>
        <wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">password</wsse:Password>        
     </wsse:UsernameToken>
  </wsse:Security>

我有三个参数:usernametoken、password、login。

    <jaxws:client id="***" name="***"
              endpointName="***"
              serviceName="***"
              address="***"
              serviceClass="***"
              username="***"
              password="***"
              xmlns:tns="***">
</jaxws:client>

上面的代码可以工作并发送soap消息,但没有安全头! 您能给我一些想法如何添加该标题吗?

【问题讨论】:

    标签: java spring cxf jax-ws cxf-client


    【解决方案1】:

    使用此配置

    <jaxws:client   etc...>
          <jaxws:outInterceptors>     
           <bean class="org.apache.cxf.ws.security.wss4j.WSS4JOutInterceptor">
              <constructor-arg>
                  <map>
                      <entry key="action" value="UsernameToken"/>
                      <entry key="user" value="login"/>
                      <entry key="passwordType" value="PasswordText"/>
                      <entry key="passwordCallbackRef" value-ref="myPasswordCallback"/>
                   </map>
               </constructor-arg>
            </bean>
          </jaxws:outInterceptors>
       </jaxws:client>
    
       <bean id="myPasswordCallback" class="client.ClientPasswordCallback"/>
    

    还有这个类来管理密码

    public class ClientPasswordCallback implements CallbackHandler {
    
        public void handle(Callback[] callbacks) throws IOException, 
                UnsupportedCallbackException {
            WSPasswordCallback pc = (WSPasswordCallback) callbacks[0];
    
            if ("login".equals(pc.getIdentifier())) {
                pc.setPassword("thepassword");
            } // else {...} - can add more users, access DB, etc.
        }
    }
    

    如果你更喜欢Java代码,也是可以的

    Client client = ClientProxy.getClient(port);
    Endpoint cxfEndpoint = client.getEndpoint();
    Map<String,Object> outProps = new HashMap<String,Object>();
    outProps.put("action", "UsernameToken");
    outProps.put("user", "login");
    outProps.put("passwordType","PasswordText");
    ClientPasswordCallback c = new ClientPasswordCallback();
    outProps.put("passwordCallbackRef",c);
    
    WSS4JOutInterceptor wssOut = new WSS4JOutInterceptor(outProps);
    cxfEndpoint.getOutInterceptors().add(wssOut);
    

    【讨论】:

    • 嗨,我们为什么要检查用户?这是客户端的代码吗?看起来像服务器端的这段代码。我没有配置端点,我只想添加一个安全标头并发送soap请求
    • 此代码用于客户端(请参阅 jax-ws:client 标签)。输出拦截器在输出被发送以添加标头之前拦截输出。如果您不喜欢 spring 配置,请使用最后一个 java 示例。也许你觉得提供密码的方式很奇怪,但它是 CXF 的默认设置
    • 我正在将 Redhat fuse-karaf 7.10 与 Java 11 一起使用。同样的设置现在会抛出 javax.xml.ws.soap.SOAPFaultException: HIERARCHY_REQUEST_ERR: An attempt was made to insert a node where it is not permitted. 这曾经在 Java 8 和 Redhat fuse-karaf 7.4 中正常工作。
    【解决方案2】:

    您需要使用 CXF 拦截器添加安全标头。

    所以你基本上需要定义一个新的拦截器 bean(来自 cxf-security 的WSS4JOutInterceptor)并将正确的键值作为输入传递给它的构造函数:

    <bean id="fooSecurityOutInterceptor" class="org.apache.cxf.ws.security.wss4j.WSS4JOutInterceptor">
        <constructor-arg>
            <map>
            [...]
            </map>
        </constructor-arg>
    </bean>
    

    请注意,这已记录在 http://cxf.apache.org/docs/ws-security.html,但您可能需要查看 org.apache.ws.security.handler.WSHandlerConstants 的源代码以了解所有可能的密钥(在您的情况下,请查看 USERNAME_TOKEN、PASSWORD_TYPE. ..) 并将您的值注入此 bean 中的相应键。

    然后,您只需将此 bean 作为一个输出拦截器分配给您的 jaxws-client bean。

    <jaxws:client id="***" name="***" endpointName="***" serviceName="***" address="***" serviceClass="***" xmlns:tns="***">
        <jaxws:outInterceptors>
            <ref bean="fooSecurityOutInterceptor" />
        </jaxws:outInterceptors>
    </jaxws:client>
    

    这应该可以解决问题。 您可以添加第二个输出拦截器,例如org.apache.cxf.interceptor.LoggingOutInterceptor,以检查您的标头是否已添加以稍微调整键/值。

    【讨论】:

    • 嗨。感谢您的回答。好吧,我找到了一个类:UsernameTokenInterceptor,它将解决我的问题。我如何在 spring 上下文中添加它?
    猜你喜欢
    • 2016-02-10
    • 1970-01-01
    • 2011-01-20
    • 2011-06-20
    • 1970-01-01
    • 2016-05-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多