Issues with proxy using basic authentication

I am trying to get gradle running behind a proxy server. However, the connection for resolving dependencies is unsuccessful, even after setting systemProp.http.proxyHost, proxyPort, proxyUser and proxyPassword (and the same for https) in ~/.gradle/gradle.properties.

The system is Ubuntu 14.04 and I tried both gradle 1.4 from the repository as well as gradle 2.10 downloaded from the website. The test case is a very simple test project using the plugin ‘checkstyle’. When running gradle :check, the download of checkstyle from the default maven repository fails.

From the debug output, it seems that the problem is very similar to this old issue. Gradle (or rather the org.apache.http library) tries three different authentication methods (NEGOTIATE, NTLM, BASIC). While it should use BASIC for this proxy server, it first tries NEGOTIATE (which fails) and NTLM. For NTLM, it gets a 500 error response but interprets that as successful authentication and proceeds. The download of the dependencies then fails with a 500 error too.

It seems like the issue could be fixed by allowing to set the authentication scheme or by detecting the failure of the NTLM authentication.

If there is anything I can do to fix this issue or provide further information, please let me know.

Strange the proxy returns a 500, that seems incorrect. It should return a 407. HttpClient simply isn’t configured to interpret a 500 response code as an authentication challenge (and I don’t believe it should). That said, you actually can explicitly configuration authentication schemes.

repositories {
    maven {
        url 'https://repo.mycompany.com/maven2'
        credentials {
            username 'user'
            password 'password'
        }
        authentication {
            basic(BasicAuthentication)
        }
    }
}

I wasn’t aware that JIRA existed, I think we can mark it as fixed now :slight_smile:

Actually I recant my previous response as that only applies to authenticating to repositories. That does not affect proxy authentication. There’s no workaround for this at the moment aside from possibly investigating why the proxy is incorrectly returning a 500.

I have looked at the problem some more and something is really weird. I wrote a little test program that uses the Apache HTTP libraries from the gradle/lib folder to connect to an URL through the proxy and it works fine, even with NTLM and no matter what the domain and workstation strings are set to. I have then compared the HTTP headers of the request sent from my test program and from gradle.

Using the Proxy-Authorization header from gradle and the simple test program (with empty domain & workstation in both cases), I can replicate the problem on the command line with curl, as shown in this gist. I agree that the proxy should not return a 500, but could it be possible that gradle does something strange with the NTLM header?

This is the code of the test program:

 public class ProxyTest {
    public static void main(String[] args) throws IOException {

        NTCredentials ntcredentials = new NTCredentials("%USER%","%PASSWORD%","","");

        CredentialsProvider credProvider = new BasicCredentialsProvider();
        credProvider.setCredentials(AuthScope.ANY, ntcredentials);
        HttpClient client = HttpClients.custom().setDefaultCredentialsProvider(credProvider).build();

        HttpHost proxy = new HttpHost("%PROXY%", 8080);
        RequestConfig config = RequestConfig.custom().setProxy(proxy).build();

        HttpGet get = new HttpGet("http://repo1.maven.org/maven2/com/puppycrawl/tools/checkstyle/5.6/checkstyle-5.6.pom");
        get.setConfig(config);
        HttpResponse response = client.execute(get);
        String headers = Arrays.toString(response.getAllHeaders());
        System.out.println(headers);
    }
}

It’s worth noting that Gradle uses the JCIFS library implementation for NTLM authentication rather then the one bundled with Apache HttpClient. There might be a subtle difference in default configurations. The relevant code can be found here:

Thanks for the pointer! With this, I have been able to narrow down the problem to the “Negotiate NTLM2 Key” flag: When it is set, the connection works, when it isn’t set, I get the 500 response.

working: TlRMTVNTUAABAAAAAQIIAA==
failing: TlRMTVNTUAABAAAAAQIAAA==

I suppose there is no way of getting gradle to set this flag, other than changing the code?

There’s no way for the user to configure this. Perhaps this is something that could be configured on the proxy side to support NTLM auth. It seems the proxy is requiring session auth.

Looks like there is a difference in the NTLM code in Gradle compared to where it was originally copied from. The original code does special handling for the flags. I wonder why this is missing from Gradle.

I’m not certain what the original intention was other than perhaps thinking going with the default flags was a good starting point. I’m also no sure what this would mean from a compatibility standpoint to change this. Making this configurable seems like it would be a good idea, perhaps by exposing some system properties.

I’m pretty sure the code in Gradle is a direct copy of http://hc.apache.org/httpcomponents-client-ga/ntlm.html as it was published at the time (HTTP Client 4.1.2). There’s no reason that we shouldn’t update it to the current published version, except that we don’t have sufficient test coverage for NTML so we might break something.