1. /*
  2. * $Header: /home/cvs/jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/auth/AuthChallengeProcessor.java,v 1.2 2004/04/18 23:51:36 jsdever Exp $
  3. * $Revision: 1.2 $
  4. * $Date: 2004/04/18 23:51:36 $
  5. *
  6. * ====================================================================
  7. *
  8. * Copyright 2002-2004 The Apache Software Foundation
  9. *
  10. * Licensed under the Apache License, Version 2.0 (the "License");
  11. * you may not use this file except in compliance with the License.
  12. * You may obtain a copy of the License at
  13. *
  14. * http://www.apache.org/licenses/LICENSE-2.0
  15. *
  16. * Unless required by applicable law or agreed to in writing, software
  17. * distributed under the License is distributed on an "AS IS" BASIS,
  18. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  19. * See the License for the specific language governing permissions and
  20. * limitations under the License.
  21. * ====================================================================
  22. *
  23. * This software consists of voluntary contributions made by many
  24. * individuals on behalf of the Apache Software Foundation. For more
  25. * information on the Apache Software Foundation, please see
  26. * <http://www.apache.org/>.
  27. *
  28. */
  29. package org.apache.commons.httpclient.auth;
  30. import java.util.Collection;
  31. import java.util.Iterator;
  32. import java.util.Map;
  33. import org.apache.commons.httpclient.params.HttpParams;
  34. import org.apache.commons.logging.Log;
  35. import org.apache.commons.logging.LogFactory;
  36. /**
  37. * This class provides utility methods for processing HTTP www and proxy authentication
  38. * challenges.
  39. *
  40. * @author <a href="mailto:oleg@ural.ru">Oleg Kalnichevski</a>
  41. *
  42. * @since 3.0
  43. */
  44. public final class AuthChallengeProcessor {
  45. private static final Log LOG = LogFactory.getLog(AuthChallengeProcessor.class);
  46. private HttpParams params = null;
  47. /**
  48. * Creates an authentication challenge processor with the given {@link HttpParams HTTP
  49. * parameters}
  50. *
  51. * @param params the {@link HttpParams HTTP parameters} used by this processor
  52. */
  53. public AuthChallengeProcessor(final HttpParams params) {
  54. super();
  55. if (params == null) {
  56. throw new IllegalArgumentException("Parameter collection may not be null");
  57. }
  58. this.params = params;
  59. }
  60. /**
  61. * Determines the preferred {@link AuthScheme authentication scheme} that can be used
  62. * to respond to the given collection of challenges.
  63. *
  64. * @param challenges the collection of authentication challenges
  65. *
  66. * @return the preferred {@link AuthScheme authentication scheme}
  67. *
  68. * @throws AuthChallengeException if the preferred authentication scheme
  69. * cannot be determined or is not supported
  70. */
  71. public AuthScheme selectAuthScheme(final Map challenges) throws AuthChallengeException {
  72. if (challenges == null) {
  73. throw new IllegalArgumentException("Challenge map may not be null");
  74. }
  75. Collection authPrefs = (Collection) this.params.getParameter(
  76. AuthPolicy.AUTH_SCHEME_PRIORITY);
  77. if (authPrefs == null || authPrefs.isEmpty()) {
  78. authPrefs = AuthPolicy.getDefaultAuthPrefs();
  79. }
  80. if (LOG.isDebugEnabled()) {
  81. LOG.debug("Supported authentication schemes in the order of preference: "
  82. + authPrefs);
  83. }
  84. AuthScheme authscheme = null;
  85. String challenge = null;
  86. Iterator item = authPrefs.iterator();
  87. while (item.hasNext()) {
  88. String id = (String) item.next();
  89. challenge = (String) challenges.get(id.toLowerCase());
  90. if (challenge != null) {
  91. if (LOG.isInfoEnabled()) {
  92. LOG.info(id + " authentication scheme selected");
  93. }
  94. try {
  95. authscheme = AuthPolicy.getAuthScheme(id);
  96. } catch (IllegalStateException e) {
  97. throw new AuthChallengeException(e.getMessage());
  98. }
  99. break;
  100. } else {
  101. if (LOG.isDebugEnabled()) {
  102. LOG.debug("Challenge for " + id + " authentication scheme not available");
  103. // Try again
  104. }
  105. }
  106. }
  107. if (authscheme == null) {
  108. // If none selected, something is wrong
  109. throw new AuthChallengeException(
  110. "Unable to respond to any of these challenges: "
  111. + challenges);
  112. }
  113. return authscheme;
  114. }
  115. /**
  116. * Processes the given collection of challenges and updates the
  117. * {@link AuthState state} of the authentication process.
  118. *
  119. * @param challenges the collection of authentication challenges
  120. *
  121. * @return the {@link AuthScheme authentication scheme} used to
  122. * process the challenge
  123. *
  124. * @throws AuthChallengeException if authentication challenges cannot be
  125. * successfully processed or the preferred authentication scheme cannot
  126. * be determined
  127. */
  128. public AuthScheme processChallenge(final AuthState state, final Map challenges)
  129. throws MalformedChallengeException, AuthenticationException
  130. {
  131. if (state == null) {
  132. throw new IllegalArgumentException("Authentication state may not be null");
  133. }
  134. if (challenges == null) {
  135. throw new IllegalArgumentException("Challenge map may not be null");
  136. }
  137. if (state.getAuthScheme() == null) {
  138. // Authentication not attempted before
  139. state.setAuthScheme(selectAuthScheme(challenges));
  140. }
  141. AuthScheme authscheme = state.getAuthScheme();
  142. String id = authscheme.getSchemeName();
  143. if (LOG.isDebugEnabled()) {
  144. LOG.debug("Using authentication scheme: " + id);
  145. }
  146. String challenge = (String) challenges.get(id.toLowerCase());
  147. if (challenge == null) {
  148. throw new AuthenticationException(id +
  149. " authorization challenge expected, but not found");
  150. }
  151. authscheme.processChallenge(challenge);
  152. return authscheme;
  153. }
  154. }