1 /*
2  * ====================================================================
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  * ====================================================================
20  *
21  * This software consists of voluntary contributions made by many
22  * individuals on behalf of the Apache Software Foundation.  For more
23  * information on the Apache Software Foundation, please see
24  * <http://www.apache.org/>.
25  *
26  */
27 
28 package ch.boye.httpclientandroidlib.client.protocol;
29 
30 import java.io.IOException;
31 
32 import ch.boye.httpclientandroidlib.androidextra.HttpClientAndroidLog;
33 /* LogFactory removed by HttpClient for Android script. */
34 import ch.boye.httpclientandroidlib.HttpException;
35 import ch.boye.httpclientandroidlib.HttpHost;
36 import ch.boye.httpclientandroidlib.HttpRequest;
37 import ch.boye.httpclientandroidlib.HttpRequestInterceptor;
38 import ch.boye.httpclientandroidlib.annotation.Immutable;
39 import ch.boye.httpclientandroidlib.auth.AuthProtocolState;
40 import ch.boye.httpclientandroidlib.auth.AuthScheme;
41 import ch.boye.httpclientandroidlib.auth.AuthScope;
42 import ch.boye.httpclientandroidlib.auth.AuthState;
43 import ch.boye.httpclientandroidlib.auth.Credentials;
44 import ch.boye.httpclientandroidlib.client.AuthCache;
45 import ch.boye.httpclientandroidlib.client.CredentialsProvider;
46 import ch.boye.httpclientandroidlib.conn.routing.RouteInfo;
47 import ch.boye.httpclientandroidlib.protocol.HttpContext;
48 import ch.boye.httpclientandroidlib.util.Args;
49 
50 /**
51  * Request interceptor that can preemptively authenticate against known hosts,
52  * if there is a cached {@link AuthScheme} instance in the local
53  * {@link AuthCache} associated with the given target or proxy host.
54  *
55  * @since 4.1
56  */
57 @Immutable
58 public class RequestAuthCache implements HttpRequestInterceptor {
59 
60     public HttpClientAndroidLog log = new HttpClientAndroidLog(getClass());
61 
RequestAuthCache()62     public RequestAuthCache() {
63         super();
64     }
65 
process(final HttpRequest request, final HttpContext context)66     public void process(final HttpRequest request, final HttpContext context)
67             throws HttpException, IOException {
68         Args.notNull(request, "HTTP request");
69         Args.notNull(context, "HTTP context");
70 
71         final HttpClientContext clientContext = HttpClientContext.adapt(context);
72 
73         final AuthCache authCache = clientContext.getAuthCache();
74         if (authCache == null) {
75             this.log.debug("Auth cache not set in the context");
76             return;
77         }
78 
79         final CredentialsProvider credsProvider = clientContext.getCredentialsProvider();
80         if (credsProvider == null) {
81             this.log.debug("Credentials provider not set in the context");
82             return;
83         }
84 
85         final RouteInfo route = clientContext.getHttpRoute();
86         if (route == null) {
87             this.log.debug("Route info not set in the context");
88             return;
89         }
90 
91         HttpHost target = clientContext.getTargetHost();
92         if (target == null) {
93             this.log.debug("Target host not set in the context");
94             return;
95         }
96 
97         if (target.getPort() < 0) {
98             target = new HttpHost(
99                     target.getHostName(),
100                     route.getTargetHost().getPort(),
101                     target.getSchemeName());
102         }
103 
104         final AuthState targetState = clientContext.getTargetAuthState();
105         if (targetState != null && targetState.getState() == AuthProtocolState.UNCHALLENGED) {
106             final AuthScheme authScheme = authCache.get(target);
107             if (authScheme != null) {
108                 doPreemptiveAuth(target, authScheme, targetState, credsProvider);
109             }
110         }
111 
112         final HttpHost proxy = route.getProxyHost();
113         final AuthState proxyState = clientContext.getProxyAuthState();
114         if (proxy != null && proxyState != null && proxyState.getState() == AuthProtocolState.UNCHALLENGED) {
115             final AuthScheme authScheme = authCache.get(proxy);
116             if (authScheme != null) {
117                 doPreemptiveAuth(proxy, authScheme, proxyState, credsProvider);
118             }
119         }
120     }
121 
doPreemptiveAuth( final HttpHost host, final AuthScheme authScheme, final AuthState authState, final CredentialsProvider credsProvider)122     private void doPreemptiveAuth(
123             final HttpHost host,
124             final AuthScheme authScheme,
125             final AuthState authState,
126             final CredentialsProvider credsProvider) {
127         final String schemeName = authScheme.getSchemeName();
128         if (this.log.isDebugEnabled()) {
129             this.log.debug("Re-using cached '" + schemeName + "' auth scheme for " + host);
130         }
131 
132         final AuthScope authScope = new AuthScope(host, AuthScope.ANY_REALM, schemeName);
133         final Credentials creds = credsProvider.getCredentials(authScope);
134 
135         if (creds != null) {
136             if ("BASIC".equalsIgnoreCase(authScheme.getSchemeName())) {
137                 authState.setState(AuthProtocolState.CHALLENGED);
138             } else {
139                 authState.setState(AuthProtocolState.SUCCESS);
140             }
141             authState.update(authScheme, creds);
142         } else {
143             this.log.debug("No credentials for preemptive authentication");
144         }
145     }
146 
147 }
148