1 /* 2 * reserved comment block 3 * DO NOT REMOVE OR ALTER! 4 */ 5 /** 6 * Licensed to the Apache Software Foundation (ASF) under one 7 * or more contributor license agreements. See the NOTICE file 8 * distributed with this work for additional information 9 * regarding copyright ownership. The ASF licenses this file 10 * to you under the Apache License, Version 2.0 (the 11 * "License"); you may not use this file except in compliance 12 * with the License. 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, 17 * software distributed under the License is distributed on an 18 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 19 * KIND, either express or implied. See the License for the 20 * specific language governing permissions and limitations 21 * under the License. 22 */ 23 package com.sun.org.apache.xml.internal.security.utils.resolver.implementations; 24 25 import java.io.ByteArrayOutputStream; 26 import java.io.IOException; 27 import java.io.InputStream; 28 import java.net.InetSocketAddress; 29 import java.net.MalformedURLException; 30 import java.net.Proxy; 31 import java.net.URISyntaxException; 32 import java.net.URI; 33 import java.net.URL; 34 import java.net.URLConnection; 35 36 import com.sun.org.apache.xml.internal.security.signature.XMLSignatureInput; 37 import com.sun.org.apache.xml.internal.security.utils.Base64; 38 import com.sun.org.apache.xml.internal.security.utils.resolver.ResourceResolverContext; 39 import com.sun.org.apache.xml.internal.security.utils.resolver.ResourceResolverException; 40 import com.sun.org.apache.xml.internal.security.utils.resolver.ResourceResolverSpi; 41 42 /** 43 * A simple ResourceResolver for HTTP requests. This class handles only 'pure' 44 * HTTP URIs which means without a fragment. The Fragment handling is done by the 45 * {@link ResolverFragment} class. 46 * <BR> 47 * If the user has a corporate HTTP proxy which is to be used, the usage can be 48 * switched on by setting properties for the resolver: 49 * <PRE> 50 * resourceResolver.setProperty("http.proxy.host", "proxy.company.com"); 51 * resourceResolver.setProperty("http.proxy.port", "8080"); 52 * 53 * // if we need a password for the proxy 54 * resourceResolver.setProperty("http.proxy.username", "proxyuser3"); 55 * resourceResolver.setProperty("http.proxy.password", "secretca"); 56 * </PRE> 57 * 58 * @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> 59 * @see <A HREF="http://docs.oracle.com/javase/1.4.2/docs/guide/net/properties.html">SUN J2SE docs for network properties</A> 60 * @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> 61 */ 62 public class ResolverDirectHTTP extends ResourceResolverSpi { 63 64 /** {@link org.apache.commons.logging} logging facility */ 65 private static java.util.logging.Logger log = 66 java.util.logging.Logger.getLogger(ResolverDirectHTTP.class.getName()); 67 68 /** Field properties[] */ 69 private static final String properties[] = { 70 "http.proxy.host", "http.proxy.port", 71 "http.proxy.username", "http.proxy.password", 72 "http.basic.username", "http.basic.password" 73 }; 74 75 /** Field HttpProxyHost */ 76 private static final int HttpProxyHost = 0; 77 78 /** Field HttpProxyPort */ 79 private static final int HttpProxyPort = 1; 80 81 /** Field HttpProxyUser */ 82 private static final int HttpProxyUser = 2; 83 84 /** Field HttpProxyPass */ 85 private static final int HttpProxyPass = 3; 86 87 /** Field HttpProxyUser */ 88 private static final int HttpBasicUser = 4; 89 90 /** Field HttpProxyPass */ 91 private static final int HttpBasicPass = 5; 92 93 @Override 94 public boolean engineIsThreadSafe() { 95 return true; 96 } 97 98 /** 99 * Method resolve 100 * 101 * @param uri 102 * @param baseURI 103 * 104 * @throws ResourceResolverException 105 * @return 106 * $todo$ calculate the correct URI from the attribute and the baseURI 107 */ 108 @Override 109 public XMLSignatureInput engineResolveURI(ResourceResolverContext context) 110 throws ResourceResolverException { 111 try { 112 113 // calculate new URI 114 URI uriNew = getNewURI(context.uriToResolve, context.baseUri); 115 URL url = uriNew.toURL(); 116 URLConnection urlConnection; 117 urlConnection = openConnection(url); 118 119 // check if Basic authentication is required 120 String auth = urlConnection.getHeaderField("WWW-Authenticate"); 121 122 if (auth != null && auth.startsWith("Basic")) { 123 // do http basic authentication 124 String user = 125 engineGetProperty(ResolverDirectHTTP.properties[ResolverDirectHTTP.HttpBasicUser]); 126 String pass = 127 engineGetProperty(ResolverDirectHTTP.properties[ResolverDirectHTTP.HttpBasicPass]); 128 129 if ((user != null) && (pass != null)) { 130 urlConnection = openConnection(url); 131 132 String password = user + ":" + pass; 133 String encodedPassword = Base64.encode(password.getBytes("ISO-8859-1")); 134 135 // set authentication property in the http header 136 urlConnection.setRequestProperty("Authorization", 137 "Basic " + encodedPassword); 138 } 139 } 140 141 String mimeType = urlConnection.getHeaderField("Content-Type"); 142 InputStream inputStream = urlConnection.getInputStream(); 143 ByteArrayOutputStream baos = new ByteArrayOutputStream(); 144 byte buf[] = new byte[4096]; 145 int read = 0; 146 int summarized = 0; 147 148 while ((read = inputStream.read(buf)) >= 0) { 149 baos.write(buf, 0, read); 150 summarized += read; 151 } 152 153 if (log.isLoggable(java.util.logging.Level.FINE)) { 154 log.log(java.util.logging.Level.FINE, "Fetched " + summarized + " bytes from URI " + uriNew.toString()); 155 } 156 157 XMLSignatureInput result = new XMLSignatureInput(baos.toByteArray()); 158 159 result.setSourceURI(uriNew.toString()); 160 result.setMIMEType(mimeType); 161 162 return result; 163 } catch (URISyntaxException ex) { 164 throw new ResourceResolverException("generic.EmptyMessage", ex, context.attr, context.baseUri); 165 } catch (MalformedURLException ex) { 166 throw new ResourceResolverException("generic.EmptyMessage", ex, context.attr, context.baseUri); 167 } catch (IOException ex) { 168 throw new ResourceResolverException("generic.EmptyMessage", ex, context.attr, context.baseUri); 169 } catch (IllegalArgumentException e) { 170 throw new ResourceResolverException("generic.EmptyMessage", e, context.attr, context.baseUri); 171 } 172 } 173 174 private URLConnection openConnection(URL url) throws IOException { 175 176 String proxyHostProp = 177 engineGetProperty(ResolverDirectHTTP.properties[ResolverDirectHTTP.HttpProxyHost]); 178 String proxyPortProp = 179 engineGetProperty(ResolverDirectHTTP.properties[ResolverDirectHTTP.HttpProxyPort]); 180 String proxyUser = 181 engineGetProperty(ResolverDirectHTTP.properties[ResolverDirectHTTP.HttpProxyUser]); 182 String proxyPass = 183 engineGetProperty(ResolverDirectHTTP.properties[ResolverDirectHTTP.HttpProxyPass]); 184 185 Proxy proxy = null; 186 if ((proxyHostProp != null) && (proxyPortProp != null)) { 187 int port = Integer.parseInt(proxyPortProp); 188 proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(proxyHostProp, port)); 189 } 190 191 URLConnection urlConnection; 192 if (proxy != null) { 193 urlConnection = url.openConnection(proxy); 194 195 if ((proxyUser != null) && (proxyPass != null)) { 196 String password = proxyUser + ":" + proxyPass; 197 String authString = "Basic " + Base64.encode(password.getBytes("ISO-8859-1")); 198 199 urlConnection.setRequestProperty("Proxy-Authorization", authString); 200 } 201 } else { 202 urlConnection = url.openConnection(); 203 } 204 205 return urlConnection; 206 } 207 208 /** 209 * We resolve http URIs <I>without</I> fragment... 210 * 211 * @param uri 212 * @param baseURI 213 * @return true if can be resolved 214 */ 215 public boolean engineCanResolveURI(ResourceResolverContext context) { 216 if (context.uriToResolve == null) { 217 if (log.isLoggable(java.util.logging.Level.FINE)) { 218 log.log(java.util.logging.Level.FINE, "quick fail, uri == null"); 219 } 220 return false; 221 } 222 223 if (context.uriToResolve.equals("") || (context.uriToResolve.charAt(0)=='#')) { 224 if (log.isLoggable(java.util.logging.Level.FINE)) { 225 log.log(java.util.logging.Level.FINE, "quick fail for empty URIs and local ones"); 226 } 227 return false; 228 } 229 230 if (log.isLoggable(java.util.logging.Level.FINE)) { 231 log.log(java.util.logging.Level.FINE, "I was asked whether I can resolve " + context.uriToResolve); 232 } 233 234 if (context.uriToResolve.startsWith("http:") || 235 (context.baseUri != null && context.baseUri.startsWith("http:") )) { 236 if (log.isLoggable(java.util.logging.Level.FINE)) { 237 log.log(java.util.logging.Level.FINE, "I state that I can resolve " + context.uriToResolve); 238 } 239 return true; 240 } 241 242 if (log.isLoggable(java.util.logging.Level.FINE)) { 243 log.log(java.util.logging.Level.FINE, "I state that I can't resolve " + context.uriToResolve); 244 } 245 246 return false; 247 } 248 249 /** 250 * @inheritDoc 251 */ 252 public String[] engineGetPropertyKeys() { 253 return ResolverDirectHTTP.properties.clone(); 254 } 255 256 private static URI getNewURI(String uri, String baseURI) throws URISyntaxException { 257 URI newUri = null; 258 if (baseURI == null || "".equals(baseURI)) { 259 newUri = new URI(uri); 260 } else { 261 newUri = new URI(baseURI).resolve(uri); 262 } 263 264 // if the URI contains a fragment, ignore it 265 if (newUri.getFragment() != null) { 266 URI uriNewNoFrag = 267 new URI(newUri.getScheme(), newUri.getSchemeSpecificPart(), null); 268 return uriNewNoFrag; 269 } 270 return newUri; 271 } 272 273 }