View Javadoc
1   package org.apache.maven.report.projectinfo;
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.io.IOException;
23  import java.io.InputStream;
24  import java.net.Authenticator;
25  import java.net.PasswordAuthentication;
26  import java.net.URL;
27  import java.net.URLConnection;
28  import java.security.KeyManagementException;
29  import java.security.NoSuchAlgorithmException;
30  import java.security.SecureRandom;
31  import java.security.cert.X509Certificate;
32  import java.util.Properties;
33  
34  import javax.net.ssl.HostnameVerifier;
35  import javax.net.ssl.HttpsURLConnection;
36  import javax.net.ssl.SSLContext;
37  import javax.net.ssl.SSLSession;
38  import javax.net.ssl.SSLSocketFactory;
39  import javax.net.ssl.TrustManager;
40  import javax.net.ssl.X509TrustManager;
41  
42  import org.apache.commons.validator.routines.RegexValidator;
43  import org.apache.commons.validator.routines.UrlValidator;
44  import org.apache.maven.artifact.Artifact;
45  import org.apache.maven.artifact.ArtifactUtils;
46  import org.apache.maven.project.MavenProject;
47  import org.apache.maven.project.ProjectBuilder;
48  import org.apache.maven.project.ProjectBuildingException;
49  import org.apache.maven.project.ProjectBuildingRequest;
50  import org.apache.maven.reporting.AbstractMavenReportRenderer;
51  import org.apache.maven.repository.RepositorySystem;
52  import org.apache.maven.settings.Proxy;
53  import org.apache.maven.settings.Server;
54  import org.apache.maven.settings.Settings;
55  import org.codehaus.plexus.util.Base64;
56  import org.codehaus.plexus.util.IOUtil;
57  import org.codehaus.plexus.util.StringUtils;
58  
59  /**
60   * Utilities methods.
61   *
62   * @author <a href="mailto:vincent.siveton@gmail.com">Vincent Siveton</a>
63   * @version $Id$
64   * @since 2.1
65   */
66  public class ProjectInfoReportUtils
67  {
68      private static final UrlValidator URL_VALIDATOR = new UrlValidator( new String[] { "http", "https" },
69                                                                          new RegexValidator( "^([" + "\\p{Alnum}\\-\\."
70                                                                              + "]*)(:\\d*)?(.*)?" ), 0 );
71  
72      /** The timeout when getting the url input stream */
73      private static final int TIMEOUT = 1000 * 5;
74  
75      /** The default encoding used to transform bytes to characters */
76      private static final String DEFAULT_ENCODING = "UTF-8";
77  
78      /**
79       * Get the input stream using UTF-8 as character encoding from a URL.
80       *
81       * @param url not null
82       * @param settings not null to handle proxy settings
83       * @return the UTF-8 decoded input stream as string
84       * @throws IOException if any
85       * @see #getContent(URL, Settings, String)
86       */
87      public static String getContent( URL url, Settings settings )
88          throws IOException
89      {
90          return getContent( url, settings, DEFAULT_ENCODING );
91      }
92  
93      /**
94       * Get the input stream from a URL.
95       *
96       * @param url not null
97       * @param settings not null to handle proxy settings
98       * @param encoding the wanted encoding for the URL input stream. If null, UTF-8 will be used.
99       * @return the input stream decoded with the wanted encoding as string
100      * @throws IOException if any
101      */
102     public static String getContent( URL url, Settings settings, String encoding )
103         throws IOException
104     {
105         return getContent( url, null, settings, encoding );
106     }
107 
108     /**
109      * Get the input stream from a URL.
110      *
111      * @param url not null
112      * @param project could be null
113      * @param settings not null to handle proxy settings
114      * @param encoding the wanted encoding for the URL input stream. If null, UTF-8 will be used.
115      * @return the input stream decoded with the wanted encoding as string
116      * @throws IOException if any
117      * @since 2.3
118      */
119     public static String getContent( URL url, MavenProject project, Settings settings, String encoding )
120         throws IOException
121     {
122         String scheme = url.getProtocol();
123 
124         if ( StringUtils.isEmpty( encoding ) )
125         {
126             encoding = DEFAULT_ENCODING;
127         }
128 
129         if ( "file".equals( scheme ) )
130         {
131             InputStream in = null;
132             try
133             {
134                 URLConnection conn = url.openConnection();
135                 in = conn.getInputStream();
136 
137                 final String content = IOUtil.toString( in, encoding );
138 
139                 in.close();
140                 in = null;
141 
142                 return content;
143             }
144             finally
145             {
146                 IOUtil.close( in );
147             }
148         }
149 
150         Proxy proxy = settings.getActiveProxy();
151         if ( proxy != null )
152         {
153             if ( "http".equals( scheme ) || "https".equals( scheme ) || "ftp".equals( scheme ) )
154             {
155                 scheme += ".";
156             }
157             else
158             {
159                 scheme = "";
160             }
161 
162             String host = proxy.getHost();
163             if ( !StringUtils.isEmpty( host ) )
164             {
165                 Properties p = System.getProperties();
166                 p.setProperty( scheme + "proxySet", "true" );
167                 p.setProperty( scheme + "proxyHost", host );
168                 p.setProperty( scheme + "proxyPort", String.valueOf( proxy.getPort() ) );
169                 if ( !StringUtils.isEmpty( proxy.getNonProxyHosts() ) )
170                 {
171                     p.setProperty( scheme + "nonProxyHosts", proxy.getNonProxyHosts() );
172                 }
173 
174                 final String userName = proxy.getUsername();
175                 if ( !StringUtils.isEmpty( userName ) )
176                 {
177                     final String pwd = StringUtils.isEmpty( proxy.getPassword() ) ? "" : proxy.getPassword();
178                     Authenticator.setDefault( new Authenticator()
179                     {
180                         /** {@inheritDoc} */
181                         @Override
182                         protected PasswordAuthentication getPasswordAuthentication()
183                         {
184                             return new PasswordAuthentication( userName, pwd.toCharArray() );
185                         }
186                     } );
187                 }
188             }
189         }
190 
191         InputStream in = null;
192         try
193         {
194             URLConnection conn = getURLConnection( url, project, settings );
195             in = conn.getInputStream();
196 
197             final String string = IOUtil.toString( in, encoding );
198 
199             in.close();
200             in = null;
201 
202             return string;
203         }
204         finally
205         {
206             IOUtil.close( in );
207         }
208     }
209 
210     /**
211      * @param repositorySystem not null
212      * @param artifact not null
213      * @param projectBuilder not null
214      * @param buildingRequest not null
215      * @return the artifact url or null if an error occurred.
216      */
217     public static String getArtifactUrl( RepositorySystem repositorySystem, Artifact artifact,
218                                          ProjectBuilder projectBuilder, ProjectBuildingRequest buildingRequest )
219     {
220         if ( Artifact.SCOPE_SYSTEM.equals( artifact.getScope() ) )
221         {
222             return null;
223         }
224 
225         Artifact copyArtifact = ArtifactUtils.copyArtifact( artifact );
226         if ( !"pom".equals( copyArtifact.getType() ) )
227         {
228             copyArtifact =
229                 repositorySystem.createProjectArtifact( copyArtifact.getGroupId(), copyArtifact.getArtifactId(),
230                                                         copyArtifact.getVersion() );
231         }
232         try
233         {
234             MavenProject pluginProject = projectBuilder.build( copyArtifact, buildingRequest ).getProject();
235 
236             if ( isArtifactUrlValid( pluginProject.getUrl() ) )
237             {
238                 return pluginProject.getUrl();
239             }
240 
241             return null;
242         }
243         catch ( ProjectBuildingException e )
244         {
245             return null;
246         }
247     }
248 
249     /**
250      * @param artifactId not null
251      * @param link could be null
252      * @return the artifactId cell with or without a link pattern
253      * @see AbstractMavenReportRenderer#linkPatternedText(String)
254      */
255     public static String getArtifactIdCell( String artifactId, String link )
256     {
257         if ( StringUtils.isEmpty( link ) )
258         {
259             return artifactId;
260         }
261 
262         return "{" + artifactId + "," + link + "}";
263     }
264 
265     /**
266      * @param url not null
267      * @return <code>true</code> if the url is valid, <code>false</code> otherwise.
268      */
269     public static boolean isArtifactUrlValid( String url )
270     {
271         if ( StringUtils.isEmpty( url ) )
272         {
273             return false;
274         }
275 
276         return URL_VALIDATOR.isValid( url );
277     }
278 
279     /**
280      * @param url not null
281      * @param project not null
282      * @param settings not null
283      * @return the url connection with auth if required. Don't check the certificate if SSL scheme.
284      * @throws IOException if any
285      */
286     private static URLConnection getURLConnection( URL url, MavenProject project, Settings settings )
287         throws IOException
288     {
289         URLConnection conn = url.openConnection();
290         conn.setConnectTimeout( TIMEOUT );
291         conn.setReadTimeout( TIMEOUT );
292 
293         // conn authorization
294         //@formatter:off
295         if ( settings.getServers() != null
296             && !settings.getServers().isEmpty()
297             && project != null
298             && project.getDistributionManagement() != null
299             && (
300                     project.getDistributionManagement().getRepository() != null
301                  || project.getDistributionManagement().getSnapshotRepository() != null
302                )
303             && ( StringUtils.isNotEmpty( project.getDistributionManagement().getRepository().getUrl() )
304                  || StringUtils.isNotEmpty( project.getDistributionManagement().getSnapshotRepository().getUrl() ) )
305                )
306         //@formatter:on
307         {
308             Server server = null;
309             if ( url.toString().contains( project.getDistributionManagement().getRepository().getUrl() ) )
310             {
311                 server = settings.getServer( project.getDistributionManagement().getRepository().getId() );
312             }
313             if ( server == null
314                 && url.toString().contains( project.getDistributionManagement().getSnapshotRepository().getUrl() ) )
315             {
316                 server = settings.getServer( project.getDistributionManagement().getSnapshotRepository().getId() );
317             }
318 
319             if ( server != null && StringUtils.isNotEmpty( server.getUsername() )
320                 && StringUtils.isNotEmpty( server.getPassword() ) )
321             {
322                 String up = server.getUsername().trim() + ":" + server.getPassword().trim();
323                 String upEncoded = new String( Base64.encodeBase64Chunked( up.getBytes() ) ).trim();
324 
325                 conn.setRequestProperty( "Authorization", "Basic " + upEncoded );
326             }
327         }
328 
329         if ( conn instanceof HttpsURLConnection )
330         {
331             HostnameVerifier hostnameverifier = new HostnameVerifier()
332             {
333                 /** {@inheritDoc} */
334                 public boolean verify( String urlHostName, SSLSession session )
335                 {
336                     return true;
337                 }
338             };
339             ( (HttpsURLConnection) conn ).setHostnameVerifier( hostnameverifier );
340 
341             TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager()
342             {
343                 /** {@inheritDoc} */
344                 public void checkClientTrusted( final X509Certificate[] chain, final String authType )
345                 {
346                 }
347 
348                 /** {@inheritDoc} */
349                 public void checkServerTrusted( final X509Certificate[] chain, final String authType )
350                 {
351                 }
352 
353                 /** {@inheritDoc} */
354                 public X509Certificate[] getAcceptedIssuers()
355                 {
356                     return null;
357                 }
358             } };
359 
360             try
361             {
362                 SSLContext sslContext = SSLContext.getInstance( "SSL" );
363                 sslContext.init( null, trustAllCerts, new SecureRandom() );
364 
365                 SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
366 
367                 ( (HttpsURLConnection) conn ).setSSLSocketFactory( sslSocketFactory );
368             }
369             catch ( NoSuchAlgorithmException | KeyManagementException e1 )
370             {
371                 // ignore
372             }
373         }
374 
375         return conn;
376     }
377 }