diff --git a/httpclient/src/main/java/org/apache/http/client/params/AuthPolicy.java b/httpclient/src/main/java/org/apache/http/client/params/AuthPolicy.java
index 3f7731034..a27857846 100644
--- a/httpclient/src/main/java/org/apache/http/client/params/AuthPolicy.java
+++ b/httpclient/src/main/java/org/apache/http/client/params/AuthPolicy.java
@@ -60,10 +60,17 @@ public final class AuthPolicy {
public static final String BASIC = "Basic";
/**
- * SPNEGO/Kerberos Authentication scheme.
+ * SPNEGO Authentication scheme.
*
* @since 4.1
*/
- public static final String SPNEGO = "negotiate";
+ public static final String SPNEGO = "Negotiate";
+
+ /**
+ * Kerberos Authentication scheme.
+ *
+ * @since 4.2
+ */
+ public static final String KERBEROS = "Kerberos";
}
diff --git a/httpclient/src/main/java/org/apache/http/impl/auth/GGSSchemeBase.java b/httpclient/src/main/java/org/apache/http/impl/auth/GGSSchemeBase.java
new file mode 100644
index 000000000..330655bb0
--- /dev/null
+++ b/httpclient/src/main/java/org/apache/http/impl/auth/GGSSchemeBase.java
@@ -0,0 +1,192 @@
+/*
+ * ====================================================================
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * .
+ */
+
+package org.apache.http.impl.auth;
+
+import org.apache.commons.codec.binary.Base64;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.http.Header;
+import org.apache.http.HttpHost;
+import org.apache.http.HttpRequest;
+import org.apache.http.auth.AuthenticationException;
+import org.apache.http.auth.Credentials;
+import org.apache.http.auth.InvalidCredentialsException;
+import org.apache.http.auth.MalformedChallengeException;
+import org.apache.http.message.BasicHeader;
+import org.apache.http.protocol.ExecutionContext;
+import org.apache.http.protocol.HttpContext;
+import org.apache.http.util.CharArrayBuffer;
+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;
+
+public abstract class GGSSchemeBase extends AuthSchemeBase {
+
+ enum State {
+ UNINITIATED,
+ CHALLENGE_RECEIVED,
+ TOKEN_GENERATED,
+ FAILED,
+ }
+
+ private final Log log = LogFactory.getLog(getClass());
+
+ private final boolean stripPort;
+ private final Base64 base64codec;
+
+ /** Authentication process state */
+ private State state;
+
+ /** base64 decoded challenge **/
+ private byte[] token;
+
+ GGSSchemeBase(boolean stripPort) {
+ super();
+ this.base64codec = new Base64();
+ this.state = State.UNINITIATED;
+ this.stripPort = stripPort;
+ }
+
+ GGSSchemeBase() {
+ this(false);
+ }
+
+ protected GSSManager getManager() {
+ return GSSManager.getInstance();
+ }
+
+ protected byte[] generateGSSToken(
+ final byte[] input, final Oid oid, final String authServer) throws GSSException {
+ byte[] token = input;
+ if (token == null) {
+ token = new byte[0];
+ }
+ GSSManager manager = getManager();
+ GSSName serverName = manager.createName("HTTP@" + authServer, GSSName.NT_HOSTBASED_SERVICE);
+ GSSContext gssContext = manager.createContext(
+ serverName.canonicalize(oid), oid, null, GSSContext.DEFAULT_LIFETIME);
+ gssContext.requestMutualAuth(true);
+ gssContext.requestCredDeleg(true);
+ return gssContext.initSecContext(token, 0, token.length);
+ }
+
+ protected abstract byte[] generateToken(
+ byte[] input, final String authServer) throws GSSException;
+
+ public boolean isComplete() {
+ return this.state == State.TOKEN_GENERATED || this.state == State.FAILED;
+ }
+
+ @Deprecated
+ public Header authenticate(
+ final Credentials credentials,
+ final HttpRequest request) throws AuthenticationException {
+ return authenticate(credentials, request, null);
+ }
+
+ @Override
+ public Header authenticate(
+ final Credentials credentials,
+ final HttpRequest request,
+ final HttpContext context) throws AuthenticationException {
+ if (request == null) {
+ throw new IllegalArgumentException("HTTP request may not be null");
+ }
+ switch (state) {
+ case UNINITIATED:
+ throw new AuthenticationException(getSchemeName() + " authentication has not been initiated");
+ case FAILED:
+ throw new AuthenticationException(getSchemeName() + " authentication has failed");
+ case CHALLENGE_RECEIVED:
+ 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);
+ }
+ token = generateToken(token, authServer);
+ state = State.TOKEN_GENERATED;
+ } 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());
+ }
+ case TOKEN_GENERATED:
+ String tokenstr = new String(base64codec.encode(token));
+ if (log.isDebugEnabled()) {
+ log.debug("Sending response '" + tokenstr + "' back to the auth server");
+ }
+ return new BasicHeader("Authorization", "Negotiate " + tokenstr);
+ default:
+ throw new IllegalStateException("Illegal state: " + state);
+ }
+ }
+
+ @Override
+ protected void parseChallenge(
+ final CharArrayBuffer buffer,
+ int beginIndex, int endIndex) throws MalformedChallengeException {
+ String challenge = buffer.substringTrimmed(beginIndex, endIndex);
+ if (log.isDebugEnabled()) {
+ log.debug("Received challenge '" + challenge + "' from the auth server");
+ }
+ if (state == State.UNINITIATED) {
+ token = base64codec.decode(challenge.getBytes());
+ state = State.CHALLENGE_RECEIVED;
+ } else {
+ log.debug("Authentication already attempted");
+ state = State.FAILED;
+ }
+ }
+
+}
diff --git a/httpclient/src/main/java/org/apache/http/impl/auth/KerberosScheme.java b/httpclient/src/main/java/org/apache/http/impl/auth/KerberosScheme.java
new file mode 100644
index 000000000..d9971c1ce
--- /dev/null
+++ b/httpclient/src/main/java/org/apache/http/impl/auth/KerberosScheme.java
@@ -0,0 +1,114 @@
+/*
+ * ====================================================================
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * .
+ */
+
+package org.apache.http.impl.auth;
+
+import org.apache.http.Header;
+import org.apache.http.HttpRequest;
+import org.apache.http.auth.AuthenticationException;
+import org.apache.http.auth.Credentials;
+import org.apache.http.protocol.HttpContext;
+import org.ietf.jgss.GSSException;
+import org.ietf.jgss.Oid;
+
+/**
+ * KERBEROS authentication scheme.
+ *
+ * @since 4.2
+ */
+public class KerberosScheme extends GGSSchemeBase {
+
+ private static final String KERBEROS_OID = "1.2.840.113554.1.2.2";
+
+ public KerberosScheme(boolean stripPort) {
+ super(stripPort);
+ }
+
+ public KerberosScheme() {
+ super(false);
+ }
+
+ public String getSchemeName() {
+ return "Kerberos";
+ }
+
+ /**
+ * Produces KERBEROS authorization Header based on token created by
+ * processChallenge.
+ *
+ * @param credentials not used by the KERBEROS scheme.
+ * @param request The request being authenticated
+ *
+ * @throws AuthenticationException if authentication string cannot
+ * be generated due to an authentication failure
+ *
+ * @return KERBEROS authentication Header
+ */
+ @Override
+ public Header authenticate(
+ final Credentials credentials,
+ final HttpRequest request,
+ final HttpContext context) throws AuthenticationException {
+ return super.authenticate(credentials, request, context);
+ }
+
+ @Override
+ protected byte[] generateToken(final byte[] input, final String authServer) throws GSSException {
+ return generateGSSToken(input, new Oid(KERBEROS_OID), authServer);
+ }
+
+ /**
+ * There are no valid parameters for KERBEROS authentication so this
+ * method always returns null
.
+ *
+ * @return null
+ */
+ public String getParameter(String name) {
+ if (name == null) {
+ throw new IllegalArgumentException("Parameter name may not be null");
+ }
+ return null;
+ }
+
+ /**
+ * The concept of an authentication realm is not supported by the Negotiate
+ * authentication scheme. Always returns null
.
+ *
+ * @return null
+ */
+ public String getRealm() {
+ return null;
+ }
+
+ /**
+ * Returns true. KERBEROS authentication scheme is connection based.
+ *
+ * @return true.
+ */
+ public boolean isConnectionBased() {
+ return true;
+ }
+
+}
diff --git a/httpclient/src/main/java/org/apache/http/impl/auth/KerberosSchemeFactory.java b/httpclient/src/main/java/org/apache/http/impl/auth/KerberosSchemeFactory.java
new file mode 100644
index 000000000..6bb8a64a4
--- /dev/null
+++ b/httpclient/src/main/java/org/apache/http/impl/auth/KerberosSchemeFactory.java
@@ -0,0 +1,61 @@
+/*
+ * ====================================================================
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * .
+ *
+ */
+
+package org.apache.http.impl.auth;
+
+import org.apache.http.annotation.Immutable;
+import org.apache.http.auth.AuthScheme;
+import org.apache.http.auth.AuthSchemeFactory;
+import org.apache.http.params.HttpParams;
+
+/**
+ * Kerberos authentication scheme factory.
+ *
+ * @since 4.2
+ */
+@Immutable
+public class KerberosSchemeFactory implements AuthSchemeFactory {
+
+ private final boolean stripPort;
+
+ public KerberosSchemeFactory(boolean stripPort) {
+ super();
+ this.stripPort = stripPort;
+ }
+
+ public KerberosSchemeFactory() {
+ this(false);
+ }
+
+ public AuthScheme newInstance(final HttpParams params) {
+ return new KerberosScheme(this.stripPort);
+ }
+
+ public boolean isStripPort() {
+ return stripPort;
+ }
+
+}
diff --git a/httpclient/src/main/java/org/apache/http/impl/auth/NegotiateScheme.java b/httpclient/src/main/java/org/apache/http/impl/auth/NegotiateScheme.java
index 990c9e09f..5d3e84605 100644
--- a/httpclient/src/main/java/org/apache/http/impl/auth/NegotiateScheme.java
+++ b/httpclient/src/main/java/org/apache/http/impl/auth/NegotiateScheme.java
@@ -27,24 +27,14 @@ package org.apache.http.impl.auth;
import java.io.IOException;
-import org.apache.commons.codec.binary.Base64;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.http.Header;
-import org.apache.http.HttpHost;
import org.apache.http.HttpRequest;
import org.apache.http.auth.AuthenticationException;
import org.apache.http.auth.Credentials;
-import org.apache.http.auth.InvalidCredentialsException;
-import org.apache.http.auth.MalformedChallengeException;
-import org.apache.http.message.BasicHeader;
-import org.apache.http.protocol.ExecutionContext;
import org.apache.http.protocol.HttpContext;
-import org.apache.http.util.CharArrayBuffer;
-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;
/**
@@ -52,44 +42,26 @@ import org.ietf.jgss.Oid;
* scheme.
*
* @since 4.1
+ *
+ * @deprecated use {@link SPNegoScheme} or {@link KerberosScheme}.
*/
-public class NegotiateScheme extends AuthSchemeBase {
+@Deprecated
+public class NegotiateScheme extends GGSSchemeBase {
- enum State {
- UNINITIATED,
- CHALLENGE_RECEIVED,
- TOKEN_GENERATED,
- FAILED,
- }
+ private final Log log = LogFactory.getLog(getClass());
private static final String SPNEGO_OID = "1.3.6.1.5.5.2";
private static final String KERBEROS_OID = "1.2.840.113554.1.2.2";
- private final Log log = LogFactory.getLog(getClass());
-
private final SpnegoTokenGenerator spengoGenerator;
- private final boolean stripPort;
-
- private GSSContext gssContext = null;
-
- /** Authentication process state */
- private State state;
-
- /** base64 decoded challenge **/
- private byte[] token;
-
- private Oid negotiationOid = null;
-
/**
* Default constructor for the Negotiate authentication scheme.
*
*/
public NegotiateScheme(final SpnegoTokenGenerator spengoGenerator, boolean stripPort) {
- super();
- this.state = State.UNINITIATED;
+ super(stripPort);
this.spengoGenerator = spengoGenerator;
- this.stripPort = stripPort;
}
public NegotiateScheme(final SpnegoTokenGenerator spengoGenerator) {
@@ -100,17 +72,6 @@ public class NegotiateScheme extends AuthSchemeBase {
this(null, false);
}
- /**
- * Tests if the Negotiate authentication process has been completed.
- *
- * @return true if authorization has been processed,
- * false otherwise.
- *
- */
- public boolean isComplete() {
- return this.state == State.TOKEN_GENERATED || this.state == State.FAILED;
- }
-
/**
* Returns textual designation of the Negotiate authentication scheme.
*
@@ -120,17 +81,6 @@ public class NegotiateScheme extends AuthSchemeBase {
return "Negotiate";
}
- @Deprecated
- public Header authenticate(
- final Credentials credentials,
- final HttpRequest request) throws AuthenticationException {
- return authenticate(credentials, request, null);
- }
-
- protected GSSManager getManager() {
- return GSSManager.getInstance();
- }
-
/**
* Produces Negotiate authorization Header based on token created by
* processChallenge.
@@ -149,130 +99,62 @@ public class NegotiateScheme extends AuthSchemeBase {
final Credentials credentials,
final HttpRequest request,
final HttpContext context) throws AuthenticationException {
- if (request == null) {
- throw new IllegalArgumentException("HTTP request may not be null");
+ return super.authenticate(credentials, request, context);
+ }
+
+ @Override
+ protected byte[] generateToken(final byte[] input, final String authServer) throws GSSException {
+ /* 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 */
+ Oid negotiationOid = new Oid(SPNEGO_OID);
+
+ byte[] token = input;
+ boolean tryKerberos = false;
+ try {
+ token = generateGSSToken(token, negotiationOid, authServer);
+ } 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;
+ }
+
}
- 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 {
- 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 (tryKerberos){
+ /* Kerberos v5 GSS-API mechanism defined in RFC 1964.*/
+ log.debug("Using Kerberos MECH " + KERBEROS_OID);
+ negotiationOid = new Oid(KERBEROS_OID);
+ token = generateGSSToken(token, negotiationOid, authServer);
- 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;
+ /*
+ * IIS accepts Kerberos and SPNEGO tokens. Some other servers Jboss, Glassfish?
+ * seem to only accept SPNEGO. Below wraps Kerberos into SPNEGO token.
+ */
+ if (token != null && spengoGenerator != null) {
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);
+ } catch (IOException ex) {
+ log.error(ex.getMessage(), ex);
}
-
- state = State.TOKEN_GENERATED;
- } 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());
}
- 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);
- default:
- throw new IllegalStateException("Illegal state: " + state);
}
+ return token;
}
/**
@@ -312,21 +194,4 @@ public class NegotiateScheme extends AuthSchemeBase {
return true;
}
- @Override
- protected void parseChallenge(
- final CharArrayBuffer buffer,
- int beginIndex, int endIndex) throws MalformedChallengeException {
- String challenge = buffer.substringTrimmed(beginIndex, endIndex);
- if (log.isDebugEnabled()) {
- log.debug("Received challenge '" + challenge + "' from the auth server");
- }
- if (state == State.UNINITIATED) {
- token = new Base64().decode(challenge.getBytes());
- state = State.CHALLENGE_RECEIVED;
- } else {
- log.debug("Authentication already attempted");
- state = State.FAILED;
- }
- }
-
}
diff --git a/httpclient/src/main/java/org/apache/http/impl/auth/NegotiateSchemeFactory.java b/httpclient/src/main/java/org/apache/http/impl/auth/NegotiateSchemeFactory.java
index 4ad002d46..fb38d83e5 100644
--- a/httpclient/src/main/java/org/apache/http/impl/auth/NegotiateSchemeFactory.java
+++ b/httpclient/src/main/java/org/apache/http/impl/auth/NegotiateSchemeFactory.java
@@ -26,7 +26,6 @@
package org.apache.http.impl.auth;
-import org.apache.http.annotation.Immutable;
import org.apache.http.auth.AuthScheme;
import org.apache.http.auth.AuthSchemeFactory;
import org.apache.http.params.HttpParams;
@@ -36,8 +35,10 @@ import org.apache.http.params.HttpParams;
* scheme factory.
*
* @since 4.1
+ *
+ * @deprecated
*/
-@Immutable
+@Deprecated
public class NegotiateSchemeFactory implements AuthSchemeFactory {
private final SpnegoTokenGenerator spengoGenerator;
diff --git a/httpclient/src/main/java/org/apache/http/impl/auth/SPNegoScheme.java b/httpclient/src/main/java/org/apache/http/impl/auth/SPNegoScheme.java
new file mode 100644
index 000000000..66ee8db87
--- /dev/null
+++ b/httpclient/src/main/java/org/apache/http/impl/auth/SPNegoScheme.java
@@ -0,0 +1,115 @@
+/*
+ * ====================================================================
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * .
+ */
+
+package org.apache.http.impl.auth;
+
+import org.apache.http.Header;
+import org.apache.http.HttpRequest;
+import org.apache.http.auth.AuthenticationException;
+import org.apache.http.auth.Credentials;
+import org.apache.http.protocol.HttpContext;
+import org.ietf.jgss.GSSException;
+import org.ietf.jgss.Oid;
+
+/**
+ * SPNEGO (Simple and Protected GSSAPI Negotiation Mechanism) authentication
+ * scheme.
+ *
+ * @since 4.2
+ */
+public class SPNegoScheme extends GGSSchemeBase {
+
+ private static final String SPNEGO_OID = "1.3.6.1.5.5.2";
+
+ public SPNegoScheme(boolean stripPort) {
+ super(stripPort);
+ }
+
+ public SPNegoScheme() {
+ super(false);
+ }
+
+ public String getSchemeName() {
+ return "Negotiate";
+ }
+
+ /**
+ * Produces SPNEGO authorization Header based on token created by
+ * processChallenge.
+ *
+ * @param credentials not used by the SPNEGO scheme.
+ * @param request The request being authenticated
+ *
+ * @throws AuthenticationException if authentication string cannot
+ * be generated due to an authentication failure
+ *
+ * @return SPNEGO authentication Header
+ */
+ @Override
+ public Header authenticate(
+ final Credentials credentials,
+ final HttpRequest request,
+ final HttpContext context) throws AuthenticationException {
+ return super.authenticate(credentials, request, context);
+ }
+
+ @Override
+ protected byte[] generateToken(final byte[] input, final String authServer) throws GSSException {
+ return generateGSSToken(input, new Oid(SPNEGO_OID), authServer);
+ }
+
+ /**
+ * There are no valid parameters for SPNEGO authentication so this
+ * method always returns null
.
+ *
+ * @return null
+ */
+ public String getParameter(String name) {
+ if (name == null) {
+ throw new IllegalArgumentException("Parameter name may not be null");
+ }
+ return null;
+ }
+
+ /**
+ * The concept of an authentication realm is not supported by the Negotiate
+ * authentication scheme. Always returns null
.
+ *
+ * @return null
+ */
+ public String getRealm() {
+ return null;
+ }
+
+ /**
+ * Returns true. SPNEGO authentication scheme is connection based.
+ *
+ * @return true.
+ */
+ public boolean isConnectionBased() {
+ return true;
+ }
+
+}
diff --git a/httpclient/src/main/java/org/apache/http/impl/auth/SPNegoSchemeFactory.java b/httpclient/src/main/java/org/apache/http/impl/auth/SPNegoSchemeFactory.java
new file mode 100644
index 000000000..6ee3ac62c
--- /dev/null
+++ b/httpclient/src/main/java/org/apache/http/impl/auth/SPNegoSchemeFactory.java
@@ -0,0 +1,62 @@
+/*
+ * ====================================================================
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * .
+ *
+ */
+
+package org.apache.http.impl.auth;
+
+import org.apache.http.annotation.Immutable;
+import org.apache.http.auth.AuthScheme;
+import org.apache.http.auth.AuthSchemeFactory;
+import org.apache.http.params.HttpParams;
+
+/**
+ * SPNEGO (Simple and Protected GSSAPI Negotiation Mechanism) authentication
+ * scheme factory.
+ *
+ * @since 4.2
+ */
+@Immutable
+public class SPNegoSchemeFactory implements AuthSchemeFactory {
+
+ private final boolean stripPort;
+
+ public SPNegoSchemeFactory(boolean stripPort) {
+ super();
+ this.stripPort = stripPort;
+ }
+
+ public SPNegoSchemeFactory() {
+ this(false);
+ }
+
+ public AuthScheme newInstance(final HttpParams params) {
+ return new SPNegoScheme(this.stripPort);
+ }
+
+ public boolean isStripPort() {
+ return stripPort;
+ }
+
+}
diff --git a/httpclient/src/main/java/org/apache/http/impl/auth/SpnegoTokenGenerator.java b/httpclient/src/main/java/org/apache/http/impl/auth/SpnegoTokenGenerator.java
index 3e474bb49..0def2f420 100644
--- a/httpclient/src/main/java/org/apache/http/impl/auth/SpnegoTokenGenerator.java
+++ b/httpclient/src/main/java/org/apache/http/impl/auth/SpnegoTokenGenerator.java
@@ -35,7 +35,11 @@ import java.io.IOException;
* Implementations of this interface are expected to be thread-safe.
*
* @since 4.1
+ *
+ * @deprecated subclass {@link KerberosScheme} and override
+ * {@link KerberosScheme#generateGSSToken(byte[], org.ietf.jgss.Oid, String)}
*/
+@Deprecated
public interface SpnegoTokenGenerator {
byte [] generateSpnegoDERObject(byte [] kerberosTicket) throws IOException;
diff --git a/httpclient/src/main/java/org/apache/http/impl/client/AbstractHttpClient.java b/httpclient/src/main/java/org/apache/http/impl/client/AbstractHttpClient.java
index 4ef1dd006..956b097f6 100644
--- a/httpclient/src/main/java/org/apache/http/impl/client/AbstractHttpClient.java
+++ b/httpclient/src/main/java/org/apache/http/impl/client/AbstractHttpClient.java
@@ -74,8 +74,9 @@ import org.apache.http.cookie.CookieSpecRegistry;
import org.apache.http.impl.DefaultConnectionReuseStrategy;
import org.apache.http.impl.auth.BasicSchemeFactory;
import org.apache.http.impl.auth.DigestSchemeFactory;
+import org.apache.http.impl.auth.KerberosSchemeFactory;
import org.apache.http.impl.auth.NTLMSchemeFactory;
-import org.apache.http.impl.auth.NegotiateSchemeFactory;
+import org.apache.http.impl.auth.SPNegoSchemeFactory;
import org.apache.http.impl.conn.DefaultHttpRoutePlanner;
import org.apache.http.impl.conn.PoolingClientConnectionManager;
import org.apache.http.impl.conn.SchemeRegistryFactory;
@@ -346,7 +347,10 @@ public abstract class AbstractHttpClient implements HttpClient {
new NTLMSchemeFactory());
registry.register(
AuthPolicy.SPNEGO,
- new NegotiateSchemeFactory());
+ new SPNegoSchemeFactory());
+ registry.register(
+ AuthPolicy.KERBEROS,
+ new KerberosSchemeFactory());
return registry;
}
diff --git a/httpclient/src/main/java/org/apache/http/impl/client/AuthenticationStrategyImpl.java b/httpclient/src/main/java/org/apache/http/impl/client/AuthenticationStrategyImpl.java
index 79de9792c..e6263615f 100644
--- a/httpclient/src/main/java/org/apache/http/impl/client/AuthenticationStrategyImpl.java
+++ b/httpclient/src/main/java/org/apache/http/impl/client/AuthenticationStrategyImpl.java
@@ -66,6 +66,7 @@ class AuthenticationStrategyImpl implements AuthenticationStrategy {
private static final List DEFAULT_SCHEME_PRIORITY =
Collections.unmodifiableList(Arrays.asList(new String[] {
AuthPolicy.SPNEGO,
+ AuthPolicy.KERBEROS,
AuthPolicy.NTLM,
AuthPolicy.DIGEST,
AuthPolicy.BASIC
diff --git a/httpclient/src/main/java/org/apache/http/impl/client/ProxyClient.java b/httpclient/src/main/java/org/apache/http/impl/client/ProxyClient.java
index 41ff8892f..19771a433 100644
--- a/httpclient/src/main/java/org/apache/http/impl/client/ProxyClient.java
+++ b/httpclient/src/main/java/org/apache/http/impl/client/ProxyClient.java
@@ -56,8 +56,9 @@ import org.apache.http.impl.DefaultConnectionReuseStrategy;
import org.apache.http.impl.DefaultHttpClientConnection;
import org.apache.http.impl.auth.BasicSchemeFactory;
import org.apache.http.impl.auth.DigestSchemeFactory;
+import org.apache.http.impl.auth.KerberosSchemeFactory;
import org.apache.http.impl.auth.NTLMSchemeFactory;
-import org.apache.http.impl.auth.NegotiateSchemeFactory;
+import org.apache.http.impl.auth.SPNegoSchemeFactory;
import org.apache.http.message.BasicHttpRequest;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpParams;
@@ -104,7 +105,8 @@ public class ProxyClient {
this.authSchemeRegistry.register(AuthPolicy.BASIC, new BasicSchemeFactory());
this.authSchemeRegistry.register(AuthPolicy.DIGEST, new DigestSchemeFactory());
this.authSchemeRegistry.register(AuthPolicy.NTLM, new NTLMSchemeFactory());
- this.authSchemeRegistry.register(AuthPolicy.SPNEGO, new NegotiateSchemeFactory());
+ this.authSchemeRegistry.register(AuthPolicy.SPNEGO, new SPNegoSchemeFactory());
+ this.authSchemeRegistry.register(AuthPolicy.KERBEROS, new KerberosSchemeFactory());
this.reuseStrategy = new DefaultConnectionReuseStrategy();
this.params = params;
}
diff --git a/httpclient/src/test/java/org/apache/http/impl/auth/TestNegotiateScheme.java b/httpclient/src/test/java/org/apache/http/impl/auth/TestSPNegoScheme.java
similarity index 96%
rename from httpclient/src/test/java/org/apache/http/impl/auth/TestNegotiateScheme.java
rename to httpclient/src/test/java/org/apache/http/impl/auth/TestSPNegoScheme.java
index 80295f0ea..b3a80f56b 100644
--- a/httpclient/src/test/java/org/apache/http/impl/auth/TestNegotiateScheme.java
+++ b/httpclient/src/test/java/org/apache/http/impl/auth/TestSPNegoScheme.java
@@ -64,7 +64,7 @@ import org.mockito.Mockito;
/**
* Tests for {@link NegotiateScheme}.
*/
-public class TestNegotiateScheme extends BasicServerTestBase {
+public class TestSPNegoScheme extends BasicServerTestBase {
@Before
public void setUp() throws Exception {
@@ -96,14 +96,14 @@ public class TestNegotiateScheme extends BasicServerTestBase {
* Kerberos configuration.
*
*/
- private static class NegotiateSchemeWithMockGssManager extends NegotiateScheme {
+ private static class NegotiateSchemeWithMockGssManager extends SPNegoScheme {
GSSManager manager = Mockito.mock(GSSManager.class);
GSSName name = Mockito.mock(GSSName.class);
GSSContext context = Mockito.mock(GSSContext.class);
NegotiateSchemeWithMockGssManager() throws Exception {
- super(null, true);
+ super(true);
Mockito.when(context.initSecContext(
Matchers.any(byte[].class), Matchers.anyInt(), Matchers.anyInt()))
.thenReturn("12345678".getBytes());
@@ -135,7 +135,7 @@ public class TestNegotiateScheme extends BasicServerTestBase {
}
- private static class NegotiateSchemeFactoryWithMockGssManager extends NegotiateSchemeFactory {
+ private static class NegotiateSchemeFactoryWithMockGssManager extends SPNegoSchemeFactory {
NegotiateSchemeWithMockGssManager scheme;
@@ -161,7 +161,7 @@ public class TestNegotiateScheme extends BasicServerTestBase {
HttpHost target = new HttpHost("localhost", port);
- NegotiateSchemeFactory nsf = new NegotiateSchemeFactoryWithMockGssManager();
+ SPNegoSchemeFactory nsf = new NegotiateSchemeFactoryWithMockGssManager();
this.httpclient.getAuthSchemes().register(AuthPolicy.SPNEGO, nsf);