Better state handling in NegotiateScheme#authenticate
git-svn-id: https://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk@1181015 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
90b6853111
commit
8f46fbacd8
|
@ -152,124 +152,129 @@ public class NegotiateScheme extends AuthSchemeBase {
|
||||||
if (request == null) {
|
if (request == null) {
|
||||||
throw new IllegalArgumentException("HTTP request may not be null");
|
throw new IllegalArgumentException("HTTP request may not be null");
|
||||||
}
|
}
|
||||||
if (state != State.CHALLENGE_RECEIVED) {
|
switch (state) {
|
||||||
throw new IllegalStateException(
|
case UNINITIATED:
|
||||||
"Negotiation authentication process has not been initiated");
|
throw new AuthenticationException("SPNEGO authentication has not been initiated");
|
||||||
}
|
case FAILED:
|
||||||
try {
|
throw new AuthenticationException("SPNEGO authentication has failed");
|
||||||
String key = null;
|
case CHALLENGE_RECEIVED:
|
||||||
if (isProxy()) {
|
|
||||||
key = ExecutionContext.HTTP_PROXY_HOST;
|
|
||||||
} else {
|
|
||||||
key = ExecutionContext.HTTP_TARGET_HOST;
|
|
||||||
}
|
|
||||||
HttpHost host = (HttpHost) context.getAttribute(key);
|
|
||||||
if (host == null) {
|
|
||||||
throw new AuthenticationException("Authentication host is not set " +
|
|
||||||
"in the execution context");
|
|
||||||
}
|
|
||||||
String authServer;
|
|
||||||
if (!this.stripPort && host.getPort() > 0) {
|
|
||||||
authServer = host.toHostString();
|
|
||||||
} else {
|
|
||||||
authServer = host.getHostName();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (log.isDebugEnabled()) {
|
|
||||||
log.debug("init " + authServer);
|
|
||||||
}
|
|
||||||
/* Using the SPNEGO OID is the correct method.
|
|
||||||
* Kerberos v5 works for IIS but not JBoss. Unwrapping
|
|
||||||
* the initial token when using SPNEGO OID looks like what is
|
|
||||||
* described here...
|
|
||||||
*
|
|
||||||
* http://msdn.microsoft.com/en-us/library/ms995330.aspx
|
|
||||||
*
|
|
||||||
* Another helpful URL...
|
|
||||||
*
|
|
||||||
* http://publib.boulder.ibm.com/infocenter/wasinfo/v7r0/index.jsp?topic=/com.ibm.websphere.express.doc/info/exp/ae/tsec_SPNEGO_token.html
|
|
||||||
*
|
|
||||||
* Unfortunately SPNEGO is JRE >=1.6.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/** Try SPNEGO by default, fall back to Kerberos later if error */
|
|
||||||
negotiationOid = new Oid(SPNEGO_OID);
|
|
||||||
|
|
||||||
boolean tryKerberos = false;
|
|
||||||
try {
|
try {
|
||||||
GSSManager manager = getManager();
|
String key = null;
|
||||||
GSSName serverName = manager.createName("HTTP@" + authServer, GSSName.NT_HOSTBASED_SERVICE);
|
if (isProxy()) {
|
||||||
gssContext = manager.createContext(
|
key = ExecutionContext.HTTP_PROXY_HOST;
|
||||||
serverName.canonicalize(negotiationOid), negotiationOid, null,
|
|
||||||
GSSContext.DEFAULT_LIFETIME);
|
|
||||||
gssContext.requestMutualAuth(true);
|
|
||||||
gssContext.requestCredDeleg(true);
|
|
||||||
} catch (GSSException ex){
|
|
||||||
// BAD MECH means we are likely to be using 1.5, fall back to Kerberos MECH.
|
|
||||||
// Rethrow any other exception.
|
|
||||||
if (ex.getMajor() == GSSException.BAD_MECH ){
|
|
||||||
log.debug("GSSException BAD_MECH, retry with Kerberos MECH");
|
|
||||||
tryKerberos = true;
|
|
||||||
} else {
|
} else {
|
||||||
throw ex;
|
key = ExecutionContext.HTTP_TARGET_HOST;
|
||||||
|
}
|
||||||
|
HttpHost host = (HttpHost) context.getAttribute(key);
|
||||||
|
if (host == null) {
|
||||||
|
throw new AuthenticationException("Authentication host is not set " +
|
||||||
|
"in the execution context");
|
||||||
|
}
|
||||||
|
String authServer;
|
||||||
|
if (!this.stripPort && host.getPort() > 0) {
|
||||||
|
authServer = host.toHostString();
|
||||||
|
} else {
|
||||||
|
authServer = host.getHostName();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
if (log.isDebugEnabled()) {
|
||||||
if (tryKerberos){
|
log.debug("init " + authServer);
|
||||||
/* Kerberos v5 GSS-API mechanism defined in RFC 1964.*/
|
}
|
||||||
log.debug("Using Kerberos MECH " + KERBEROS_OID);
|
/* Using the SPNEGO OID is the correct method.
|
||||||
negotiationOid = new Oid(KERBEROS_OID);
|
* Kerberos v5 works for IIS but not JBoss. Unwrapping
|
||||||
GSSManager manager = getManager();
|
* the initial token when using SPNEGO OID looks like what is
|
||||||
GSSName serverName = manager.createName("HTTP@" + authServer, GSSName.NT_HOSTBASED_SERVICE);
|
* described here...
|
||||||
gssContext = manager.createContext(
|
*
|
||||||
serverName.canonicalize(negotiationOid), negotiationOid, null,
|
* http://msdn.microsoft.com/en-us/library/ms995330.aspx
|
||||||
GSSContext.DEFAULT_LIFETIME);
|
*
|
||||||
gssContext.requestMutualAuth(true);
|
* Another helpful URL...
|
||||||
gssContext.requestCredDeleg(true);
|
*
|
||||||
}
|
* http://publib.boulder.ibm.com/infocenter/wasinfo/v7r0/index.jsp?topic=/com.ibm.websphere.express.doc/info/exp/ae/tsec_SPNEGO_token.html
|
||||||
if (token == null) {
|
*
|
||||||
token = new byte[0];
|
* Unfortunately SPNEGO is JRE >=1.6.
|
||||||
}
|
*/
|
||||||
token = gssContext.initSecContext(token, 0, token.length);
|
|
||||||
if (token == null) {
|
/** Try SPNEGO by default, fall back to Kerberos later if error */
|
||||||
|
negotiationOid = new Oid(SPNEGO_OID);
|
||||||
|
|
||||||
|
boolean tryKerberos = false;
|
||||||
|
try {
|
||||||
|
GSSManager manager = getManager();
|
||||||
|
GSSName serverName = manager.createName("HTTP@" + authServer, GSSName.NT_HOSTBASED_SERVICE);
|
||||||
|
gssContext = manager.createContext(
|
||||||
|
serverName.canonicalize(negotiationOid), negotiationOid, null,
|
||||||
|
GSSContext.DEFAULT_LIFETIME);
|
||||||
|
gssContext.requestMutualAuth(true);
|
||||||
|
gssContext.requestCredDeleg(true);
|
||||||
|
} catch (GSSException ex){
|
||||||
|
// BAD MECH means we are likely to be using 1.5, fall back to Kerberos MECH.
|
||||||
|
// Rethrow any other exception.
|
||||||
|
if (ex.getMajor() == GSSException.BAD_MECH ){
|
||||||
|
log.debug("GSSException BAD_MECH, retry with Kerberos MECH");
|
||||||
|
tryKerberos = true;
|
||||||
|
} else {
|
||||||
|
throw ex;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
if (tryKerberos){
|
||||||
|
/* Kerberos v5 GSS-API mechanism defined in RFC 1964.*/
|
||||||
|
log.debug("Using Kerberos MECH " + KERBEROS_OID);
|
||||||
|
negotiationOid = new Oid(KERBEROS_OID);
|
||||||
|
GSSManager manager = getManager();
|
||||||
|
GSSName serverName = manager.createName("HTTP@" + authServer, GSSName.NT_HOSTBASED_SERVICE);
|
||||||
|
gssContext = manager.createContext(
|
||||||
|
serverName.canonicalize(negotiationOid), negotiationOid, null,
|
||||||
|
GSSContext.DEFAULT_LIFETIME);
|
||||||
|
gssContext.requestMutualAuth(true);
|
||||||
|
gssContext.requestCredDeleg(true);
|
||||||
|
}
|
||||||
|
if (token == null) {
|
||||||
|
token = new byte[0];
|
||||||
|
}
|
||||||
|
token = gssContext.initSecContext(token, 0, token.length);
|
||||||
|
if (token == null) {
|
||||||
|
state = State.FAILED;
|
||||||
|
throw new AuthenticationException("GSS security context initialization failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* IIS accepts Kerberos and SPNEGO tokens. Some other servers Jboss, Glassfish?
|
||||||
|
* seem to only accept SPNEGO. Below wraps Kerberos into SPNEGO token.
|
||||||
|
*/
|
||||||
|
if (spengoGenerator != null && negotiationOid.toString().equals(KERBEROS_OID)) {
|
||||||
|
token = spengoGenerator.generateSpnegoDERObject(token);
|
||||||
|
}
|
||||||
|
|
||||||
|
state = State.TOKEN_GENERATED;
|
||||||
|
} catch (GSSException gsse) {
|
||||||
state = State.FAILED;
|
state = State.FAILED;
|
||||||
throw new AuthenticationException("GSS security context initialization failed");
|
if (gsse.getMajor() == GSSException.DEFECTIVE_CREDENTIAL
|
||||||
|
|| gsse.getMajor() == GSSException.CREDENTIALS_EXPIRED)
|
||||||
|
throw new InvalidCredentialsException(gsse.getMessage(), gsse);
|
||||||
|
if (gsse.getMajor() == GSSException.NO_CRED )
|
||||||
|
throw new InvalidCredentialsException(gsse.getMessage(), gsse);
|
||||||
|
if (gsse.getMajor() == GSSException.DEFECTIVE_TOKEN
|
||||||
|
|| gsse.getMajor() == GSSException.DUPLICATE_TOKEN
|
||||||
|
|| gsse.getMajor() == GSSException.OLD_TOKEN)
|
||||||
|
throw new AuthenticationException(gsse.getMessage(), gsse);
|
||||||
|
// other error
|
||||||
|
throw new AuthenticationException(gsse.getMessage());
|
||||||
|
} catch (IOException ex){
|
||||||
|
state = State.FAILED;
|
||||||
|
throw new AuthenticationException(ex.getMessage());
|
||||||
}
|
}
|
||||||
|
case TOKEN_GENERATED:
|
||||||
/*
|
|
||||||
* IIS accepts Kerberos and SPNEGO tokens. Some other servers Jboss, Glassfish?
|
|
||||||
* seem to only accept SPNEGO. Below wraps Kerberos into SPNEGO token.
|
|
||||||
*/
|
|
||||||
if (spengoGenerator != null && negotiationOid.toString().equals(KERBEROS_OID)) {
|
|
||||||
token = spengoGenerator.generateSpnegoDERObject(token);
|
|
||||||
}
|
|
||||||
|
|
||||||
state = State.TOKEN_GENERATED;
|
|
||||||
String tokenstr = new String(Base64.encodeBase64(token, false));
|
String tokenstr = new String(Base64.encodeBase64(token, false));
|
||||||
if (log.isDebugEnabled()) {
|
if (log.isDebugEnabled()) {
|
||||||
log.debug("Sending response '" + tokenstr + "' back to the auth server");
|
log.debug("Sending response '" + tokenstr + "' back to the auth server");
|
||||||
}
|
}
|
||||||
return new BasicHeader("Authorization", "Negotiate " + tokenstr);
|
return new BasicHeader("Authorization", "Negotiate " + tokenstr);
|
||||||
} catch (GSSException gsse) {
|
default:
|
||||||
state = State.FAILED;
|
throw new IllegalStateException("Illegal state: " + state);
|
||||||
if (gsse.getMajor() == GSSException.DEFECTIVE_CREDENTIAL
|
|
||||||
|| gsse.getMajor() == GSSException.CREDENTIALS_EXPIRED)
|
|
||||||
throw new InvalidCredentialsException(gsse.getMessage(), gsse);
|
|
||||||
if (gsse.getMajor() == GSSException.NO_CRED )
|
|
||||||
throw new InvalidCredentialsException(gsse.getMessage(), gsse);
|
|
||||||
if (gsse.getMajor() == GSSException.DEFECTIVE_TOKEN
|
|
||||||
|| gsse.getMajor() == GSSException.DUPLICATE_TOKEN
|
|
||||||
|| gsse.getMajor() == GSSException.OLD_TOKEN)
|
|
||||||
throw new AuthenticationException(gsse.getMessage(), gsse);
|
|
||||||
// other error
|
|
||||||
throw new AuthenticationException(gsse.getMessage());
|
|
||||||
} catch (IOException ex){
|
|
||||||
state = State.FAILED;
|
|
||||||
throw new AuthenticationException(ex.getMessage());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the authentication parameter with the given name, if available.
|
* Returns the authentication parameter with the given name, if available.
|
||||||
*
|
*
|
||||||
|
|
Loading…
Reference in New Issue