Some background: This is a Weblogic Web Services created Service client creates via Eclipse. I believe this uses clientgen behind the scenes.
I'm trying to make a SOAP call that requires preemptive Basic Authentication. The request is being sent but the Mimeheaders I'm setting are not going with it. The recipient of the call has informed me that the request itself is coming through but any mimeheaders I set are not.
The service call is rather simple.
DescriptionService service = new DescriptionService(wsdlLocation, new QName("urn:descriptionService.service.company.com", "DescriptionService"));
service.setHandlerResolver(new HandlerResolver() {
#SuppressWarnings("rawtypes")
#Override
public List<Handler> getHandlerChain(final PortInfo portInfo) {
final List<Handler> handlerList = new ArrayList<Handler>();
handlerList.add(new SOAPDescriptionServiceHeaderHandler());
return handlerList;
}
});
DescriptionServicePortType portType = service.getDescriptionServicePort();
DescriptionRequest request = new DescriptionRequest();
request.setId(id);
DescriptionResponse description = portType.describe(request);
The handler is where I set the Mimeheaders:
#Override
public boolean handleMessage(final SOAPMessageContext context) {
final Boolean outboundProperty = (Boolean) context.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);
final SOAPMessage message = context.getMessage();
if (outboundProperty.booleanValue()) {
try {
MimeHeaders mimeheaders = message.getMimeHeaders();
String encodedAuth = Base64.encode(new String("un:pw").getBytes());
mimeheaders.addHeader("Authorization", "Basic " + encodedAuth);
this.logMessage(message, outboundProperty.booleanValue(), false);
} catch (final Exception e) {
// Log Error
}
} else {
this.logMessage(message, outboundProperty.booleanValue(), false);
}
return true;
}
It does hit this handler and set the mimeheaders. If I set a break point and look at the mime headers before it leaves the handleMessage method, I can see that they are set.
I'm able to call the request and get a response in SoapUI. I set up preemptive basic auth and it works fine. When I send the request through the Java Client, I get no response and actually get an error that says it's the incorrect content type. I believe this error is referring to the fault response as I don't actually get the response (doesn't hit the handleMessage() method in the handler either) and I know the request is going through with text/xml which is what the error is asking for.
I'm unsure if it has something to do with the "preemptive" requirement? Is there a way to set basic auth set up this way as preemptive?
Thoughts?
Any assistance would be appreciated.
Basic Auth is done at the HTTP layer, not the SOAP layer, so you need to configure the underlying HTTP library. (MIME headers have nothing to do with it)
For example for CXF, have a look at this question HTTP basic authentication through CXF interceptor not working
Related
I'm trying to implement a soap service consumer in Java, using spring WebServiceGatewaySupport.
When I'm using curl to consume the service as below, it is giving proper response.
curl -d #request.xml -H 'SOAPAction:abc:mnEvent#DoAction' https://myhost.org/cd/doAction.jsp
I'm trying to implement the same using JAVA, by adding following HttpHeaders in a template class inheriting from WebServiceGatewaySupport
public O callWebService(String url, I request) {
return (O) getWebServiceTemplate().marshalSendAndReceive(url, request, new WebServiceMessageCallback() {
#Override
public void doWithMessage(WebServiceMessage message) {
TransportContext transportContext = TransportContextHolder.getTransportContext();
HttpComponentsConnection connection = (HttpComponentsConnection) transportContext.getConnection();
connection.getHttpPost().addHeader("SOAPAction", "abc:mnEvent#DoAction");
}
});
}
With this code, I'm getting an error message like below.
SOP-330006 The method 'DoAction, ""' is not defined in SOAP service 'abc:mnEvent'.
What do I miss here when moving curl command to JAVA?
The error message SOP-330006 The method 'DoAction, ""' is not defined in SOAP service 'abc:mnEvent'. indicates, there are two soap actions in the request.
Explicit SoapAction added in HttpHeader
Implicit SoapAction in SoapMessage
To avoid this issue, we need to remove the soapAction from header and set it in SoapMessage.
SaajSoapMessage soapMessage = (SaajSoapMessage) message;
soapMessage.setSoapAction("abc:mnEvent#DoAction");
I intercept the incoming and outgoing soap messages using a SoapHandler like this:
#Override
public boolean handleMessage(SOAPMessageContext context) {
boolean isResponse = (Boolean)context.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);
if(!isResponse){
logger.debug("MySoapHandler.handleMessage(): this is a soap request");
SOAPMessage soapMsg = context.getMessage();
SOAPMessage = createNewSoapRequest(soapMsg);
context.setMessage(newSoapMsg);
}
else {
logger.debug("MySoapHandler.handleMessage(): this is a soap response");
SOAPMessage soapMsg = context.getMessage();
SOAPMessage newSoapMsg = createNewSoapResponse(soapMsg);
context.setMessage(newSoapMsg);
}
return true;
}
I receive the incoming soap message and replace it with a new one and send it on its way. I can monitor the incoming message and its replacement and everything looks right. If I comment out the incoming part and test the outgoing part by sending the correct request using SoapUI, the outgoing soap response is intercepted and replaced with a new message. That too seems to work ok.
When I un-comment the incoming portion and let er' rip, the incoming one is triggered correctly, but the outgoing response seems to get triggered prematurely, before the main code for generating it has completed. Can anyone shed some light?
I will be extremely grateful if someone share his experience in solving the following problem.
I have a SOAP service in the JDK implementation (which is Metro, I believe).
For the logging purpose we need to extract the body of both the incoming request and generated response.
I try to fetch it by implementing a SOAPHandler on the server side.
I configure handler as a Spring bean.
All the examples I found essentially replicate the example from the Oracle documentation: https://docs.oracle.com/cd/E23943_01/web.1111/e13734/handlers.htm#WSADV170:
public boolean handleMessage(SOAPMessageContext messageContext)
{
Boolean outboundProperty = (Boolean)
messageContext.get (MessageContext.MESSAGE_OUTBOUND_PROPERTY);
if (outboundProperty.booleanValue()) {
System.out.println("\nOutbound message:");
} else {
System.out.println("\nInbound message:");
}
System.out.println("** Response: "+messageContext.getMessage().toString());
return true;
}
Here one reads one of the Boolean properties of the SOAP message context which, as I see it, corresponds to either request or response.
But debugger in my experiments never enters the branch corresponding to response (else-branch). How is such handler supposed to trace both request and response?
I also wonder what message is read as messageContext.getMessage(): is it incoming (request) or outbound (response)
I wonder now is it possible indeed by implementing handleMessage() method to get access to both request and response?
Does a single handler intercepts both request and its response?
Did I misunderstand the example?
And ... SOAPHandler - is it a specific instance for every request (request-response pair)?
Thank you
Try this for SoapHandler:
Boolean isRequest = (Boolean) context.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);
if (isRequest) {
//handle request
} else {
//handle response
}
And this for LogicalHandler:
Boolean outboundProperty = (Boolean)
messageContext.get (MessageContext.MESSAGE_OUTBOUND_PROPERTY);
if (outboundProperty.booleanValue()) {
System.out.println("\nOutbound message:");
} else {
System.out.println("\nInbound message:");
}
I'm trying to a write simple REST Java web-service. I use Provider interface on the server side and Dispatch on the clients. I'm trying to transmit a value in header of POST request but there is some problem.
My client code:
private void invoke(Dispatch<Source> dispatch
Object data) {
Map<String, Object> request_context = dispatch.getRequestContext();
request_context.put(MessageContext.HTTP_REQUEST_METHOD, "POST");
request_context.put("org.kpi.asd", "SOME TEXT");
StreamSource source = make_stream_source(data.toString());
dispatch.invoke(source);
}
My server code:
public Source invoke(Source request) {
// Filter on the HTTP request verb
if (ws_ctx == null) throw new RuntimeException("DI failed on ws_ctx.");
// Grab the message context and extract the request verb.
MessageContext msg_ctx = ws_ctx.getMessageContext();
String aaa = (String) msg_ctx.get("org.kpi.asd");
}
On server: aaa is null. I can't understand why. Help me, please (:
the message context is not where you set arbitrary http headers. there is another property in the message context which contains the http headers, see HTTP_REQUEST_HEADERS.
I've got a simple command line Java JAX-WS app to test a SOAP request, but the server is expecting the Password Type to be PasswordText and I'm stumped on how to set this...
The code looks like so:
#WebServiceRef
private static final HelloService helloService = new HelloService(url, new QName(
URL, "HelloService"));
public static void main(final String... args) {
try {
final HelloPort helloPort = helloService.getHelloPort();
final BindingProvider hB = ((BindingProvider) helloPort);
hB.getRequestContext().put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY,
END_POINT_ADDRESS);
hB.getRequestContext().put(BindingProvider.USERNAME_PROPERTY,
USERNAME);
hB.getRequestContext().put(BindingProvider.PASSWORD_PROPERTY,
PASSWORD);
...
I've tested the request using SOAP-UI so I know it's working. Any help on setting the password type would be appreciated.
Thanks.
That will set the username and password for Basic HTTP authentication. If you've tested it in SoapUI, I'm guessing the 'PasswordText' value you speak of is the 'WSS-Password Type' in the request details pane. That sets WSS security, not HTTP security.
With JAX-WS in Java6 you need to attach a SOAPHandler to inject the WSS-Usertoken into the SOAP Header. There are plenty of bits and bobs about this round the net, but I couldn't find one single link to post, so here's some code instead to get you going...
To add a handler you need something like:
final Binding binding = ((BindingProvider) servicePort).getBinding();
List<Handler> handlerList = binding.getHandlerChain();
if (handlerList == null)
handlerList = new ArrayList<Handler>();
handlerList.add(new SecurityHandler());
binding.setHandlerChain(handlerList); // <- important!
Then the SecurityHandler class will do the deed. Handlers are general things and get called for both successful messages and for faults, but perhaps more importantly they get called in both message directions - for the outgoing request and then again for the incoming response. You only want to handle outgoing messages. So you'll need something like:
public final class SecurityHandler implements SOAPHandler<SOAPMessageContext> {
...
#Override
public boolean handleMessage(final SOAPMessageContext msgCtx) {
// Indicator telling us which direction this message is going in
final Boolean outInd = (Boolean) msgCtx.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);
// Handler must only add security headers to outbound messages
if (outInd.booleanValue()) {
try {
// Get the SOAP Envelope
final SOAPEnvelope envelope = msgCtx.getMessage().getSOAPPart().getEnvelope();
// Header may or may not exist yet
SOAPHeader header = envelope.getHeader();
if (header == null)
header = envelope.addHeader();
// Add WSS Usertoken Element Tree
final SOAPElement security = header.addChildElement("Security", "wsse",
"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd");
final SOAPElement userToken = security.addChildElement("UsernameToken", "wsse");
userToken.addChildElement("Username", "wsse").addTextNode("MyWSSUsername");
userToken.addChildElement("Password", "wsse").addTextNode("MyWSSPassword");
} catch (final Exception e) {
LOG.error(e);
return false;
}
}
return true;
}
...
// Other required methods on interface need no guts
}
I've made a few assumptions here, but hopefully it'll get you going!
Kind regards.
If you implement SOAPHandler interface, the method msgCtx.getMessage() will render the entire XML, and if you are working with big files you will have Out of Memory errors. I tested with UsernameToken authentication on JAX-WS client and it works:
String SECURITY_NS = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd";
String PASSWORD_TYPE = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText";
String AUTH_PREFIX = "wss";
MyService service = new MyService();
MyServicePort port = service.getMyServicePort();
try {
SOAPFactory soapFactory = SOAPFactory.newInstance();
SOAPElement security = soapFactory.createElement("Security", AUTH_PREFIX, SECURITY_NS);
SOAPElement uToken = soapFactory.createElement("UsernameToken", AUTH_PREFIX, SECURITY_NS);
SOAPElement username = soapFactory.createElement("Username", AUTH_PREFIX, SECURITY_NS);
username.addTextNode("username");
SOAPElement pass = soapFactory.createElement("Password", AUTH_PREFIX, SECURITY_NS);
pass.addAttribute(new QName("Type"), PASSWORD_TYPE);
pass.addTextNode("password");
uToken.addChildElement(username);
uToken.addChildElement(pass);
security.addChildElement(uToken);
Header header = Headers.create(security);
((WSBindingProvider) port).setOutboundHeaders(header);
// now, call webservice
} catch (SOAPException ex) {
ex.printStackTrace();
}
Edit: You should add the "rt.jar" from jre to classpath.