summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLaurent Goujon <lgoujon@twitter.com>2014-02-24 14:47:51 -0800
committerChris Aniszczyk <caniszczyk@gmail.com>2014-05-21 11:00:26 -0500
commit4cb0bd8a43a8f09f8d7a1684870c5e6797f428d6 (patch)
treef79dd9753f31f577339a2250b0b27ef0a25075d7
parent0b5441a8ce9a13ac255609f0a978ccd81b755b6d (diff)
downloadjgit-4cb0bd8a43a8f09f8d7a1684870c5e6797f428d6.tar.gz
jgit-4cb0bd8a43a8f09f8d7a1684870c5e6797f428d6.zip
Adds support for SPNEGO
Adds support for Negotiate(SPNEGO) HTTP authentication method. This method is set to have a higher priority as Digest HTTP authentication method. Bug: 428836 Change-Id: Ib181096d39f538df1dd7d3f36516843777bf12ae Signed-off-by: Laurent Goujon <lgoujon@twitter.com> Signed-off-by: Chris Aniszczyk <caniszczyk@gmail.com>
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/HttpAuthTest.java9
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/transport/HttpAuthMethod.java63
2 files changed, 72 insertions, 0 deletions
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/HttpAuthTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/HttpAuthTest.java
index 5a64b458fa..5233013582 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/HttpAuthTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/HttpAuthTest.java
@@ -64,22 +64,31 @@ public class HttpAuthTest {
private static String bearerHeader = "WWW-Authenticate: Bearer";
+ private static String negotiateHeader = "WWW-Authenticate: Negotiate";
+
private static String URL_SAMPLE = "http://everyones.loves.git/u/2";
private static String BASIC = "Basic";
private static String DIGEST = "Digest";
+ private static String NEGOTIATE = "Negotiate";
+
@Test
public void testHttpAuthScanResponse() {
checkResponse(new String[] { basicHeader }, BASIC);
checkResponse(new String[] { digestHeader }, DIGEST);
+ checkResponse(new String[] { negotiateHeader }, NEGOTIATE);
checkResponse(new String[] { basicHeader, digestHeader }, DIGEST);
checkResponse(new String[] { digestHeader, basicHeader }, DIGEST);
+ checkResponse(new String[] { digestHeader, negotiateHeader }, NEGOTIATE);
+ checkResponse(new String[] { negotiateHeader, digestHeader }, NEGOTIATE);
checkResponse(new String[] { ntlmHeader, basicHeader, digestHeader,
bearerHeader }, DIGEST);
checkResponse(new String[] { ntlmHeader, basicHeader, bearerHeader },
BASIC);
+ checkResponse(new String[] { ntlmHeader, basicHeader, digestHeader,
+ negotiateHeader, bearerHeader }, NEGOTIATE);
}
private static void checkResponse(String[] headers,
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/HttpAuthMethod.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/HttpAuthMethod.java
index 4d80acc53f..6c30824e6e 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/HttpAuthMethod.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/HttpAuthMethod.java
@@ -61,6 +61,12 @@ import java.util.Random;
import org.eclipse.jgit.transport.http.HttpConnection;
import org.eclipse.jgit.util.Base64;
+import org.eclipse.jgit.util.GSSManagerFactory;
+import org.ietf.jgss.GSSContext;
+import org.ietf.jgss.GSSException;
+import org.ietf.jgss.GSSManager;
+import org.ietf.jgss.GSSName;
+import org.ietf.jgss.Oid;
/**
* Support class to populate user authentication data on a connection.
@@ -91,6 +97,12 @@ abstract class HttpAuthMethod {
public HttpAuthMethod method(String hdr) {
return new Digest(hdr);
}
+ },
+ NEGOTIATE {
+ @Override
+ public HttpAuthMethod method(String hdr) {
+ return new Negotiate(hdr);
+ }
};
/**
* Creates a HttpAuthMethod instance configured with the provided HTTP
@@ -458,4 +470,55 @@ abstract class HttpAuthMethod {
return p;
}
}
+
+ private static class Negotiate extends HttpAuthMethod {
+ private static final GSSManagerFactory GSS_MANAGER_FACTORY = GSSManagerFactory
+ .detect();
+
+ private static final Oid OID;
+ static {
+ try {
+ // OID for SPNEGO
+ OID = new Oid("1.3.6.1.5.5.2"); //$NON-NLS-1$
+ } catch (GSSException e) {
+ throw new Error("Cannot create NEGOTIATE oid.", e); //$NON-NLS-1$
+ }
+ }
+
+ private final byte[] prevToken;
+
+ public Negotiate(String hdr) {
+ super(Type.NEGOTIATE);
+ prevToken = Base64.decode(hdr);
+ }
+
+ @Override
+ void authorize(String user, String pass) {
+ // not used
+ }
+
+ @Override
+ void configureRequest(HttpConnection conn) throws IOException {
+ GSSManager gssManager = GSS_MANAGER_FACTORY.newInstance(conn
+ .getURL());
+ String host = conn.getURL().getHost();
+ String peerName = "HTTP@" + host.toLowerCase(); //$NON-NLS-1$
+ try {
+ GSSName gssName = gssManager.createName(peerName,
+ GSSName.NT_HOSTBASED_SERVICE);
+ GSSContext context = gssManager.createContext(gssName, OID,
+ null, GSSContext.DEFAULT_LIFETIME);
+ // Respect delegation policy in HTTP/SPNEGO.
+ context.requestCredDeleg(true);
+
+ byte[] token = context.initSecContext(prevToken, 0,
+ prevToken.length);
+
+ conn.setRequestProperty(HDR_AUTHORIZATION, getType().name()
+ + " " + Base64.encodeBytes(token)); //$NON-NLS-1$
+ } catch (GSSException e) {
+ throw new IOException(e);
+ }
+ }
+ }
}