HTTPCLIENT-1156: Refactored NegotiateScheme into separate SPNegoScheme and KerberosScheme implementations; deprecated NegotiateScheme and related classes
git-svn-id: https://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk@1233319 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
74e1be5ca8
commit
9867254c97
|
@ -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";
|
||||
|
||||
}
|
||||
|
|
|
@ -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
|
||||
* <http://www.apache.org/>.
|
||||
*/
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -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
|
||||
* <http://www.apache.org/>.
|
||||
*/
|
||||
|
||||
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 <code>null</code>.
|
||||
*
|
||||
* @return <code>null</code>
|
||||
*/
|
||||
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 <code>null</code>.
|
||||
*
|
||||
* @return <code>null</code>
|
||||
*/
|
||||
public String getRealm() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns <tt>true</tt>. KERBEROS authentication scheme is connection based.
|
||||
*
|
||||
* @return <tt>true</tt>.
|
||||
*/
|
||||
public boolean isConnectionBased() {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
|
@ -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
|
||||
* <http://www.apache.org/>.
|
||||
*
|
||||
*/
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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 <tt>true</tt> if authorization has been processed,
|
||||
* <tt>false</tt> 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,37 +99,11 @@ 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");
|
||||
}
|
||||
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();
|
||||
return super.authenticate(credentials, request, context);
|
||||
}
|
||||
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("init " + authServer);
|
||||
}
|
||||
@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
|
||||
|
@ -195,17 +119,12 @@ public class NegotiateScheme extends AuthSchemeBase {
|
|||
*/
|
||||
|
||||
/** Try SPNEGO by default, fall back to Kerberos later if error */
|
||||
negotiationOid = new Oid(SPNEGO_OID);
|
||||
Oid negotiationOid = new Oid(SPNEGO_OID);
|
||||
|
||||
byte[] token = input;
|
||||
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);
|
||||
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.
|
||||
|
@ -221,58 +140,21 @@ public class NegotiateScheme extends AuthSchemeBase {
|
|||
/* 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");
|
||||
}
|
||||
token = generateGSSToken(token, negotiationOid, authServer);
|
||||
|
||||
/*
|
||||
* 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)) {
|
||||
if (token != null && spengoGenerator != null) {
|
||||
try {
|
||||
token = spengoGenerator.generateSpnegoDERObject(token);
|
||||
}
|
||||
|
||||
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());
|
||||
log.error(ex.getMessage(), ex);
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
* <http://www.apache.org/>.
|
||||
*/
|
||||
|
||||
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 <code>null</code>.
|
||||
*
|
||||
* @return <code>null</code>
|
||||
*/
|
||||
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 <code>null</code>.
|
||||
*
|
||||
* @return <code>null</code>
|
||||
*/
|
||||
public String getRealm() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns <tt>true</tt>. SPNEGO authentication scheme is connection based.
|
||||
*
|
||||
* @return <tt>true</tt>.
|
||||
*/
|
||||
public boolean isConnectionBased() {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
|
@ -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
|
||||
* <http://www.apache.org/>.
|
||||
*
|
||||
*/
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -66,6 +66,7 @@ class AuthenticationStrategyImpl implements AuthenticationStrategy {
|
|||
private static final List<String> DEFAULT_SCHEME_PRIORITY =
|
||||
Collections.unmodifiableList(Arrays.asList(new String[] {
|
||||
AuthPolicy.SPNEGO,
|
||||
AuthPolicy.KERBEROS,
|
||||
AuthPolicy.NTLM,
|
||||
AuthPolicy.DIGEST,
|
||||
AuthPolicy.BASIC
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
Loading…
Reference in New Issue