com.sun.xml.ws.message.saaj.SAAJHeader не может быть приведен к com.sun.xml.ws.security.opt.impl.outgoing.SecurityHeader - PullRequest
5 голосов
/ 12 января 2012

Я пытаюсь получить доступ к стороннему веб-сервису, который требует от меня создания заголовка безопасности с передачей информации о времени, имени пользователя и пароля. Я искал в Интернете рабочие примеры и пробовал множество способов. Я пытаюсь сделать это только с тем, что встроено в Java 6. Я не уверен, что я делаю неправильно. После генерации клиентских классов веб-служб из WSDL я создал обработчик ниже.

import java.util.Set;
import java.util.TimeZone;
import javax.xml.namespace.QName;
import javax.xml.soap.Node;
import javax.xml.soap.SOAPElement;
import javax.xml.soap.SOAPEnvelope;
import javax.xml.soap.SOAPFactory;
import javax.xml.soap.SOAPHeader;
import javax.xml.soap.SOAPMessage;
import javax.xml.soap.Text;
import javax.xml.ws.handler.MessageContext;
import javax.xml.ws.handler.soap.SOAPHandler;
import javax.xml.ws.handler.soap.SOAPMessageContext;

public class MyHeaderHandler implements SOAPHandler<SOAPMessageContext>
{
  public boolean handleMessage(SOAPMessageContext context) 
  {
    String prefixUri = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-";
    String uri = prefixUri + "wssecurity-secext-1.0.xsd";
    String uta = prefixUri + "wssecurity-utility-1.0.xsd";
    String ta = prefixUri + "username-token-profile-1.0#PasswordText";
    Boolean isRequest = (Boolean)context.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);
    if(isRequest)
    {
      try
      {
        SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:dd.SSS'Z'");
        formatter.setTimeZone(TimeZone.getTimeZone("GMT"));
        java.util.Date created = new java.util.Date();
        java.util.Date expires = new java.util.Date(created.getTime() + (5l * 60l * 1000l));
        SOAPMessage soapMsg = context.getMessage();
        SOAPEnvelope soapEnv = soapMsg.getSOAPPart().getEnvelope();
        SOAPHeader soapHeader = soapEnv.getHeader();
        if (soapHeader == null)
          soapHeader = soapEnv.addHeader();
        SOAPFactory factory = SOAPFactory.newInstance();
        SOAPElement securityElem = factory.createElement("Security", "o", uri);
        securityElem.addAttribute(QName.valueOf("s:mustUnderstand"), "0");
        SOAPElement timestampElem = factory.createElement("Timestamp", "u", uta);
        timestampElem.addAttribute(QName.valueOf("xmlns:u"), uta);
        timestampElem.addAttribute(QName.valueOf("Id"), "_0");
        SOAPElement elem = factory.createElement("Created", "u", uta);
        elem.addTextNode(formatter.format(created));
        timestampElem.addChildElement(elem);
        elem = factory.createElement("Expires", "u", uta);
        elem.addTextNode(formatter.format(expires));
        timestampElem.addChildElement(elem);
        securityElem.addChildElement(timestampElem);
        SOAPElement usernameElem = factory.createElement("UsernameToken", "o", uri);
        elem = factory.createElement("Username", "o", uri);
        elem.addTextNode("xxxxx");
        usernameElem.addChildElement(elem);
        elem = factory.createElement("Password", "o", uri);
        elem.addTextNode("xxxxx");
        elem.addAttribute(QName.valueOf("Type"), ta);
        usernameElem.addChildElement(elem);
        securityElem.addChildElement(usernameElem);
        soapHeader.addChildElement(securityElem);
      }
      catch(Exception e)
      {
        System.out.println("Handler error!!!! - " + e);
      }
    }
    return true;
  }

public boolean handleFault(SOAPMessageContext context) 
  {
    return true;
  }

public void close(MessageContext context)
  {
  }

public Set<QName> getHeaders() 
  {
    return null;
  }
}

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

import java.util.ArrayList;
import java.util.List;
import javax.xml.namespace.QName;
import javax.xml.ws.handler.Handler;
import javax.xml.ws.handler.HandlerResolver;
import javax.xml.ws.handler.PortInfo;
import org.tempuri.ServiceName;
import org.tempuri.IServiceName;


public class test
{
 public static void main(String[] args)
 throws Exception
 {
   ServiceName service = new ServiceName(new URL("https://url.to.service/services/ServiceName.svc?wsdl"), new QName("http://org.tempuri/", "ServiceName"));
   service.setHandlerResolver(new HandlerResolver() 
   {
     public List<Handler> getHandlerChain(PortInfo portInfo) 
     {
       List<Handler> handlerList = new ArrayList<Handler>();
       handlerList.add(new MyHeaderHandler());
       return handlerList;
     }
   });
   IServiceName binding = service.getBasicHttpBindingIServiceName();
   ArrayLiist results = binding.getMyData("my parm");
   System.out.println("Size: " + results.size());
 }
}

Когда я запускаю это, я получаю следующую ошибку в строке, где я делаю binding.getMyData ():

Exception in thread "main" java.lang.ClassCastException: com.sun.xml.ws.message.saaj.SAAJHeader cannot be cast to com.sun.xml.ws.security.opt.impl.outgoing.SecurityHeader
 at com.sun.xml.ws.security.opt.impl.JAXBFilterProcessingContext.setJAXWSMessage(JAXBFilterProcessingContext.java:140)
 at com.sun.xml.wss.jaxws.impl.SecurityPipeBase.secureOutboundMessage(SecurityPipeBase.java:389)
 at com.sun.xml.wss.jaxws.impl.SecurityClientPipe.process(SecurityClientPipe.java:196)
 at com.sun.xml.ws.api.pipe.helper.PipeAdapter.processRequest(PipeAdapter.java:115)
 at com.sun.xml.ws.api.pipe.Fiber.__doRun(Fiber.java:595)
 at com.sun.xml.ws.api.pipe.Fiber._doRun(Fiber.java:554)
 at com.sun.xml.ws.api.pipe.Fiber.doRun(Fiber.java:539)
 at com.sun.xml.ws.api.pipe.Fiber.runSync(Fiber.java:436)
 at com.sun.xml.ws.client.Stub.process(Stub.java:248)
 at com.sun.xml.ws.client.sei.SEIStub.doProcess(SEIStub.java:135)
 at com.sun.xml.ws.client.sei.SyncMethodHandler.invoke(SyncMethodHandler.java:109)
 at com.sun.xml.ws.client.sei.SyncMethodHandler.invoke(SyncMethodHandler.java:89)
 at com.sun.xml.ws.client.sei.SEIStub.invoke(SEIStub.java:118)
 at $Proxy40.getM(Unknown Source)
 at test.main(test.java:30)

Каждый подход, который я пробую, заканчивается в одной и той же точке. Как мне обойти это? Я не могу понять, как создать SecurityHeader для размещения в заголовке. Любая помощь будет принята с благодарностью. Рабочий пример был бы великолепен.

Спасибо!

Ответы [ 2 ]

1 голос
/ 23 июня 2012

Когда я решал подобную проблему, этот поток действительно помог мне.

Проблема в том, что когда у вас есть библиотеки Metro (стек Oracle) в пути к классам, они автоматически определяются и включаются вобработка WS.Одной из функций является прозрачная аутентификация / обработка безопасности, когда в WSDL присутствует политика конечных точек.К сожалению, эта обработка безопасности не

Я не смог изменить WSDL. Решением для меня было удаление нежелательного JAR (wsit-rt) из пути к классам.

0 голосов
/ 17 мая 2016

Старый вопрос, но у меня была такая же проблема. Решение состояло в том, чтобы удалить дополнительные заголовки безопасности, которые я включил вручную. Поэтому, если вы столкнетесь с этой проблемой, проверьте, есть ли у вас какие-либо обработчики (SOAPHandler), записывающие какие-либо заголовки в вашу часть заголовка сообщения <Security>.

...