I'm trying to access an old SOAP based system written in C# from a Java backend service. This C# application is looking for an AddressHeader to be populated with a specific value on every request. I'm using Apache CXF to create the requests to this service. Unfortunately, for the life of me, I cannot find out how to add this address header to each of the requests. Does anyone know what the equivalent in Java is and how to add it using Apache CXF?
The address header is the same as the SOAP header, hence we only need to add a particular SOAP header to every request so that be capable of making a successful call.
Here is an example I found on the internet.
ClientProxyFactoryBean factory = new JaxWsProxyFactoryBean();
factory.setServiceClass(singz.ws.cxf.sample.SampleServiceInterface.class);
factory.setAddress("http://xxx.xxx.com/services/SampleService/v1");
SampleServiceInterface serviceClient = (SampleServiceInterface) factory.create();
Client proxy = ClientProxy.getClient(serviceClient);
List<Header> headersList = new ArrayList<Header>();
Header testSoapHeader1 = new Header(new QName("uri:singz.ws.sample", "soapheader1"), "SOAP Header Message 1", new JAXBDataBinding(String.class));
Header testSoapHeader2 = new Header(new QName("uri:singz.ws.sample", "soapheader2"), "SOAP Header Message 2", new JAXBDataBinding(String.class));
headersList.add(testSoapHeader1);
headersList.add(testSoapHeader2);
proxy.getRequestContext().put(Header.HEADER_LIST, headersList);
Please refer to the below links, wish it is useful to you.
https://dzone.com/articles/apache-cxf-how-add-custom-soap-0
How do you add a Soap Header defined in a wsdl to a web service client in CXF?
https://dzone.com/articles/apache-cxf-how-add-custom-soap
Feel free to let me know if there is anything I can help with.
Related
I'm trying to use Opentext Content Web Services(CWS) from my axis2-based web-service.
This is a piece of code that creates a proxy client to CWS and passes an authentication token in a header.
DocumentManagement_Service docManService = new DocumentManagement_Service();
DocumentManagement docManClient = docManService.getBasicHttpBindingDocumentManagement();
try
{
// The namespace of the OTAuthentication object
final String ECM_API_NAMESPACE = "urn:api.ecm.opentext.com";
// Create a SOAP header
SOAPHeader header = MessageFactory.newInstance().createMessage().getSOAPPart().getEnvelope().getHeader();
// Add the OTAuthentication SOAP header element
SOAPHeaderElement otAuthElement = header.addHeaderElement(new QName(ECM_API_NAMESPACE, "OTAuthentication"));
// Add the AuthenticationToken SOAP element
SOAPElement authTokenElement = otAuthElement.addChildElement(new QName(ECM_API_NAMESPACE, "AuthenticationToken"));
authTokenElement.addTextNode(authToken);
// Set the SOAP header on the docManClient
String ENDPOINT_ADDRESS_PROPERTY = WSBindingProvider.ENDPOINT_ADDRESS_PROPERTY;
((WSBindingProvider) docManClient).setOutboundHeaders(Headers.create(otAuthElement));
}
catch (SOAPException e)
{
System.out.println("Failed to set authentication SOAP header!\n");
System.out.println(e.getMessage());
System.out.println(e.getStackTrace());
return;
}
This code works fine when executed from simple java application. In that case docManClient is a SEIStub object and setOutboundHeaders method works after casting to WSBindingProvider.
But when this code is executed inside my axis2 webservice, docManClient is JAXWSProxyHandler object and it can not be casted into WSBindingProvider nor execute setOutboundHeaders method.
So my question is - How do I pass my header with AuthElement using JAXWSProxyHandler (do the same as setOutBoundHeaders method do) OR Can I somehow convert JAXWSProxyHandler object to SEIStub object?
The problem occurs because you are using an API that is specific to the JAX-WS implementation in the JRE. However, when running on Axis2, the JAX-WS implementation provided by Axis2 will be used instead. That implementation supports a different set of API extensions.
What this means is that your code is not portable across different JAX-WS implementations. You have two options:
Make it portable by only using standard APIs. In your case this would require implementing a JAX-WS handler that adds the header. To pass the authToken to the handler, you would cast the client to BindingProvider and add the data to the request context.
Remove the axis2-jaxws JAR from your Axis2 deployment so that your code will use the JAX-WS implementation from the JRE. Of course this won't work if the service itself is deployed as a JAX-WS service. Unfortunately the code snippet doesn't show whether that's the case or not.
I've created a set of proxy classes in NetBeans for a SOAP web service.
I'd like to add an HTTP header to the outgoing request.
Map<String, Object> requestHeaders = new HashMap<>();
requestHeaders.put("X-Header", header);
AccountManagementService service = new AccountManagementService();
AccountManagementServiceSoap soap = service.getAccountManagementServiceSoap();
GetMembershipSummaryResponse.GetMembershipSummaryResult membershipSummary = soap.getMembershipSummary("mikeb#foobar.com");
I saw a bunch of JAX-WS header examples for when you are getting the individual port from the service. Is there an easier way? Can I just add the header to some collection on service or soap object?
after some digging I found this post: jax-ws change Content-type to Content-Type because server is hyper sensitive
which isn't really a full answer, so I am going to post the full answer here:
AccountManagementService service = new AccountManagementService();
AccountManagementServiceSoap soap = service.getAccountManagementServiceSoap();
((BindingProvider)soap).getRequestContext().put(MessageContext.HTTP_REQUEST_HEADERS,
Collections.singletonMap("X-Header",Collections.singletonList(header)));
GetMembershipSummaryResponse.GetMembershipSummaryResult membershipSummary = soap.getMembershipSummary("mikeb#foobar.com");
I created the jar from the WSDL for my client using the wsdl2java command. Now, I need to know how I can authenticate my client in order to complete an operation?
I am using CXF 2.7.16. I created my service using the generated class MyApp_Service, I am struggling with this. Isn't there a simple way to tell my client the credentials it should use to gain access to the web service?
I read about the Spring configuration, however I am unable to figure out if it applies to my case and how if yes. I tried to cast the MyApp_Service class to BindingProvider in order to use the method which consist to put the USERNAME and PASSWORD properties in the context with a value. However, MyApp_Service cannot be cast to BindingProvider.
This is my first web service client application ever. So, any help will be welcomed.
Update 2015-05-28: I tried to define the AuthenticationPolicy but is seems not working. Here is the code:
Client client = JaxWsDynamicClientFactory.newInstance().createClient(wsdlUrl);
ClientImpl clt = (ClientImpl) client;
HTTPConduit cc = (HTTPConduit) clt.getConduit();
org.apache.cxf.configuration.security.ObjectFactory secOF = new org.apache.cxf.configuration.security.ObjectFactory();
AuthorizationPolicy ap = secOF.createAuthorizationPolicy();
ap.setUserName(usagerWS);
ap.setPassword(mdpWS);
ap.setAuthorizationType("Basic");
cc.setAuthorization(ap);
Sniffing with WireShark, the Authorization header is clearly missing in the HTTP request.
What is missing?
Problem solved, here is the solution:
MyApp_Service service = new MyApp_Service(wsdlUrl, new QName(namespace, serviceName));
MyApp port = service.getMyApp();
// Set credentials
Map<String, Object> reqCtxt = ((javax.xml.ws.BindingProvider) port).getRequestContext();
reqCtxt.put(javax.xml.ws.BindingProvider.USERNAME_PROPERTY, username);
reqCtxt.put(javax.xml.ws.BindingProvider.PASSWORD_PROPERTY, password);
No more usage of the dynamic client. Only the classes generated with wsdl2java are used.
I am trying to implement a simple client for a webservice, the only problem I am facing with the webservice is, it has a generic endpoint: http://myserver3333.com:8080/ws/services and the way you lookup for web services deployed is via SOAP header.
So, for example, if you try to hit the service vis SOAP UI,
the endpoint I specify is: http://myserver3333.com:8080/ws/services
In the SOAP headers I specific the following:
SERVICE-NAME = MyAwesomeService
OPERATION-NAME = makeMeMoreAwesome
So, how can I do the same thing using apache cxf client?
My current code:
URL wsdlLocation = new URL("http://myserver3333.com:8080/ws/service");
MyAwesomeService service = new MyAwesomeService(wsdlLocation);
MyAwesomeServicePort port = service.getMyAwesomeServiceSOAPPort();
List<Header> headers = new ArrayList<Header>();
Header operationNameHeader = new Header(new QName("OPERATION-NAME"), "makeMeMoreAwesome",
new JAXBDataBinding(String.class));
Header serviceNameHeader = new Header(new QName("SERVICE-NAME"), "MyAwesomeService",
new JAXBDataBinding(String.class));
headers.add(operationNameHeader);
headers.add(serviceNameHeader);
BindingProvider bindingProvider = (BindingProvider)port;
bindingProvider.getRequestContext().put(Header.HEADER_LIST, headers);
MakeMeMoreAwesomeRequest request = new MakeMeMoreAwesomeRequest();
MakeMeMoreAwesomeResponse response = port.makeMeMoreAwesome(request);
System.out.println(response.getAck());
But when I run this, I get this error:
Exception in thread "main" com.sun.xml.ws.wsdl.parser.InaccessibleWSDLException: 2 counts of InaccessibleWSDLException.
java.io.IOException: Server returned HTTP response code: 500 for URL: http://myserver3333.com:8080/ws/services
java.io.IOException: Server returned HTTP response code: 500 for URL: http://myserver3333.com:8080/ws/services?wsdl
Which is correct because there is no WSDL at that location, it need to follow the soap header to get the service.
Update:
After two points from #Daniel Kulp I am here:
I added a new line: bindingProvider.getRequestContext().put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, "http://myserver3333.com:8080/ws/services");
And now I get this error:
org.apache.cxf.binding.soap.SoapFault: "http://www.myserver.com/ws/services", the namespace on the "errorMessage" element, is not a valid SOAP version.
at org.apache.cxf.binding.soap.interceptor.ReadHeadersInterceptor.readVersion(ReadHeadersInterceptor.java:115)
at org.apache.cxf.binding.soap.interceptor.ReadHeadersInterceptor.handleMessage(ReadHeadersInterceptor.java:141)
at org.apache.cxf.binding.soap.interceptor.ReadHeadersInterceptor.handleMessage(ReadHeadersInterceptor.java:60)
at org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:263)
at org.apache.cxf.endpoint.ClientImpl.onMessage(ClientImpl.java:771)
My assumption is, this error is same as this one. But I am not using ?wsdl. So, any suggestions?
2 comments:
1) You aren't picking up CXF. Check your classpath to make sure CXF is there and not the Sun/Oracle implementation. com.sun.xml.ws.wsdl.parser.InaccessibleWSDLException shows you are picking up the Sun implementation.
2) The URL passed into MyAwesomeService(wsdlLocation) MUST be a URL to the WSDL, not the endpoint itself.
UPDATED
I have a Metro 2.1.1 WebService secured with the mechanism Transport Security (SSL). I want to access this service with a .NET 3.5+ WCF client. I found this link which solves the same problem problem, however I was still unable to make a working client. I think I'm mixing up stuff in the client config.
The WCF team has released a set of interoperability bindings at this link. This blog post provides details on how to use them. One of the supported bindings is specifically for Metro based service. Haven't tried to set this binding up but it seems this scenario is covered.
Client Code:
//IMPORTANT - THIS LINE IS ONLY FOR TESTING PURPOSES!
//This code is for accepting self-signed server certificate
ServicePointManager.ServerCertificateValidationCallback += (sender_ws, cert, chain, sslPolicyErrors) => true;
//instantiate transport binding element, leave the defaults
HttpsTransportBindingElement transport = new HttpsTransportBindingElement();
//instantiate message encoding element, where message version must be Soap11WSAddressing10 to match metro web service requirement.
TextMessageEncodingBindingElement text = new TextMessageEncodingBindingElement();
text.MessageVersion = MessageVersion.Soap11WSAddressing10;
//instantiate transport security binding element, with all the suggested values in app.config
TransportSecurityBindingElement b_element = new TransportSecurityBindingElement();
b_element.DefaultAlgorithmSuite = new Basic128SecurityAlgorithmSuite();
b_element.IncludeTimestamp = true;
b_element.KeyEntropyMode = SecurityKeyEntropyMode.CombinedEntropy;
b_element.MessageSecurityVersion = MessageSecurityVersion.WSSecurity11WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11;
b_element.SecurityHeaderLayout = SecurityHeaderLayout.Lax;
//instantiate the custom binding and add the elements created above
CustomBinding customBinding = new CustomBinding();
customBinding.Name = "myOwnPersonalCustomBinding";
customBinding.Elements.Add(b_element);
customBinding.Elements.Add(text);
customBinding.Elements.Add(transport);
//instantiate the client
Uri uri = new Uri("https://localhost:8181/test/hello");
HelloWebServiceClient wsClient = new HelloWebServiceClient (customBinding, new EndpointAddress(uri));
//Call
richTextBox1.Text = wsClient.hello(textBox1.Text);