hc-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ol...@apache.org
Subject svn commit: r881935 - in /httpcomponents/httpclient/trunk: ./ httpclient/src/examples/org/apache/http/examples/client/ httpclient/src/main/java/org/apache/http/client/ httpclient/src/main/java/org/apache/http/client/protocol/ httpclient/src/main/java/o...
Date Wed, 18 Nov 2009 21:07:36 GMT
Author: olegk
Date: Wed Nov 18 21:07:35 2009
New Revision: 881935

URL: http://svn.apache.org/viewvc?rev=881935&view=rev
Log:
HTTPCLIENT-872: HttpClient can now persist authentication data between request executions
as long as they share the same execution context. It has also become much easier to make HttpClient
authenticate preemptively by pre-populating authentication data cache

Added:
    httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/client/AuthCache.java
  (with props)
    httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/client/protocol/RequestAuthCache.java
  (with props)
    httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/client/protocol/ResponseAuthCache.java
  (with props)
    httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/client/BasicAuthCache.java
  (with props)
Modified:
    httpcomponents/httpclient/trunk/RELEASE_NOTES.txt
    httpcomponents/httpclient/trunk/httpclient/src/examples/org/apache/http/examples/client/ClientPreemptiveBasicAuthentication.java
    httpcomponents/httpclient/trunk/httpclient/src/examples/org/apache/http/examples/client/ClientPreemptiveDigestAuthentication.java
    httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/client/protocol/ClientContext.java
    httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/client/BasicCredentialsProvider.java
    httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/client/DefaultHttpClient.java
    httpcomponents/httpclient/trunk/httpclient/src/test/java/org/apache/http/impl/client/TestClientAuthentication.java
    httpcomponents/httpclient/trunk/httpclient/src/test/java/org/apache/http/localserver/RequestBasicAuth.java
    httpcomponents/httpclient/trunk/src/docbkx/authentication.xml

Modified: httpcomponents/httpclient/trunk/RELEASE_NOTES.txt
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/RELEASE_NOTES.txt?rev=881935&r1=881934&r2=881935&view=diff
==============================================================================
--- httpcomponents/httpclient/trunk/RELEASE_NOTES.txt (original)
+++ httpcomponents/httpclient/trunk/RELEASE_NOTES.txt Wed Nov 18 21:07:35 2009
@@ -1,6 +1,12 @@
 Changes since 4.0
 -------------------
 
+* [HTTPCLIENT-872] HttpClient can now persist authentication data between request 
+  executions as long as they share the same execution context. It has also become
+  much easier to make HttpClient authenticate preemptively by pre-populating 
+  authentication data cache.
+  Contributed by Oleg Kalnichevski <olegk at apache.org>
+
 * [HTTPCLIENT-885] URLEncodedUtils now correctly parses form-url-encoded 
   entities that specify a charset.
   Contributed by Oleg Kalnichevski <olegk at apache.org>

Modified: httpcomponents/httpclient/trunk/httpclient/src/examples/org/apache/http/examples/client/ClientPreemptiveBasicAuthentication.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient/src/examples/org/apache/http/examples/client/ClientPreemptiveBasicAuthentication.java?rev=881935&r1=881934&r2=881935&view=diff
==============================================================================
--- httpcomponents/httpclient/trunk/httpclient/src/examples/org/apache/http/examples/client/ClientPreemptiveBasicAuthentication.java
(original)
+++ httpcomponents/httpclient/trunk/httpclient/src/examples/org/apache/http/examples/client/ClientPreemptiveBasicAuthentication.java
Wed Nov 18 21:07:35 2009
@@ -25,27 +25,18 @@
 
 package org.apache.http.examples.client;
 
-import java.io.IOException;
-
 import org.apache.http.HttpEntity;
-import org.apache.http.HttpException;
 import org.apache.http.HttpHost;
-import org.apache.http.HttpRequest;
-import org.apache.http.HttpRequestInterceptor;
 import org.apache.http.HttpResponse;
-import org.apache.http.auth.AuthScheme;
 import org.apache.http.auth.AuthScope;
-import org.apache.http.auth.AuthState;
-import org.apache.http.auth.Credentials;
 import org.apache.http.auth.UsernamePasswordCredentials;
-import org.apache.http.client.CredentialsProvider;
+import org.apache.http.client.AuthCache;
 import org.apache.http.client.methods.HttpGet;
 import org.apache.http.client.protocol.ClientContext;
 import org.apache.http.impl.auth.BasicScheme;
+import org.apache.http.impl.client.BasicAuthCache;
 import org.apache.http.impl.client.DefaultHttpClient;
 import org.apache.http.protocol.BasicHttpContext;
-import org.apache.http.protocol.ExecutionContext;
-import org.apache.http.protocol.HttpContext;
 
 /**
  * An example of HttpClient can be customized to authenticate 
@@ -54,31 +45,30 @@
  * Generally, preemptive authentication can be considered less
  * secure than a response to an authentication challenge
  * and therefore discouraged.
- * <b/>
- * This code is NOT officially supported! Use at your risk.
  */
 public class ClientPreemptiveBasicAuthentication {
 
     public static void main(String[] args) throws Exception {
 
+        HttpHost targetHost = new HttpHost("localhost", 80, "http"); 
+        
         DefaultHttpClient httpclient = new DefaultHttpClient();
 
         httpclient.getCredentialsProvider().setCredentials(
-                new AuthScope("localhost", 80), 
+                new AuthScope(targetHost.getHostName(), targetHost.getPort()), 
                 new UsernamePasswordCredentials("username", "password"));
 
-        BasicHttpContext localcontext = new BasicHttpContext();
-
-        // Generate BASIC scheme object and stick it to the local 
-        // execution context
+        // Create AuthCache instance
+        AuthCache authCache = new BasicAuthCache();
+        // Generate BASIC scheme object and add it to the local 
+        // auth cache
         BasicScheme basicAuth = new BasicScheme();
-        localcontext.setAttribute("preemptive-auth", basicAuth);
+        authCache.put(targetHost, basicAuth);
         
-        // Add as the first request interceptor
-        httpclient.addRequestInterceptor(new PreemptiveAuth(), 0);
+        // Add AuthCache to the execution context
+        BasicHttpContext localcontext = new BasicHttpContext();
+        localcontext.setAttribute(ClientContext.AUTH_CACHE, authCache);        
         
-        HttpHost targetHost = new HttpHost("localhost", 80, "http"); 
-
         HttpGet httpget = new HttpGet("/");
 
         System.out.println("executing request: " + httpget.getRequestLine());
@@ -102,37 +92,4 @@
         httpclient.getConnectionManager().shutdown();        
     }
     
-    static class PreemptiveAuth implements HttpRequestInterceptor {
-
-        public void process(
-                final HttpRequest request, 
-                final HttpContext context) throws HttpException, IOException {
-            
-            AuthState authState = (AuthState) context.getAttribute(
-                    ClientContext.TARGET_AUTH_STATE);
-            
-            // If no auth scheme avaialble yet, try to initialize it preemptively
-            if (authState.getAuthScheme() == null) {
-                AuthScheme authScheme = (AuthScheme) context.getAttribute(
-                        "preemptive-auth");
-                CredentialsProvider credsProvider = (CredentialsProvider) context.getAttribute(
-                        ClientContext.CREDS_PROVIDER);
-                HttpHost targetHost = (HttpHost) context.getAttribute(
-                        ExecutionContext.HTTP_TARGET_HOST);
-                if (authScheme != null) {
-                    Credentials creds = credsProvider.getCredentials(
-                            new AuthScope(
-                                    targetHost.getHostName(), 
-                                    targetHost.getPort()));
-                    if (creds == null) {
-                        throw new HttpException("No credentials for preemptive authentication");
-                    }
-                    authState.setAuthScheme(authScheme);
-                    authState.setCredentials(creds);
-                }
-            }
-            
-        }
-        
-    }
 }

Modified: httpcomponents/httpclient/trunk/httpclient/src/examples/org/apache/http/examples/client/ClientPreemptiveDigestAuthentication.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient/src/examples/org/apache/http/examples/client/ClientPreemptiveDigestAuthentication.java?rev=881935&r1=881934&r2=881935&view=diff
==============================================================================
--- httpcomponents/httpclient/trunk/httpclient/src/examples/org/apache/http/examples/client/ClientPreemptiveDigestAuthentication.java
(original)
+++ httpcomponents/httpclient/trunk/httpclient/src/examples/org/apache/http/examples/client/ClientPreemptiveDigestAuthentication.java
Wed Nov 18 21:07:35 2009
@@ -25,28 +25,18 @@
 
 package org.apache.http.examples.client;
 
-import java.io.IOException;
-
 import org.apache.http.HttpEntity;
-import org.apache.http.HttpException;
 import org.apache.http.HttpHost;
-import org.apache.http.HttpRequest;
-import org.apache.http.HttpRequestInterceptor;
 import org.apache.http.HttpResponse;
-import org.apache.http.HttpResponseInterceptor;
-import org.apache.http.auth.AuthScheme;
 import org.apache.http.auth.AuthScope;
-import org.apache.http.auth.AuthState;
-import org.apache.http.auth.Credentials;
 import org.apache.http.auth.UsernamePasswordCredentials;
-import org.apache.http.client.CredentialsProvider;
+import org.apache.http.client.AuthCache;
 import org.apache.http.client.methods.HttpGet;
 import org.apache.http.client.protocol.ClientContext;
 import org.apache.http.impl.auth.DigestScheme;
+import org.apache.http.impl.client.BasicAuthCache;
 import org.apache.http.impl.client.DefaultHttpClient;
 import org.apache.http.protocol.BasicHttpContext;
-import org.apache.http.protocol.ExecutionContext;
-import org.apache.http.protocol.HttpContext;
 
 /**
  * An example of HttpClient can be customized to authenticate 
@@ -55,36 +45,34 @@
  * Generally, preemptive authentication can be considered less
  * secure than a response to an authentication challenge
  * and therefore discouraged.
- * <b/>
- * This code is NOT officially supported! Use at your risk.
  */
 public class ClientPreemptiveDigestAuthentication {
 
     public static void main(String[] args) throws Exception {
 
+        HttpHost targetHost = new HttpHost("localhost", 80, "http"); 
+
         DefaultHttpClient httpclient = new DefaultHttpClient();
 
         httpclient.getCredentialsProvider().setCredentials(
-                new AuthScope("localhost", 80), 
+                new AuthScope(targetHost.getHostName(), targetHost.getPort()), 
                 new UsernamePasswordCredentials("username", "password"));
 
-        BasicHttpContext localcontext = new BasicHttpContext();
-        // Generate DIGEST scheme object, initialize it and stick it to 
-        // the local execution context
+        // Create AuthCache instance
+        AuthCache authCache = new BasicAuthCache();
+        // Generate DIGEST scheme object, initialize it and add it to the local 
+        // auth cache
         DigestScheme digestAuth = new DigestScheme();
         // Suppose we already know the realm name
         digestAuth.overrideParamter("realm", "some realm");        
         // Suppose we already know the expected nonce value 
         digestAuth.overrideParamter("nonce", "whatever");        
-        localcontext.setAttribute("preemptive-auth", digestAuth);
+        authCache.put(targetHost, digestAuth);
         
-        // Add as the first request interceptor
-        httpclient.addRequestInterceptor(new PreemptiveAuth(), 0);
-        // Add as the last response interceptor
-        httpclient.addResponseInterceptor(new PersistentDigest());
+        // Add AuthCache to the execution context
+        BasicHttpContext localcontext = new BasicHttpContext();
+        localcontext.setAttribute(ClientContext.AUTH_CACHE, authCache);        
         
-        HttpHost targetHost = new HttpHost("localhost", 80, "http"); 
-
         HttpGet httpget = new HttpGet("/");
 
         System.out.println("executing request: " + httpget.getRequestLine());
@@ -108,58 +96,4 @@
         httpclient.getConnectionManager().shutdown();        
     }
     
-    static class PreemptiveAuth implements HttpRequestInterceptor {
-
-        public void process(
-                final HttpRequest request, 
-                final HttpContext context) throws HttpException, IOException {
-            
-            AuthState authState = (AuthState) context.getAttribute(
-                    ClientContext.TARGET_AUTH_STATE);
-            
-            // If no auth scheme avaialble yet, try to initialize it preemptively
-            if (authState.getAuthScheme() == null) {
-                AuthScheme authScheme = (AuthScheme) context.getAttribute(
-                        "preemptive-auth");
-                CredentialsProvider credsProvider = (CredentialsProvider) context.getAttribute(
-                        ClientContext.CREDS_PROVIDER);
-                HttpHost targetHost = (HttpHost) context.getAttribute(
-                        ExecutionContext.HTTP_TARGET_HOST);
-                if (authScheme != null) {
-                    Credentials creds = credsProvider.getCredentials(
-                            new AuthScope(
-                                    targetHost.getHostName(), 
-                                    targetHost.getPort()));
-                    if (creds == null) {
-                        throw new HttpException("No credentials for preemptive authentication");
-                    }
-                    authState.setAuthScheme(authScheme);
-                    authState.setCredentials(creds);
-                }
-            }
-            
-        }
-        
-    }
-
-    static class PersistentDigest implements HttpResponseInterceptor {
-
-        public void process(
-                final HttpResponse response, 
-                final HttpContext context) throws HttpException, IOException {
-            AuthState authState = (AuthState) context.getAttribute(
-                    ClientContext.TARGET_AUTH_STATE);
-            if (authState != null) {
-                AuthScheme authScheme = authState.getAuthScheme();
-                // Stick the auth scheme to the local context, so
-                // we could try to authenticate subsequent requests
-                // preemptively
-                if (authScheme instanceof DigestScheme) {
-                    context.setAttribute("preemptive-auth", authScheme);
-                }
-            }
-        }
-        
-    }
-    
 }

Added: httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/client/AuthCache.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/client/AuthCache.java?rev=881935&view=auto
==============================================================================
--- httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/client/AuthCache.java
(added)
+++ httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/client/AuthCache.java
Wed Nov 18 21:07:35 2009
@@ -0,0 +1,49 @@
+/*
+ * ====================================================================
+ *
+ *  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.client;
+
+import org.apache.http.HttpHost;
+import org.apache.http.auth.AuthScheme;
+
+/**
+ * Abstract {@link AuthScheme} cache. Initialized {@link AuthScheme} objects 
+ * from this cache can be used to preemptively authenticate against known 
+ * hosts.
+ * 
+ * @since 4.1
+ */
+public interface AuthCache {
+
+    void put(HttpHost host, AuthScheme authScheme);
+
+    AuthScheme get(HttpHost host);
+
+    void remove(HttpHost host);
+
+    void clear();
+    
+}

Propchange: httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/client/AuthCache.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/client/AuthCache.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/client/AuthCache.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/client/protocol/ClientContext.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/client/protocol/ClientContext.java?rev=881935&r1=881934&r2=881935&view=diff
==============================================================================
--- httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/client/protocol/ClientContext.java
(original)
+++ httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/client/protocol/ClientContext.java
Wed Nov 18 21:07:35 2009
@@ -72,11 +72,17 @@
 
     /**
      * Attribute name of a {@link org.apache.http.client.CredentialsProvider} 
-     * object that represents the actual crednetials provider.
+     * object that represents the actual credentials provider.
      */
     public static final String CREDS_PROVIDER        = "http.auth.credentials-provider";

 
     /**
+     * Attribute name of a {@link org.apache.http.client.AuthCache} object 
+     * that represents the auth scheme cache.
+     */
+    public static final String AUTH_CACHE            = "http.auth.auth-cache"; 
+
+    /**
      * Attribute name of a {@link org.apache.http.auth.AuthState} 
      * object that represents the actual target authentication state.
      */

Added: httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/client/protocol/RequestAuthCache.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/client/protocol/RequestAuthCache.java?rev=881935&view=auto
==============================================================================
--- httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/client/protocol/RequestAuthCache.java
(added)
+++ httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/client/protocol/RequestAuthCache.java
Wed Nov 18 21:07:35 2009
@@ -0,0 +1,129 @@
+/*
+ * ====================================================================
+ * 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.client.protocol;
+
+import java.io.IOException;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.http.HttpException;
+import org.apache.http.HttpHost;
+import org.apache.http.HttpRequest;
+import org.apache.http.HttpRequestInterceptor;
+import org.apache.http.annotation.Immutable;
+import org.apache.http.auth.AuthScheme;
+import org.apache.http.auth.AuthScope;
+import org.apache.http.auth.AuthState;
+import org.apache.http.auth.Credentials;
+import org.apache.http.client.AuthCache;
+import org.apache.http.client.CredentialsProvider;
+import org.apache.http.impl.client.BasicAuthCache;
+import org.apache.http.protocol.ExecutionContext;
+import org.apache.http.protocol.HttpContext;
+
+/**
+ * Request interceptor that can preemptively authenticate against known hosts, 
+ * if there is a cached {@link AuthScheme} instance in the local 
+ * {@link AuthCache} associated with the given target or proxy host.
+ * 
+ * @since 4.1
+ */
+@Immutable
+public class RequestAuthCache implements HttpRequestInterceptor {
+
+    private final Log log = LogFactory.getLog(getClass());
+    
+    public RequestAuthCache() {
+        super();
+    }
+    
+    public void process(final HttpRequest request, final HttpContext context) 
+            throws HttpException, IOException {
+        if (request == null) {
+            throw new IllegalArgumentException("HTTP request may not be null");
+        }
+        if (context == null) {
+            throw new IllegalArgumentException("HTTP context may not be null");
+        }
+
+        AuthCache authCache = (AuthCache) context.getAttribute(ClientContext.AUTH_CACHE);
+        if (authCache == null) {
+            context.setAttribute(ClientContext.AUTH_CACHE, new BasicAuthCache());
+        } else {
+            
+            CredentialsProvider credsProvider = (CredentialsProvider) context.getAttribute(
+                    ClientContext.CREDS_PROVIDER);
+            
+            HttpHost target = (HttpHost) context.getAttribute(ExecutionContext.HTTP_TARGET_HOST);
+            if (target != null) {
+                AuthScheme authScheme = authCache.get(target);
+                if (authScheme != null) {
+                    doPreemptiveAuth(
+                            target, 
+                            authScheme,                     
+                            (AuthState) context.getAttribute(ClientContext.TARGET_AUTH_STATE),

+                            credsProvider);
+                }
+            }
+
+            HttpHost proxy = (HttpHost) context.getAttribute(ExecutionContext.HTTP_PROXY_HOST);
+            if (proxy != null) {
+                AuthScheme authScheme = authCache.get(proxy);
+                if (authScheme != null) {
+                    doPreemptiveAuth(
+                            proxy, 
+                            authScheme,                     
+                            (AuthState) context.getAttribute(ClientContext.PROXY_AUTH_STATE),

+                            credsProvider);
+                }
+            }
+        }
+    }
+
+    private void doPreemptiveAuth(
+            final HttpHost host, 
+            final AuthScheme authScheme, 
+            final AuthState authState,
+            final CredentialsProvider credsProvider) {
+        String schemeName = authScheme.getSchemeName();
+        if (this.log.isDebugEnabled()) {
+            this.log.debug("Re-using cached '" + schemeName + "' auth scheme for " + host);
+        }
+        
+        Credentials creds = credsProvider.getCredentials(
+                new AuthScope(host.getHostName(), host.getPort(), schemeName));
+        
+        if (creds != null) {
+            authState.setAuthScheme(authScheme);
+            authState.setCredentials(creds);
+        } else {
+            this.log.debug("No credentials for preemptive authentication");
+        }
+    }
+    
+}

Propchange: httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/client/protocol/RequestAuthCache.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/client/protocol/RequestAuthCache.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/client/protocol/RequestAuthCache.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/client/protocol/ResponseAuthCache.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/client/protocol/ResponseAuthCache.java?rev=881935&view=auto
==============================================================================
--- httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/client/protocol/ResponseAuthCache.java
(added)
+++ httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/client/protocol/ResponseAuthCache.java
Wed Nov 18 21:07:35 2009
@@ -0,0 +1,110 @@
+/*
+ * ====================================================================
+ * 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.client.protocol;
+
+import java.io.IOException;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.http.HttpException;
+import org.apache.http.HttpHost;
+import org.apache.http.HttpResponse;
+import org.apache.http.HttpResponseInterceptor;
+import org.apache.http.annotation.Immutable;
+import org.apache.http.auth.AuthScheme;
+import org.apache.http.auth.AuthState;
+import org.apache.http.client.AuthCache;
+import org.apache.http.client.params.AuthPolicy;
+import org.apache.http.protocol.ExecutionContext;
+import org.apache.http.protocol.HttpContext;
+
+/**
+ * Response interceptor that adds successfully completed {@link AuthScheme}s
+ * to the local {@link AuthCache} instance. Cached {@link AuthScheme}s can be 
+ * re-used when executing requests against known hosts, thus avoiding 
+ * additional authentication round-trips. 
+ * 
+ * @since 4.1
+ */
+@Immutable
+public class ResponseAuthCache implements HttpResponseInterceptor {
+
+    private final Log log = LogFactory.getLog(getClass());
+    
+    public ResponseAuthCache() {
+        super();
+    }
+    
+    public void process(final HttpResponse response, final HttpContext context) 
+            throws HttpException, IOException {
+        if (response == null) {
+            throw new IllegalArgumentException("HTTP request may not be null");
+        }
+        if (context == null) {
+            throw new IllegalArgumentException("HTTP context may not be null");
+        }
+        AuthCache authCache = (AuthCache) context.getAttribute(ClientContext.AUTH_CACHE);
+        if (authCache != null) {
+            cache(authCache, 
+                    (HttpHost) context.getAttribute(ExecutionContext.HTTP_TARGET_HOST),
+                    (AuthState) context.getAttribute(ClientContext.TARGET_AUTH_STATE));
+            cache(authCache, 
+                    (HttpHost) context.getAttribute(ExecutionContext.HTTP_PROXY_HOST),
+                    (AuthState) context.getAttribute(ClientContext.PROXY_AUTH_STATE));
+        }
+    }
+    
+    private void cache(final AuthCache authCache, final HttpHost host, final AuthState authState)
{
+        if (authState == null) {
+            return;
+        }
+        
+        AuthScheme authScheme = authState.getAuthScheme();
+        if (authScheme == null || !authScheme.isComplete()) {
+            return;
+        }
+        
+        String schemeName = authScheme.getSchemeName();
+        if (!schemeName.equalsIgnoreCase(AuthPolicy.BASIC) && 
+                !schemeName.equalsIgnoreCase(AuthPolicy.DIGEST)) {
+            return;
+        }
+        
+        if (authState.getAuthScope() != null) {
+            if (authState.getCredentials() != null) {
+                if (this.log.isDebugEnabled()) {
+                    this.log.debug("Caching '" + schemeName + "' auth scheme for " + host);
+                }
+                authCache.put(host, authScheme);
+            } else {
+                authCache.remove(host);
+            }
+        }
+    }
+     
+}

Propchange: httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/client/protocol/ResponseAuthCache.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/client/protocol/ResponseAuthCache.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/client/protocol/ResponseAuthCache.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/client/BasicAuthCache.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/client/BasicAuthCache.java?rev=881935&view=auto
==============================================================================
--- httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/client/BasicAuthCache.java
(added)
+++ httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/client/BasicAuthCache.java
Wed Nov 18 21:07:35 2009
@@ -0,0 +1,84 @@
+/*
+ * ====================================================================
+ *
+ *  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.client;
+
+import java.util.HashMap;
+
+import org.apache.http.HttpHost;
+import org.apache.http.annotation.NotThreadSafe;
+import org.apache.http.auth.AuthScheme;
+import org.apache.http.client.AuthCache;
+
+/**
+ * Default implementation of {@link AuthCache}.
+ * 
+ * @since 4.0
+ */
+@NotThreadSafe
+public class BasicAuthCache implements AuthCache {
+
+    private final HashMap<HttpHost, AuthScheme> map;
+
+    /**
+     * Default constructor.
+     */
+    public BasicAuthCache() {
+        super();
+        this.map = new HashMap<HttpHost, AuthScheme>();
+    }
+
+    public void put(final HttpHost host, final AuthScheme authScheme) {
+        if (host == null) {
+            throw new IllegalArgumentException("HTTP host may not be null");
+        }
+        this.map.put(host, authScheme);
+    }
+
+    public AuthScheme get(final HttpHost host) {
+        if (host == null) {
+            throw new IllegalArgumentException("HTTP host may not be null");
+        }
+        return this.map.get(host);
+    }
+    
+    public void remove(final HttpHost host) {
+        if (host == null) {
+            throw new IllegalArgumentException("HTTP host may not be null");
+        }
+        this.map.remove(host);
+    }
+
+    public void clear() {
+        this.map.clear();
+    }
+    
+    @Override
+    public String toString() {
+        return this.map.toString();
+    }
+    
+}

Propchange: httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/client/BasicAuthCache.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/client/BasicAuthCache.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/client/BasicAuthCache.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/client/BasicCredentialsProvider.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/client/BasicCredentialsProvider.java?rev=881935&r1=881934&r2=881935&view=diff
==============================================================================
--- httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/client/BasicCredentialsProvider.java
(original)
+++ httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/client/BasicCredentialsProvider.java
Wed Nov 18 21:07:35 2009
@@ -102,13 +102,13 @@
         return matchCredentials(this.credMap, authscope);
     }
 
+    public synchronized void clear() {
+        this.credMap.clear();
+    }
+    
     @Override
     public String toString() {
         return credMap.toString();
     }
     
-    public synchronized void clear() {
-        this.credMap.clear();
-    }
-    
 }

Modified: httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/client/DefaultHttpClient.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/client/DefaultHttpClient.java?rev=881935&r1=881934&r2=881935&view=diff
==============================================================================
--- httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/client/DefaultHttpClient.java
(original)
+++ httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/client/DefaultHttpClient.java
Wed Nov 18 21:07:35 2009
@@ -43,10 +43,12 @@
 import org.apache.http.client.params.CookiePolicy;
 import org.apache.http.client.protocol.ClientContext;
 import org.apache.http.client.protocol.RequestAddCookies;
+import org.apache.http.client.protocol.RequestAuthCache;
 import org.apache.http.client.protocol.RequestClientConnControl;
 import org.apache.http.client.protocol.RequestDefaultHeaders;
 import org.apache.http.client.protocol.RequestProxyAuthentication;
 import org.apache.http.client.protocol.RequestTargetAuthentication;
+import org.apache.http.client.protocol.ResponseAuthCache;
 import org.apache.http.client.protocol.ResponseProcessCookies;
 import org.apache.http.conn.ClientConnectionManager;
 import org.apache.http.conn.ClientConnectionManagerFactory;
@@ -337,6 +339,8 @@
         httpproc.addInterceptor(new RequestAddCookies());
         httpproc.addInterceptor(new ResponseProcessCookies());
         // HTTP authentication interceptors
+        httpproc.addInterceptor(new RequestAuthCache());
+        httpproc.addInterceptor(new ResponseAuthCache());
         httpproc.addInterceptor(new RequestTargetAuthentication());
         httpproc.addInterceptor(new RequestProxyAuthentication());
         return httpproc;

Modified: httpcomponents/httpclient/trunk/httpclient/src/test/java/org/apache/http/impl/client/TestClientAuthentication.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient/src/test/java/org/apache/http/impl/client/TestClientAuthentication.java?rev=881935&r1=881934&r2=881935&view=diff
==============================================================================
--- httpcomponents/httpclient/trunk/httpclient/src/test/java/org/apache/http/impl/client/TestClientAuthentication.java
(original)
+++ httpcomponents/httpclient/trunk/httpclient/src/test/java/org/apache/http/impl/client/TestClientAuthentication.java
Wed Nov 18 21:07:35 2009
@@ -50,6 +50,7 @@
 import org.apache.http.localserver.LocalTestServer;
 import org.apache.http.localserver.RequestBasicAuth;
 import org.apache.http.localserver.ResponseBasicUnauthorized;
+import org.apache.http.protocol.BasicHttpContext;
 import org.apache.http.protocol.BasicHttpProcessor;
 import org.apache.http.protocol.HTTP;
 import org.apache.http.protocol.HttpContext;
@@ -248,4 +249,67 @@
         }
     }
 
+    static class TestTargetAuthenticationHandler extends DefaultTargetAuthenticationHandler
{
+
+        private int count;
+        
+        public TestTargetAuthenticationHandler() {
+            super();
+            this.count = 0;
+        }
+        
+        @Override
+        public boolean isAuthenticationRequested(
+                final HttpResponse response, 
+                final HttpContext context) {
+            boolean res = super.isAuthenticationRequested(response, context);
+            if (res == true) {
+                synchronized (this) {
+                    this.count++;
+                }                
+            }
+            return res;
+        }
+        
+        public int getCount() {
+            synchronized (this) {
+                return this.count;
+            }                
+        }
+        
+    }
+    
+    public void testBasicAuthenticationCredentialsCaching() throws Exception {
+        localServer.register("*", new AuthHandler());
+        localServer.start();
+        
+        BasicCredentialsProvider credsProvider = new BasicCredentialsProvider();
+        credsProvider.setCredentials(AuthScope.ANY, 
+                new UsernamePasswordCredentials("test", "test"));
+        
+        TestTargetAuthenticationHandler authHandler = new TestTargetAuthenticationHandler();
       
+        
+        DefaultHttpClient httpclient = new DefaultHttpClient();
+        httpclient.setCredentialsProvider(credsProvider);
+        httpclient.setTargetAuthenticationHandler(authHandler);
+        
+        HttpContext context = new BasicHttpContext();
+        
+        HttpGet httpget = new HttpGet("/");
+        
+        HttpResponse response1 = httpclient.execute(getServerHttp(), httpget, context);
+        HttpEntity entity1 = response1.getEntity();
+        assertEquals(HttpStatus.SC_OK, response1.getStatusLine().getStatusCode());
+        assertNotNull(entity1);
+        entity1.consumeContent();
+
+        HttpResponse response2 = httpclient.execute(getServerHttp(), httpget, context);
+        HttpEntity entity2 = response1.getEntity();
+        assertEquals(HttpStatus.SC_OK, response2.getStatusLine().getStatusCode());
+        assertNotNull(entity2);
+        entity1.consumeContent();
+        
+        assertEquals(1, authHandler.getCount());
+    }
+
 }

Modified: httpcomponents/httpclient/trunk/httpclient/src/test/java/org/apache/http/localserver/RequestBasicAuth.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient/src/test/java/org/apache/http/localserver/RequestBasicAuth.java?rev=881935&r1=881934&r2=881935&view=diff
==============================================================================
--- httpcomponents/httpclient/trunk/httpclient/src/test/java/org/apache/http/localserver/RequestBasicAuth.java
(original)
+++ httpcomponents/httpclient/trunk/httpclient/src/test/java/org/apache/http/localserver/RequestBasicAuth.java
Wed Nov 18 21:07:35 2009
@@ -47,6 +47,8 @@
             final HttpRequest request, 
             final HttpContext context) throws HttpException, IOException {
         
+        context.removeAttribute("creds");
+
         String auth = null;
         
         Header h = request.getFirstHeader(AUTH.WWW_AUTH_RESP);

Modified: httpcomponents/httpclient/trunk/src/docbkx/authentication.xml
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/src/docbkx/authentication.xml?rev=881935&r1=881934&r2=881935&view=diff
==============================================================================
--- httpcomponents/httpclient/trunk/src/docbkx/authentication.xml (original)
+++ httpcomponents/httpclient/trunk/src/docbkx/authentication.xml Wed Nov 18 21:07:35 2009
@@ -305,6 +305,14 @@
                         takes precedence over the default one.</para>
                 </formalpara>
             </listitem>
+            <listitem>
+                <formalpara>
+                    <title>'http.auth.auth-cache':</title>
+                    <para><interfacename>AuthCache</interfacename> instance
representing the actual
+                        authentication data cache. The value of this attribute set in the
local 
+                        context takes precedence over the default one.</para>
+                </formalpara>
+            </listitem>
         </itemizedlist>
         <para>The local <interfacename>HttpContext</interfacename> object
can be used to customize
             the HTTP authentication context prior to request execution or examine its state
after
@@ -328,52 +336,50 @@
 ]]></programlisting>
     </section>
     <section>
+        <title>Caching of authentication data</title>
+        <para>As of version 4.1 HttpClient automatically caches information about hosts
it 
+            successfully authenticated with. Please note that one must use the same execution

+            context to execute logically related requests in order for cached authentication
data
+            to propagate from one request to another. Authentication data will be lost as
soon as 
+            the execution context goes out of scope.</para>
+    </section>
+    <section>
         <title>Preemptive authentication</title>
         <para>HttpClient does not support preemptive authentication out of the box,
because if
             misused or used incorrectly the preemptive authentication can lead to significant
             security issues, such as sending user credentials in clear text to an unauthorized
third
             party. Therefore, users are expected to evaluate potential benefits of preemptive
             authentication versus security risks in the context of their specific application
-            environment and are required to add support for preemptive authentication using
standard
-            HttpClient extension mechanisms such as protocol interceptors.</para>
-        <para>This is an example of a simple protocol interceptor that preemptively
introduces an
-            instance of <classname>BasicScheme</classname> to the execution context,
if no
-            authentication has been attempted yet. Please note that this interceptor must
be added
-            to the protocol processing chain before the standard authentication interceptors.</para>
+            environment.</para>
+        <para>Nonethess one can configure HttpClient to authenticate preemptively by
prepopulating
+            the authentication data cache.</para>
         <programlisting><![CDATA[
-HttpRequestInterceptor preemptiveAuth = new HttpRequestInterceptor() {
-    
-    public void process(
-            final HttpRequest request, 
-            final HttpContext context) throws HttpException, IOException {
-        
-        AuthState authState = (AuthState) context.getAttribute(
-                ClientContext.TARGET_AUTH_STATE);
-        CredentialsProvider credsProvider = (CredentialsProvider) context.getAttribute(
-                ClientContext.CREDS_PROVIDER);
-        HttpHost targetHost = (HttpHost) context.getAttribute(
-                ExecutionContext.HTTP_TARGET_HOST);
-        
-        // If not auth scheme has been initialized yet
-        if (authState.getAuthScheme() == null) {
-            AuthScope authScope = new AuthScope(
-                    targetHost.getHostName(), 
-                    targetHost.getPort());
-            // Obtain credentials matching the target host
-            Credentials creds = credsProvider.getCredentials(authScope);
-            // If found, generate BasicScheme preemptively
-            if (creds != null) {
-                authState.setAuthScheme(new BasicScheme());
-                authState.setCredentials(creds);
-            }
-        }
-    }
-    
-};
+HttpHost targetHost = new HttpHost("localhost", 80, "http"); 
 
 DefaultHttpClient httpclient = new DefaultHttpClient();
-// Add as the very first interceptor in the protocol chain
-httpclient.addRequestInterceptor(preemptiveAuth, 0);
+
+httpclient.getCredentialsProvider().setCredentials(
+        new AuthScope(targetHost.getHostName(), targetHost.getPort()), 
+        new UsernamePasswordCredentials("username", "password"));
+
+// Create AuthCache instance
+AuthCache authCache = new BasicAuthCache();
+// Generate BASIC scheme object and add it to the local auth cache
+BasicScheme basicAuth = new BasicScheme();
+authCache.put(targetHost, basicAuth);
+
+// Add AuthCache to the execution context
+BasicHttpContext localcontext = new BasicHttpContext();
+localcontext.setAttribute(ClientContext.AUTH_CACHE, authCache);        
+
+HttpGet httpget = new HttpGet("/");
+for (int i = 0; i < 3; i++) {
+    HttpResponse response = httpclient.execute(targetHost, httpget, localcontext);
+    HttpEntity entity = response.getEntity();
+    if (entity != null) {
+        entity.consumeContent();
+    }
+}
 ]]></programlisting>
     </section>
 



Mime
View raw message