1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28 package org.apache.http.impl.auth;
29
30 import java.io.IOException;
31 import java.util.Locale;
32 import java.util.Map;
33 import java.util.Queue;
34
35 import org.apache.commons.logging.Log;
36 import org.apache.commons.logging.LogFactory;
37 import org.apache.http.Header;
38 import org.apache.http.HttpException;
39 import org.apache.http.HttpHost;
40 import org.apache.http.HttpRequest;
41 import org.apache.http.HttpResponse;
42 import org.apache.http.auth.AuthOption;
43 import org.apache.http.auth.AuthProtocolState;
44 import org.apache.http.auth.AuthScheme;
45 import org.apache.http.auth.AuthState;
46 import org.apache.http.auth.AuthenticationException;
47 import org.apache.http.auth.ContextAwareAuthScheme;
48 import org.apache.http.auth.Credentials;
49 import org.apache.http.auth.MalformedChallengeException;
50 import org.apache.http.client.AuthenticationStrategy;
51 import org.apache.http.protocol.HttpContext;
52 import org.apache.http.util.Asserts;
53
54
55
56
57 public class HttpAuthenticator {
58
59 private final Log log;
60
61 public HttpAuthenticator(final Log log) {
62 super();
63 this.log = log != null ? log : LogFactory.getLog(getClass());
64 }
65
66 public HttpAuthenticator() {
67 this(null);
68 }
69
70 public boolean isAuthenticationRequested(
71 final HttpHost host,
72 final HttpResponse response,
73 final AuthenticationStrategy authStrategy,
74 final AuthState authState,
75 final HttpContext context) {
76 if (authStrategy.isAuthenticationRequested(host, response, context)) {
77 this.log.debug("Authentication required");
78 if (authState.getState() == AuthProtocolState.SUCCESS) {
79 authStrategy.authFailed(host, authState.getAuthScheme(), context);
80 }
81 return true;
82 }
83 switch (authState.getState()) {
84 case CHALLENGED:
85 case HANDSHAKE:
86 this.log.debug("Authentication succeeded");
87 authState.setState(AuthProtocolState.SUCCESS);
88 authStrategy.authSucceeded(host, authState.getAuthScheme(), context);
89 break;
90 case SUCCESS:
91 break;
92 default:
93 authState.setState(AuthProtocolState.UNCHALLENGED);
94 }
95 return false;
96 }
97
98 public boolean handleAuthChallenge(
99 final HttpHost host,
100 final HttpResponse response,
101 final AuthenticationStrategy authStrategy,
102 final AuthState authState,
103 final HttpContext context) {
104 try {
105 if (this.log.isDebugEnabled()) {
106 this.log.debug(host.toHostString() + " requested authentication");
107 }
108 final Map<String, Header> challenges = authStrategy.getChallenges(host, response, context);
109 if (challenges.isEmpty()) {
110 this.log.debug("Response contains no authentication challenges");
111 return false;
112 }
113
114 final AuthScheme authScheme = authState.getAuthScheme();
115 switch (authState.getState()) {
116 case FAILURE:
117 return false;
118 case SUCCESS:
119 authState.reset();
120 break;
121 case CHALLENGED:
122 case HANDSHAKE:
123 if (authScheme == null) {
124 this.log.debug("Auth scheme is null");
125 authStrategy.authFailed(host, null, context);
126 authState.reset();
127 authState.setState(AuthProtocolState.FAILURE);
128 return false;
129 }
130 case UNCHALLENGED:
131 if (authScheme != null) {
132 final String id = authScheme.getSchemeName();
133 final Header challenge = challenges.get(id.toLowerCase(Locale.ROOT));
134 if (challenge != null) {
135 this.log.debug("Authorization challenge processed");
136 authScheme.processChallenge(challenge);
137 if (authScheme.isComplete()) {
138 this.log.debug("Authentication failed");
139 authStrategy.authFailed(host, authState.getAuthScheme(), context);
140 authState.reset();
141 authState.setState(AuthProtocolState.FAILURE);
142 return false;
143 }
144 authState.setState(AuthProtocolState.HANDSHAKE);
145 return true;
146 }
147 authState.reset();
148
149 }
150 }
151 final Queue<AuthOption> authOptions = authStrategy.select(challenges, host, response, context);
152 if (authOptions != null && !authOptions.isEmpty()) {
153 if (this.log.isDebugEnabled()) {
154 this.log.debug("Selected authentication options: " + authOptions);
155 }
156 authState.setState(AuthProtocolState.CHALLENGED);
157 authState.update(authOptions);
158 return true;
159 }
160 return false;
161 } catch (final MalformedChallengeException ex) {
162 if (this.log.isWarnEnabled()) {
163 this.log.warn("Malformed challenge: " + ex.getMessage());
164 }
165 authState.reset();
166 return false;
167 }
168 }
169
170 public void generateAuthResponse(
171 final HttpRequest request,
172 final AuthState authState,
173 final HttpContext context) throws HttpException, IOException {
174 AuthScheme authScheme = authState.getAuthScheme();
175 Credentials creds = authState.getCredentials();
176 switch (authState.getState()) {
177 case FAILURE:
178 return;
179 case SUCCESS:
180 ensureAuthScheme(authScheme);
181 if (authScheme.isConnectionBased()) {
182 return;
183 }
184 break;
185 case CHALLENGED:
186 final Queue<AuthOption> authOptions = authState.getAuthOptions();
187 if (authOptions != null) {
188 while (!authOptions.isEmpty()) {
189 final AuthOption authOption = authOptions.remove();
190 authScheme = authOption.getAuthScheme();
191 creds = authOption.getCredentials();
192 authState.update(authScheme, creds);
193 if (this.log.isDebugEnabled()) {
194 this.log.debug("Generating response to an authentication challenge using "
195 + authScheme.getSchemeName() + " scheme");
196 }
197 try {
198 final Header header = doAuth(authScheme, creds, request, context);
199 request.addHeader(header);
200 break;
201 } catch (final AuthenticationException ex) {
202 if (this.log.isWarnEnabled()) {
203 this.log.warn(authScheme + " authentication error: " + ex.getMessage());
204 }
205 }
206 }
207 return;
208 }
209 ensureAuthScheme(authScheme);
210 }
211 if (authScheme != null) {
212 try {
213 final Header header = doAuth(authScheme, creds, request, context);
214 request.addHeader(header);
215 } catch (final AuthenticationException ex) {
216 if (this.log.isErrorEnabled()) {
217 this.log.error(authScheme + " authentication error: " + ex.getMessage());
218 }
219 }
220 }
221 }
222
223 private void ensureAuthScheme(final AuthScheme authScheme) {
224 Asserts.notNull(authScheme, "Auth scheme");
225 }
226
227 @SuppressWarnings("deprecation")
228 private Header doAuth(
229 final AuthScheme authScheme,
230 final Credentials creds,
231 final HttpRequest request,
232 final HttpContext context) throws AuthenticationException {
233 return authScheme instanceof ContextAwareAuthScheme
234 ? ((ContextAwareAuthScheme) authScheme).authenticate(creds, request,
235 context)
236 : authScheme.authenticate(creds, request);
237 }
238
239 }