Page 1 of 2 12 LastLast
Results 1 to 10 of 17

Thread: Proxy Workaround for M3

  1. #1
    Join Date
    Dec 2010
    Posts
    315

    Default Proxy Workaround for M3

    It took me hours to figure out (I'm not even sure if I would call this a progress) to make Spring Social work behind our proxy.

    The main problem is there's no easy way to setup the proxy. A direct call to HttpClient is entirely impossible via plain XML config. (Maybe even via Java-config?)

    Basically the idea is to modify the RequestFactory that is passed to RestTemplate's constructor. So that it contains the proxy settings:
    Code:
    		SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
    		Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress("my.company.org", 9999));
    		requestFactory.setProxy(proxy);
    		RestTemplate restTemplate = new RestTemplate(requestFactory);
    The workaround is two parts:

    First, I had to reimplement FacebookOAuth2Template createRestTemplate() method:

    Code:
    @Override
    	protected RestTemplate createRestTemplate() {
    		SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
    		Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress("my.company.org", 9999));
    		requestFactory.setProxy(proxy);
    		RestTemplate restTemplate = new RestTemplate(requestFactory);
    		FormHttpMessageConverter messageConverter = new FormHttpMessageConverter() {
    			public boolean canRead(Class<?> clazz, MediaType mediaType) {
    				// always read as x-www-url-formencoded even though Facebook sets contentType to text/plain				
    				return true;
    			}
    		};
    		restTemplate.setMessageConverters(Collections.<HttpMessageConverter<?>>singletonList(messageConverter));
    		return restTemplate;
    	}
    Literally, I created a new class and copied the whole implementation of FacebookOAuth2Template and renamed the new class as ModifiedFacebookOAuth2Template.

    This works on the authentication part to Facebook. I can see clearly in the userconnection table that the Facebook connection has been created. However, when I try to view my profile and post to my wall, I get a timeout error. Again, it's because the proxy is not setup though I already did!

    It turns out I also have to modify the RequestFactory that's declared inside the FacebookTemplate. This is the second part.

    FacebookTemplate calls the following factory class to initialize its RestTemplate:

    Code:
    	this.restTemplate = ProtectedResourceClientFactory.draft10(accessToken);
    So basically I had to modify ProtectedResourceClientFactory and re-implemented it like the following:
    Code:
    private static RestTemplate version(String accessToken, OAuth2Version version) {
    
    		SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
    		Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress("my.company.org", 9999));
    		requestFactory.setProxy(proxy);
    		RestTemplate client = new RestTemplate(requestFactory);
    		if (interceptorsSupported) {
    			// favored
    			client.setInterceptors(new ClientHttpRequestInterceptor[] { new OAuth2RequestInterceptor(accessToken, version) });
    		} else {
    			// 3.0.x compatibility
    			client.setRequestFactory(new Spring30OAuth2RequestFactory(client.getRequestFactory(), accessToken, version));
    		}
    		return client;				
    	}
    But then in order for this to work, I had to literally copy 20+ classes and modify their visibility to public so that my custom package is able to see them! For example, EventTemplate, CommentList, AlbumList, ReferenceList, VideoList, OAuth2Version, and so forth.

    It's too lengthy and takes a lot of work. The visibility of these classes made the modification tedious.

    My application works, but I believe there should be a simpler way to set this up. I tried adding Apache Commons HttpClient 4.1 in the classpath and see if I can modify it's parameters so that the proxy settings are assingned to. Unfortunately, the HttpClient is created runtime and not via configuration.

    I assume it would also work if I copy and modify the classes that contain HttpClient but that would even require more classes to edit.

    Or maybe there's an easy that I've missed?

  2. #2
    Join Date
    Aug 2004
    Posts
    1,075

    Default

    You're right in saying that there is no easy way to configure Spring Social to be used behind a proxy. But this should definitely be addressed. Therefore, I've created https://jira.springsource.org/browse/SOCIAL-146 to track this issue and will be working to resolve it.
    Craig Walls
    Spring Social Project Lead

  3. #3
    Join Date
    Dec 2010
    Posts
    315

    Default

    Thanks for confirming it. At least this gives me comfort that I haven't missed a thing Thanks for opening-up a JIRA as well. I appreciate it.

  4. #4
    Join Date
    Aug 2004
    Location
    Melbourne, FL
    Posts
    2,794

    Default

    We just landed a patch that allows the RequestFactory to be configured against each API binding. It's available now in the latest snapshot. Let us know if that meets your needs!
    Keith Donald
    Core Spring Development Team

  5. #5
    Join Date
    Aug 2004
    Posts
    1,075

    Default

    The latest snapshot builds include the ability to specify the proxy host/port using the "http.proxyHost" and "http.proxyPort" system properties (commonly set on the JVM via -Dhttp.proxyHost=somehost -Dhttp.proxyPort=8080). This works without the need to configure a custom request factory. Could you try this out and let us know if it works for you and meets your needs? Thanks!
    Craig Walls
    Spring Social Project Lead

  6. #6
    Join Date
    Dec 2010
    Posts
    315

    Default

    That's nice to know. I will certainly try it later. I will have to be at work to test it I've just woke-up (6am here).

  7. #7
    Join Date
    Dec 2010
    Posts
    315

    Default

    Great! It works. I had three hiccups but I was able to resolve them:

    First, I had to setup the correct repositories for the snapshot. I found your post at http://forum.springsource.org/showth...book-social-M2

    For reference, I used the following pom.xml configuration:

    Code:
                            
            <properties>
    		...
    		<spring.social.version>1.0.0.BUILD-SNAPSHOT</spring.social.version>
    	</properties>
    
    	...
    
    	<repository>
    		<id>org.springframework.maven.release</id>
    		<name>Spring Maven Release Repository</name>
    		<url>http://maven.springframework.org/release</url>
    		<releases>
    			<enabled>true</enabled>
    		</releases>
    		<snapshots>
    			<enabled>false</enabled>
    		</snapshots>
    	</repository>
    	<!-- For testing against latest Spring snapshots -->
    	<repository>
    		<id>org.springframework.maven.snapshot</id>
    		<name>Spring Maven Snapshot Repository</name>
    		<url>http://maven.springframework.org/snapshot</url>
    		<releases>
    			<enabled>false</enabled>
    		</releases>
    		<snapshots>
    			<enabled>true</enabled>
    		</snapshots>
    	</repository>
    	<!-- For developing against latest Spring milestones -->
    	<repository>
    		<id>org.springframework.maven.milestone</id>
    		<name>Spring Maven Milestone Repository</name>
    		<url>http://maven.springframework.org/milestone</url>
    		<snapshots>
    			<enabled>false</enabled>
    		</snapshots>
    	</repository>

    Second, I had to find an elegant way to inject the proxy settings, and found the following (See http://stackoverflow.com/questions/3...iguration-file)

    Code:
     
    	<bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
    	    <property name="targetObject">
    	        <!-- System.getProperties() -->
    	        <bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
    	            <property name="targetClass" value="java.lang.System" />
    	            <property name="targetMethod" value="getProperties" />
    	        </bean>
    	    </property>
    	    <property name="targetMethod" value="putAll" />
    	    <property name="arguments">
    	        <!-- The new Properties -->
    	        <util:properties>
    	            <prop key="http.proxyHost">xxxxxx</prop>
    	            <prop key="http.proxyPort">1111</prop>
    	        </util:properties>
    	    </property>
    	</bean>
    Third, I have to rename FacebookApi to Facebook.

    Everything is working fine in relation to the proxy issue. I'm gonna continue my project now Thanks a lot

  8. #8
    Join Date
    Dec 2010
    Posts
    315

    Default

    Following-up, I was able to simplify the setup of the proxy settings using SpEL as indicated in the comments in the stackoverflow.com post:

    Code:
    <!-- http://stackoverflow.com/questions/3339736/set-system-property-with-spring-configuration-file -->
    	<bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
    	    <property name="targetObject" value="#{@systemProperties}" />
    	    <property name="targetMethod" value="putAll" />
    	    <property name="arguments">
    	        <!-- The new Properties -->
    	        <util:properties>
    	            <prop key="http.proxyHost">xxxxxxx</prop>
    	            <prop key="http.proxyPort">1111</prop>
    	        </util:properties>
    	    </property>
    	</bean>

  9. #9
    Join Date
    Dec 2010
    Posts
    315

    Default

    I tried the latest snapshot. For some reason the proxy isn't working again. I'm getting connection timeout. The same exact behavior when I had problems with the proxy settings.

    The only difference I see from the previous snapshot (the one that worked) and today's snapshot is the addition of a private HttpComponentsClientRequestFactoryCreator inside the ClientHttpRequestFactorySelector.

    Snapshot that was still working:
    https://github.com/SpringSource/spri...0c6156128ec804

    Updated snapshot that somehow broke the proxy functionality:
    https://github.com/SpringSource/spri...8d47d2b778f6fa https://github.com/SpringSource/spri...ec6c250d3c73d4

  10. #10
    Join Date
    Dec 2010
    Posts
    315

    Default

    I've enabled DEBUG logging and here's what I got:

    Code:
    Caused by: org.apache.commons.httpclient.ConnectTimeoutException: The host did not accept the connection within timeout of 3000 ms
    	at org.apache.commons.httpclient.protocol.ReflectionSocketFactory.createSocket(ReflectionSocketFactory.java:155)
    	at org.apache.commons.httpclient.protocol.SSLProtocolSocketFactory.createSocket(SSLProtocolSocketFactory.java:130)
    	at org.apache.commons.httpclient.HttpConnection.open(HttpConnection.java:707)
    	at org.apache.commons.httpclient.MultiThreadedHttpConnectionManager$HttpConnectionAdapter.open(MultiThreadedHttpConnectionManager.java:1361)
    	at org.apache.commons.httpclient.HttpMethodDirector.executeWithRetry(HttpMethodDirector.java:387)
    	at org.apache.commons.httpclient.HttpMethodDirector.executeMethod(HttpMethodDirector.java:171)
    	at org.apache.commons.httpclient.HttpClient.executeMethod(HttpClient.java:397)
    	at org.apache.commons.httpclient.HttpClient.executeMethod(HttpClient.java:323)
    	at org.openid4java.util.HttpCache.head(HttpCache.java:296)
    	at org.openid4java.discovery.yadis.YadisResolver.retrieveXrdsLocation(YadisResolver.java:360)
    	... 33 more
    Caused by: java.net.SocketTimeoutException: connect timed out
    	at java.net.PlainSocketImpl.socketConnect(Native Method)
    	at java.net.PlainSocketImpl.doConnect(PlainSocketImpl.java:333)
    	at java.net.PlainSocketImpl.connectToAddress(PlainSocketImpl.java:195)
    	at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:182)
    	at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:366)
    	at java.net.Socket.connect(Socket.java:519)
    	at com.sun.net.ssl.internal.ssl.SSLSocketImpl.connect(SSLSocketImpl.java:550)
    	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    	at java.lang.reflect.Method.invoke(Method.java:597)
    	at org.apache.commons.httpclient.protocol.ReflectionSocketFactory.createSocket(ReflectionSocketFactory.java:140)
    	... 42 more
    Apparently, I can still connect to Facebook with proxy enabled. However, the problem seems to manifest when I implement an OpenID login using Spring Security 3.1.0.RC1. This only started when I used the latest spring-social snapshot. Yesterday, everything still works. In fact, I was able to upload my app to CloudFoundry.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •