* Added HTTP parameters to define the order of preference for supported auth schemes for target host and proxy authentication

* Added SPNEGO auth policy

git-svn-id: https://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk@818601 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Oleg Kalnichevski 2009-09-24 19:35:03 +00:00
parent 9cbf76568f
commit af4b944189
8 changed files with 195 additions and 49 deletions

View File

@ -1,6 +1,10 @@
Changes since 4.0
-------------------
* Added parameters to define the order of preference for supported auth
schemes for target host and proxy authentication.
Contributed by Oleg Kalnichevski <olegk at apache.org>
* [HTTPCLIENT-875] DefaultClientConnectionOperator#openConnection doesn't
update the connection state if the connection socket changed after
the call to SocketFactory#connectSocket().

View File

@ -27,6 +27,8 @@
package org.apache.http.auth.params;
import org.apache.http.auth.AuthScheme;
/**
* Parameter names for HTTP authentication classes.
*
@ -42,4 +44,26 @@ public interface AuthPNames {
*/
public static final String CREDENTIAL_CHARSET = "http.auth.credential-charset";
/**
* Defines the order of preference for supported {@link AuthScheme}s when
* authenticating with the target host.
* <p>
* This parameter expects a value of type {@link java.util.Collection}. The
* collection is expected to contain {@link String} instances representing
* a name of an authentication scheme as returned by
* {@link AuthScheme#getSchemeName()}.
*/
public static final String TARGET_AUTH_PREF = "http.auth.target-scheme-pref";
/**
* Defines the order of preference for supported {@link AuthScheme}s when
* authenticating with the proxy host.
* <p>
* This parameter expects a value of type {@link java.util.Collection}. The
* collection is expected to contain {@link String} instances representing
* a name of an authentication scheme as returned by
* {@link AuthScheme#getSchemeName()}.
*/
public static final String PROXY_AUTH_PREF = "http.auth.proxy-scheme-pref";
}

View File

@ -59,4 +59,11 @@ public final class AuthPolicy {
*/
public static final String BASIC = "Basic";
/**
* SPNEGO/Kerberos Authentication scheme.
*
* @since 4.1
*/
public static final String SPNEGO = "negotiate";
}

View File

@ -89,8 +89,9 @@ public interface ClientContext {
public static final String PROXY_AUTH_STATE = "http.auth.proxy-scope";
/**
* RESERVED. DO NOT USE!!!
* @deprecated do not use
*/
@Deprecated
public static final String AUTH_SCHEME_PREF = "http.auth.scheme-pref";
/**

View File

@ -35,18 +35,18 @@ import java.util.List;
import java.util.Locale;
import java.util.Map;
import org.apache.http.annotation.Immutable;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.http.FormattedHeader;
import org.apache.http.Header;
import org.apache.http.HttpResponse;
import org.apache.http.annotation.Immutable;
import org.apache.http.auth.AuthScheme;
import org.apache.http.auth.AuthSchemeRegistry;
import org.apache.http.auth.AuthenticationException;
import org.apache.http.auth.MalformedChallengeException;
import org.apache.http.client.AuthenticationHandler;
import org.apache.http.client.params.AuthPolicy;
import org.apache.http.client.protocol.ClientContext;
import org.apache.http.protocol.HTTP;
import org.apache.http.protocol.HttpContext;
@ -64,9 +64,10 @@ public abstract class AbstractAuthenticationHandler implements AuthenticationHan
private static final List<String> DEFAULT_SCHEME_PRIORITY =
Collections.unmodifiableList(Arrays.asList(new String[] {
"ntlm",
"digest",
"basic"
AuthPolicy.SPNEGO,
AuthPolicy.NTLM,
AuthPolicy.DIGEST,
AuthPolicy.BASIC
}));
public AbstractAuthenticationHandler() {
@ -106,11 +107,31 @@ public abstract class AbstractAuthenticationHandler implements AuthenticationHan
return map;
}
/**
* Returns default list of auth scheme names in their order of preference.
*
* @return list of auth scheme names
*/
protected List<String> getAuthPreferences() {
return DEFAULT_SCHEME_PRIORITY;
}
public AuthScheme selectScheme(
/**
* Returns default list of auth scheme names in their order of preference
* based on the HTTP response and the current execution context.
*
* @param response HTTP response.
* @param context HTTP execution context.
*
* @since 4.1
*/
protected List<String> getAuthPreferences(
final HttpResponse response,
final HttpContext context) {
return getAuthPreferences();
}
public AuthScheme selectScheme(
final Map<String, Header> challenges,
final HttpResponse response,
final HttpContext context) throws AuthenticationException {
@ -121,11 +142,9 @@ public abstract class AbstractAuthenticationHandler implements AuthenticationHan
throw new IllegalStateException("AuthScheme registry not set in HTTP context");
}
@SuppressWarnings("unchecked")
Collection<String> authPrefs = (Collection<String>) context.getAttribute(
ClientContext.AUTH_SCHEME_PREF);
Collection<String> authPrefs = getAuthPreferences(response, context);
if (authPrefs == null) {
authPrefs = getAuthPreferences();
authPrefs = DEFAULT_SCHEME_PRIORITY;
}
if (this.log.isDebugEnabled()) {

View File

@ -27,6 +27,7 @@
package org.apache.http.impl.client;
import java.util.List;
import java.util.Map;
import org.apache.http.annotation.Immutable;
@ -36,6 +37,7 @@ import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.auth.AUTH;
import org.apache.http.auth.MalformedChallengeException;
import org.apache.http.auth.params.AuthPNames;
import org.apache.http.client.AuthenticationHandler;
import org.apache.http.protocol.HttpContext;
@ -72,4 +74,18 @@ public class DefaultProxyAuthenticationHandler extends AbstractAuthenticationHan
return parseChallenges(headers);
}
@Override
protected List<String> getAuthPreferences(
final HttpResponse response,
final HttpContext context) {
@SuppressWarnings("unchecked")
List<String> authpref = (List<String>) response.getParams().getParameter(
AuthPNames.PROXY_AUTH_PREF);
if (authpref != null) {
return authpref;
} else {
return super.getAuthPreferences(response, context);
}
}
}

View File

@ -27,6 +27,7 @@
package org.apache.http.impl.client;
import java.util.List;
import java.util.Map;
import org.apache.http.annotation.Immutable;
@ -36,6 +37,7 @@ import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.auth.AUTH;
import org.apache.http.auth.MalformedChallengeException;
import org.apache.http.auth.params.AuthPNames;
import org.apache.http.client.AuthenticationHandler;
import org.apache.http.protocol.HttpContext;
@ -72,4 +74,19 @@ public class DefaultTargetAuthenticationHandler extends AbstractAuthenticationHa
return parseChallenges(headers);
}
@Override
protected List<String> getAuthPreferences(
final HttpResponse response,
final HttpContext context) {
@SuppressWarnings("unchecked")
List<String> authpref = (List<String>) response.getParams().getParameter(
AuthPNames.TARGET_AUTH_PREF);
if (authpref != null) {
return authpref;
} else {
return super.getAuthPreferences(response, context);
}
}
}

View File

@ -103,8 +103,8 @@ pwd
those applications that do not want the overhead of full transport security
through TLS/SSL encryption.</para>
</formalpara>
<listitem>
</listitem>
<listitem>
<formalpara>
<title>NTLM:</title>
<para>NTLM is a proprietary authentication scheme developed by Microsoft and
@ -130,8 +130,8 @@ pwd
If this parameter is not set HttpClient will handle authentication
automatically.</para>
</formalpara>
<listitem>
</listitem>
<listitem>
<formalpara>
<title>'http.auth.credential-charset':</title>
<para>defines the charset to be used when encoding user credentials. This
@ -139,7 +139,41 @@ pwd
this parameter is not set <literal>US-ASCII</literal> will be used.</para>
</formalpara>
</listitem>
<listitem>
<formalpara>
<title>'http.auth.target-scheme-pref':</title>
<para>Defines the order of preference for supported
<interfacename>AuthScheme</interfacename>s when authenticating with the
target host. This parameter expects a value of type
<interface>java.util.Collection</interface>. The collection is expected
to contain <classname>java.lang.String</classname> instances representing a
name of an authentication scheme as returned by
<methodname>AuthScheme#getSchemeName()</methodname></para>
</formalpara>
</listitem>
<listitem>
<formalpara>
<title>'http.auth.proxy-scheme-pref':</title>
<para>Defines the order of preference for supported
<interfacename>AuthScheme</interfacename>s when authenticating with the
proxy host. This parameter expects a value of type
<interface>java.util.Collection</interface>. The collection is expected
to contain <classname>java.lang.String</classname> instances representing a
name of an authentication scheme as returned by
<methodname>AuthScheme#getSchemeName()</methodname></para>
</formalpara>
</listitem>
</itemizedlist>
<para>For example, one can force HttpClient to use a different order of preference for
authentication schemes</para>
<programlisting><![CDATA[
DefaultHttpClient httpclient = new DefaultHttpClient(ccm, params);
// Choose BASIC over DIGEST for proxy authentication
List<String> authpref = new ArrayList<String>();
authpref.add(AuthPolicy.BASIC);
authpref.add(AuthPolicy.DIGEST);
httpclient.getParams().setParameter(AuthPNames.PROXY_AUTH_PREF, authpref);
]]></programlisting>
</section>
<section>
<title>Authentication scheme registry</title>
@ -332,44 +366,59 @@ httpclient.addRequestInterceptor(preemptiveAuth, 0);
<section>
<title><literal>SPNEGO</literal>/Kerberos Authentication</title>
<para><literal>SPNEGO</literal> (<emphasis>S</emphasis>imple and <emphasis>P</emphasis>rotected <literal>GSSAPI</literal>
<emphasis>Nego</emphasis>tiation Mechanism) is designed to allow for authentication
to services when neither end knows what the other can use/provide. It is most
commonly used to do Kerberos authentication. It can wrap other mechanisms, however
the current version in HTTPClient is designed solely with Kerberos in mind. The image below shows a simple authentication process.
</para>
<para><literal>SPNEGO</literal> (<emphasis>S</emphasis>imple and
<emphasis>P</emphasis>rotected <literal>GSSAPI</literal>
<emphasis>Nego</emphasis>tiation Mechanism) is designed to allow for authentication to
services when neither end knows what the other can use/provide. It is most commonly used
to do Kerberos authentication. It can wrap other mechanisms, however the current version
in HTTPClient is designed solely with Kerberos in mind. The image below shows a simple
authentication process. </para>
<mediaobject>
<imageobject>
<imagedata fileref=".//images/SPNEGO_cropped.png" />
<imagedata fileref=".//images/SPNEGO_cropped.png"/>
</imageobject>
</mediaobject>
<sidebar>
<para>1. Client Web Browser does HTTP GET for resource.</para>
<para>2. Web server returns HTTP 401 status and a header: &quot;WWW-Authenticate: Negotiate</para>
<para>3. Client generates a NegTokenInit, base64 encodes it, and resubmits the GET with an Authorization header: &quot;Authorization: Negotiate &lt;base64 encoding&gt;&quot;.</para>
<para>4. Server decodes the NegTokenInit, extracts the supported MechTypes (only Kerberos V5 in our case), ensures it is one of the expected ones, and then extracts the MechToken (Kerberos Token) and authenticates it.</para>
<para>4a. If more processing is required another HTTP 401 is returned to the client with more data in the the WWW-Authenticate header. Client takes the info and generates another token passing this back in the Authorization header.... until complete.</para>
<para>5. When the client has been authenticated the Web server should return the HTTP 200 status, a final WWW-Authenticate header and the page content.</para>
<sidebar>
<para>1. Client Web Browser does HTTP GET for resource.</para>
<para>2. Web server returns HTTP 401 status and a header: &quot;WWW-Authenticate:
Negotiate</para>
<para>3. Client generates a NegTokenInit, base64 encodes it, and resubmits the GET with
an Authorization header: &quot;Authorization: Negotiate &lt;base64
encoding&gt;&quot;.</para>
<para>4. Server decodes the NegTokenInit, extracts the supported MechTypes (only
Kerberos V5 in our case), ensures it is one of the expected ones, and then extracts
the MechToken (Kerberos Token) and authenticates it.</para>
<para>4a. If more processing is required another HTTP 401 is returned to the client with
more data in the the WWW-Authenticate header. Client takes the info and generates
another token passing this back in the Authorization header.... until
complete.</para>
<para>5. When the client has been authenticated the Web server should return the HTTP
200 status, a final WWW-Authenticate header and the page content.</para>
</sidebar>
<section>
<title>HTTPClient Implementation</title>
<para>Supports Sun Java versions 1.5 and up.</para>
<para>The JRE provides the supporting classes to do nearly all the kerberos and SPNEGO token handling. This means that a lot of the setup
is for the GSS classes. The NegotiateScheme is a simple class to handle marshalling the tokens and reading and writing the correct headers.</para>
<para>The JRE provides the supporting classes to do nearly all the kerberos and SPNEGO
token handling. This means that a lot of the setup is for the GSS classes. The
NegotiateScheme is a simple class to handle marshalling the tokens and reading and
writing the correct headers.</para>
</section>
<section>
<title>Usage.</title>
<para>The best way to start is to grab the KerberosHttpClient.java file in examples and try and get it to work.
There are a lot of issues that can happen but if lucky it'll work without too much problem. It should also
provide some output to debug with.</para>
<para>The best way to start is to grab the KerberosHttpClient.java file in examples and
try and get it to work. There are a lot of issues that can happen but if lucky it'll
work without too much problem. It should also provide some output to debug
with.</para>
<para>In windows it should default to using the logged in credentials, this
can be overridden by using 'kinit' e.g. <literal>$JAVA_HOME\bin\kinit testuser@AD.EXAMPLE.NET</literal>, which is very
helpful for testing and debugging issues. Remove the cache file created to revert back to the windows
Kerberos cache.</para>
<para>Make sure to list domain_realms in the krb5.conf file. This is a major source of problems.</para>
<para>In windows it should default to using the logged in credentials, this can be
overridden by using 'kinit' e.g. <literal>$JAVA_HOME\bin\kinit
testuser@AD.EXAMPLE.NET</literal>, which is very helpful for testing and
debugging issues. Remove the cache file created to revert back to the windows
Kerberos cache.</para>
<para>Make sure to list domain_realms in the krb5.conf file. This is a major source of
problems.</para>
</section>
<section>
<title>NegotiateSchemeFactory Class</title>
@ -379,35 +428,44 @@ Kerberos cache.</para>
<section>
<title>setStripPort(boolean)</title>
<para>Strips the port off service names e.g. HTTP/webserver.ad.example.net:8080 -> HTTP/webserver.ad.example.net</para>
<para>Strips the port off service names e.g. HTTP/webserver.ad.example.net:8080 ->
HTTP/webserver.ad.example.net</para>
<para>Found it useful when using JbossNegotiation.</para>
</section>
<section>
<title> setSpnegoCreate(boolean)</title>
<para>If using Java 1.5 or a Kerberos ticket an attempt will be made to wrap it up into a SPNEGO token. Again for JbossNegotiation. II7 accepts plain Kerberos tickets.</para>
<para>If using Java 1.5 or a Kerberos ticket an attempt will be made to wrap it up into
a SPNEGO token. Again for JbossNegotiation. II7 accepts plain Kerberos
tickets.</para>
</section>
<section>
<title>setSpengoGenerator(SpnegoTokenGenerator)</title>
<para>Inject a custom SpnegoTokenGenerator class to do the Kerberos to SPNEGO token wrapping. BouncySpnegoTokenGenerator example
is provided. This requires the BouncyCastle libs <ulink url="http://www.bouncycastle.org/java.html">"http://www.bouncycastle.org/java.html"</ulink>
</para>
<para>Inject a custom SpnegoTokenGenerator class to do the Kerberos to SPNEGO token
wrapping. BouncySpnegoTokenGenerator example is provided. This requires the
BouncyCastle libs <ulink url="http://www.bouncycastle.org/java.html"
>"http://www.bouncycastle.org/java.html"</ulink>
</para>
</section>
<section>
<title>GSS/Java Kerberos Setup.</title>
<para>This documentation assumes you are using windows but much of the informationapplies to Unix as well.</para>
<para>The org.ietf.jgss classes have lots of possible configuration parameters,
mainly in the krb5.conf/krb5.ini file. Some more info on the format at
<ulink url="http://web.mit.edu/kerberos/krb5-1.4/krb5-1.4.1/doc/krb5-admin/krb5.conf.html">http://web.mit.edu/kerberos/krb5-1.4/krb5-1.4.1/doc/krb5-admin/krb5.conf.html</ulink>.</para>
<para>This documentation assumes you are using windows but much of the
informationapplies to Unix as well.</para>
<para>The org.ietf.jgss classes have lots of possible configuration parameters, mainly
in the krb5.conf/krb5.ini file. Some more info on the format at <ulink
url="http://web.mit.edu/kerberos/krb5-1.4/krb5-1.4.1/doc/krb5-admin/krb5.conf.html"
>http://web.mit.edu/kerberos/krb5-1.4/krb5-1.4.1/doc/krb5-admin/krb5.conf.html</ulink>.</para>
</section>
<section>
<title>login.conf file</title>
<para>The following configuration is a basic setup that works in Windows XP against both IIS7 and JbossNegotiate modules.</para>
<para>The system property that can be use to point to the login.conf file is <emphasis>java.security.auth.login.config</emphasis>.</para>
<para>The following configuration is a basic setup that works in Windows XP against both
IIS7 and JbossNegotiate modules.</para>
<para>The system property that can be use to point to the login.conf file is
<emphasis>java.security.auth.login.config</emphasis>.</para>
<para>Sample usage...</para>
<programlisting>System.setProperty("java.security.auth.login.config", "login.conf");</programlisting>
@ -432,7 +490,7 @@ com.sun.security.jgss.accept {
<para>If unspecified the system default will be used. Override with...</para>
<programlisting>System.setProperty("java.security.krb5.conf", "krb5.conf");</programlisting>
<para>Example file contents...</para>
<programlisting><![CDATA[
[libdefaults]
default_realm = AD.EXAMPLE.NET