diff --git a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/sync/TestSPNegoScheme.java b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/sync/TestMutualSpnegoScheme.java
similarity index 99%
rename from httpclient5-testing/src/test/java/org/apache/hc/client5/testing/sync/TestSPNegoScheme.java
rename to httpclient5-testing/src/test/java/org/apache/hc/client5/testing/sync/TestMutualSpnegoScheme.java
index 1347dd928..55b5c08c1 100644
--- a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/sync/TestSPNegoScheme.java
+++ b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/sync/TestMutualSpnegoScheme.java
@@ -49,7 +49,7 @@ import org.apache.hc.client5.http.auth.StandardAuthScheme;
import org.apache.hc.client5.http.classic.methods.HttpGet;
import org.apache.hc.client5.http.impl.DefaultAuthenticationStrategy;
import org.apache.hc.client5.http.impl.auth.CredentialsProviderBuilder;
-import org.apache.hc.client5.http.impl.auth.SPNegoScheme;
+import org.apache.hc.client5.http.impl.auth.MutualSpnegoScheme;
import org.apache.hc.client5.http.protocol.HttpClientContext;
import org.apache.hc.client5.http.utils.Base64;
import org.apache.hc.client5.testing.extension.sync.ClientProtocolLevel;
@@ -80,9 +80,9 @@ import org.mockito.Mockito;
/**
* Tests for {@link SPNegoScheme}.
*/
-public class TestSPNegoScheme extends AbstractIntegrationTestBase {
+public class TestMutualSpnegoScheme extends AbstractIntegrationTestBase {
- protected TestSPNegoScheme() {
+ protected TestMutualSpnegoScheme() {
super(URIScheme.HTTP, ClientProtocolLevel.STANDARD);
}
@@ -191,7 +191,7 @@ public class TestSPNegoScheme extends AbstractIntegrationTestBase {
* Kerberos configuration.
*
*/
- private static class NegotiateSchemeWithMockGssManager extends SPNegoScheme {
+ private static class NegotiateSchemeWithMockGssManager extends MutualSpnegoScheme {
final GSSManager manager = Mockito.mock(GSSManager.class);
final GSSName name = Mockito.mock(GSSName.class);
@@ -218,7 +218,7 @@ public class TestSPNegoScheme extends AbstractIntegrationTestBase {
}
- private static class MutualNegotiateSchemeWithMockGssManager extends SPNegoScheme {
+ private static class MutualNegotiateSchemeWithMockGssManager extends MutualSpnegoScheme {
final GSSManager manager = Mockito.mock(GSSManager.class);
final GSSName name = Mockito.mock(GSSName.class);
diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/auth/GGSSchemeBase.java b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/auth/GGSSchemeBase.java
index 245fbb733..2953416f3 100644
--- a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/auth/GGSSchemeBase.java
+++ b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/auth/GGSSchemeBase.java
@@ -32,14 +32,14 @@ import java.security.Principal;
import org.apache.hc.client5.http.DnsResolver;
import org.apache.hc.client5.http.SystemDefaultDnsResolver;
import org.apache.hc.client5.http.auth.AuthChallenge;
-import org.apache.hc.client5.http.auth.AuthScheme2;
+import org.apache.hc.client5.http.auth.AuthScheme;
import org.apache.hc.client5.http.auth.AuthScope;
import org.apache.hc.client5.http.auth.AuthenticationException;
import org.apache.hc.client5.http.auth.Credentials;
import org.apache.hc.client5.http.auth.CredentialsProvider;
import org.apache.hc.client5.http.auth.InvalidCredentialsException;
+import org.apache.hc.client5.http.auth.MalformedChallengeException;
import org.apache.hc.client5.http.auth.StandardAuthScheme;
-import org.apache.hc.client5.http.auth.KerberosConfig;
import org.apache.hc.client5.http.protocol.HttpClientContext;
import org.apache.hc.client5.http.utils.Base64;
import org.apache.hc.core5.http.HttpHost;
@@ -60,51 +60,45 @@ import org.slf4j.LoggerFactory;
*
* @since 4.2
*
+ * @deprecated Do not use. This class implements functionality for the old deprecated non mutual
+ * authentication capable {@link SPNegoScheme} and {@link KerberosScheme} classes.
+ * The new mutual authentication capable implementation is {@link MutualGSSSchemeBase}.
*/
-// FIXME The class name looks like a Typo. Rename in 6.0 ?
-public abstract class GGSSchemeBase implements AuthScheme2 {
+@Deprecated
+public abstract class GGSSchemeBase implements AuthScheme {
enum State {
UNINITIATED,
- TOKEN_READY,
- TOKEN_SENT,
- SUCCEEDED,
+ CHALLENGE_RECEIVED,
+ TOKEN_GENERATED,
FAILED,
}
private static final Logger LOG = LoggerFactory.getLogger(GGSSchemeBase.class);
private static final String NO_TOKEN = "";
private static final String KERBEROS_SCHEME = "HTTP";
-
- // The GSS spec does not specify how long the conversation can be. This should be plenty.
- // Realistically, we get one initial token, then one maybe one more for mutual authentication.
- private static final int MAX_GSS_CHALLENGES = 3;
- private final KerberosConfig config;
+ private final org.apache.hc.client5.http.auth.KerberosConfig config;
private final DnsResolver dnsResolver;
- private final boolean mutualAuth;
- private int challengesLeft = MAX_GSS_CHALLENGES;
/** Authentication process state */
private State state;
private GSSCredential gssCredential;
- private GSSContext gssContext;
private String challenge;
- private byte[] queuedToken = new byte[0];
+ private byte[] token;
- GGSSchemeBase(final KerberosConfig config, final DnsResolver dnsResolver) {
+ GGSSchemeBase(final org.apache.hc.client5.http.auth.KerberosConfig config, final DnsResolver dnsResolver) {
super();
- this.config = config != null ? config : KerberosConfig.DEFAULT;
+ this.config = config != null ? config : org.apache.hc.client5.http.auth.KerberosConfig.DEFAULT;
this.dnsResolver = dnsResolver != null ? dnsResolver : SystemDefaultDnsResolver.INSTANCE;
- this.mutualAuth = config.getRequestMutualAuth() == KerberosConfig.Option.ENABLE;
this.state = State.UNINITIATED;
}
- GGSSchemeBase(final KerberosConfig config) {
+ GGSSchemeBase(final org.apache.hc.client5.http.auth.KerberosConfig config) {
this(config, SystemDefaultDnsResolver.INSTANCE);
}
GGSSchemeBase() {
- this(KerberosConfig.DEFAULT, SystemDefaultDnsResolver.INSTANCE);
+ this(org.apache.hc.client5.http.auth.KerberosConfig.DEFAULT, SystemDefaultDnsResolver.INSTANCE);
}
@Override
@@ -112,115 +106,24 @@ public abstract class GGSSchemeBase implements AuthScheme2 {
return null;
}
- // The AuthScheme API maps awkwardly to GSSAPI, where proccessChallange and generateAuthResponse
- // map to the same single method call. Hence the generated token is only stored in this method.
@Override
public void processChallenge(
- final HttpHost host,
final AuthChallenge authChallenge,
- final HttpContext context,
- final boolean challenged) throws AuthenticationException {
+ final HttpContext context) throws MalformedChallengeException {
+ Args.notNull(authChallenge, "AuthChallenge");
- if (challengesLeft-- <= 0 ) {
+ this.challenge = authChallenge.getValue() != null ? authChallenge.getValue() : NO_TOKEN;
+
+ if (state == State.UNINITIATED) {
+ token = Base64.decodeBase64(challenge.getBytes());
+ state = State.CHALLENGE_RECEIVED;
+ } else {
if (LOG.isDebugEnabled()) {
final HttpClientContext clientContext = HttpClientContext.cast(context);
final String exchangeId = clientContext.getExchangeId();
- LOG.debug("{} GSS error: too many challenges received. Infinite loop ?", exchangeId);
+ LOG.debug("{} Authentication already attempted", exchangeId);
}
- // TODO: Should we throw an exception ? There is a test for this behaviour.
state = State.FAILED;
- return;
- }
-
- final byte[] challengeToken = Base64.decodeBase64(authChallenge == null ? null : authChallenge.getValue());
-
- final String gssHostname;
- String hostname = host.getHostName();
- if (config.getUseCanonicalHostname() != KerberosConfig.Option.DISABLE) {
- try {
- hostname = dnsResolver.resolveCanonicalHostname(host.getHostName());
- } catch (final UnknownHostException ignore) {
- }
- }
- if (config.getStripPort() != KerberosConfig.Option.DISABLE) {
- gssHostname = hostname;
- } else {
- gssHostname = hostname + ":" + host.getPort();
- }
-
- if (LOG.isDebugEnabled()) {
- final HttpClientContext clientContext = HttpClientContext.cast(context);
- final String exchangeId = clientContext.getExchangeId();
- LOG.debug("{} GSS init {}", exchangeId, gssHostname);
- }
- try {
- queuedToken = generateToken(challengeToken, KERBEROS_SCHEME, gssHostname);
- switch (state) {
- case UNINITIATED:
- if (challenge != NO_TOKEN) {
- if (LOG.isDebugEnabled()) {
- final HttpClientContext clientContext = HttpClientContext.cast(context);
- final String exchangeId = clientContext.getExchangeId();
- LOG.debug("{} Internal GSS error: token received when none was sent yet: {}", exchangeId, challengeToken);
- }
- // TODO Should we fail ? That would break existing tests that send a token
- // in the first response, which is against the RFC.
- }
- state = State.TOKEN_READY;
- break;
- case TOKEN_SENT:
- if (challenged) {
- state = State.TOKEN_READY;
- } else if (mutualAuth) {
- // We should have received a valid mutualAuth token
- if (!gssContext.isEstablished()) {
- if (LOG.isDebugEnabled()) {
- final HttpClientContext clientContext =
- HttpClientContext.cast(context);
- final String exchangeId = clientContext.getExchangeId();
- LOG.debug("{} GSSContext is not established ", exchangeId);
- }
- state = State.FAILED;
- // TODO should we have specific exception(s) for these ?
- throw new AuthenticationException(
- "requireMutualAuth is set but GSSContext is not established");
- } else if (!gssContext.getMutualAuthState()) {
- if (LOG.isDebugEnabled()) {
- final HttpClientContext clientContext =
- HttpClientContext.cast(context);
- final String exchangeId = clientContext.getExchangeId();
- LOG.debug("{} requireMutualAuth is set but GSSAUthContext does not have"
- + " mutualAuthState set", exchangeId);
- }
- state = State.FAILED;
- throw new AuthenticationException(
- "requireMutualAuth is set but GSSContext mutualAuthState is not set");
- } else {
- state = State.SUCCEEDED;
- }
- }
- break;
- default:
- state = State.FAILED;
- throw new IllegalStateException("Illegal state: " + state);
-
- }
- } catch (final 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(), gsse);
}
}
@@ -232,13 +135,11 @@ public abstract class GGSSchemeBase implements AuthScheme2 {
* @since 4.4
*/
protected byte[] generateGSSToken(
- final byte[] input, final Oid oid, final String gssServiceName, final String gssHostname) throws GSSException {
+ final byte[] input, final Oid oid, final String serviceName, final String authServer) throws GSSException {
final GSSManager manager = getManager();
- final GSSName peerName = manager.createName(gssServiceName + "@" + gssHostname, GSSName.NT_HOSTBASED_SERVICE);
+ final GSSName serverName = manager.createName(serviceName + "@" + authServer, GSSName.NT_HOSTBASED_SERVICE);
- if (gssContext == null) {
- gssContext = createGSSContext(manager, oid, peerName, gssCredential);
- }
+ final GSSContext gssContext = createGSSContext(manager, oid, serverName, gssCredential);
if (input != null) {
return gssContext.initSecContext(input, 0, input.length);
}
@@ -251,35 +152,24 @@ public abstract class GGSSchemeBase implements AuthScheme2 {
protected GSSContext createGSSContext(
final GSSManager manager,
final Oid oid,
- final GSSName peerName,
+ final GSSName serverName,
final GSSCredential gssCredential) throws GSSException {
- final GSSContext gssContext = manager.createContext(peerName.canonicalize(oid), oid, gssCredential,
+ final GSSContext gssContext = manager.createContext(serverName.canonicalize(oid), oid, gssCredential,
GSSContext.DEFAULT_LIFETIME);
gssContext.requestMutualAuth(true);
- if (config.getRequestDelegCreds() != KerberosConfig.Option.DEFAULT) {
- gssContext.requestCredDeleg(config.getRequestDelegCreds() == KerberosConfig.Option.ENABLE);
- }
- if (config.getRequestMutualAuth() != KerberosConfig.Option.DEFAULT) {
- gssContext.requestMutualAuth(config.getRequestMutualAuth() == KerberosConfig.Option.ENABLE);
+ if (config.getRequestDelegCreds() != org.apache.hc.client5.http.auth.KerberosConfig.Option.DEFAULT) {
+ gssContext.requestCredDeleg(config.getRequestDelegCreds() == org.apache.hc.client5.http.auth.KerberosConfig.Option.ENABLE);
}
return gssContext;
}
/**
* @since 4.4
*/
- protected abstract byte[] generateToken(byte[] input, String gssServiceName, String gssHostname) throws GSSException;
+ protected abstract byte[] generateToken(byte[] input, String serviceName, String authServer) throws GSSException;
@Override
public boolean isChallengeComplete() {
- // For the mutual authentication response, this is should technically return true.
- // However, the HttpAuthenticator immediately fails the authentication
- // process if we return true, so we only return true here if the authentication has failed.
- return this.state == State.FAILED;
- }
-
- @Override
- public boolean isChallengeExpected() {
- return state == State.TOKEN_SENT && mutualAuth;
+ return this.state == State.TOKEN_GENERATED || this.state == State.FAILED;
}
@Override
@@ -306,8 +196,6 @@ public abstract class GGSSchemeBase implements AuthScheme2 {
return null;
}
- // Format the queued token and update the state.
- // All token processing is done in processChallenge()
@Override
public String generateAuthResponse(
final HttpHost host,
@@ -320,16 +208,53 @@ public abstract class GGSSchemeBase implements AuthScheme2 {
throw new AuthenticationException(getName() + " authentication has not been initiated");
case FAILED:
throw new AuthenticationException(getName() + " authentication has failed");
- case SUCCEEDED:
- return null;
- case TOKEN_READY:
- state = State.TOKEN_SENT;
+ case CHALLENGE_RECEIVED:
+ try {
+ final String authServer;
+ String hostname = host.getHostName();
+ if (config.getUseCanonicalHostname() != org.apache.hc.client5.http.auth.KerberosConfig.Option.DISABLE) {
+ try {
+ hostname = dnsResolver.resolveCanonicalHostname(host.getHostName());
+ } catch (final UnknownHostException ignore) {
+ }
+ }
+ if (config.getStripPort() != org.apache.hc.client5.http.auth.KerberosConfig.Option.DISABLE) {
+ authServer = hostname;
+ } else {
+ authServer = hostname + ":" + host.getPort();
+ }
+
+ if (LOG.isDebugEnabled()) {
+ final HttpClientContext clientContext = HttpClientContext.cast(context);
+ final String exchangeId = clientContext.getExchangeId();
+ LOG.debug("{} init {}", exchangeId, authServer);
+ }
+ token = generateToken(token, KERBEROS_SCHEME, authServer);
+ state = State.TOKEN_GENERATED;
+ } catch (final 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:
final Base64 codec = new Base64(0);
- final String tokenstr = new String(codec.encode(queuedToken));
+ final String tokenstr = new String(codec.encode(token));
if (LOG.isDebugEnabled()) {
final HttpClientContext clientContext = HttpClientContext.cast(context);
final String exchangeId = clientContext.getExchangeId();
- LOG.debug("{} Sending GSS response '{}' back to the auth server", exchangeId, tokenstr);
+ LOG.debug("{} Sending response '{}' back to the auth server", exchangeId, tokenstr);
}
return StandardAuthScheme.SPNEGO + " " + tokenstr;
default:
diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/auth/KerberosScheme.java b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/auth/KerberosScheme.java
index 5b00e0fe1..9b2adb96d 100644
--- a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/auth/KerberosScheme.java
+++ b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/auth/KerberosScheme.java
@@ -41,8 +41,10 @@ import org.ietf.jgss.Oid;
*
* @since 4.2
*
- * @deprecated Do not use. Consider using Spengo, Basic or Bearer authentication with TLS instead.
+ * @deprecated Do not use. The Kerberos authentication scheme was never standardised.
+ * Use {@link MutualSpnegoScheme} or some other scheme instead.
*
+ * @see MutualSpnegoScheme
* @see BasicScheme
* @see BearerScheme
*/
diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/auth/KerberosSchemeFactory.java b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/auth/KerberosSchemeFactory.java
index 25930f099..9c6cf9349 100644
--- a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/auth/KerberosSchemeFactory.java
+++ b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/auth/KerberosSchemeFactory.java
@@ -45,9 +45,10 @@ import org.apache.hc.core5.http.protocol.HttpContext;
*
* @since 4.2
*
- * @deprecated Do not use. The GGS based experimental authentication schemes are no longer
- * supported. Consider using Basic or Bearer authentication with TLS instead.
+ * @deprecated Do not use. The Kerberos authentication scheme was never standardised.
+ * Use {@link MutualSpnegoScheme} or some other scheme instead.
*
+ * @see MutualSpnegoSchemeFactory
* @see BasicSchemeFactory
* @see BearerSchemeFactory
*/
diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/auth/MutualGssSchemeBase.java b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/auth/MutualGssSchemeBase.java
new file mode 100644
index 000000000..9fbee575a
--- /dev/null
+++ b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/auth/MutualGssSchemeBase.java
@@ -0,0 +1,348 @@
+/*
+ * ====================================================================
+ * 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
+ *
+ * This is the new mutual authentication capable Scheme which replaces the old deprecated non mutual + * authentication capable {@link SPNegoScheme} + *
+ * + *+ * Note that this scheme is not enabled by default. To use it, you need create a custom + * {@link AuthenticationStrategy} and a custom {@link AuthSchemeFactory} {@link Registry}, + * and set them on the HttpClientBuilder. + *
+ * + *+ * {@code + * private static class SpnegoAuthenticationStrategy extends DefaultAuthenticationStrategy { + * private static final List+ * + * @since 5.5 + */ +@Experimental +public class MutualSpnegoScheme extends MutualGssSchemeBase { + + private static final String SPNEGO_OID = "1.3.6.1.5.5.2"; + + /** + * @since 5.0 + */ + public MutualSpnegoScheme(final org.apache.hc.client5.http.auth.KerberosConfig config, final DnsResolver dnsResolver) { + super(config, dnsResolver); + } + + public MutualSpnegoScheme() { + super(); + } + + @Override + public String getName() { + return StandardAuthScheme.SPNEGO; + } + + @Override + protected byte[] generateToken(final byte[] input, final String gssServiceName, final String gssHostname) throws GSSException { + return generateGSSToken(input, new Oid(SPNEGO_OID), gssServiceName, gssHostname); + } + + @Override + public boolean isConnectionBased() { + return true; + } + +} diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/auth/MutualSpnegoSchemeFactory.java b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/auth/MutualSpnegoSchemeFactory.java new file mode 100644 index 000000000..5880f47ad --- /dev/null +++ b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/auth/MutualSpnegoSchemeFactory.java @@ -0,0 +1,76 @@ +/* + * ==================================================================== + * 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 + *SPNEGO_SCHEME_PRIORITY = + * Collections.unmodifiableList( + * Arrays.asList(StandardAuthScheme.SPNEGO + * // Add other Schemes as needed + * ); + * + * @Override + * protected final List getSchemePriority() { + * return SPNEGO_SCHEME_PRIORITY; + * } + * } + * + * AuthenticationStrategy mutualStrategy = new SpnegoAuthenticationStrategy(); + * + * AuthSchemeFactory mutualFactory = new MutualSpnegoSchemeFactory(); + * Registry mutualSchemeRegistry = RegistryBuilder. create() + * .register(StandardAuthScheme.SPNEGO, mutualFactory) + * //register other schemes as needed + * .build(); + * + * CloseableHttpClient mutualClient = HttpClientBuilder.create() + * .setTargetAuthenticationStrategy(mutualStrategy); + * .setDefaultAuthSchemeRegistry(mutualSchemeRegistry); + * .build(); + * } + *
+ * This replaces the old deprecated {@link SPNegoSchemeFactory} + *
+ * + * @since 5.5 + * + * @see SPNegoSchemeFactory + */ +@Contract(threading = ThreadingBehavior.STATELESS) +@Experimental +public class MutualSpnegoSchemeFactory implements AuthSchemeFactory { + + /** + * Singleton instance for the default configuration. + */ + public static final MutualSpnegoSchemeFactory DEFAULT = new MutualSpnegoSchemeFactory(org.apache.hc.client5.http.auth.KerberosConfig.DEFAULT, + SystemDefaultDnsResolver.INSTANCE); + + private final org.apache.hc.client5.http.auth.KerberosConfig config; + private final DnsResolver dnsResolver; + + /** + * @since 5.0 + */ + public MutualSpnegoSchemeFactory(final org.apache.hc.client5.http.auth.KerberosConfig config, final DnsResolver dnsResolver) { + super(); + this.config = config; + this.dnsResolver = dnsResolver; + } + + @Override + public AuthScheme create(final HttpContext context) { + return new MutualSpnegoScheme(this.config, this.dnsResolver); + } + +} diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/auth/SPNegoScheme.java b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/auth/SPNegoScheme.java index 2ec37febe..6d9f9408f 100644 --- a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/auth/SPNegoScheme.java +++ b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/auth/SPNegoScheme.java @@ -36,12 +36,19 @@ import org.ietf.jgss.Oid; * SPNEGO (Simple and Protected GSSAPI Negotiation Mechanism) authentication * scheme. *- * Please note this class is considered experimental and may be discontinued or removed - * in the future. + * This class implements the old deprecated non mutual authentication capable SPNEGO implementation. + * Use {@link MutualSpnegoScheme} instead. *
* * @since 4.2 + * + * @deprecated Use {@link MutualSpnegoScheme} or some other auth scheme instead. + * + * @see MutualSpnegoScheme + * @see BasicScheme + * @see BearerScheme */ +@Deprecated @Experimental public class SPNegoScheme extends GGSSchemeBase { @@ -64,8 +71,8 @@ public class SPNegoScheme extends GGSSchemeBase { } @Override - protected byte[] generateToken(final byte[] input, final String gssServiceName, final String gssHostname) throws GSSException { - return generateGSSToken(input, new Oid(SPNEGO_OID), gssServiceName, gssHostname); + protected byte[] generateToken(final byte[] input, final String serviceName, final String authServer) throws GSSException { + return generateGSSToken(input, new Oid(SPNEGO_OID), serviceName, authServer); } @Override diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/auth/SPNegoSchemeFactory.java b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/auth/SPNegoSchemeFactory.java index 14d8528c5..1231d47e4 100644 --- a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/auth/SPNegoSchemeFactory.java +++ b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/auth/SPNegoSchemeFactory.java @@ -39,15 +39,15 @@ import org.apache.hc.core5.http.protocol.HttpContext; * {@link AuthSchemeFactory} implementation that creates and initializes * {@link SPNegoScheme} instances. *- * Please note this class is considered experimental and may be discontinued or removed - * in the future. + * This factory creates the old deprecated non mutual authentication capable SPNEGO implementation. + * Use {@link MutualSpnegoAuthFactory} instead. *
* * @since 4.2 * - * @deprecated Do not use. The GGS based experimental authentication schemes are no longer - * supported. Consider using Basic or Bearer authentication with TLS instead. + * @deprecated Use {@link MutualSpnegoAuthFactory} or some other auth scheme instead. * + * @see MutualSpnegoAuthFactory * @see BasicSchemeFactory * @see BearerSchemeFactory */