In my Camel (2.13) flow, I want to call a webservice using Camel-CXF.
The webservice is secured using NTLM. I did find out thaat CXF itself supports NTLM, but I can't find anything on Camel-CXF. I did try the parameters username and password of course, but that didn't work.
Ik looks like Camel-CXF doesn't support it.
Any ideas on how to solve this?
I'm using java6 so i don't needs jcifs I think.
Roald
<cxf:cxfEndpoint id="sharepointQueryEndpoint"
address="http://yourhostwithpathtowsdl/_vti_bin/search.asmx"
serviceClass="com.somewhere.special.generated.QueryServiceSoap"
endpointName="ssp:SecureConnection"
xmlns:ssp="http://microsoft.com/webservices/OfficeServer/QueryService"
>
<cxf:properties>
<entry key="dataFormat" value="POJO"/>
<entry key="loggingFeatureEnabled" value="true" />
</cxf:properties>
<cxf:inInterceptors>
<bean class="org.apache.cxf.interceptor.LoggingInInterceptor"/>
</cxf:inInterceptors>
<cxf:outInterceptors>
<bean class="org.apache.cxf.interceptor.LoggingOutInterceptor"/>
</cxf:outInterceptors>
</cxf:cxfEndpoint>
<http:conduit name="{http://microsoft.com/webservices/OfficeServer/QueryService}SecureConnection.http-conduit">
<http:client
AllowChunking="false"
MaxRetransmits="11"
Connection="Keep-Alive"
ReceiveTimeout="60000"
CacheControl="No-Cache"
/>
<http:authorization>
<sec:UserName>Domain\Username</sec:UserName>
<sec:Password>Password</sec:Password>
<sec:Authorization>NTLM</sec:Authorization>
</http:authorization>
</http:conduit>
The attribute serviceClass in the cxfEndpoint configuration is point to the Interface which is generated by wsdl2java.enter code here
Note: When this condfiguration is run from a Windows based machine it is not working. During the handshake it will substitute the configured username/password in the http-conduit with the credentials of the user currently logged in.
See Can Java's 'single sign-on' (use credentials from 'Credential Manager') on Windows be disabled? for more information
Related
We are moving an old java / spring app into AWS, so it is behind an AWS Application Load Balancer. Tomcat is running directly behind the load balancers on port 8080, and we are using HTTP between the load balancer and tomcat.
The problem is under this scenario the spring security module doesn't recognize that the connection is secure.
I can resolve this issue by configuring the Connection:
<Connector port="8080"
protocol="HTTP/1.1"
connectionTimeout="20000"
proxyName="single-host.example.com"
secure="true"
scheme="https"
redirectPort="443"
proxyPort="443" />
Which works for a single host name. However, I need this to work across multiple host names.
I have tried skipping the proxy and adding:
server.tomcat.remote_ip_header=X-Forwarded-For
server.tomcat.protocol_header=X-Forwarded-Proto
But this doesn't seem to make any difference.
Is there a way to support multiple hostnames in this scenario?
AWS LoadBalancer sends X-Forwarded-Proto header when proxying request.
On Tomcat configure RemoteIpValve to have request.secure and other request variable interpreted from those headers.
<Valve className="org.apache.catalina.valves.RemoteIpValve"/>
You should also omit setting proxyName on Connector conifiguration since it should come automatically from valve.
I am got some solution procedure. So I have provided 2 suggestion. First one is step by step pictorial view to solve your issue. If not, then go to the second one.
Second one is using X-Forwarded-Proto and related configuration to solve the issue. Hope it will help you.
Suggestion#1:
Amazon cloud environment with load balance support process is pretty straight-forward. A step by step tutorial is given here:Elastic Load Balancing (ELB) with a Java Web Application + Tomcat + Session Stickiness
Suggestion#2:
phillipuniverse has given a solution.
Configuring the following valve in Tomcat will make request.isSecure() function properly with the X-Forwarded-Proto header:
<Valve className="org.apache.catalina.valves.RemoteIpValve" protocolHeader="X-Forwarded-Proto" />
This can be added to Tomcat's server.xml under the <Host> element.
And of course, after all that, there is a very, VERY simple solution that fixes this problem from the very beginning. All that really needed to happen was to modify the proto channel filters from this:
if ("https".equals(invocation.getHttpRequest().getHeader("X-Forwarded-Proto"))) {
getEntryPoint().commence(invocation.getRequest(), invocation.getResponse());
}
to:
if (invocation.getHttpRequest().isSecure() ||
"https".equals(invocation.getHttpRequest().getHeader("X-Forwarded-Proto"))) {
getEntryPoint().commence(invocation.getRequest(), invocation.getResponse());
}
The final configuration here should be this:
<bean class="org.broadleafcommerce.common.security.channel.ProtoChannelBeanPostProcessor">
<property name="channelProcessorOverrides">
<list>
<bean class="org.broadleafcommerce.common.security.channel.ProtoInsecureChannelProcessor" />
<bean class="org.broadleafcommerce.common.security.channel.ProtoSecureChannelProcessor" />
</list>
</property>
</bean>
After that,
Some prefer to terminate SSL at the load balancer, and to not use Apache web server. In that case, you often accept traffic at the LB on 80 / 443, and then route traffic to Tomcat on 8080.
If you are using Spring's port mapping:
<sec:port-mappings>
<sec:port-mapping http="8080" https="443"/>
</sec:port-mappings>
This will not work as it does not override the port mapping in the new Channel Processors. Here is a configuration that will work, though:
<bean class="org.broadleafcommerce.common.security.channel.ProtoChannelBeanPostProcessor">
<property name="channelProcessorOverrides">
<list>
<bean class="org.broadleafcommerce.common.security.channel.ProtoInsecureChannelProcessor" >
<property name="entryPoint">
<bean class="org.springframework.security.web.access.channel.RetryWithHttpEntryPoint">
<property name="portMapper" ref="portMapper"/>
</bean>
</property>
</bean>
<bean class="org.broadleafcommerce.common.security.channel.ProtoSecureChannelProcessor" >
<property name="entryPoint">
<bean class="org.springframework.security.web.access.channel.RetryWithHttpsEntryPoint">
<property name="portMapper" ref="portMapper"/>
</bean>
</property>
</bean>
</list>
</property>
</bean>
Resource Link: HTTPS/SSL/Spring Security doesn't work in both a load balancer and non-load balancer environment #424
You should setup HTTPS connection on the LB, then you'll have a proper TLS connection between the LB and the tomcat so spring will stop crying. You'll just have to provide a self-signed certificate to the LB and setup your spring security module with the private key that have generated this self signed certificate.
(a more complex option: setup properly the tomcat proxy, to force it to encapsulate the HTTP stream of the LB in an HTTPS stream. Setup all TLS requirements in the proxy: certificate, private key...)
Did you try to put LB address as proxyName? It might work on your case.
I am working on Spring Integration for calling a SOAP services. Anyhow I am able to call a SOAP service through outbound gateways and I am receiving the response. But now I need to call a SOAP service which is secured. How to call this using Spring Integration. Can anyone help me out in this issue. Thank you in advance.
Although this is a relatively old thread, I thought it might be useful to share the following details for future visitors.
To invoke a secured web service using Spring Integration's web service outbound gateway, you can set the interceptor attribute of the gateway bean to point to an interceptor bean which you will have to specify. An example below using plain text password:
<bean id="wsSecurityInterceptor"
class="org.springframework.ws.soap.security.wss4j.Wss4jSecurityInterceptor">
<property name="securementActions" value="UsernameToken" />
<property name="securementUsername" value="${ws-user}" />
<property name="securementPassword" value="${ws-password}" />
<property name="securementPasswordType" value="PasswordText" />
<int-ws:outbound-gateway id="yourWebServiceGateway"
uri="${ws-uri}"
interceptor="wsSecurityInterceptor" />
Note that spring-ws-security and Apache's wss4j libraries will be required for this to work.
Spring Integration uses Spring Web Services for the web service support; refer to its documentation for advanced configuration.
For a SOAP web service, I have a working example of the configuration for PasswordDigest authentication via camel-cxf and WSS4J :
<camel-cxf:cxfEndpoint id="myService"
address="${ws.endpoint.address}"
serviceName="es:MyService"
wsdlURL="wsdl/myservice.wsdl"
endpointName="es:MyServicePort"
serviceClass="com.us.MyServiceEndpoint"
xmlns:es="http://us.com/services/MyService">
<camel-cxf:inInterceptors>
<bean class="org.apache.cxf.ws.security.wss4j.PolicyBasedWSS4JInInterceptor">
<property name="properties">
<map>
<entry key="action" value="UsernameToken"/>
<entry key="passwordType" value="PasswordDigest"/>
<entry key="passwordCallbackRef" value-ref="myPasswordCallback"/>
</map>
</property>
</bean>
</camel-cxf:inInterceptors>
</camel-cxf:cxfEndpoint>
We have a request to enable the same resource for BASIC authentication - how can this configuration be modified to do that?
I have changed the following line and tested via SOAP UI:
<entry key="passwordType" value="PasswordText"/>
However the result is a SOAP fault from UsernameTokenValidator.java:
<soap:Fault>
<faultcode>soap:Server</faultcode>
<faultstring>These policy alternatives can not be satisfied:
{http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702}
UsernameToken: Password hashing policy not enforced</faultstring>
</soap:Fault>
If anyone has some guidance here it would be appreciated.
You are mixing up the two different ways of configuring WS-Security in CXF.
The "PolicyBasedWSS4JInInterceptor" is used when you have a WS-SecurityPolicy to configure security. You don't need to actually add it at all, as CXF will automatically add it to the interceptor chain. It's configured via the configuration tags specified here: http://cxf.apache.org/docs/ws-securitypolicy.html. The configuration tags you are specifying as "properties" are ignored for the security policy case.
If you want to configure security via a policy in this case, you will need to remove the "HashPassword" policy if you want to support plaintext passwords.
If you want to only configure via "actions" you should be using the "WSS4JInInterceptor" instead (which the policy based interceptor extends).
Colm.
The WSS-PasswordType needed to change from PasswordText to PasswordDigest.
I wanted to connect one of my web apps with CAS server. I successfully created my CAS server also with SSL setting. but there is an ambiguity when I wanted to set up my CAS client.
In spring web site there is a bean like this which they say we should initialize and create it.
<bean id="serviceProperties" class="org.springframework.security.cas.ServiceProperties">
<property name="service" value="https://localhost:8443/cas-sample/j_spring_cas_security_check" />
<property name="sendRenew" value="false" />
</bean>
The problem here I can't understand what is "service" and what URL it is referred to? I mean in my web app, what the value of "service" should be?
From the Spring Security 3 book:
The service property indicates to CAS the service to which the user will be
authenticated.
For example: https://localhost:8443/your-web-application/j_spring_cas_security_check
I have two webapps: a web-service client and a server (both CXF-based, using the Simple Front-End approach).
This is the server definition:
<simple:server id="server" bindingId="http://schemas.xmlsoap.org/soap/"
address="/thingy" transportId="http://schemas.xmlsoap.org/soap/"
serviceName="cs:thingyService"
serviceClass="com.mycompany.thingy.api.service.ThingyService"
endpointName="cs:thingyServicePort">
<simple:serviceBean>
<bean class="com.mycompany.thingy.server.service.ThingyServiceDelegate">
<property name="thingyService" ref="thingyService"></property>
</bean>
</simple:serviceBean>
<simple:dataBinding>
<bean class="org.apache.cxf.aegis.databinding.AegisDatabinding" />
</simple:dataBinding>
<simple:binding>
<soap:soapBinding version="1.1" mtomEnabled="true" />
</simple:binding>
</simple:server>
And here the client:
<http-conf:conduit name="*.http-conduit">
<http-conf:client AllowChunking="false" />
</http-conf:conduit>
<simple:client id="thingyService" wsdlLocation="${wsdl.url}?wsdl"
serviceName="cs:thingyService"
endpointName="cs:thingyServicePort"
transportId="http://schemas.xmlsoap.org/soap/"
address="${wsdl.url}"
bindingId="http://schemas.xmlsoap.org/soap/"
serviceClass="com.mycompany.thingy.api.service.ThingyService">
<simple:dataBinding>
<bean class="org.apache.cxf.aegis.databinding.AegisDatabinding" />
</simple:dataBinding>
<simple:binding>
<soap:soapBinding mtomEnabled="true" version="1.1" />
</simple:binding>
</simple:client>
I have an interface called ThingyService (the names have been changed ...) that is known to both client and server and the above client definition creates a proxy client that can be injected using this interface.
Everything works beautifully when both webapps are running, specifically when I deploy the server first and then the client. But when the server webapps does not start correctly, the client webapp hangs in an infinite loop trying to create the proxy from the non-existent WSDL.
Basically what I'd like is a proxy around the service proxy that lets the calls pass through when the service is available and throws an adequate exception when the service is down, which I can catch and show a "sorry, we're offline" page in the gui and resumes service when the web service is available again. I have access to the WSDL in static form through the build process (generated automatically through cxf maven plugins), so I could use this for the initial configuration, so from that point of view I am independent of the server.
Does anybody have any pointers in how to implement this functionality? The server is tomcat. The webapps may or may not be deployed onto the same server during production. The backend uses spring / jpa / cxf, the front end uses spring / wicket.
Instead of generating a proxy at runtime, it sounds like you want to create the web service proxy / client code offline.
I'm not sure how this is handled with CXF but you can use tools like wsdl2java to generate the web service client code for a given wsdl document.
As an alternative approach, the client bean could be pointed at a static wsdl file, rather than one located on a remote server.
Although the static wsdl creation approach was promising, I chose a different one (mainly because the cxf maven code generation is buggy).
I wrapped another factoryBean around the existing one, and I attached it to a service provider object that regularly pings the wsdl URL for availability. I keep a service proxy in a cache inside the factory bean, once it is created, and delete it as soon as the service provider ping fails.
If the service is currently not available, my FactoryBean throws a ServiceNotAvailableException. My front end catches this and shows a nice "Service currently unavailable" page.
Additionally, an AspectJ aspect catches all writing calls to the service and re-schedules them when the service is available again.
Here is an excerpt from my spring config:
<bean id="outerFactoryBean">
<property name="innerFactory">
<bean class="org.apache.cxf.frontend.ClientProxyFactoryBean">
<!-- translation of spring:client definition from question -->
</bean>
</property>
<property name="serviceProvider" ref="serviceProvider" />
</bean>
<bean id="serviceProvider" class="de.mytoys.shop.coupons.web.client.ServiceProvider">
<property name="wsdlUrl" value="${wsdl.url}?wsdl" />
<property name="connectionFactory">
<bean class="org.apache.cxf.transport.http.HttpURLConnectionFactoryImpl" />
</property>
</bean>
<task:scheduled-tasks>
<task:scheduled ref="serviceProvider" method="checkAvailability"
fixed-delay="1000" />
</task:scheduled-tasks>
<task:scheduler id="scheduler" pool-size="1" />