]> source.dussan.org Git - jgit.git/commitdiff
Adds support for SPNEGO 89/22489/3
authorLaurent Goujon <lgoujon@twitter.com>
Mon, 24 Feb 2014 22:47:51 +0000 (14:47 -0800)
committerChris Aniszczyk <caniszczyk@gmail.com>
Wed, 21 May 2014 16:00:26 +0000 (11:00 -0500)
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>
org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/HttpAuthTest.java
org.eclipse.jgit/src/org/eclipse/jgit/transport/HttpAuthMethod.java

index 5a64b458fad5edac0805ccd69716c470b87c914e..52330135829dde444c458c246397522a6eb24e4f 100644 (file)
@@ -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,
index 4d80acc53f227716f4ee0f5e69e0d28a05e728a9..6c30824e6ebbcffd559ad8fed0f3115c0bad8391 100644 (file)
@@ -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);
+                       }
+               }
+       }
 }