Uploaded image for project: 'MINA'
  1. MINA
  2. DIRMINA-844

Http Proxy Authentication failed to complete (see description for exact point of failure)

    Details

    • Type: Bug
    • Status: Open
    • Priority: Major
    • Resolution: Unresolved
    • Affects Version/s: 2.0.3
    • Fix Version/s: 2.0.8
    • Component/s: Core
    • Labels:
      None
    • Environment:
      Mac OS X 10.6.8
      JDK 1.6
      squid/2.6
      Eclipse

      Description

      When trying to connect through an Squid Http Proxy using ProxyConnector (requiring basic authentication). While debugging issue, I walked through MINA code. Following are my observations:
      1. First attempt made by MINA do not send any authentication details even though property set, seems like its to get first response mentioning authentication method.
      2. So a second connection is initiated from ProxyConnector and this time request contains the authentication header.

      ISSUE: My client kept waiting at this point and it seems that second connection never got completed. I used eclipse debugger and found that AbstractPollingIoConnector.connect0 method is getting called with proper destination (As I used a NioSocketConnector to construct ProxyConnector) but after that no progress.

      Also at Line#343 following were the content of request variable (I wonder if this could be of help )

      request AbstractPollingIoConnector$ConnectionRequest (id=82)
      deadline 1310717009666
      firstListener null
      handle SocketChannelImpl (id=88)
      lock AbstractPollingIoConnector$ConnectionRequest (id=82)
      otherListeners null
      ready false
      result null
      session null
      sessionInitializer ProxyIoSessionInitializer<T> (id=104)
      this$0 NioSocketConnector (id=40)
      waiters 0

        Issue Links

          Activity

          Hide
          asilvestrer Antonio Silvestre added a comment - - edited

          I had got the same issue. The problem is an error design into the handshake process with an http authentication required proxy. When we try to connect to the proxy for the first time, we don't send any authentication header, so we receive a 407 code response, and from the "Proxy-Authenticate" header we get the required authentication method and set the corresponding AuthHandler class.

          The first error is in class "org.apache.mina.proxy.handlers.http.AbstractHttpLogicHandler", method "", line 377:

          AbstractHttpLogicHandler.java
              protected HttpProxyResponse decodeResponse(final String response) throws Exception {
                  LOGGER.debug("  parseResponse()");
          
                  // Break response into lines
                  String[] responseLines = response.split(HttpProxyConstants.CRLF);
          
                  // Status-Line = HTTP-Version SP Status-Code SP Reason-Phrase CRLF
                  // BUG FIX : Trimed to prevent failures with some proxies that add 
                  // extra space chars like "Microsoft-IIS/5.0" ...
                  String[] statusLine = responseLines[0].trim().split(" ", 2);
          
                  if (statusLine.length < 2) {
                      throw new Exception("Invalid response status line (" + statusLine + "). Response: " + response);
                  }
          
                  // Status code is 3 digits
                  if (!statusLine[1].matches("^\\d\\d\\d")) {
                      throw new Exception("Invalid response code (" + statusLine[1] + "). Response: " + response);
                  }
          
                  Map<String, List<String>> headers = new HashMap<String, List<String>>();
          
                  for (int i = 1; i < responseLines.length; i++) {
                      String[] args = responseLines[i].split(":\\s?", 2);
                      StringUtilities.addValueToHeader(headers, args[0], args[1], false);
                  }
          
                  return new HttpProxyResponse(statusLine[0], statusLine[1], headers);
              }
          

          The value "statusLine[1]" is expected to be a string starting with the http returned code (in this case 407) followed by a space and the corresponding message added by the server (as we're splitting the full status line into only 2 strings). Here you are an example taken from my company proxy:

          407 Proxy Authentication Required

          the regular expression to match

          "^\\d\\d\\d"

          is expecting only the ciphers, not the text, so I've changed this regular expression to add any followed text:

          "^\\d\\d\\d.*".

          The HttpProxyResponse constructor gets the substring from the first 3 chars and parses it to the integer return code, so the remaining text doesn't affect. Depending of how do you handle this exception, you may not see the error trace.

          After correcting this error, instead of throwing the exception the code goes on and it tries to reconnect to the proxy, creating a new session and rebuilding the http request to add the corresponding authentication headers to it, but here there's another problem... The process never launch the second http request, as the "operationComplete" callback defined into the "reconnect" method, line 342 is never called:

          AbstractHttpLogicHandler.java
              private void reconnect(final NextFilter nextFilter, final HttpProxyRequest request) {
                  LOGGER.debug("Reconnecting to proxy ...");
          
                  final ProxyIoSession proxyIoSession = getProxyIoSession();
          
                  // Fires reconnection
                  proxyIoSession.getConnector().connect(new IoSessionInitializer<ConnectFuture>() {
                      public void initializeSession(final IoSession session, ConnectFuture future) {
                          LOGGER.debug("Initializing new session: {}", session);
                          session.setAttribute(ProxyIoSession.PROXY_SESSION, proxyIoSession);
                          proxyIoSession.setSession(session);
                          LOGGER.debug("  setting up proxyIoSession: {}", proxyIoSession);
                          future.addListener(new IoFutureListener<ConnectFuture>() {
                              public void operationComplete(ConnectFuture future) {
                                  // Reconnection is done so we send the
                                  // request to the proxy
                                  proxyIoSession.setReconnectionNeeded(false);
                                  writeRequest0(nextFilter, request);
                              }
                          });
                      }
                  });
              }
          

          The operation is considered "completed" when the handshake phase is completed, but we're into this phase now, and we need to execute the request to complete it, so here we have a deadlock. As we haven't completed the handshake phase, we never call the "operationComplete" method and of course we never do the second http request with the right headers. To solve this problem we need to remove the custom IoFutureListener and put the inner code into the "initializeSession" callback directly.

          I'm going to make a pull request with this changes. They have been tested and they're working.

          Show
          asilvestrer Antonio Silvestre added a comment - - edited I had got the same issue. The problem is an error design into the handshake process with an http authentication required proxy. When we try to connect to the proxy for the first time, we don't send any authentication header, so we receive a 407 code response, and from the "Proxy-Authenticate" header we get the required authentication method and set the corresponding AuthHandler class. The first error is in class "org.apache.mina.proxy.handlers.http.AbstractHttpLogicHandler", method "", line 377: AbstractHttpLogicHandler.java protected HttpProxyResponse decodeResponse( final String response) throws Exception { LOGGER.debug( " parseResponse()" ); // Break response into lines String [] responseLines = response.split(HttpProxyConstants.CRLF); // Status-Line = HTTP-Version SP Status-Code SP Reason-Phrase CRLF // BUG FIX : Trimed to prevent failures with some proxies that add // extra space chars like "Microsoft-IIS/5.0" ... String [] statusLine = responseLines[0].trim().split( " " , 2); if (statusLine.length < 2) { throw new Exception( "Invalid response status line (" + statusLine + "). Response: " + response); } // Status code is 3 digits if (!statusLine[1].matches( "^\\d\\d\\d" )) { throw new Exception( "Invalid response code (" + statusLine[1] + "). Response: " + response); } Map< String , List< String >> headers = new HashMap< String , List< String >>(); for ( int i = 1; i < responseLines.length; i++) { String [] args = responseLines[i].split( ":\\s?" , 2); StringUtilities.addValueToHeader(headers, args[0], args[1], false ); } return new HttpProxyResponse(statusLine[0], statusLine[1], headers); } The value "statusLine [1] " is expected to be a string starting with the http returned code (in this case 407) followed by a space and the corresponding message added by the server (as we're splitting the full status line into only 2 strings). Here you are an example taken from my company proxy: 407 Proxy Authentication Required the regular expression to match "^\\d\\d\\d" is expecting only the ciphers, not the text, so I've changed this regular expression to add any followed text: "^\\d\\d\\d.*". The HttpProxyResponse constructor gets the substring from the first 3 chars and parses it to the integer return code, so the remaining text doesn't affect. Depending of how do you handle this exception, you may not see the error trace. After correcting this error, instead of throwing the exception the code goes on and it tries to reconnect to the proxy, creating a new session and rebuilding the http request to add the corresponding authentication headers to it, but here there's another problem... The process never launch the second http request, as the "operationComplete" callback defined into the "reconnect" method, line 342 is never called: AbstractHttpLogicHandler.java private void reconnect( final NextFilter nextFilter, final HttpProxyRequest request) { LOGGER.debug( "Reconnecting to proxy ..." ); final ProxyIoSession proxyIoSession = getProxyIoSession(); // Fires reconnection proxyIoSession.getConnector().connect( new IoSessionInitializer<ConnectFuture>() { public void initializeSession( final IoSession session, ConnectFuture future ) { LOGGER.debug( "Initializing new session: {}" , session); session.setAttribute(ProxyIoSession.PROXY_SESSION, proxyIoSession); proxyIoSession.setSession(session); LOGGER.debug( " setting up proxyIoSession: {}" , proxyIoSession); future .addListener( new IoFutureListener<ConnectFuture>() { public void operationComplete(ConnectFuture future ) { // Reconnection is done so we send the // request to the proxy proxyIoSession.setReconnectionNeeded( false ); writeRequest0(nextFilter, request); } }); } }); } The operation is considered "completed" when the handshake phase is completed, but we're into this phase now, and we need to execute the request to complete it, so here we have a deadlock. As we haven't completed the handshake phase, we never call the "operationComplete" method and of course we never do the second http request with the right headers. To solve this problem we need to remove the custom IoFutureListener and put the inner code into the "initializeSession" callback directly. I'm going to make a pull request with this changes. They have been tested and they're working.
          Hide
          githubbot ASF GitHub Bot added a comment -

          GitHub user asilvestrer opened a pull request:

          https://github.com/apache/mina/pull/8

          FIX DIRMINA-844 Http Proxy Authentication failed to complete

          See comment in https://issues.apache.org/jira/browse/DIRMINA-844

          You can merge this pull request into a Git repository by running:

          $ git pull https://github.com/asilvestrer/mina 2.0

          Alternatively you can review and apply these changes as the patch at:

          https://github.com/apache/mina/pull/8.patch

          To close this pull request, make a commit to your master/trunk branch
          with (at least) the following in the commit message:

          This closes #8


          commit a752a6dec1e54a1583a76693bfc953bbe75fe926
          Author: Antonio Silvestre <asilvestre.r@gmail.com>
          Date: 2016-05-18T13:49:42Z

          FIX DIRMINA-844 Http Proxy Authentication failed to complete (see description for exact point of failure)


          Show
          githubbot ASF GitHub Bot added a comment - GitHub user asilvestrer opened a pull request: https://github.com/apache/mina/pull/8 FIX DIRMINA-844 Http Proxy Authentication failed to complete See comment in https://issues.apache.org/jira/browse/DIRMINA-844 You can merge this pull request into a Git repository by running: $ git pull https://github.com/asilvestrer/mina 2.0 Alternatively you can review and apply these changes as the patch at: https://github.com/apache/mina/pull/8.patch To close this pull request, make a commit to your master/trunk branch with (at least) the following in the commit message: This closes #8 commit a752a6dec1e54a1583a76693bfc953bbe75fe926 Author: Antonio Silvestre <asilvestre.r@gmail.com> Date: 2016-05-18T13:49:42Z FIX DIRMINA-844 Http Proxy Authentication failed to complete (see description for exact point of failure)

            People

            • Assignee:
              Unassigned
              Reporter:
              bansalparijat Parijat Bansal
            • Votes:
              1 Vote for this issue
              Watchers:
              4 Start watching this issue

              Dates

              • Created:
                Updated:

                Development