3 Replies Latest reply: Oct 20, 2010 5:16 AM by Matt Carless RSS

SSL calls thru a proxy with authentication?

Fredrik Carlowitz Newbie

Hi!
Have to pass a bluecoat proxy with authentication to make client SSL calls from my application to an external webservice. Running solaris, jdk5 and jboss_4.0.5.GA.

Version 1.4.3.GA accoding to the jboss-remoting.jar

When i read the user documentation for remoting 1.4.0 this seamed like a simple thing. Providing system parameters
-Dhttp.proxyHost=ginger
-Dhttp.proxyPort=80
-DproxySet=true

and some more for usr/passw for proxy invocations:
-Dhttp.proxy.username=username
-Dhttp.proxy.password=password

or these for non-proxied invocations:
-Dhttp.basic.username=username
-Dhttp.basic.password=password

Not really sure what to use so i specify them both.


Using these settings generates this stack:


java.net.UnknownHostException: test.remotehost.com
at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:177)
at java.net.Socket.connect(Socket.java:516)
at java.net.Socket.connect(Socket.java:466)
at sun.net.NetworkClient.doConnect(NetworkClient.java:157)
at sun.net.www.http.HttpClient.openServer(HttpClient.java:365)
at sun.net.www.http.HttpClient.openServer(HttpClient.java:477)
at sun.net.www.protocol.https.HttpsClient.(HttpsClient.java:278)
at sun.net.www.protocol.https.HttpsClient.New(HttpsClient.java:335)
at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.getNewHttpClient(AbstractDelegateHttpsURLConnecti
on.java:176)
at sun.net.www.protocol.http.HttpURLConnection.plainConnect(HttpURLConnection.java:747)
at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:1
62)
at sun.net.www.protocol.http.HttpURLConnection.getOutputStream(HttpURLConnection.java:839)
at sun.net.www.protocol.https.HttpsURLConnectionImpl.getOutputStream(HttpsURLConnectionImpl.java:230)
at org.jboss.remoting.transport.http.HTTPClientInvoker.useHttpURLConnection(HTTPClientInvoker.java:163)
at org.jboss.remoting.transport.http.HTTPClientInvoker.transport(HTTPClientInvoker.java:81)
at org.jboss.remoting.RemoteClientInvoker.invoke(RemoteClientInvoker.java:143)
at org.jboss.remoting.Client.invoke(Client.java:525)
at org.jboss.remoting.Client.invoke(Client.java:488)
at org.jboss.ws.soap.SOAPConnectionImpl.call(SOAPConnectionImpl.java:189)
at org.jboss.ws.jaxrpc.CallImpl.invokeInternal(CallImpl.java:687)
at org.jboss.ws.jaxrpc.CallImpl.invoke(CallImpl.java:404)
at org.jboss.ws.jaxrpc.CallProxy.invoke(CallProxy.java:148)
at $Proxy105.SSEKService(Unknown Source)


No calls to my proxyHost according to a netstat -a.
If i check the jboss source code it's not in a state where it could handle any kind of response like "407 Proxy Authentication Required"

If i then change all settings to instead use -Dhttps i get a bit further but it gives me this stack:

java.io.IOException: Unable to tunnel through proxy. Proxy returns "HTTP/1.1 407 Proxy Authentication Required"
at sun.net.www.protocol.http.HttpURLConnection.doTunneling(HttpURLConnection.java:1327)
at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnec
tion.java:168)
at sun.net.www.protocol.http.HttpURLConnection.getOutputStream(HttpURLConnection.java:839)
at sun.net.www.protocol.https.HttpsURLConnectionImpl.getOutputStream(HttpsURLConnectionImpl.java:230)
at org.jboss.remoting.transport.http.HTTPClientInvoker.useHttpURLConnection(HTTPClientInvoker.java:163)
at org.jboss.remoting.transport.http.HTTPClientInvoker.transport(HTTPClientInvoker.java:81)
at org.jboss.remoting.RemoteClientInvoker.invoke(RemoteClientInvoker.java:143)
at org.jboss.remoting.Client.invoke(Client.java:525)
at org.jboss.remoting.Client.invoke(Client.java:488)
at org.jboss.ws.soap.SOAPConnectionImpl.call(SOAPConnectionImpl.java:189)
at org.jboss.ws.jaxrpc.CallImpl.invokeInternal(CallImpl.java:687)
at org.jboss.ws.jaxrpc.CallImpl.invoke(CallImpl.java:404)
at org.jboss.ws.jaxrpc.CallProxy.invoke(CallProxy.java:148)
at $Proxy105.SSEKService(Unknown Source)


If i do a snoop on this network activity, i can see the proxy trying to get some authentication from my outgoing call, but it doesnt provide it. Now i seams to using the proxy part from jdk5 according to the stack (and by looking in the jdk-source).

Any suggestions on correct way to specify the host, user and password?

Thanks in advance :) /Fredrik

  • 1. Re: SSL calls thru a proxy with authentication?
    Matt Carless Newbie

    I would also like to know how to connect jboss through a proxy that requires authentication.

    I have tried

     

    java.net.Authenticator.setDefault(new ProxyAuthenticator("user", "pass"));
               System.setProperty("http.proxySet", "true");
               System.setProperty("http.proxyHost", "proxy"); 
               System.setProperty("http.proxyPort", "8080");

     

    with  this authenticator

    import java.net.PasswordAuthentication;

     

    public class ProxyAuthenticator extends java.net.Authenticator{

     

          private String user, password; 
          
             public ProxyAuthenticator(String user, String password) { 
                 this.user = user; 
                 this.password = password; 
             } 
          
             protected PasswordAuthentication getPasswordAuthentication() { 
                 return new PasswordAuthentication(user, password.toCharArray()); 
             } 
    }

     

    and I receoive a HTTP 407 proxyauthentication error.

     

    The reason I need to do this is to access an external webservice from within a jboss app.

  • 2. Re: SSL calls thru a proxy with authentication?
    Matt Carless Newbie

    After many painful hours of trying various things I finally have the answer.

     

    The following is the only way I could get proxy authentication working via aweb service using jboss 5.1.0.GA.

     

    First upgrade your jbossws to jbossws-cxf-3.3.1.GA(latest version as of writing) from (http://www.jboss.org/jbossws/downloads.html). It's a simple task make sure you have apache ant installed as you will need it to install this update into jboss.

    To upgrage download and unpack the zip file

     

    Follow the instuctions in the doc folder, basically it's set the home folder of your jboss app in the ant.properties file and run ant deploy-jboss510

     

    You should be able to run ant test to test your installation (Don't forget to start your server first).

     

    Now jboss should be in good shape to handle proxies for web service clients

     

    You will need to create a proxySelector

     

    Register the proxySelector

     

    Add some proxy-Authentication to the header of the web service request and your done.

     

    Here's an example proxy selector. This has been taken from the JDK5 documetation. Change the proxy address to yours.

     

    package com.fugrodata.webservices.session;

     

    import java.net.*;
    import java.util.ArrayList;
    import java.util.HashMap;
    import java.io.IOException;

     

    public class MyProxySelector extends ProxySelector {
        // Keep a reference on the previous default
        ProxySelector defsel = null;
       
        /*
         * Inner class representing a Proxy and a few extra data
         */
        class InnerProxy {
            Proxy proxy;
            SocketAddress addr;
            // How many times did we fail to reach this proxy?
            int failedCount = 0;
           
            InnerProxy(InetSocketAddress a) {
                addr = a;
                proxy = new Proxy(Proxy.Type.HTTP, a);
            }
           
            SocketAddress address() {
                return addr;
            }
           
            Proxy toProxy() {
                return proxy;
            }
           
            int failed() {
                return ++failedCount;
            }
        }
       
        /*
         * A list of proxies, indexed by their address.
         */
        HashMap<SocketAddress, InnerProxy> proxies = new HashMap<SocketAddress, InnerProxy>();

     

        MyProxySelector(ProxySelector def) {
          // Save the previous default
          defsel = def;
         
          // Populate the HashMap (List of proxies)
          InnerProxy i = new InnerProxy(new InetSocketAddress("proxy", 8080));
          proxies.put(i.address(), i);
          //i = new InnerProxy(new InetSocketAddress("webcache2.mydomain.com", 8080));
          //proxies.put(i.address(), i);
          //i = new InnerProxy(new InetSocketAddress("webcache3.mydomain.com", 8080));
          //proxies.put(i.address(), i);
          }
         
          /*
           * This is the method that the handlers will call.
           * Returns a List of proxy.
           */
          public java.util.List<Proxy> select(URI uri) {
            // Let's stick to the specs.
            if (uri == null) {
                throw new IllegalArgumentException("URI can't be null.");
            }
           
           
           
            /*
             * If it's a http (or https) URL, then we use our own
             * list.
             */
            String protocol = uri.getScheme();
            if ("http".equalsIgnoreCase(protocol) ||
                "https".equalsIgnoreCase(protocol)) {
                ArrayList<Proxy> l = new ArrayList<Proxy>();
                for (InnerProxy p : proxies.values()) {
                  l.add(p.toProxy());
                }
                return l;
            }
           
            /*
             * Not HTTP or HTTPS (could be SOCKS or FTP)
             * defer to the default selector.
             */
            if (defsel != null) {
                return defsel.select(uri);
            } else {
                ArrayList<Proxy> l = new ArrayList<Proxy>();
                l.add(Proxy.NO_PROXY);
                return l;
            }
        }
       
        /*
         * Method called by the handlers when it failed to connect
         * to one of the proxies returned by select().
         */
        public void connectFailed(URI uri, SocketAddress sa, IOException ioe) {
            // Let's stick to the specs again.
            if (uri == null || sa == null || ioe == null) {
                throw new IllegalArgumentException("Arguments can't be null.");
            }
           
            /*
             * Let's lookup for the proxy
             */
            InnerProxy p = proxies.get(sa);
                if (p != null) {
                    /*
                     * It's one of ours, if it failed more than 3 times
                     * let's remove it from the list.
                     */
                    if (p.failed() >= 3)
                        proxies.remove(sa);
                } else {
                    /*
                     * Not one of ours, let's delegate to the default.
                     */
                    if (defsel != null)
                      defsel.connectFailed(uri, sa, ioe);
                }
         }
    }

     

     

     

    Register the proxy above using this code

     

    MyProxySelector ps = new MyProxySelector(ProxySelector.getDefault());

    ProxySelector.setDefault(ps);

     

    Your jvm will start to use the proxy selector from this point forward. Now to add the authentication for the webservice request to authenticate against the proxy. The Proxy-Authorization header is added manually to the web service request. This is done on the webservice classes, here's an example.

     

               Service service = new Service();
               ServiceOperations portType = service.getService();
               
         
               
             Map<String,  List<String>> map2 = (Map<String,  List<String>>) ((BindingProvider) portType).getRequestContext().get(MessageContext.HTTP_REQUEST_HEADERS);
             Map<String, List<String>> map = map2;
             if (map == null)
                 map = new HashMap<String, List<String>>();
           
             map.put("Proxy-Authorization", Collections.singletonList(
                     "Basic " +  Base64.encodeBytes(("username:password").getBytes())));
           
             System.out.println("Adding to HttpRequestHeaders [map="+map+"]  ...");
             ((BindingProvider) portType).getRequestContext().put(MessageContext.HTTP_REQUEST_HEADERS,  map);
                  
    ///        portType.webserviceMethod(...);

     

     

    Change the username and password to suit your proxy in the code above.

     

    Job done!

  • 3. Re: SSL calls thru a proxy with authentication?
    Matt Carless Newbie

    The above post doesn't work through SSL because the headers get encrypted. However after upgrading the webservice stack(included in the above post), the Authenticator function works.

     

    So, add an authenticator

     

    import java.net.PasswordAuthentication;

     

    public class ProxyAuthenticator extends java.net.Authenticator{

     

          private String user, password; 
          
             public ProxyAuthenticator(String user, String password) { 
                 this.user = user; 
                 this.password = password; 
             } 
          
             protected PasswordAuthentication getPasswordAuthentication() { 
                 return new PasswordAuthentication(user, password.toCharArray()); 
             } 
    }

     

    Then set the user name and password in your app, it will be applied to your JRE session

    Authenticator.setDefault(new ProxyAuthenticator("user", "pass" ));

     

    and it now works through SSL