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
29
30
31 package org.apache.commons.httpclient.auth;
32
33 import java.util.Collection;
34 import java.util.Iterator;
35 import java.util.Map;
36
37 import org.apache.commons.httpclient.params.HttpParams;
38 import org.apache.commons.logging.Log;
39 import org.apache.commons.logging.LogFactory;
40
41 /***
42 * This class provides utility methods for processing HTTP www and proxy authentication
43 * challenges.
44 *
45 * @author <a href="mailto:oleg@ural.ru">Oleg Kalnichevski</a>
46 *
47 * @since 3.0
48 */
49 public final class AuthChallengeProcessor {
50
51 private static final Log LOG = LogFactory.getLog(AuthChallengeProcessor.class);
52
53 private HttpParams params = null;
54
55 /***
56 * Creates an authentication challenge processor with the given {@link HttpParams HTTP
57 * parameters}
58 *
59 * @param params the {@link HttpParams HTTP parameters} used by this processor
60 */
61 public AuthChallengeProcessor(final HttpParams params) {
62 super();
63 if (params == null) {
64 throw new IllegalArgumentException("Parameter collection may not be null");
65 }
66 this.params = params;
67 }
68
69 /***
70 * Determines the preferred {@link AuthScheme authentication scheme} that can be used
71 * to respond to the given collection of challenges.
72 *
73 * @param challenges the collection of authentication challenges
74 *
75 * @return the preferred {@link AuthScheme authentication scheme}
76 *
77 * @throws AuthChallengeException if the preferred authentication scheme
78 * cannot be determined or is not supported
79 */
80 public AuthScheme selectAuthScheme(final Map challenges) throws AuthChallengeException {
81 if (challenges == null) {
82 throw new IllegalArgumentException("Challenge map may not be null");
83 }
84 Collection authPrefs = (Collection) this.params.getParameter(
85 AuthPolicy.AUTH_SCHEME_PRIORITY);
86 if (authPrefs == null || authPrefs.isEmpty()) {
87 authPrefs = AuthPolicy.getDefaultAuthPrefs();
88 }
89 if (LOG.isDebugEnabled()) {
90 LOG.debug("Supported authentication schemes in the order of preference: "
91 + authPrefs);
92 }
93 AuthScheme authscheme = null;
94 String challenge = null;
95 Iterator item = authPrefs.iterator();
96 while (item.hasNext()) {
97 String id = (String) item.next();
98 challenge = (String) challenges.get(id.toLowerCase());
99 if (challenge != null) {
100 if (LOG.isInfoEnabled()) {
101 LOG.info(id + " authentication scheme selected");
102 }
103 try {
104 authscheme = AuthPolicy.getAuthScheme(id);
105 } catch (IllegalStateException e) {
106 throw new AuthChallengeException(e.getMessage());
107 }
108 break;
109 } else {
110 if (LOG.isDebugEnabled()) {
111 LOG.debug("Challenge for " + id + " authentication scheme not available");
112
113 }
114 }
115 }
116 if (authscheme == null) {
117
118 throw new AuthChallengeException(
119 "Unable to respond to any of these challenges: "
120 + challenges);
121 }
122 return authscheme;
123 }
124
125 /***
126 * Processes the given collection of challenges and updates the
127 * {@link AuthState state} of the authentication process.
128 *
129 * @param challenges the collection of authentication challenges
130 *
131 * @return the {@link AuthScheme authentication scheme} used to
132 * process the challenge
133 *
134 * @throws AuthChallengeException if authentication challenges cannot be
135 * successfully processed or the preferred authentication scheme cannot
136 * be determined
137 */
138 public AuthScheme processChallenge(final AuthState state, final Map challenges)
139 throws MalformedChallengeException, AuthenticationException
140 {
141 if (state == null) {
142 throw new IllegalArgumentException("Authentication state may not be null");
143 }
144 if (challenges == null) {
145 throw new IllegalArgumentException("Challenge map may not be null");
146 }
147
148 if (state.isPreemptive() || state.getAuthScheme() == null) {
149
150 state.setAuthScheme(selectAuthScheme(challenges));
151 }
152 AuthScheme authscheme = state.getAuthScheme();
153 String id = authscheme.getSchemeName();
154 if (LOG.isDebugEnabled()) {
155 LOG.debug("Using authentication scheme: " + id);
156 }
157 String challenge = (String) challenges.get(id.toLowerCase());
158 if (challenge == null) {
159 throw new AuthenticationException(id +
160 " authorization challenge expected, but not found");
161 }
162 authscheme.processChallenge(challenge);
163 LOG.debug("Authorization challenge processed");
164 return authscheme;
165 }
166 }