View Javadoc

1   /*
2    * $HeadURL: https://svn.apache.org/repos/asf/httpcomponents/oac.hc3x/trunk/src/java/org/apache/commons/httpclient/auth/AuthChallengeProcessor.java $
3    * $Revision: 1425331 $
4    * $Date: 2012-12-22 18:29:41 +0000 (Sat, 22 Dec 2012) $
5    *
6    * ====================================================================
7    *
8    *  Licensed to the Apache Software Foundation (ASF) under one or more
9    *  contributor license agreements.  See the NOTICE file distributed with
10   *  this work for additional information regarding copyright ownership.
11   *  The ASF licenses this file to You under the Apache License, Version 2.0
12   *  (the "License"); you may not use this file except in compliance with
13   *  the License.  You may obtain a copy of the License at
14   *
15   *      http://www.apache.org/licenses/LICENSE-2.0
16   *
17   *  Unless required by applicable law or agreed to in writing, software
18   *  distributed under the License is distributed on an "AS IS" BASIS,
19   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20   *  See the License for the specific language governing permissions and
21   *  limitations under the License.
22   * ====================================================================
23   *
24   * This software consists of voluntary contributions made by many
25   * individuals on behalf of the Apache Software Foundation.  For more
26   * information on the Apache Software Foundation, please see
27   * <http://www.apache.org/>.
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                     // Try again
113                 }
114             }
115         }
116         if (authscheme == null) {
117             // If none selected, something is wrong
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             // Authentication not attempted before
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 }