SignedSupportingTokens wssecurity policy cxf client - java

I'm trying to put together a small CXF client for a soap service which is having SignedSupportingTokens ws-security policy in its wsdl. I have configured CXF client as follows
<jaxws:client id="secretService" name="{http:/mySecretServiceEndpoint//}Service" createdFromAPI="true">
<jaxws:properties>
<entry key="ws-security.signature.properties" value="keystore/secret.properties" />
<entry key="ws-security.encryption.properties" value="keystore/secret.properties" />
<entry key="ws-security.timestamp.timeToLive" value="600" />
</jaxws:properties>
</jaxws:client>
Unfortunately it fails to send out messages with following error.
Caused by: org.apache.cxf.ws.policy.PolicyException: None of the policy alternatives can be satisfied.
at org.apache.cxf.ws.policy.EffectivePolicyImpl.chooseAlternative(EffectivePolicyImpl.java:199)
at org.apache.cxf.ws.policy.EffectivePolicyImpl.chooseAlternative(EffectivePolicyImpl.java:192)
at org.apache.cxf.ws.policy.EffectivePolicyImpl.initialise(EffectivePolicyImpl.java:96)
at org.apache.cxf.ws.policy.PolicyEngineImpl.getEffectiveClientRequestPolicy(PolicyEngineImpl.java:205)
at org.apache.cxf.ws.policy.PolicyOutInterceptor.handle(PolicyOutInterceptor.java:98)
at org.apache.cxf.ws.policy.AbstractPolicyInterceptor.handleMessage(AbstractPolicyInterceptor.java:44)
at org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:307)
at org.apache.cxf.endpoint.ClientImpl.doInvoke(ClientImpl.java:514)
at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:423)
at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:326)
at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:279)
at org.apache.cxf.frontend.ClientProxy.invokeSync(ClientProxy.java:96)
at org.apache.cxf.jaxws.JaxWsClientProxy.invoke(JaxWsClientProxy.java:138)
I was wondering if CXF supports SignedSupportingTokens policy by default? Do I need to register some handlers or am I missing something else? I don't have much experience with WS-Security and WS-SecurityPolicy, any response will be highly appreciated.

Answering my own question as it might help somebody someday! CXF does supports SignedSupportingTokens and a lot more, In my case, service WSDL was having a different namespace for SignedSupportingTokens which CXF client dint understand (couldn't match up).
I was able to fix the issue by using ws-security interceptors to configure the client.

Related

How to setup TLS Server to authenticate client in spring integration?

Refer to Running the client with SSL/TLS. This explains a scenario where server does a client authentication. I am using Spring Integration to process TLS connections. My spring-context file is:
<bean id="sslContextSupport"
class="org.springframework.integration.ip.tcp.connection.DefaultTcpSSLContextSupport">
<constructor-arg value="file:keystore.jks"/>
<constructor-arg value="file:truststore.jks"/>
<constructor-arg value="keystorepass"/>
<constructor-arg value="trustpass"/>
</bean>
<int-ip:tcp-connection-factory id="crLfServer"
type="server"
port="${availableServerSocket}"
single-use="true"
so-timeout="10000"
using-nio="false"
ssl-context-support="sslContextSupport" />
My Server is accepting SSL connections and processing with certificates installed on my server and client.
I am not sure whether the above spring configuration is setup for client authentication or not. is the client authentication done at the SSL transaport level or in the Application code?
The Spring Integration DefaultTcpSSLContextSupport is fully based on the SSLContext sslContext = SSLContext.getInstance(protocol);. So, what you see in the standard Java SSL/TLS documentation is applied here as well.
Since that your <int-ip:tcp-connection-factory> produces type="server", that is definitely the case of
the server does client authentication
All the hard SSL work is done in the SSLContext layer, not in the TcpNetServerConnectionFactory, if that is the question.
In other words: it doesn't matter that it is Spring Integration or not. Everything works the same way as in any other Java application which users standard SSL/TLS approach.

Java and Metadata Exchange MEX

I'm trying to generate classes using an MEX endpoint unfortunately doesn't seems to be possible, because it won't find the WSDL.
I also want create a client for that web services using spring and Apache CXF but I don't know if I'm in the right path. I tried declaring the following on my spring-config:
<jaxws:client name="{http://payments.com:8080/}IOriginatorPaymentsService"
createdFromAPI="true">
<jaxws:properties>
<entry key="ws-security.username" value="Username"/>
<entry key="ws-security.password" value="Password"/>
</jaxws:properties>
</jaxws:client>
My questions are:
1. It's possible to generate the classes using only the following MEX endpoint http://payments.com:8080/OriginatorPaymentsHNL/Service/OriginatorPaymentsService.svc/mex the WSDL appears to be unexposed.
Could you provide an example of how to use spring and Apache CXF to create a client for the MEX endpoint.
As far I understand I can't unless the web service has enable the httpGetEnabled flag to expose the WSDL.
Thank you
Enable httpGetEnabled flag to expose the WSDL

Consuming a webservice with CXF in Mule 3.5

I am trying to consume web service using CXF component in mule(Anypoint Studio).
So I tried genrating the WSDL file from URL but I was getting this errror: Rpc/encoded wsdls are not supported in CXF so I followed this answer.
It worked and it generated client stubs, then copied the files into my mule project.
but I am getting this error:
Service.SomeService.<init>(java.net.URL, javax.xml.namespace.QName) (java.lang.NoSuchMethodException)
This is my flow:
<flow name="WebServiceTest">
<cxf:jaxws-client
clientClass="service.SomeService"
wsdlLocation="http://127.0.0.1:8000/api/v2_soap/?wsdl"
operation="test"/>
<outbound-endpoint address="http://127.0.0.1:8000/api.php/?type=v2_soap"/>
</flow>
Any ideas?
Your configuration is not correct specially your outbound endpoint url.
You can try configuring a CXF client as per Mule documentation.
You can also build a client for your JAX-WS services without generating a client from WSDL. Here you need a copy of your service interface and all your data objects locally to use something like this :-
<flow name="csvPublisher">
...
<cxf:jaxws-client serviceClass="org.example.HelloService" operation="sayHi"/>
<outbound-endpoint address="http://localhost:63081/services/greeter"/>
</flow>
Another approach is you can use a CXF-generated client as an outbound endpoint. First, you need to generate a CXF client using the WSDL to Java tool from CXF or the Maven plugin.
Then you need to configure something like the following :-
<flow name="csvPublisher">
...
<cxf:jaxws-client
clientClass="org.apache.hello_world_soap_http.SOAPService"
port="SoapPort"
wsdlLocation="classpath:/wsdl/hello_world.wsdl"
operation="greetMe"/>
<outbound-endpoint address="http://localhost:63081/services/greeter"/>
</flow>
It is better to put the wsdl in your local classpath.
Please checkout the full documentation here as reference to get it configured :-
https://docs.mulesoft.com/mule-user-guide/v/3.7/consuming-web-services-with-cxf
and
Consuming a Webservice Using Mule 3.4

Building SOAP Envelope from Java using Strings

I am working on understanding how SOAP services work.My client is in Java and the service is using WCF (although in theory this shouldn't matter). If I am given an example of a SOAP envelope and do the following:
-Build a SOAP envelope that exactly follows the example
-Use an HttpPost object to post the data to www.service.com/service.svc
Is this a correct (although improper) way to call the service? Because when I do this, I receive a 400 response, even though my SOAP envelope is the exact same as the example.
It should work. You are probably missing some required headers. I suggest to use a TCP monitor, intercept a working request and analize its content.
I think the reason you are getting an HTTP 400 (Bad Request) is that your service is using BasicHttpBinding which is SOAP 1.1, and you are most likely sending a SOAP 1.2 message (as you indicated in the comments that you are using SOAP 1.2). The message formats are different between the two.
The simplest solution would be to use SOAP 1.1, but if you must (or want) to use SOAP 1.2, the following may help.
In your config file, you haven't defined any endpoints or bindings - which is ok, as WCF will use defaults in 4.0 and later.
However, the default binding for HTTP is BasicHttpBinding. You need to use a binding that supports SOAP 1.2 (or change your message to SOAP 1.1). You could use WSHttpBinding, which does support SOAP 1.2, but you mau have to change the security setting (by default it's Windows).
Another option is to use a custom binding that implements SOAP1.1.
I'll give a couple of examples (I've never written a non-.NET client for a WCF service, so I can't say for certain that it will work but it should at least get you going in the right direction.
WSHttpBinding
Change the default protocol mapping for HTTP requests from BasicHttpBinding to WsHttpBinding by overriding the protocol mapping in your config file:
<protocolMapping>
<addBinding protocol="wsHttpBinding" scheme="http" />
</protocolMapping>
Add a binding section to your config file so you can set the security mode to None. This goes under the <system.serviceModel> section:
<bindings>
<wsHttpBinding>
<binding>
<security mode="None" />
</binding>
</wsHttpBinding>
</bindings>
Notice that I didn't set a value for the name attribute on the binding. This will set the binding definition as the default, and in conjunction with changing the default protocol for HTTP to wsHttpBinding should enable you to send SOAP 1.2.
SECURITY NOTE* Setting security to none is fine if you're just trying to get a better understanding of SOAP, but I would highly recommend doing it in production.
Custom Binding
I've never used a custom binding, but something like this should work:
<bindings>
<customBinding>
<binding name="Custom">
<textMessageEncoding messageVersion="Soap12" />
<httTransport />
</binding>
</customBinding>
</bindings>
You will need to explicitly set this to your endpoint (using the bindingConfiguration attribute of the endpoint), which means you'll need to create an endpoint definition in your config file.
The custom binding idea is from SOAP 1.2 message format with BasicHttpBinding
Hopefully this will give you some ideas and get you going again.

passwordCallback in CXF

I develop a webservice client for an existing webservice. I am using Apache CXF 2.2. The service requires security with Username and plain text password, which I configured like this:
<bean id="myPasswordCallback"
class="com.kraemer_imd.mobilized.m2m_adapter.ClientPasswordCallback"/>
<jaxws:client id="m2mClientService"
serviceClass="de.vodafone.easypu.ws.EasyPUOrderServicePortType"
address="http://m2m.vodafone.de/speasy/services/EasyPUOrderService"
bindingId="http://www.w3.org/2003/05/soap/bindings/HTTP/">
<jaxws:outInterceptors>
<bean class="org.apache.cxf.ws.security.wss4j.WSS4JOutInterceptor">
<constructor-arg>
<map>
<entry key="action" value="UsernameToken Timestamp"/>
<entry key="passwordType" value="PasswordText"/>
<entry key="user" value="myusername"/>
<entry key="passwordCallbackRef">
<ref bean="myPasswordCallback"/>
</entry>
</map>
</constructor-arg>
</bean>
</jaxws:outInterceptors>
</jaxws:client>
That works quite well. But I did not understand why I have to provide the password via a callback handler instead of just providing it via configuration. The documentation says it is for security reasons, but I donĀ“t see why this should be more secure to have a callback handler that reads it from a property file (or worse has it hard coded in the callback).
So, could somebody explain this to me? Maybe the callback is intended for some magic stuff that I missed..
Thanks
Michel
The password callback is provided by Apache CXF as a mechanism for the client application to retrieve the credentials for the targeted webservice, which at runtime is likely to be stored in the database, configuration fiels, LDAP or some other store. This callback hook provides the flexibility to the application to retrieve the credentials from application specific configuration.
If password is stored in clear text in the configuration then this approach may not give you any extra security.
However having password stored as clear text in some configuration may have some security issues as there can be folks that may need access to this configuration and will be able to hold of password although it may not have been intended to.
Better is to store the encrypted password in the configuration. In this case, you need some code that will decrypt this password before it's use. Password callback will come to rescue in this scenario.

Categories