001package org.eclipse.aether.util.repository; 002 003/* 004 * Licensed to the Apache Software Foundation (ASF) under one 005 * or more contributor license agreements. See the NOTICE file 006 * distributed with this work for additional information 007 * regarding copyright ownership. The ASF licenses this file 008 * to you under the Apache License, Version 2.0 (the 009 * "License"); you may not use this file except in compliance 010 * with the License. You may obtain a copy of the License at 011 * 012 * http://www.apache.org/licenses/LICENSE-2.0 013 * 014 * Unless required by applicable law or agreed to in writing, 015 * software distributed under the License is distributed on an 016 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 017 * KIND, either express or implied. See the License for the 018 * specific language governing permissions and limitations 019 * under the License. 020 */ 021 022import java.net.Authenticator; 023import java.net.InetSocketAddress; 024import java.net.PasswordAuthentication; 025import java.net.SocketAddress; 026import java.net.URI; 027import java.net.URL; 028import java.util.List; 029import java.util.Map; 030import java.util.UUID; 031 032import org.eclipse.aether.repository.Authentication; 033import org.eclipse.aether.repository.AuthenticationContext; 034import org.eclipse.aether.repository.AuthenticationDigest; 035import org.eclipse.aether.repository.Proxy; 036import org.eclipse.aether.repository.ProxySelector; 037import org.eclipse.aether.repository.RemoteRepository; 038 039import static java.util.Objects.requireNonNull; 040 041/** 042 * A proxy selector that uses the {@link java.net.ProxySelector#getDefault() JRE's global proxy selector}. In 043 * combination with the system property {@code java.net.useSystemProxies}, this proxy selector can be employed to pick 044 * up the proxy configuration from the operating system, see <a 045 * href="http://docs.oracle.com/javase/6/docs/technotes/guides/net/proxies.html">Java Networking and Proxies</a> for 046 * details. The {@link java.net.Authenticator JRE's global authenticator} is used to look up credentials for a proxy 047 * when needed. 048 */ 049public final class JreProxySelector 050 implements ProxySelector 051{ 052 053 /** 054 * Creates a new proxy selector that delegates to {@link java.net.ProxySelector#getDefault()}. 055 */ 056 public JreProxySelector() 057 { 058 } 059 060 public Proxy getProxy( RemoteRepository repository ) 061 { 062 requireNonNull( repository, "repository cannot be null" ); 063 List<java.net.Proxy> proxies = null; 064 try 065 { 066 URI uri = new URI( repository.getUrl() ).parseServerAuthority(); 067 proxies = java.net.ProxySelector.getDefault().select( uri ); 068 } 069 catch ( Exception e ) 070 { 071 // URL invalid or not accepted by selector or no selector at all, simply use no proxy 072 } 073 if ( proxies != null ) 074 { 075 for ( java.net.Proxy proxy : proxies ) 076 { 077 if ( java.net.Proxy.Type.DIRECT.equals( proxy.type() ) ) 078 { 079 break; 080 } 081 if ( java.net.Proxy.Type.HTTP.equals( proxy.type() ) && isValid( proxy.address() ) ) 082 { 083 InetSocketAddress addr = (InetSocketAddress) proxy.address(); 084 return new Proxy( Proxy.TYPE_HTTP, addr.getHostName(), addr.getPort(), 085 JreProxyAuthentication.INSTANCE ); 086 } 087 } 088 } 089 return null; 090 } 091 092 private static boolean isValid( SocketAddress address ) 093 { 094 if ( address instanceof InetSocketAddress ) 095 { 096 /* 097 * NOTE: On some platforms with java.net.useSystemProxies=true, unconfigured proxies show up as proxy 098 * objects with empty host and port 0. 099 */ 100 InetSocketAddress addr = (InetSocketAddress) address; 101 if ( addr.getPort() <= 0 ) 102 { 103 return false; 104 } 105 if ( addr.getHostName() == null || addr.getHostName().isEmpty() ) 106 { 107 return false; 108 } 109 return true; 110 } 111 return false; 112 } 113 114 private static final class JreProxyAuthentication 115 implements Authentication 116 { 117 118 public static final Authentication INSTANCE = new JreProxyAuthentication(); 119 120 public void fill( AuthenticationContext context, String key, Map<String, String> data ) 121 { 122 requireNonNull( context, "digest cannot be null" ); 123 Proxy proxy = context.getProxy(); 124 if ( proxy == null ) 125 { 126 return; 127 } 128 if ( !AuthenticationContext.USERNAME.equals( key ) && !AuthenticationContext.PASSWORD.equals( key ) ) 129 { 130 return; 131 } 132 133 try 134 { 135 URL url; 136 try 137 { 138 url = new URL( context.getRepository().getUrl() ); 139 } 140 catch ( Exception e ) 141 { 142 url = null; 143 } 144 145 PasswordAuthentication auth = 146 Authenticator.requestPasswordAuthentication( proxy.getHost(), null, proxy.getPort(), "http", 147 "Credentials for proxy " + proxy, null, url, 148 Authenticator.RequestorType.PROXY ); 149 if ( auth != null ) 150 { 151 context.put( AuthenticationContext.USERNAME, auth.getUserName() ); 152 context.put( AuthenticationContext.PASSWORD, auth.getPassword() ); 153 } 154 else 155 { 156 context.put( AuthenticationContext.USERNAME, System.getProperty( "http.proxyUser" ) ); 157 context.put( AuthenticationContext.PASSWORD, System.getProperty( "http.proxyPassword" ) ); 158 } 159 } 160 catch ( SecurityException e ) 161 { 162 // oh well, let's hope the proxy can do without auth 163 } 164 } 165 166 public void digest( AuthenticationDigest digest ) 167 { 168 requireNonNull( digest, "digest cannot be null" ); 169 // we don't know anything about the JRE's current authenticator, assume the worst (i.e. interactive) 170 digest.update( UUID.randomUUID().toString() ); 171 } 172 173 @Override 174 public boolean equals( Object obj ) 175 { 176 return this == obj || ( obj != null && getClass().equals( obj.getClass() ) ); 177 } 178 179 @Override 180 public int hashCode() 181 { 182 return getClass().hashCode(); 183 } 184 185 } 186 187}