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) {
|
||||
throw new IllegalArgumentException("HTTP request may not be null");
|
||||
}
|
||||
if (state != State.CHALLENGE_RECEIVED) {
|
||||
throw new IllegalStateException(
|
||||
"Negotiation authentication process has not been initiated");
|
||||
}
|
||||
try {
|
||||
String key = null;
|
||||
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;
|
||||
switch (state) {
|
||||
case UNINITIATED:
|
||||
throw new AuthenticationException("SPNEGO authentication has not been initiated");
|
||||
case FAILED:
|
||||
throw new AuthenticationException("SPNEGO authentication has failed");
|
||||
case CHALLENGE_RECEIVED:
|
||||
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;
|
||||
String key = null;
|
||||
if (isProxy()) {
|
||||
key = ExecutionContext.HTTP_PROXY_HOST;
|
||||
} 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 (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) {
|
||||
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 {
|
||||
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;
|
||||
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());
|
||||
}
|
||||
|
||||
/*
|
||||
* 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;
|
||||
case TOKEN_GENERATED:
|
||||
String tokenstr = new String(Base64.encodeBase64(token, false));
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Sending response '" + tokenstr + "' back to the auth server");
|
||||
}
|
||||
return new BasicHeader("Authorization", "Negotiate " + tokenstr);
|
||||
} catch (GSSException gsse) {
|
||||
state = State.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());
|
||||
default:
|
||||
throw new IllegalStateException("Illegal state: " + state);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the authentication parameter with the given name, if available.
|
||||
*
|
||||
|
|
Loading…
Reference in New Issue