Running Gradle through an NTLM proxy

I have read Gradle’s documentation (here and here) as well as previous forum threads (here, here, here, here, here, and here) about using Gradle with NTLM proxies. Maven users have reported success (here and here) by simply dropping in wagon-http-lightweight which I suspect works because lightweight is the default.

Collecting solutions from numerous places, I tried setting in gradle.properties:

systemProp.http.auth.ntlm.domain
systemProp.http.auth.ntlm.workstation
systemProp.http.connection.stalecheck=true
systemProp.http.keepAlive=true
systemProp.http.nonProxyHosts=*.example.com|localhost
systemProp.http.proxyHost
systemProp.http.proxyPassword
systemProp.http.proxyPort
systemProp.http.proxyUser
systemProp.http.socket.timeout=0
systemProp.proxySet=true

…along with their https equivalents. Not only does Gradle fail to resolve dependencies, but my account becomes locked.

Asking users to write their plain text password to a properties file or asking users to install and configure proxy-proxies such as CNTLM and NTLMAPS are not acceptable workarounds in a secure professional environment.

Is anyone actively committed to making Gradle work with NTLM proxies? I’d dislike having to switch to Maven just because of proxy support. If HttpClient is part of the solution, might be time to update from version 4.2.2 released more than 3 years ago.

These should be the only required system properties (or the https equivalents). That said, for NTLM you must supply a password, no integration with native Windows credentials exists. We have updated to HttpClient 4.4.1 in master but NTLM authentication support hasn’t changed.

I’ve seen multiple threads where people report needing http.keepAlive. Perhaps this is no longer true then. Keep in mind that I’m using latest Gradle release, 2.9, still with HttpClient 4.2.2, not master.

Is there any plan for this? Can this be accomplished with JCIFS or Waffle?

One of the earlier forum threads mentioned that his credentials specified via properties didn’t appear to be passed correctly. Such a bug would explain why my account becomes locked when I’m positive that my username with domain and password are correct. Any idea how to confirm?

Perhaps in older version. We now force this property to true so there’s no need to set it. In master we ignore its value altogether.

Perhaps. HttpClient 4.4.x also added support for this although they claim it’s unstable so we are hesitant to use it. We already use JCIFS internally for the existing NTLM support so we could potentially use it for detecting credentials if that’s something it supports. The troublesome part comes with testing this.

I’m not aware of any reason why the credentials wouldn’t get passed correctly. Try running your build with --debug. You should see some logging statements like Using Credentials [username: foo] ....

HttpClient currently appears caught up with a defect in JNA (HTTPCLIENT-1598, -1561, JNA-381). I wrote something that worked over 2 years ago with HttpClient 4.3 and could send code snippets.

JCIFS redirects to a closed-source solution, Jespa for NTLM SSO.

Java SE 7 and later natively supports SSO (see last section). I’d be glad to test changes to Gradle if you can make them.

What appears in the logs is correct, though password is omitted. Here’s what I get:

[org.apache.http.impl.client.SystemDefaultHttpClient] Selected authentication options: [NEGOTIATE, NTLM, BASIC]
[org.apache.http.impl.conn.DefaultClientConnection] Connection 0.0.0.0:51933<->x.y.z.w:80 closed
[org.apache.http.impl.conn.DefaultClientConnectionOperator] Connecting to proxy.example.com:80
[org.apache.http.client.protocol.RequestAuthCache] Auth cache not set in the context
[org.apache.http.client.protocol.RequestProxyAuthentication] Proxy auth state: CHALLENGED
[org.apache.http.client.protocol.RequestProxyAuthentication] Generating response to an authentication challenge using Negotiate scheme
[org.apache.http.impl.auth.SPNegoScheme] init proxy.example.com:80
[org.apache.http.client.protocol.RequestProxyAuthentication] NEGOTIATE authentication error: No valid credentials provided (Mechanism level: No valid credentials provided (Mechanism level: Failed to find any Kerberos tgt))
[org.apache.http.client.protocol.RequestProxyAuthentication] Generating response to an authentication challenge using ntlm scheme
[org.apache.http.impl.conn.DefaultClientConnection] Sending request: CONNECT maven.eveoh.nl:443 HTTP/1.1
[org.apache.http.impl.conn.DefaultClientConnection] Receiving response: HTTP/1.0 407 Proxy Authentication Required

Nothing in the log stands out to me. Looks like it’s correctly attempting NTLM auth against the proxy. Perhaps try using the lastest nightly which uses HttpClient 4.4.1 and see if that behaves differently.

You might also be running into GRADLE-2233.

I’ve also opened GRADLE-3372 to address lack of support for native Windows credentials.

Also unsuccessful. I know the credentials are good because I use them with RDC, VPN, CNTLM. The debug output appears less helpful: I see protocols and cipher suites but no warnings or exceptions before:

[org.gradle.BuildExceptionReporter] > Could not resolve all dependencies for configuration ‘:classpath’.
[org.gradle.BuildExceptionReporter] > Could not resolve org.jfrog.buildinfo:build-info-extractor-gradle:3.1.2.
[org.gradle.BuildExceptionReporter] Required by:
[org.gradle.BuildExceptionReporter] :cabaret:unspecified
[org.gradle.BuildExceptionReporter] > Could not resolve org.jfrog.buildinfo:build-info-extractor-gradle:3.1.2.
[org.gradle.BuildExceptionReporter] > Could not get resource ‘https://plugins.gradle.org/m2/org/jfrog/buildinfo/build-info-extractor-gradle/3.1.2/build-info-extractor-gradle-3.1.2.pom’.
[org.gradle.BuildExceptionReporter] > Could not HEAD ‘https://plugins.gradle.org/m2/org/jfrog/buildinfo/build-info-extractor-gradle/3.1.2/build-info-extractor-gradle-3.1.2.pom’.
[org.gradle.BuildExceptionReporter] > Unrecognized SSL message, plaintext connection?

“Unrecognized SSL message, plaintext connection” is peculiar. May or may not be significant that plugins.gradle.org appears to redirect to amazonaws.com (when I browse the pom).

Thanks! I hope someone will use the references above if necessary to save users from writing their clear text passwords to gradle.properties.

Does using the nightly also lock out your account? The lockout bit makes me think we are sending the credentials, or at least the username since it’s successfully associating the authentication attempt with your account. Perhaps if you have access to the proxy logs they might divulge some information.

No lockout with the nightly. I think you are right that at least my username and domain have been provided correctly if I was locked out. I’m seeing a 5 minute gap here:

00:11:49.460 [DEBUG] [org.apache.http.conn.ssl.SSLConnectionSocketFactory] Starting handshake
00:16:48.800 [DEBUG] [org.apache.http.impl.conn.DefaultManagedHttpClientConnection] http-outgoing-11: Shutdown connection
00:16:48.801 [DEBUG] [org.apache.http.impl.execchain.MainClientExec] Connection discarded
00:16:48.801 [DEBUG] [org.apache.http.impl.conn.DefaultManagedHttpClientConnection] http-outgoing-11: Close connection

Are you using an SSL proxy? In the log above it mentions port 80 for the proxy but not sure if that was just an example.

All protocols go through the same port on the same proxy server. That’s how Internet Explorer and Eclipse are configured and work for me.

The Gradle source code references HttpClient’s suggested usage of JCIFS for NTLM. However, the Gradle source code uses the default flags instead of the suggested flags. Is this intentional?

Perhaps, if for no other reason then we don’t have test coverage for every NTLM authentication method. Particularly NTLMv2 Session Security which is effectively disabled with the default flags we are using. Perhaps your proxy requires this, which would explain the failure.

I verified that the native Java SE Spnego SSO implementation works with Windows authentication (no credentials specified) by writing login.conf and krb5.conf (copied from a Linux machine in our domain) to my project directory and by writing the following into ~/.gradle/init.d/*.properties:

// http://docs.oracle.com/javase/7/docs/technotes/guides/net/http-auth.html
apply plugin: EnableSpnegoSSO

class EnableSpnegoSSO implements Plugin {
void apply(Gradle gradle) {
System.setProperty(‘http.nonProxyHosts’, ‘.example.com|localhost’)
System.setProperty(‘http.proxyHost’, ‘proxy.example.com’)
System.setProperty(‘http.proxyPort’, ‘80’)
System.setProperty(‘https.nonProxyHosts’, '
.example.com|localhost’)
System.setProperty(‘https.proxyHost’, ‘proxy.example.com’)
System.setProperty(‘https.proxyPort’, ‘80’)
System.setProperty(‘java.security.auth.login.conf’, ‘login.conf’)
System.setProperty(‘java.security.krb5.conf’, ‘krb5.conf’)
System.setProperty(‘javax.security.auth.userSubjectCredsOnly’, ‘false’)
URL url = new URL(“https://plugins.gradle.org/m2/org/jfrog/buildinfo/build-info-extractor-gradle/3.2.0/build-info-extractor-gradle-3.2.0.pom”);
InputStream ins = url.openConnection().getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(ins));
String str;
while((str = reader.readLine()) != null)
System.out.println(str);
}
}

I see the contents of the POM printed. This does not help connections created by Gradle with HttpClient, i.e. the buildscript plugins still fail to download.

So how much work to drop HttpClient in Gradle? Or need I download all the dependencies into Gradle’s cache in my init script, lol?

If your proxy is using SPNEGO+Kerberos then you should be able to leverage Kerberos auth. You’ll still need to supply http.proxyUser and http.proxyPassword (they’ll be ignored) for us to configuration proxy authentication but I see no reason why Kerberos auth wouldn’t work.

Same result as before with no credentials or incorrect credentials. Dependencies were successfully downloaded when I specified my correct credentials, but then my account was locked out afterwards. :frowning:

This is interesting. So If I understand correctly, it actually did successfully authenticate (since you were able to access the repository behind the proxy) but it ended up locking out your account anyhow?

Yeah. But this may be complicated by other factors: accessing Artifactory through the proxy. I get 401 Unauthorized using my encrypted API key. I get through when I use my clear text password instead. With krb5.conf, login.conf, userSubjectCredsOnly=false, and clear text passwords for both NTLM proxy and Artifactory, I appear to download dependencies and build successfully without lockout.

I hope that Gradle will switch to the native Java SE approach in an upcoming release to avoid my domain clear text password. As for 401 from Artifactory, I’m not yet sure who to blame. Maybe JFrog’s plugin?

I’m not sure. I typically recommend avoiding the Artifactory plugin as it’s really just an abstraction on top of Gradle’s existing functionality. I prefer to simply configure my repositories via the Gradle DSL, although I understand how the Artifactory plugin is a bit more convenient (configurations repositories and publishing in one step).

Not sure how Artifactory expects to receive the API key. I imagine it’s just using basic or digest auth under the hood?