View Javadoc

    1   /* Rfc2617Credential
    2    *
    3    * Created on Apr 7, 2004
    4    *
    5    * Copyright (C) 2004 Internet Archive.
    6    *
    7    * This file is part of the Heritrix web crawler (crawler.archive.org).
    8    *
    9    * Heritrix is free software; you can redistribute it and/or modify
    10   * it under the terms of the GNU Lesser Public License as published by
    11   * the Free Software Foundation; either version 2.1 of the License, or
    12   * any later version.
    13   *
    14   * Heritrix is distributed in the hope that it will be useful,
    15   * but WITHOUT ANY WARRANTY; without even the implied warranty of
    16   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    17   * GNU Lesser Public License for more details.
    18   *
    19   * You should have received a copy of the GNU Lesser Public License
    20   * along with Heritrix; if not, write to the Free Software
    21   * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
    22   */
    23  package org.archive.crawler.datamodel.credential;
    24
    25
    26  import java.util.Iterator;
    27  import java.util.Set;
    28  import java.util.logging.Logger;
    29
    30  import javax.management.AttributeNotFoundException;
    31
    32  import org.apache.commons.httpclient.HttpClient;
    33  import org.apache.commons.httpclient.HttpMethod;
    34  import org.apache.commons.httpclient.URIException;
    35  import org.apache.commons.httpclient.UsernamePasswordCredentials;
    36  import org.apache.commons.httpclient.auth.AuthScope;
    37  import org.archive.crawler.datamodel.CrawlURI;
    38  import org.archive.crawler.settings.SimpleType;
    39  import org.archive.crawler.settings.Type;
    40
    41
    42
    43  /***
    44   * A Basic/Digest auth RFC2617 credential.
    45   *
    46   * @author stack
    47   * @version $Revision: 4668 $, $Date: 2006-09-26 21:49:01 +0000 (Tue, 26 Sep 2006) $
    48   */
    49  public class Rfc2617Credential extends Credential {
    50
    51      private static final long serialVersionUID = -1909614285968756188L;
    52
    53      private static Logger logger =
    54          Logger.getLogger(Rfc2617Credential.class.getName());
    55
    56      private static final String ATTR_REALM = "realm";
    57      private static final String ATTR_LOGIN = "login";
    58      private static final String ATTR_PASSWORD = "password";
    59
    60
    61      /***
    62       * Constructor.
    63       *
    64       * A constructor that takes name of the credential is required by settings
    65       * framework.
    66       *
    67       * @param name Name of this credential.
    68       */
    69      public Rfc2617Credential(String name) {
    70          super(name, "Basic/Digest Auth type credential.");
    71
    72          Type t = addElementToDefinition(new SimpleType(ATTR_REALM,
    73              "Basic/Digest Auth realm.", "Realm"));
    74          t.setOverrideable(false);
    75          t.setExpertSetting(true);
    76
    77          t = addElementToDefinition(new SimpleType(ATTR_LOGIN, "Login.",
    78              "login"));
    79          t.setOverrideable(false);
    80          t.setExpertSetting(true);
    81
    82          t = addElementToDefinition(new SimpleType(ATTR_PASSWORD, "Password.",
    83              "password"));
    84          t.setOverrideable(false);
    85          t.setExpertSetting(true);
    86      }
    87
    88      /***
    89       * @param context Context to use when searching the realm.
    90       * @return Realm using set context.
    91       * @throws AttributeNotFoundException
    92       */
    93      public String getRealm(CrawlURI context)
    94              throws AttributeNotFoundException {
    95          return (String)getAttribute(ATTR_REALM, context);
    96      }
    97
    98      /***
    99       * @param context CrawlURI ontext to use.
    100      * @return login to use doing credential.
    101      * @throws AttributeNotFoundException
    102      */
    103     public String getLogin(CrawlURI context)
    104             throws AttributeNotFoundException {
    105         return (String)getAttribute(ATTR_LOGIN, context);
    106     }
    107
    108     /***
    109      * @param context CrawlURI ontext to use.
    110      * @return Password to use doing credential.
    111      * @throws AttributeNotFoundException
    112      */
    113     public String getPassword(CrawlURI context)
    114             throws AttributeNotFoundException {
    115         return (String)getAttribute(ATTR_PASSWORD, context);
    116     }
    117
    118     public boolean isPrerequisite(CrawlURI curi) {
    119         // Return false.  Later when we implement preemptive
    120         // rfc2617, this will change.
    121         return false;
    122     }
    123
    124     public boolean hasPrerequisite(CrawlURI curi) {
    125         // Return false.  Later when we implement preemptive
    126         // rfc2617, this will change.
    127         return false;
    128     }
    129
    130     public String getPrerequisite(CrawlURI curi) {
    131         // Return null.  Later when we implement preemptive
    132         // rfc2617, this will change.
    133         return null;
    134     }
    135
    136     public String getKey(CrawlURI context) throws AttributeNotFoundException {
    137         return getRealm(context);
    138     }
    139
    140     public boolean isEveryTime() {
    141         return true;
    142     }
    143
    144     public boolean populate(CrawlURI curi, HttpClient http, HttpMethod method,
    145             String payload) {
    146         boolean result = false;
    147         String authRealm = payload;
    148         if (authRealm == null) {
    149             logger.severe("No authscheme though creds: " + curi);
    150             return result;
    151         }
    152
    153         // Always add the credential to HttpState. Doing this because no way of
    154         // removing the credential once added AND there is a bug in the
    155         // credentials management system in that it always sets URI root to
    156         // null: it means the key used to find a credential is NOT realm + root
    157         // URI but just the realm. Unless I set it everytime, there is
    158         // possibility that as this thread progresses, it might come across a
    159         // realm already loaded but the login and password are from another
    160         // server. We'll get a failed authentication that'd be difficult to
    161         // explain.
    162         //
    163         // Have to make a UsernamePasswordCredentials. The httpclient auth code
    164         // does an instanceof down in its guts.
    165         UsernamePasswordCredentials upc = null;
    166         try {
    167         	upc = new UsernamePasswordCredentials(getLogin(curi),
    168         	    getPassword(curi));
    169         	http.getState().setCredentials(new AuthScope(curi.getUURI().getHost(),
    170         	    curi.getUURI().getPort(), authRealm), upc);
    171         	logger.fine("Credentials for realm " + authRealm +
    172         	    " for CrawlURI " + curi.toString() + " added to request: " +
    173 				result);
    174         	result = true;
    175         } catch (AttributeNotFoundException e1) {
    176         	logger.severe("Failed to get login and password for " +
    177         			curi + " and " + authRealm);
    178         } catch (URIException e) {
    179         	logger.severe("Failed to parse host from " + curi + ": " +
    180         			e.getMessage());
    181         }
    182
    183         return result;
    184     }
    185
    186     public boolean isPost(CrawlURI curi) {
    187         // Return false.  This credential type doesn't care whether posted or
    188         // get'd.
    189         return false;
    190     }
    191
    192     /***
    193      * Convenience method that does look up on passed set using realm for key.
    194      *
    195      * @param rfc2617Credentials Set of Rfc2617 credentials.  If passed set is
    196      * not pure Rfc2617Credentials then will be ClassCastExceptions.
    197      * @param realm Realm to find in passed set.
    198      * @param context Context to use when searching the realm.
    199      * @return Credential of passed realm name else null.  If more than one
    200      * credential w/ passed realm name, and there shouldn't be, we return first
    201      * found.
    202      */
    203     public static Rfc2617Credential getByRealm(Set rfc2617Credentials,
    204             String realm, CrawlURI context) {
    205
    206         Rfc2617Credential result = null;
    207         if (rfc2617Credentials == null || rfc2617Credentials.size() <= 0) {
    208             return result;
    209         }
    210         if (rfc2617Credentials != null && rfc2617Credentials.size() > 0) {
    211             for (Iterator i = rfc2617Credentials.iterator(); i.hasNext();) {
    212                 Rfc2617Credential c = (Rfc2617Credential)i.next();
    213                 try {
    214                     if (c.getRealm(context).equals(realm)) {
    215                         result = c;
    216                         break;
    217                     }
    218                 } catch (AttributeNotFoundException e) {
    219                     logger.severe("Failed look up by realm " + realm + " " + e);
    220                 }
    221             }
    222         }
    223         return result;
    224     }
    225 }