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