HTTP Proxy Setup For Java JVM - java

Setting up an HTTP proxy for Java JVM 6.x isn't working for me; I'm hoping someone can spot what I'm missing.
I have a Java application deployed on JBOSS 5.1.2 that makes several calls to external web services. I'd like to be able to intercept these calls using a proxy: Fiddler version 4.4.8.0.
After doing an SO search I added the following flags to my JBOSS VM parameters at startup:
-DproxySet=true -Dhttp.proxyHost=localhost -Dhttp.proxyPort=8888 -Dhttps.proxyHost=localhost -Dhttps.proxyPort=8888
I'm running JBOSS in IntelliJ 14.
I can see traffic from the browser to the application if I start JBOSS, Fiddler, and open the UI in Chrome. I do not see any calls from JBOSS to external services being intercepted. I thought I would see all the calls from JBOSS to external services in addition to those from the browser to JBOSS.
Update:
I tried adding these to properties-service.xml per this SO answer - no joy.
I'm running Spring 3, using Apache HttpClient as my web service client. I'm going to look into configuring proxy just for it.

Thanks to bmargulies and anyone else who looked at this. I have a solution that I hope will help someone else.
Adding -Dhttp.proxyHost parameters to my JVM startup options did nothing.
Adding those same parameters to JBOSS 5.1.2 configuration in my deployment properties-services.xml did nothing.
I believe that using Spring 3.x is a factor in explaining this behavior. I had to tell the Spring web service clients to use a proxy.
I added some Spring beans to wire in a Fiddler proxy HttpClient and injected that into the web service client, replacing the non-proxied version.
It failed the first time I tried it. It took me a while to figure out that the Apache Commons HttpConfiguration class didn’t follow the Java bean standard, so Spring blew up when it tried to wire it. I had to use the Spring MethodInvokingFactoryBean to get around it.
Here's the pertinent Spring configuration XML:
<!-- New beans for Fiddler proxy -->
<bean id="fiddlerProxyHost" class="org.apache.commons.httpclient.ProxyHost">
<constructor-arg name="hostname" value="localhost"/>
<constructor-arg name="port" value="8888"/>
</bean>
<bean id="fiddlerProxyHostConfiguration" class="org.apache.commons.httpclient.HostConfiguration"/>
<bean id="fiddlerProxyHostSetter" class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
<property name="targetObject" ref="fiddlerProxyHostConfiguration"/>
<property name="targetMethod" value="setProxyHost"/>
<property name="arguments" ref="fiddlerProxyHost"/>
</bean>
<bean id="fiddlerProxyClient" class="org.apache.commons.httpclient.HttpClient">
<property name="hostConfiguration" ref="fiddlerProxyHostConfiguration"/>
</bean>
Now I can see the calls from the application to the web service in Fiddler. Joy!

Those parameters, first and foremost, are read by HttpURLConnection. They are specific to HTTP, of course, and so any other means of connecting to the outside world will necessarily ignore them.
There are many good reasons for code to avoid HttpURLConnection and just open a TCP connection through a plain old socket, even if that code plans to talk HTTP. HttpURLConnection has several 'browser emulation features' that get in the way. For example, it's broken for CORS and rejects some legitimate HTTP verbs.
Code that does that and in turn happens to do HTTP might choose to respect those parameters, and it might not. For example, I'm reasonably sure that the Apache Commons HTTP library gives the caller a choice.
If you put JBoss in a debugger and break on the socket connection primitives, I think you'll find out what's happening to you pretty quick in this respect.

Related

How can I get spring security to work behind a load balancer across multiple domains?

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.

JmxResource published with simplejmx does not appear in JConsole

I am using simplejmx to publish my JMX Resources.
I have got jmx-config.xml
<bean id="beanPublisher" class="com.j256.simplejmx.spring.BeanPublisher">
<property name="jmxServer" ref="jmxServer" />
</bean>
<bean id="jmxServer" class="com.j256.simplejmx.server.JmxServer"
init-method="start" destroy-method="stop">
<property name="registryPort" value="8123" />
</bean>
I am starting my JBoss application, everything is ok:
15:20:11,860 INFO [org.springframework.beans.factory.support.DefaultListableBeanFactory] (MSC service thread 1-8) Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory#1be30160: defining beans [...,beanPublisher,jmxServer,...]; root of factory hierarchy
I created a simply class.
package com.mypckg.jmx;
import com.j256.simplejmx.common.JmxAttributeField;
import com.j256.simplejmx.common.JmxResource;
#JmxResource(description = "Blah1", domainName = "Blah2", beanName = "Blah3")
public class DummyJMX {
#JmxAttributeField(description = "Blah4")
private int var = 3;
}
I am starting JConsole, I am choosing JBoss application and I am going to MBeans. That is what I see:
*
Probably, my DummyJMX class has not been published (or I just cannot find it).
About which step I forgot?
Thank you in advance
EDIT :
EDIT :
#Andrei Stefan
An error which I got using your link:
#Gray
An error which I got using localhost:8123:
Try the following url in JConsole, with Remote Process option: service:jmx:rmi:///jndi/rmi://localhost:8123/jmxrmi
It's a bit different than what I provided in the comments.
Finally, I am connected to my JMX Beans using JConsole.
Probably, I did something wrong in the beginning of my work with simplejmx.
I have not changed a lot of things. I kept jmx-config file and I still use version 1.8 of simplejmx.
I can easily connect to this bean locally - I have no idea why I was not able to do that earlier. Could you tell me, why in your opinion it should not be a local process?
Below, you can see that my JMX Bean appears in JConsole:
Probably, my DummyJMX class has not been published (or I just cannot find it).
When you are using the registryPort configuration for JmxServer then it will not show up in the "Local Process" list under Jconsole. It will be able to be accessed as a "Remote Process" with localhost:8123. If you are on a Linux box, you might use netstat -an | grep LISTEN to see what ports your application is listening on. If you don't see 8123 in the list then maybe it already has a RMI server configured?
If you want to use the platform mbean-server which does show up as a local process then use the new setter or constructor in version 1.9 which was released recently (4/2014). Unfortunately, SimpleJMX cannot programmatically register itself so it shows up in the process list -- that's not code that the JVM exports.
<bean id="jmxServer" class="com.j256.simplejmx.server.JmxServer"
init-method="start" destroy-method="stop">
<property name="usePlatformMBeanServer" value="true" />
</bean>

Getting the Jetty instance from Spring Web Service

I am creating a web service with spring + jetty + cxf using the following:
<import resource="classpath:META-INF/cxf/cxf.xml" />
<import resource="classpath:META-INF/cxf/cxf-servlet.xml" />
<jaxws:endpoint id="helloWorld" implementor="com.test.EndpointImp" address="http://localhost:9002/test">
</jaxws:endpoint>
This all works as expected and very well. Now I need to "serve" some servlets. Is there anyway I can get to the jetty Server instance that is created for this, so that I can add the servlets? I dont want to create another Jetty instance on another port just for the servlets I need to use.
Any information will be greatly appreciated.
The solution you are looking for is described in this article. The key points (which I also mentioned in my post) are to use org.apache.cxf.transport.servlet.CXFServlet in your web.xml, don't forget to import META-INF/cxf/cxf-servlet.xml (you did so) and also use relative address="/myservice" attribute. In this case CXF routines will not launch embedded Jetty but use this servlet for processing the inbound requests.
Of course a webapp can handle at the same time some WebServices and servlets.
I suppose your web services are in a web application.
Thus you should have a web.xml (in WEB-INF). You can add your servlets declarations in this web.xml.
Jetty should start your webapp.
We can't help you more if you don't give us more details of your project (Maven based or not, how do you launch Jetty, etc...).

How do I create a TopicConnectionFactory for MQSeries in Spring?

I have read the article http://techtots.blogspot.com/2010/01/connecting-to-mq-using-spring-without.html about configuring QueueConnectionFactories and have that side of things working nicely.
# MQ related values
mq.jms.qcf=QM_Epsilon
mq.jms.request.queue=TEST.REQUEST.QUEUE
# Connection details
mq.host.url=localhost:1414/SYSTEM.DEF.SVRCONN
mq.factoryclass=com.ibm.mq.jms.context.WMQInitialContextFactory
# Authentication details
mq.auth=simple
mq.user=******
mq.password=********
<bean id="queueConnectionFactory" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="${mq.jms.qcf}" />
<property name="resourceRef" value="false" />
<property name="jndiEnvironment">
<props>
<prop key="java.naming.factory.initial">${mq.factoryclass}</prop>
<prop key="java.naming.provider.url">${mq.host.url}</prop>
<prop key="java.naming.security.authentication">${mq.auth}</prop>
<prop key="java.naming.security.principal">${mq.user}</prop>
<prop key="java.naming.security.credentials">${mq.password}</prop>
</props>
</property>
</bean>
Using this configuration the queueConnectionFactory bean is easily injected into my classes as an MQQueueConnectionFactory.
But I am wanting to use the publish/subscribe model and, as I understand it, I need to get an MQTopicConnectionFactory for this. I have searched everywhere and tried numerous things but I cannot find any information on how to modify this configuration, or the MQ installation so that I get an MQTopicConnectionFactory instead of an MQQueueConnectionFactory.
The WMQInitialContextFactory is a class that implements a JNDI provider over a WebSphere MQ queue. Instead of the managed objects being stored in a .bindings file or LDAP, they are serialized and stored in a queue and this class allows you to treat that queue as just another JNDI store. This class was only ever intended to be a JNDI provider and not a replacement for the actual IBM JMS implementation. Since storing managed objects on a topic would not work, these classes have no topic factories in them. This is as expected.
In my opinion, the problem with WMQInitialContextFactory is that it must first connect to WebSphere MQ in order to to obtain a connection factory which then tells the app - you guessed it - how to connect to WebSphere MQ. This makes the article that was linked confusing because it appears that all that configuration, the WMQ connection details and so forth, are for the benefit of the application when in fact they just bootstrap a JNDI provider which is expected to have defined connection factory objects with all this same information.
What is missing from the article is that the author would have had to use IBM's JMSAdmin tool to connect to the MQInitialContext and define the ConnectionFactory and other administered objects before connecting the application to that same Initial Context in order to access them.
For the record, the WebSphere MQ JMS classes have supported JMS 1.1 ConnectionFactory and Destination classes for quite some time now. Prior to that they supported both queues and topics as per the JMS 1.0 spec.
You can download the IBM WMQ JMS implementation as SupportPac MQC7. There is a lot more there than just the jar files. For example, you get lots of sample code, diagnostic and trace utilities, documentation, etc. You also get the correct jar files.
If you want to use a .bindings file (File-system initial context) instead of the WMQInitialContextFactory, download the latest WebSphere MQ Explorer tool as SupportPac MS0T. You can create a directory, point WMQ Explorer to it and define all your connection factories and destinations. (Or go with domain-specific QueueConnectionFactory and TopicConnectionFactory if you rock it old school.) More information on using WMQ Explorer to define your managed objects may be found at: Creating and configuring JMS administered objects
If you want a tutorial that includes a demonstration of how to use IBM's JMSAdmin tool to create the .bindings file, look at Running a standalone Java application on WebSphere MQ V6.0. (The JMSAdmin tool is installed with the WMQ Server and I believe it also comes with the free MS0T WMQ Client install linked above.) The documentation for the JMSAdmin tool is here: Using the WebSphere MQ JMS administration tool
Whichever method you choose to create managed objects, you can look up all the possible properties supported in IBM's implementation at: Properties of WebSphere MQ classes for JMS objects

Spring, CXF: Loose coupling between web service client and server

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" />

Categories

Resources