diff options
author | Thomas Wolf <thomas.wolf@paranor.ch> | 2020-12-02 23:07:01 +0100 |
---|---|---|
committer | Thomas Wolf <thomas.wolf@paranor.ch> | 2021-01-14 16:23:45 +0100 |
commit | 58f4e6e7f8d0f897c99fa1de5970928a826c5eb8 (patch) | |
tree | 93906422672e0d88378bf26dc0451f94f191c556 /org.eclipse.jgit.http.test | |
parent | 471ad49546eec8850dd7d00b8fc2b8b50e4a9446 (diff) | |
download | jgit-58f4e6e7f8d0f897c99fa1de5970928a826c5eb8.tar.gz jgit-58f4e6e7f8d0f897c99fa1de5970928a826c5eb8.zip |
TransportHttp: support preemptive Basic authentication
If the caller knows already HTTP Basic authentication will be needed
and if it also already has the username and password, preemptive
authentication is a little bit more efficient since it avoids the
initial 401 response.
Add a setPreemptiveBasicAuthentication(username, password) method
to TransportHttp. Client code could call this for instance in a
TransportConfigCallback. The method throws an IllegalStateException
if it is called after an HTTP request has already been made.
Additionally, a URI can include userinfo. Although it is not
recommended to put passwords in URIs, JGit's URIish and also the
Java URL and URI classes still allow it. The underlying HTTP
connection may omit these fields though. If present, take these
fields as additional source for preemptive Basic authentication if
setPreemptiveBasicAuthentication() has not been called.
No preemptive authentication will be done if the connection is
redirected to a different host.
Add tests.
Bug: 541327
Change-Id: Id00b975e56a15b532de96f7bbce48106d992a22b
Signed-off-by: Thomas Wolf <thomas.wolf@paranor.ch>
Diffstat (limited to 'org.eclipse.jgit.http.test')
-rw-r--r-- | org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/SmartClientSmartServerTest.java | 200 |
1 files changed, 179 insertions, 21 deletions
diff --git a/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/SmartClientSmartServerTest.java b/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/SmartClientSmartServerTest.java index 89a254184d..887e970a0c 100644 --- a/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/SmartClientSmartServerTest.java +++ b/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/SmartClientSmartServerTest.java @@ -936,26 +936,8 @@ public class SmartClientSmartServerTest extends AllProtocolsHttpTestCase { } } - @Test - public void testInitialClone_WithAuthentication() throws Exception { - try (Repository dst = createBareRepository(); - Transport t = Transport.open(dst, authURI)) { - assertFalse(dst.getObjectDatabase().has(A_txt)); - t.setCredentialsProvider(testCredentials); - t.fetch(NullProgressMonitor.INSTANCE, mirror(master)); - assertTrue(dst.getObjectDatabase().has(A_txt)); - assertEquals(B, dst.exactRef(master).getObjectId()); - fsck(dst, B); - } - - List<AccessEvent> requests = getRequests(); - assertEquals(enableProtocolV2 ? 4 : 3, requests.size()); - - AccessEvent info = requests.get(0); - assertEquals("GET", info.getMethod()); - assertEquals(401, info.getStatus()); - - info = requests.get(1); + private void assertFetchRequests(List<AccessEvent> requests, int index) { + AccessEvent info = requests.get(index++); assertEquals("GET", info.getMethod()); assertEquals(join(authURI, "info/refs"), info.getPath()); assertEquals(1, info.getParameters().size()); @@ -967,7 +949,7 @@ public class SmartClientSmartServerTest extends AllProtocolsHttpTestCase { assertEquals("gzip", info.getResponseHeader(HDR_CONTENT_ENCODING)); } - for (int i = 2; i < requests.size(); i++) { + for (int i = index; i < requests.size(); i++) { AccessEvent service = requests.get(i); assertEquals("POST", service.getMethod()); assertEquals(join(authURI, "git-upload-pack"), service.getPath()); @@ -984,6 +966,182 @@ public class SmartClientSmartServerTest extends AllProtocolsHttpTestCase { } @Test + public void testInitialClone_WithAuthentication() throws Exception { + try (Repository dst = createBareRepository(); + Transport t = Transport.open(dst, authURI)) { + assertFalse(dst.getObjectDatabase().has(A_txt)); + t.setCredentialsProvider(testCredentials); + t.fetch(NullProgressMonitor.INSTANCE, mirror(master)); + assertTrue(dst.getObjectDatabase().has(A_txt)); + assertEquals(B, dst.exactRef(master).getObjectId()); + fsck(dst, B); + } + + List<AccessEvent> requests = getRequests(); + assertEquals(enableProtocolV2 ? 4 : 3, requests.size()); + + AccessEvent info = requests.get(0); + assertEquals("GET", info.getMethod()); + assertEquals(401, info.getStatus()); + + assertFetchRequests(requests, 1); + } + + @Test + public void testInitialClone_WithPreAuthentication() throws Exception { + try (Repository dst = createBareRepository(); + Transport t = Transport.open(dst, authURI)) { + assertFalse(dst.getObjectDatabase().has(A_txt)); + ((TransportHttp) t).setPreemptiveBasicAuthentication( + AppServer.username, AppServer.password); + t.fetch(NullProgressMonitor.INSTANCE, mirror(master)); + assertTrue(dst.getObjectDatabase().has(A_txt)); + assertEquals(B, dst.exactRef(master).getObjectId()); + fsck(dst, B); + } + + List<AccessEvent> requests = getRequests(); + assertEquals(enableProtocolV2 ? 3 : 2, requests.size()); + + assertFetchRequests(requests, 0); + } + + @Test + public void testInitialClone_WithPreAuthenticationCleared() + throws Exception { + try (Repository dst = createBareRepository(); + Transport t = Transport.open(dst, authURI)) { + assertFalse(dst.getObjectDatabase().has(A_txt)); + ((TransportHttp) t).setPreemptiveBasicAuthentication( + AppServer.username, AppServer.password); + ((TransportHttp) t).setPreemptiveBasicAuthentication(null, null); + t.setCredentialsProvider(testCredentials); + t.fetch(NullProgressMonitor.INSTANCE, mirror(master)); + assertTrue(dst.getObjectDatabase().has(A_txt)); + assertEquals(B, dst.exactRef(master).getObjectId()); + fsck(dst, B); + } + + List<AccessEvent> requests = getRequests(); + assertEquals(enableProtocolV2 ? 4 : 3, requests.size()); + + AccessEvent info = requests.get(0); + assertEquals("GET", info.getMethod()); + assertEquals(401, info.getStatus()); + + assertFetchRequests(requests, 1); + } + + @Test + public void testInitialClone_PreAuthenticationTooLate() throws Exception { + try (Repository dst = createBareRepository(); + Transport t = Transport.open(dst, authURI)) { + assertFalse(dst.getObjectDatabase().has(A_txt)); + ((TransportHttp) t).setPreemptiveBasicAuthentication( + AppServer.username, AppServer.password); + t.fetch(NullProgressMonitor.INSTANCE, mirror(master)); + assertTrue(dst.getObjectDatabase().has(A_txt)); + assertEquals(B, dst.exactRef(master).getObjectId()); + fsck(dst, B); + List<AccessEvent> requests = getRequests(); + assertEquals(enableProtocolV2 ? 3 : 2, requests.size()); + assertFetchRequests(requests, 0); + assertThrows(IllegalStateException.class, + () -> ((TransportHttp) t).setPreemptiveBasicAuthentication( + AppServer.username, AppServer.password)); + assertThrows(IllegalStateException.class, () -> ((TransportHttp) t) + .setPreemptiveBasicAuthentication(null, null)); + } + } + + @Test + public void testInitialClone_WithWrongPreAuthenticationAndCredentialProvider() + throws Exception { + try (Repository dst = createBareRepository(); + Transport t = Transport.open(dst, authURI)) { + assertFalse(dst.getObjectDatabase().has(A_txt)); + ((TransportHttp) t).setPreemptiveBasicAuthentication( + AppServer.username, AppServer.password + 'x'); + t.setCredentialsProvider(testCredentials); + t.fetch(NullProgressMonitor.INSTANCE, mirror(master)); + assertTrue(dst.getObjectDatabase().has(A_txt)); + assertEquals(B, dst.exactRef(master).getObjectId()); + fsck(dst, B); + } + + List<AccessEvent> requests = getRequests(); + assertEquals(enableProtocolV2 ? 4 : 3, requests.size()); + + AccessEvent info = requests.get(0); + assertEquals("GET", info.getMethod()); + assertEquals(401, info.getStatus()); + + assertFetchRequests(requests, 1); + } + + @Test + public void testInitialClone_WithWrongPreAuthentication() throws Exception { + try (Repository dst = createBareRepository(); + Transport t = Transport.open(dst, authURI)) { + assertFalse(dst.getObjectDatabase().has(A_txt)); + ((TransportHttp) t).setPreemptiveBasicAuthentication( + AppServer.username, AppServer.password + 'x'); + TransportException e = assertThrows(TransportException.class, + () -> t.fetch(NullProgressMonitor.INSTANCE, + mirror(master))); + String msg = e.getMessage(); + assertTrue("Unexpected exception message: " + msg, + msg.contains("no CredentialsProvider")); + } + List<AccessEvent> requests = getRequests(); + assertEquals(1, requests.size()); + + AccessEvent info = requests.get(0); + assertEquals("GET", info.getMethod()); + assertEquals(401, info.getStatus()); + } + + @Test + public void testInitialClone_WithUserInfo() throws Exception { + URIish withUserInfo = authURI.setUser(AppServer.username) + .setPass(AppServer.password); + try (Repository dst = createBareRepository(); + Transport t = Transport.open(dst, withUserInfo)) { + assertFalse(dst.getObjectDatabase().has(A_txt)); + t.fetch(NullProgressMonitor.INSTANCE, mirror(master)); + assertTrue(dst.getObjectDatabase().has(A_txt)); + assertEquals(B, dst.exactRef(master).getObjectId()); + fsck(dst, B); + } + + List<AccessEvent> requests = getRequests(); + assertEquals(enableProtocolV2 ? 3 : 2, requests.size()); + + assertFetchRequests(requests, 0); + } + + @Test + public void testInitialClone_PreAuthOverridesUserInfo() throws Exception { + URIish withUserInfo = authURI.setUser(AppServer.username) + .setPass(AppServer.password + 'x'); + try (Repository dst = createBareRepository(); + Transport t = Transport.open(dst, withUserInfo)) { + assertFalse(dst.getObjectDatabase().has(A_txt)); + ((TransportHttp) t).setPreemptiveBasicAuthentication( + AppServer.username, AppServer.password); + t.fetch(NullProgressMonitor.INSTANCE, mirror(master)); + assertTrue(dst.getObjectDatabase().has(A_txt)); + assertEquals(B, dst.exactRef(master).getObjectId()); + fsck(dst, B); + } + + List<AccessEvent> requests = getRequests(); + assertEquals(enableProtocolV2 ? 3 : 2, requests.size()); + + assertFetchRequests(requests, 0); + } + + @Test public void testInitialClone_WithAuthenticationNoCredentials() throws Exception { try (Repository dst = createBareRepository(); |