0

我有一个接受 opentravel.org OTA XML 请求并做出相应响应的 tomcat Web 服务。它使用 JibX OTA 类。

到目前为止,该服务的用户已经使用了 POX,并且它工作得非常好,但是一个新用户想要使用 SOAP 并像这样向 SOAP Header 添加安全凭证(而不是把它们放在 POS xml 片段中)......

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
  <soap:Header>
    <wsse:Security soap:mustUnderstand="1" xmlns:wsse="http://docs.oasis-open.org        /wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
      <wsse:UsernameToken>
        <wsse:Username>USERNAME</wsse:Username>
        <wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-    wss-username-token-profile-1.0#PasswordText">SECRET</wsse:Password>
      </wsse:UsernameToken>
    </wsse:Security>
  </soap:Header>

因此,为了验证请求,我认为我需要从服务实现类中访问标头。

我查看了 SOAP Headers 示例,我认为它告诉我可以通过包含 inContext 来访问标头,例如

public RoomListRS list(RoomListRQ roomListRQ, InContext inCtx){
....
}

所以在这个方法中我可以做到这一点......

Security security = (Security ) inCtx.getAttribute("security");

所以我可以访问其中的用户名令牌,

...在服务中指定了这个...

<service name="OTAService">
  <service-class>com.xx.webservice.ota.HotelServiceImpl</service-class>
  <operation method="list"/>
  <handler-class class="org.jibx.ws.io.handler.ContextAttributeUnmarshallingInHandler">
    <constructor-arg value="com.xx.shared.soap.security.Security"/>
    <constructor-arg value="security"/>
  </handler-class>
</service>

我说对了吗?

所以我创建了 Security 类,但忽略了所有命名空间的东西,只是为了开始并证明我可以访问标题中的某些内容。基于有这样的片段......

    <Security>
      <UsernameToken>
        <Username>USERNAME</Username>
        <Password>SECRET</Password>
      </UsernameToken>
    </Security>

所以我用bindgen创建了绑定,然后编译,然后用soapUI调用它

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns="http://www.opentravel.org/OTA/2003/05">
     <soapenv:Header>
     <Security>
      <UsernameToken>
        <Username>USERNAME</Username>
        <Password>SECRET</Password>
      </UsernameToken>
    </Security>
  </soapenv:Header>
   <soapenv:Body>
<OTA_HotelRoomListRQ xmlns="http://www.opentravel.org/OTA/2003/05" Version="2.0">
....
</OTA_HotelRoomListRQ>
</soapenv:Body>
</soapenv:Envelope>

但是当我尝试从上下文中获取 Security 对象时,它为空。

我弄错了棍子的一端吗?

我是否应该使用更多 SOAPY 来创建另一个具有不同端点的服务?

我试图用 JibX WS 和 inHandler 做的事情是不可能的吗?

欢迎任何评论。


非常感谢您不厌其烦地回答我的问题。

我正在尝试查看您添加的内容。我使用您的自定义和 xsd 来创建 java 源代码和 binding.xml。

我已经编译了这些类,现在我正在尝试绑定它们,但是我收到了这个错误:

C:\Java\wsse>java org.jibx.binding.generator.BindGen org.oasisopen.docs.wss.oasis200401wsswssecuritysecext1.SecurityHeaderType
Exception in thread "main" java.lang.IllegalStateException: No way to handle type java.lang.Object, referenced from org.oasisopen.docs.wss.oasis200401wsswssecuritysecext1.SecurityHeaderType
    at org.jibx.binding.generator.BindGen.expandReferences(BindGen.java:227)
    at org.jibx.binding.generator.BindGen.findReferences(BindGen.java:1010)
    at org.jibx.binding.generator.BindGen.generate(BindGen.java:1124)
    at org.jibx.binding.generator.BindGen.main(BindGen.java:1302)

我将看一下 bindgen 定制,看看这是否能说明问题,因为这是针对这个问题给出的唯一线索。你能告诉我你是怎么解决这个问题的吗?

再次感谢。

4

1 回答 1

0

我可以分享一些用于 WS-Security 用户名/密码标头的生产代码。我不明白为什么您的代码不起作用,但也许这会有所帮助。

我们从 oasis-200401-wss-wssecurity-secext-1.0.xsd 模式生成了 WS-Security 代码和绑定,并进行了以下自定义:

<!--  Contains customization elements for code generation from WS Security schema -->
<schema-set show-schema="false" generate-all="false" xmlns:xs="http://www.w3.org/2001/XMLSchema" line-width="120">
  <schema name="oasis-200401-wss-wssecurity-secext-1.0.xsd" generate-all="true" prefer-inline="true" any-handling="mapped">
    <class-decorator class="org.jibx.schema.codegen.extend.CollectionMethodsDecorator" />
  </schema>
</schema-set>

然后使用以下内容构建:

<target name="codegen-wss" description="Regenerate JiBX bindings and generated code for WS-Security schema">
  <echo message="Running code generation from schema" />
  <mkdir dir="${gen.src.dir}" />
  <java classname="org.jibx.schema.codegen.CodeGen" fork="yes" classpathref="build.classpath" failonerror="true">
    <arg value="-c" />
    <arg value="custom_jibx_gen_wssec.xml" />
    <arg value="-t" />
    <arg value="${gen.src.dir}" />
    <arg value="wsdl/wssec/oasis-200401-wss-wssecurity-secext-1.0.xsd" />
  </java>
  <move file="${gen.src.dir}/binding.xml" tofile="${wssec.binding.file}" failonerror="true" />
</target>

并绑定:

<target name="compile" depends="init" description="Compile the source code and run JiBX binding compiler">
  <mkdir dir="${dest.dir}" />
  <javac srcdir="${src.dir}:${gen.src.dir}" destdir="${dest.dir}" deprecation="on">
    <classpath refid="build.classpath" />
  </javac>
  <bind binding="${gen.src.dir}/xxx-binding.xml">
    <classpath path="${dest.dir}" />
  </bind>
  <bind binding="${wssec.binding.file}">
    <classpath path="${dest.dir}" />
  </bind>
</target>

servlet 的 Spring 配置定义了 InHandler:

<property name="handlerDefinitions">
  <list>
    <bean class="org.jibx.ws.server.HandlerDefinition" >
      <description>Handler for inbound WS/Security header</description>
      <property name="className" value="org.jibx.ws.io.handler.ContextAttributeUnmarshallingInHandler" />
      <property name="args">
        <list>
          <value>org.oasisopen.docs.wss.oasis200401wsswssecuritysecext1.SecurityHeaderType</value>
          <value>wssecurity.header</value>
        </list>
      </property>
    </bean>

并且端点使用以下方法检索标头:

public ServiceRequestReceipt processRequest(ServiceRequest request, InContext inCtx, OutContext outCtx) 
    throws WsException {
    SecurityHeaderType securityHeader = (SecurityHeaderType) inCtx.getAttribute("wssecurity.header");

我们使用 securityHeader 的代码如下所示:

        if (securityHeader == null) {
            throw new AuthenticationException("No WS-Security header found");
        }

        List<Object> securityHeaderTypes = securityHeader.getSecurityHeaderTypes();
        if (securityHeaderTypes == null || securityHeaderTypes.size() == 0) {
            throw new AuthenticationException("WS-Security header appears to be empty");
        }

        UsernameTokenType usernameToken = null;
        try {
            usernameToken = (UsernameTokenType) securityHeaderTypes.get(0);
        } catch (ClassCastException e) {
            throw new AuthenticationException("Expected UsernameToken in WS-Security header");
        }

        AttributedString usernameAttStr = usernameToken.getUsername();
        if (usernameAttStr == null) {
            throw new AuthenticationException("Expected Username in WS-Security header");
        }

        String username = usernameAttStr.getString();
        if (!username.equals(retailer.getRetailerUsername())) {
            throw new AuthenticationException("Invalid username in WS-SecurityHeader");
        }
        List<Object> any = usernameToken.getAny();
        if (any == null) {
            throw new AuthenticationException("Expected Password element in WS-Security header");
        }
        PasswordString passwordString = null;
        for (Iterator iterator = any.iterator(); iterator.hasNext();) {
            try {
                passwordString = (PasswordString) iterator.next();
            } catch (ClassCastException ignore) {
                logger.debug("Found non password string object");
            }
        }
        if (passwordString == null) {
            throw new AuthenticationException("Expected Password in WS-Security header");
        }
        if (passwordString.getAttributedString() == null) {
            throw new AuthenticationException("Expected Password AttributedString in WS-Security header");
        }

        String password = passwordString.getAttributedString().getString();
        if (!password.equals(retailer.getRetailerPassword())) {
            throw new AuthenticationException("Invalid password in WS-SecurityHeader");
        }

我希望这会有所帮助!

于 2012-05-04T22:00:37.797 回答