View Javadoc
1   package org.eclipse.aether.util.repository;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  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,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import java.net.Authenticator;
23  import java.net.InetSocketAddress;
24  import java.net.PasswordAuthentication;
25  import java.net.SocketAddress;
26  import java.net.URI;
27  import java.net.URL;
28  import java.util.List;
29  import java.util.Map;
30  import java.util.UUID;
31  
32  import org.eclipse.aether.repository.Authentication;
33  import org.eclipse.aether.repository.AuthenticationContext;
34  import org.eclipse.aether.repository.AuthenticationDigest;
35  import org.eclipse.aether.repository.Proxy;
36  import org.eclipse.aether.repository.ProxySelector;
37  import org.eclipse.aether.repository.RemoteRepository;
38  
39  import static java.util.Objects.requireNonNull;
40  
41  /**
42   * A proxy selector that uses the {@link java.net.ProxySelector#getDefault() JRE's global proxy selector}. In
43   * combination with the system property {@code java.net.useSystemProxies}, this proxy selector can be employed to pick
44   * up the proxy configuration from the operating system, see <a
45   * href="http://docs.oracle.com/javase/6/docs/technotes/guides/net/proxies.html">Java Networking and Proxies</a> for
46   * details. The {@link java.net.Authenticator JRE's global authenticator} is used to look up credentials for a proxy
47   * when needed.
48   */
49  public final class JreProxySelector
50      implements ProxySelector
51  {
52  
53      /**
54       * Creates a new proxy selector that delegates to {@link java.net.ProxySelector#getDefault()}.
55       */
56      public JreProxySelector()
57      {
58      }
59  
60      public Proxy getProxy( RemoteRepository repository )
61      {
62          requireNonNull( repository, "repository cannot be null" );
63          List<java.net.Proxy> proxies = null;
64          try
65          {
66              URI uri = new URI( repository.getUrl() ).parseServerAuthority();
67              proxies = java.net.ProxySelector.getDefault().select( uri );
68          }
69          catch ( Exception e )
70          {
71              // URL invalid or not accepted by selector or no selector at all, simply use no proxy
72          }
73          if ( proxies != null )
74          {
75              for ( java.net.Proxy proxy : proxies )
76              {
77                  if ( java.net.Proxy.Type.DIRECT.equals( proxy.type() ) )
78                  {
79                      break;
80                  }
81                  if ( java.net.Proxy.Type.HTTP.equals( proxy.type() ) && isValid( proxy.address() ) )
82                  {
83                      InetSocketAddress addr = (InetSocketAddress) proxy.address();
84                      return new Proxy( Proxy.TYPE_HTTP, addr.getHostName(), addr.getPort(),
85                                        JreProxyAuthentication.INSTANCE );
86                  }
87              }
88          }
89          return null;
90      }
91  
92      private static boolean isValid( SocketAddress address )
93      {
94          if ( address instanceof InetSocketAddress )
95          {
96              /*
97               * NOTE: On some platforms with java.net.useSystemProxies=true, unconfigured proxies show up as proxy
98               * objects with empty host and port 0.
99               */
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 }