[GRADLE-2191] HTTP Digest authentication doesn't work since changing to apache httpclient due to use of preemptive auth defaulting to Basic Created: 21/Mar/12  Updated: 04/Jan/13  Resolved: 02/Jul/12

Status: Resolved
Project: Gradle
Affects Version/s: 1.0-milestone-7, 1.0-milestone-8, 1.0-milestone-9
Fix Version/s: 1.1-rc-1

Type: Bug
Reporter: James Wiltshire Assignee: Unassigned
Resolution: Fixed Votes: 0


 Description   

Accessing a Maven repository that uses HTTP authentication that is configured to use Digest access authentication fails using gradle 1.0m7+ (since the change to using Apache httpclient).

This is due to org.gradle.api.internal.artifacts.repositories.transport.http.HttpClientConfigurer class which has the following method:

public void configureMethod(HttpRequest method) {
method.addHeader("User-Agent", "Gradle/" + GradleVersion.current().getVersion());

// Do preemptive authentication for basic auth
if (repositoryCredentials != null) {
try

{ method.addHeader(new BasicScheme().authenticate(repositoryCredentials, method)); }

catch (AuthenticationException e)

{ throw UncheckedException.throwAsUncheckedException(e); }

}
}

The method.addHeader(..) call causes the Apache HTTPClient library to always use Basic authentication within the request headers, even when it has previously handled a request that specified that Digest authentication should be used.

Here are extracts from the debug log showing the broken exchange - note that on the second request/response even though HTTPClient has logged that "Digest authentication scheme selected" it still sends a HTTP Basic auth header...

2012/03/21 17:52:32:305 GMT [DEBUG] headers - >> GET /repositories/internal/mysql/mysql-connector-java/5.1.18/mysql-connector-java-5.1.18.pom.sha1 HTTP/1.1

2012/03/21 17:52:32:322 GMT [DEBUG] DefaultClientConnection - Receiving response: HTTP/1.1 401 Authorization Required
2012/03/21 17:52:32:322 GMT [DEBUG] headers - << HTTP/1.1 401 Authorization Required
2012/03/21 17:52:32:322 GMT [DEBUG] headers - << WWW-Authenticate: Digest realm="Maven", nonce="ZI30c8S7BAA=58c6defb83b605d09b1947b527d6d2b0a507f8db", algorithm=MD5, domain="http://foo.com https://foo.com", qop="auth"

2012/03/21 17:52:32:329 GMT [DEBUG] ContentEncodingHttpClient - Target requested authentication
2012/03/21 17:52:32:329 GMT [DEBUG] DefaultTargetAuthenticationHandler - Authentication schemes in the order of preference: [negotiate, NTLM, Digest, Basic]
2012/03/21 17:52:32:329 GMT [DEBUG] DefaultTargetAuthenticationHandler - Digest authentication scheme selected
2012/03/21 17:52:32:332 GMT [DEBUG] ContentEncodingHttpClient - Authorization challenge processed
2012/03/21 17:52:32:333 GMT [DEBUG] ContentEncodingHttpClient - Authentication scope: DIGEST 'Maven'@maven.spindriftgroup.com:443
2012/03/21 17:52:32:333 GMT [DEBUG] ContentEncodingHttpClient - Found credentials

2012/03/21 17:52:32:337 GMT [DEBUG] ContentEncodingHttpClient - Attempt 2 to execute request
2012/03/21 17:52:32:337 GMT [DEBUG] DefaultClientConnection - Sending request: GET /repositories/internal/mysql/mysql-connector-java/5.1.18/mysql-connector-java-5.1.18.pom.sha1 HTTP/1.1
2012/03/21 17:52:32:338 GMT [DEBUG] headers - >> GET /repositories/internal/mysql/mysql-connector-java/5.1.18/mysql-connector-java-5.1.18.pom.sha1 HTTP/1.1
2012/03/21 17:52:32:338 GMT [DEBUG] headers - >> Authorization: Basic bWF2ZW46ZDdwMDlsNTBETDZuM1Z0Sw==

2012/03/21 17:52:32:350 GMT [DEBUG] DefaultClientConnection - Receiving response: HTTP/1.1 401 Authorization Required

Contrast that with the debug logs of the Apache HTTPClient issuing a working request - the second request issues a Digest auth header...

2012/03/21 17:52:32:305 GMT [DEBUG] headers - >> GET /repositories/internal/mysql/mysql-connector-java/5.1.18/mysql-connector-java-5.1.18.pom.sha1 HTTP/1.1

2012/03/21 17:52:32:322 GMT [DEBUG] DefaultClientConnection - Receiving response: HTTP/1.1 401 Authorization Required
2012/03/21 17:52:32:322 GMT [DEBUG] headers - << HTTP/1.1 401 Authorization Required
2012/03/21 17:52:32:322 GMT [DEBUG] headers - << WWW-Authenticate: Digest realm="Maven", nonce="ZI30c8S7BAA=58c6defb83b605d09b1947b527d6d2b0a507f8db", algorithm=MD5, domain="http://foo.com https://foo.com", qop="auth"

2012/03/21 17:52:32:329 GMT [DEBUG] ContentEncodingHttpClient - Target requested authentication
2012/03/21 17:52:32:329 GMT [DEBUG] DefaultTargetAuthenticationHandler - Authentication schemes in the order of preference: [negotiate, NTLM, Digest, Basic]
2012/03/21 17:52:32:329 GMT [DEBUG] DefaultTargetAuthenticationHandler - Digest authentication scheme selected
2012/03/21 17:52:32:332 GMT [DEBUG] ContentEncodingHttpClient - Authorization challenge processed
2012/03/21 17:52:32:333 GMT [DEBUG] ContentEncodingHttpClient - Authentication scope: DIGEST 'Maven'@maven.spindriftgroup.com:443
2012/03/21 17:52:32:333 GMT [DEBUG] ContentEncodingHttpClient - Found credentials

2012/03/21 17:52:32:337 GMT [DEBUG] ContentEncodingHttpClient - Attempt 2 to execute request
2012/03/21 17:52:32:337 GMT [DEBUG] DefaultClientConnection - Sending request: GET /repositories/internal/mysql/mysql-connector-java/5.1.18/mysql-connector-java-5.1.18.pom.sha1 HTTP/1.1
2012/03/21 17:52:32:338 GMT [DEBUG] headers - >> GET /repositories/internal/mysql/mysql-connector-java/5.1.18/mysql-connector-java-5.1.18.pom.sha1 HTTP/1.1
2012/03/21 17:52:32:338 GMT [DEBUG] headers - >> Authorization: Digest username="maven", realm="Maven", nonce="ZI30c8S7BAA=58c6defb83b605d09b1947b527d6d2b0a507f8db", uri="/repositories/internal/mysql/mysql-connector-java/5.1.18/mysql-connector-java-5.1.18.pom.sha1", response="82304c3dcfeba53c64fe65b5ead59d82", qop=auth, nc=00000001, cnonce="ce96095ff398257e", algorithm="MD5"

2012/03/21 17:52:32:350 GMT [DEBUG] DefaultClientConnection - Receiving response: HTTP/1.1 200 OK

Removing the preemptive authentication blocks of code from HttpClientConfigurer resolves this issue. This has been tested with a locally build gradle.

The repository is configured correctly using the following:

repositories {
mavenLocal()
mavenCentral()
maven {
credentials

{ username 'maven' password 'secret' }

url "https://foo.com/repositories/internal"
}



 Comments   
Comment by James Wiltshire [ 21/Mar/12 ]

diff --git a/subprojects/core-impl/src/main/groovy/org/gradle/api/internal/artifacts/repositories/transport/http/HttpClientConfigurer.java b/subprojects/core-impl/src/main/groovy/org/gradle/api/internal/artifacts/repositories/transport/http/HttpClientConfigurer.java
index e3249a3..cccf59e 100644
— a/subprojects/core-impl/src/main/groovy/org/gradle/api/internal/artifacts/repositories/transport/http/HttpClientConfigurer.java
+++ b/subprojects/core-impl/src/main/groovy/org/gradle/api/internal/artifacts/repositories/transport/http/HttpClientConfigurer.java
@@ -102,14 +102,5 @@

public void configureMethod(HttpRequest method) {
method.addHeader("User-Agent", "Gradle/" + GradleVersion.current().getVersion());
-

  • // Do preemptive authentication for basic auth
  • if (repositoryCredentials != null) {
  • try { - method.addHeader(new BasicScheme().authenticate(repositoryCredentials, method)); - }

    catch (AuthenticationException e)

    { - throw UncheckedException.throwAsUncheckedException(e); - }
  • }
    }
    }
Comment by Daz DeBoer [ 23/Mar/12 ]

Just removing pre-emptive authentication isn't enough, since it was added specifically to deal with uploading to authenticated HTTP repositories. Without pre-emptive auth, we were sending the entire file, only to get a 401 response and having to send again.

Comment by Luke Daley [ 03/Apr/12 ]

http://forums.gradle.org/gradle/topics/maven_repo_digest_authentication_fails_in_m8_m8a_m9

Generated at Wed Jun 30 12:15:11 CDT 2021 using Jira 8.4.2#804003-sha1:d21414fc212e3af190e92c2d2ac41299b89402cf.