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>
This commit is contained in:
parent
0b5441a8ce
commit
4cb0bd8a43
|
@ -64,22 +64,31 @@ public class HttpAuthTest {
|
||||||
|
|
||||||
private static String bearerHeader = "WWW-Authenticate: Bearer";
|
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 URL_SAMPLE = "http://everyones.loves.git/u/2";
|
||||||
|
|
||||||
private static String BASIC = "Basic";
|
private static String BASIC = "Basic";
|
||||||
|
|
||||||
private static String DIGEST = "Digest";
|
private static String DIGEST = "Digest";
|
||||||
|
|
||||||
|
private static String NEGOTIATE = "Negotiate";
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testHttpAuthScanResponse() {
|
public void testHttpAuthScanResponse() {
|
||||||
checkResponse(new String[] { basicHeader }, BASIC);
|
checkResponse(new String[] { basicHeader }, BASIC);
|
||||||
checkResponse(new String[] { digestHeader }, DIGEST);
|
checkResponse(new String[] { digestHeader }, DIGEST);
|
||||||
|
checkResponse(new String[] { negotiateHeader }, NEGOTIATE);
|
||||||
checkResponse(new String[] { basicHeader, digestHeader }, DIGEST);
|
checkResponse(new String[] { basicHeader, digestHeader }, DIGEST);
|
||||||
checkResponse(new String[] { digestHeader, basicHeader }, 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,
|
checkResponse(new String[] { ntlmHeader, basicHeader, digestHeader,
|
||||||
bearerHeader }, DIGEST);
|
bearerHeader }, DIGEST);
|
||||||
checkResponse(new String[] { ntlmHeader, basicHeader, bearerHeader },
|
checkResponse(new String[] { ntlmHeader, basicHeader, bearerHeader },
|
||||||
BASIC);
|
BASIC);
|
||||||
|
checkResponse(new String[] { ntlmHeader, basicHeader, digestHeader,
|
||||||
|
negotiateHeader, bearerHeader }, NEGOTIATE);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void checkResponse(String[] headers,
|
private static void checkResponse(String[] headers,
|
||||||
|
|
|
@ -61,6 +61,12 @@
|
||||||
|
|
||||||
import org.eclipse.jgit.transport.http.HttpConnection;
|
import org.eclipse.jgit.transport.http.HttpConnection;
|
||||||
import org.eclipse.jgit.util.Base64;
|
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.
|
* Support class to populate user authentication data on a connection.
|
||||||
|
@ -91,6 +97,12 @@ public HttpAuthMethod method(String hdr) {
|
||||||
public HttpAuthMethod method(String hdr) {
|
public HttpAuthMethod method(String hdr) {
|
||||||
return new Digest(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
|
* Creates a HttpAuthMethod instance configured with the provided HTTP
|
||||||
|
@ -458,4 +470,55 @@ private static Map<String, String> parse(String auth) {
|
||||||
return p;
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue