Доступ к заголовку SOAP из JibX WS

У меня есть веб-служба tomcat, которая принимает XML-запросы OTA opentravel.org и отвечает соответствующим образом. Он использует классы JibX OTA.

До сих пор пользователи сервиса использовали POX, и он работал очень хорошо, но новый пользователь хочет использовать SOAP и добавить учетные данные безопасности в заголовок SOAP следующим образом (вместо того, чтобы помещать им фрагмент 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, который, я думаю, говорит мне, что я могу получить доступ к заголовкам, также включив 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>

но когда я пытаюсь получить объект безопасности из контекста, он равен нулю.

У меня не тот конец палки?

Должен ли я просто создать другую службу с другой конечной точкой, используя что-то более 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, чтобы увидеть, проливает ли это какой-либо свет, поскольку это единственная подсказка, данная в ответ на эту проблему. Не могли бы вы рассказать мне, как вы обошли это?

Еще раз спасибо.


person iainmac999    schedule 27.04.2012    source источник
comment
Кому-нибудь еще приходилось это делать? Я единственный?   -  person iainmac999    schedule 30.04.2012


Ответы (1)


Я могу поделиться некоторым производственным кодом, который у нас есть для заголовков имени пользователя/пароля WS-Security. Я не понимаю, почему ваш код не работает, но, возможно, это поможет.

Мы сгенерировали код WS-Security и привязки из схемы oasis-200401-wss-wssecurity-secext-1.0.xsd со следующей настройкой:

<!--  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>

Конфигурация 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");
        }

Надеюсь, это поможет!

person Nigel Charman    schedule 04.05.2012