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