1 /*
   2  * reserved comment block
   3  * DO NOT REMOVE OR ALTER!
   4  */
   5 /*
   6  * Copyright  1999-2004 The Apache Software Foundation.
   7  *
   8  *  Licensed under the Apache License, Version 2.0 (the "License");
   9  *  you may not use this file except in compliance with the License.
  10  *  You may obtain a copy of the License at
  11  *
  12  *      http://www.apache.org/licenses/LICENSE-2.0
  13  *
  14  *  Unless required by applicable law or agreed to in writing, software
  15  *  distributed under the License is distributed on an "AS IS" BASIS,
  16  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  17  *  See the License for the specific language governing permissions and
  18  *  limitations under the License.
  19  *
  20  */
  21 package com.sun.org.apache.xml.internal.security.utils.resolver.implementations;
  22 
  23 import java.io.ByteArrayOutputStream;
  24 import java.io.IOException;
  25 import java.io.InputStream;
  26 import java.net.MalformedURLException;
  27 import java.net.URL;
  28 import java.net.URLConnection;
  29 
  30 import com.sun.org.apache.xml.internal.utils.URI;
  31 import com.sun.org.apache.xml.internal.security.signature.XMLSignatureInput;
  32 import com.sun.org.apache.xml.internal.security.utils.Base64;
  33 import com.sun.org.apache.xml.internal.security.utils.resolver.ResourceResolverException;
  34 import com.sun.org.apache.xml.internal.security.utils.resolver.ResourceResolverSpi;
  35 import org.w3c.dom.Attr;
  36 
  37 
  38 /**
  39  * A simple ResourceResolver for HTTP requests. This class handles only 'pure'
  40  * HTTP URIs which means without a fragment. The Fragment handling is done by the
  41  * {@link ResolverFragment} class.
  42  * <BR>
  43  * If the user has a corporate HTTP proxy which is to be used, the usage can be
  44  * switched on by setting properties for the resolver:
  45  * <PRE>
  46  * resourceResolver.setProperty("http.proxy.host", "proxy.company.com");
  47  * resourceResolver.setProperty("http.proxy.port", "8080");
  48  *
  49  * // if we need a password for the proxy
  50  * resourceResolver.setProperty("http.proxy.username", "proxyuser3");
  51  * resourceResolver.setProperty("http.proxy.password", "secretca");
  52  * </PRE>
  53  *
  54  *
  55  * @author $Author: mullan $
  56  * @see <A HREF="http://www.javaworld.com/javaworld/javatips/jw-javatip42_p.html">Java Tip 42: Write Java apps that work with proxy-based firewalls</A>
  57  * @see <A HREF="http://java.sun.com/j2se/1.4/docs/guide/net/properties.html">SUN J2SE docs for network properties</A>
  58  * @see <A HREF="http://metalab.unc.edu/javafaq/javafaq.html#proxy">The JAVA FAQ Question 9.5: How do I make Java work with a proxy server?</A>
  59  * $todo$ the proxy behaviour seems not to work; if a on-existing proxy is set, it works ?!?
  60  */
  61 public class ResolverDirectHTTP extends ResourceResolverSpi {
  62 
  63    /** {@link java.util.logging} logging facility */
  64     static java.util.logging.Logger log =
  65         java.util.logging.Logger.getLogger(
  66                             ResolverDirectHTTP.class.getName());
  67 
  68    /** Field properties[] */
  69    private static final String properties[] =
  70         { "http.proxy.host", "http.proxy.port",
  71           "http.proxy.username",
  72           "http.proxy.password",
  73           "http.basic.username",
  74           "http.basic.password" };
  75 
  76    /** Field HttpProxyHost */
  77    private static final int HttpProxyHost = 0;
  78 
  79    /** Field HttpProxyPort */
  80    private static final int HttpProxyPort = 1;
  81 
  82    /** Field HttpProxyUser */
  83    private static final int HttpProxyUser = 2;
  84 
  85    /** Field HttpProxyPass */
  86    private static final int HttpProxyPass = 3;
  87 
  88    /** Field HttpProxyUser */
  89    private static final int HttpBasicUser = 4;
  90 
  91    /** Field HttpProxyPass */
  92    private static final int HttpBasicPass = 5;
  93 
  94    public boolean engineIsThreadSafe() {
  95            return true;
  96    }
  97    /**
  98     * Method resolve
  99     *
 100     * @param uri
 101     * @param BaseURI
 102     *
 103     * @throws ResourceResolverException
 104     * @return
 105     * $todo$ calculate the correct URI from the attribute and the BaseURI
 106     */
 107    public XMLSignatureInput engineResolve(Attr uri, String BaseURI)
 108            throws ResourceResolverException {
 109 
 110       try {
 111          boolean useProxy = false;
 112          String proxyHost =
 113             engineGetProperty(ResolverDirectHTTP
 114                .properties[ResolverDirectHTTP.HttpProxyHost]);
 115          String proxyPort =
 116             engineGetProperty(ResolverDirectHTTP
 117                .properties[ResolverDirectHTTP.HttpProxyPort]);
 118 
 119          if ((proxyHost != null) && (proxyPort != null)) {
 120             useProxy = true;
 121          }
 122 
 123          String oldProxySet = null;
 124          String oldProxyHost = null;
 125          String oldProxyPort = null;
 126          // switch on proxy usage
 127          if (useProxy) {
 128             if (log.isLoggable(java.util.logging.Level.FINE)) {
 129                 log.log(java.util.logging.Level.FINE, "Use of HTTP proxy enabled: " + proxyHost + ":"
 130                       + proxyPort);
 131             }
 132             oldProxySet = System.getProperty("http.proxySet");
 133             oldProxyHost = System.getProperty("http.proxyHost");
 134             oldProxyPort = System.getProperty("http.proxyPort");
 135             System.setProperty("http.proxySet", "true");
 136             System.setProperty("http.proxyHost", proxyHost);
 137             System.setProperty("http.proxyPort", proxyPort);
 138          }
 139 
 140          boolean switchBackProxy = ((oldProxySet != null)
 141                                     && (oldProxyHost != null)
 142                                     && (oldProxyPort != null));
 143 
 144          // calculate new URI
 145          URI uriNew = getNewURI(uri.getNodeValue(), BaseURI);
 146 
 147          // if the URI contains a fragment, ignore it
 148          URI uriNewNoFrag = new URI(uriNew);
 149 
 150          uriNewNoFrag.setFragment(null);
 151 
 152          URL url = new URL(uriNewNoFrag.toString());
 153          URLConnection urlConnection = url.openConnection();
 154 
 155          {
 156 
 157             // set proxy pass
 158             String proxyUser =
 159                engineGetProperty(ResolverDirectHTTP
 160                   .properties[ResolverDirectHTTP.HttpProxyUser]);
 161             String proxyPass =
 162                engineGetProperty(ResolverDirectHTTP
 163                   .properties[ResolverDirectHTTP.HttpProxyPass]);
 164 
 165             if ((proxyUser != null) && (proxyPass != null)) {
 166                String password = proxyUser + ":" + proxyPass;
 167                String encodedPassword = Base64.encode(password.getBytes());
 168 
 169                // or was it Proxy-Authenticate ?
 170                urlConnection.setRequestProperty("Proxy-Authorization",
 171                                                 encodedPassword);
 172             }
 173          }
 174 
 175          {
 176 
 177             // check if Basic authentication is required
 178             String auth = urlConnection.getHeaderField("WWW-Authenticate");
 179 
 180             if (auth != null) {
 181 
 182                // do http basic authentication
 183                if (auth.startsWith("Basic")) {
 184                   String user =
 185                      engineGetProperty(ResolverDirectHTTP
 186                         .properties[ResolverDirectHTTP.HttpBasicUser]);
 187                   String pass =
 188                      engineGetProperty(ResolverDirectHTTP
 189                         .properties[ResolverDirectHTTP.HttpBasicPass]);
 190 
 191                   if ((user != null) && (pass != null)) {
 192                      urlConnection = url.openConnection();
 193 
 194                      String password = user + ":" + pass;
 195                      String encodedPassword =
 196                         Base64.encode(password.getBytes());
 197 
 198                      // set authentication property in the http header
 199                      urlConnection.setRequestProperty("Authorization",
 200                                                       "Basic "
 201                                                       + encodedPassword);
 202                   }
 203                }
 204             }
 205          }
 206 
 207          String mimeType = urlConnection.getHeaderField("Content-Type");
 208          InputStream inputStream = urlConnection.getInputStream();
 209          ByteArrayOutputStream baos = new ByteArrayOutputStream();
 210          byte buf[] = new byte[4096];
 211          int read = 0;
 212          int summarized = 0;
 213 
 214          while ((read = inputStream.read(buf)) >= 0) {
 215             baos.write(buf, 0, read);
 216 
 217             summarized += read;
 218          }
 219 
 220          log.log(java.util.logging.Level.FINE, "Fetched " + summarized + " bytes from URI "
 221                    + uriNew.toString());
 222 
 223          XMLSignatureInput result = new XMLSignatureInput(baos.toByteArray());
 224 
 225          // XMLSignatureInput result = new XMLSignatureInput(inputStream);
 226          result.setSourceURI(uriNew.toString());
 227          result.setMIMEType(mimeType);
 228 
 229          // switch off proxy usage
 230          if (useProxy && switchBackProxy) {
 231             System.setProperty("http.proxySet", oldProxySet);
 232             System.setProperty("http.proxyHost", oldProxyHost);
 233             System.setProperty("http.proxyPort", oldProxyPort);
 234          }
 235 
 236          return result;
 237       } catch (MalformedURLException ex) {
 238          throw new ResourceResolverException("generic.EmptyMessage", ex, uri,
 239                                              BaseURI);
 240       } catch (IOException ex) {
 241          throw new ResourceResolverException("generic.EmptyMessage", ex, uri,
 242                                              BaseURI);
 243       }
 244    }
 245 
 246    /**
 247     * We resolve http URIs <I>without</I> fragment...
 248     *
 249     * @param uri
 250     * @param BaseURI
 251     *  @return true if can be resolved
 252     */
 253    public boolean engineCanResolve(Attr uri, String BaseURI) {
 254       if (uri == null) {
 255          log.log(java.util.logging.Level.FINE, "quick fail, uri == null");
 256 
 257          return false;
 258       }
 259 
 260       String uriNodeValue = uri.getNodeValue();
 261 
 262       if (uriNodeValue.equals("") || (uriNodeValue.charAt(0)=='#')) {
 263          log.log(java.util.logging.Level.FINE, "quick fail for empty URIs and local ones");
 264 
 265          return false;
 266       }
 267 
 268       if (log.isLoggable(java.util.logging.Level.FINE)) {
 269          log.log(java.util.logging.Level.FINE, "I was asked whether I can resolve " + uriNodeValue);
 270       }
 271 
 272       if ( uriNodeValue.startsWith("http:") ||
 273                                 (BaseURI!=null && BaseURI.startsWith("http:") )) {
 274          if (log.isLoggable(java.util.logging.Level.FINE)) {
 275             log.log(java.util.logging.Level.FINE, "I state that I can resolve " + uriNodeValue);
 276          }
 277 
 278          return true;
 279       }
 280 
 281       if (log.isLoggable(java.util.logging.Level.FINE)) {
 282          log.log(java.util.logging.Level.FINE, "I state that I can't resolve " + uriNodeValue);
 283       }
 284 
 285       return false;
 286    }
 287 
 288    /**
 289     * @inheritDoc
 290     */
 291    public String[] engineGetPropertyKeys() {
 292       return ResolverDirectHTTP.properties.clone();
 293    }
 294 
 295    private URI getNewURI(String uri, String BaseURI)
 296            throws URI.MalformedURIException {
 297 
 298       if ((BaseURI == null) || "".equals(BaseURI)) {
 299          return new URI(uri);
 300       }
 301       return new URI(new URI(BaseURI), uri);
 302    }
 303 }