Thursday, June 16, 2016

Maven POST a zip through HTTPS using gmaven and HttpClient

What

Well in this blog post I put all necessary things to be able to post on a defined url a product.
This product could be provided by an assembly or (it's my case)  by a tycho repository build.

How

First of all we use maven and an integration chain. As I dont want to use a post script build in jenkins (it's external...)
So we have two main options :
  • build a Maven plugin
  • use something embed in the pom.
As we have very few site to push I target the second option and I use gmaven, that is allows to excute a groovy script so every thing is open.
To do the https post I use HttpClient from apache, this framework allow a good way to do post whith authentication, SSL and all those kind of things.

So the script :

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.cert.X509Certificate;

import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;

import org.apache.http.HttpEntity;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.TrustSelfSignedStrategy;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.mime.HttpMultipartMode;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.ssl.SSLContexts;
import org.apache.http.util.EntityUtils;

class X509TM implements X509TrustManager {
 public X509Certificate[] getAcceptedIssuers(){
  return null;
  }

 public void checkClientTrusted(X509Certificate[] certs, String authType){}
 public void checkServerTrusted(X509Certificate[] certs, String authType){}
};

String url = pom.properties["http.url"];
if(url != null)  {
 log.info("Try to post site at url : " + url);
 FileInputStream fileInputStream = null;
 try {
  //TRUST ALL : bar but it should be a temporarly workaround
  X509TrustManager X509Tm = new X509TM();
  TrustManager[] trustAllCerts = [X509Tm] as TrustManager[] ;
  SSLContext sslcontext = SSLContexts.custom()
    .loadTrustMaterial(null, new TrustSelfSignedStrategy())
    .build();
  sslcontext.init(null, trustAllCerts, new SecureRandom());
  SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslcontext);
  CloseableHttpClient httpclient = HttpClients.custom().setSSLSocketFactory(sslsf).build();
 
  String outDir = pom.properties['outputdir'];
  String pname = pom.properties['pname'];
  String pversion = pom.properties['pversion'];
  HttpPost post = new HttpPost(url);
  File file = new File(outDir+"/"+pname+"-"+pversion+".zip");
  if(file.exists())  {
   log.info("multipart to post : " + file.getAbsolutePath());
   //create multi part
   MultipartEntityBuilder builder = MultipartEntityBuilder.create();
   builder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);
   builder.addBinaryBody("site", file, ContentType.MULTIPART_FORM_DATA, file.getName());
   HttpEntity multipart = builder.build();
   post.setEntity(multipart);
   //DO POST
   CloseableHttpResponse  response = httpclient.execute(post);
   HttpEntity entityRep = response.getEntity();
   if (entityRep != null) {
    String page = EntityUtils.toString(entityRep);
    log.info("PAGE :" + page);
   }
   EntityUtils.consume(entityRep);
  } else  {
   log.info("File "+file.getAbsolutePath() +" not found");
  }
  } catch (Exception e) {
  e.printStackTrace();
  if(fileInputStream != null )
   try {
    fileInputStream.close();
   } catch (IOException e1) {
    e1.printStackTrace();
   }
  }
} else {
 log.info("Post site is disabled (url is null)");
}


And finally the  pom. As you could see I set a maven profil activated on system property :

<project>
...
<profiles>
 <profile>
  <activation>
  <!--ACTIVATE through -Denvprops=Push-->
   <property>
    <name>envprops</name>
    <value>Push</value>
   </property>
  </activation>
  <properties>
   <http.url>${YOURURL}</http.url>
   <pname>${project.name}</pname>
   <pversion>${project.version}</pversion>
   <outputdir>${project.build.directory}</outputdir>
  </properties>
 </profile>
</profiles>

<build>
 <plugins>
  <plugin>
   <groupId>org.codehaus.gmaven</groupId>
   <artifactId>gmaven-plugin</artifactId>
   <version>1.5</version>
   <dependencies>
    <dependency>
     <groupId>org.apache.httpcomponents</groupId>
     <artifactId>httpclient</artifactId>
     <version>4.5.2</version>
    </dependency>
    <dependency>
     <groupId>org.apache.httpcomponents</groupId>
     <artifactId>httpmime</artifactId>
     <version>4.5.2</version>
    </dependency>
   </dependencies>
   <executions>
    <execution>
     <!-- To be after Zip generation -->
     <phase>install</phase>
     <goals>
      <goal>execute</goal>
     </goals>
     <configuration>
      <source>${project.basedir}/post.groovy</source>
     </configuration>
    </execution>
   </executions>
  </plugin>
 </plugins>
</build>
</project>