Configurer Retrofit ssl avec un jks

Ajouts des dependences maven : Shell com.squareup.retrofit2 retrofit com.squareup.retrofit2 converter-jackson com.squareup.okhttp3 logging-interceptor com.squareup.retrofit2 converter-scalars com.fasterxml.jackson.datatype jackson-datatype-jsr310</code><code> 123456789101112131415161718192021         com.squareup.retrofit2      retrofit              com.squareup.retrofit2      converter-jackson              com.squareup.okhttp3      logging-interceptor              com.squareup.retrofit2      converter-scalars              com.fasterxml.jackson.datatype      jackson-datatype-jsr310</code><code>  Voici la classe de config : Shell import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.security.KeyManagementException; import java.security.KeyStore; import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; import java.security.UnrecoverableKeyException; import java.security.cert.CertificateException; import java.time.Duration; import javax.net.ssl.KeyManagerFactory; import javax.net.ssl.SSLContext; import javax.net.ssl.TrustManagerFactory; import javax.net.ssl.X509TrustManager; import okhttp3.OkHttpClient; import okhttp3.logging.HttpLoggingInterceptor; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import retrofit2.Retrofit; import retrofit2.converter.jackson.JacksonConverterFactory; import retrofit2.converter.scalars.ScalarsConverterFactory; @Configuration public class GedConfig { @Value("${wps.ged}") String gedUrl; @Value("${wps.jks.path}") private String pathJks; @Value("${wps.jks.password}") private String passwordJks; @Bean public Retrofit retrofitGedConfig() throws IOException, KeyStoreException, CertificateException, NoSuchAlgorithmException, UnrecoverableKeyException, KeyManagementException { String url = (StringUtils.endsWith(gedUrl, "/")) ? StringUtils.substringBeforeLast(gedUrl, "/") : gedUrl; return new Retrofit.Builder() .client(buildOkHttpClient()) .baseUrl(url) .addConverterFactory(ScalarsConverterFactory.create()) .addConverterFactory(JacksonConverterFactory.create( new ObjectMapper().registerModule(new JavaTimeModule()).disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES))) .build(); } @SuppressWarnings({"java:S5527", "java:S3510"}) private OkHttpClient buildOkHttpClient() throws CertificateException, KeyStoreException, IOException, NoSuchAlgorithmException, UnrecoverableKeyException, KeyManagementException { KeyStore keyStore = readKeyStore(new File(pathJks), passwordJks); SSLContext sslContext = SSLContext.getInstance("TLSv1.2"); TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); trustManagerFactory.init(keyStore); KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); keyManagerFactory.init(keyStore, passwordJks.toCharArray()); sslContext.init(keyManagerFactory.getKeyManagers(), trustManagerFactory.getTrustManagers(), new SecureRandom()); OkHttpClient.Builder builder = new OkHttpClient.Builder().connectTimeout(Duration.ofMinutes(3)).readTimeout(Duration.ofSeconds(60)); builder.sslSocketFactory(sslContext.getSocketFactory(), (X509TrustManager) trustManagerFactory.getTrustManagers()[0]); HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor(); interceptor.setLevel(HttpLoggingInterceptor.Level.BODY); return builder.addInterceptor(interceptor).build(); } private KeyStore readKeyStore(File keystoreFile, String password) throws KeyStoreException, IOException, CertificateException, NoSuchAlgorithmException { KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType()); try (InputStream fis = new FileInputStream(keystoreFile)) { ks.load(fis, password.toCharArray()); } return ks; } } 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485   import com.fasterxml.jackson.databind.DeserializationFeature;import com.fasterxml.jackson.databind.ObjectMapper;import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;import java.io.File;import java.io.FileInputStream;import java.io.IOException;import java.io.InputStream;import java.security.KeyManagementException;import java.security.KeyStore;import java.security.KeyStoreException;import java.security.NoSuchAlgorithmException;import java.security.SecureRandom;import java.security.UnrecoverableKeyException;import java.security.cert.CertificateException;import java.time.Duration;import javax.net.ssl.KeyManagerFactory;import javax.net.ssl.SSLContext;import javax.net.ssl.TrustManagerFactory;import javax.net.ssl.X509TrustManager;import okhttp3.OkHttpClient;import okhttp3.logging.HttpLoggingInterceptor;import org.apache.commons.lang3.StringUtils;import org.springframework.beans.factory.annotation.Value;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import retrofit2.Retrofit;import retrofit2.converter.jackson.JacksonConverterFactory;import retrofit2.converter.scalars.ScalarsConverterFactory; @Configurationpublic class GedConfig {   @Value("${wps.ged}")  String gedUrl;  @Value("${wps.jks.path}")  private String pathJks;  @Value("${wps.jks.password}")  private String passwordJks;   @Bean  public Retrofit retrofitGedConfig() throws IOException, KeyStoreException, CertificateException, NoSuchAlgorithmException,                                             UnrecoverableKeyException, KeyManagementException {    String url = (StringUtils.endsWith(gedUrl, "/")) ? StringUtils.substringBeforeLast(gedUrl, "/") : gedUrl;     return new Retrofit.Builder()            .client(buildOkHttpClient())            .baseUrl(url)            .addConverterFactory(ScalarsConverterFactory.create())            .addConverterFactory(JacksonConverterFactory.create(                    new ObjectMapper().registerModule(new JavaTimeModule()).disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)))            .build();  }   @SuppressWarnings({"java:S5527", "java:S3510"})  private OkHttpClient buildOkHttpClient() throws CertificateException, KeyStoreException, IOException, NoSuchAlgorithmException,                                                  UnrecoverableKeyException, KeyManagementException {    KeyStore keyStore = readKeyStore(new File(pathJks), passwordJks);    SSLContext sslContext = SSLContext.getInstance("TLSv1.2");    TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());    trustManagerFactory.init(keyStore);    KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());    keyManagerFactory.init(keyStore, passwordJks.toCharArray());    sslContext.init(keyManagerFactory.getKeyManagers(), trustManagerFactory.getTrustManagers(), new SecureRandom());     OkHttpClient.Builder builder = new OkHttpClient.Builder().connectTimeout(Duration.ofMinutes(3)).readTimeout(Duration.ofSeconds(60));    builder.sslSocketFactory(sslContext.getSocketFactory(), (X509TrustManager) trustManagerFactory.getTrustManagers()[0]);     HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();    interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);    return builder.addInterceptor(interceptor).build();  }   private KeyStore readKeyStore(File keystoreFile, String password) throws KeyStoreException, IOException, CertificateException,                                                                           NoSuchAlgorithmException {    KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());    try (InputStream fis = new FileInputStream(keystoreFile)) {      ks.load(fis, password.toCharArray());    }    return...

Read More

Ajouter @Autowired au constructeur générer par lombok

Shell @RequiredArgsConstructor(onConstructor_ = @Autowired) 1 @RequiredArgsConstructor(onConstructor_ =...

Read More

DB2 suppression d’une clonne

Lorsqu’on execute une requete de supression de colonne sur l’as400 Shell ALTER TABLE COMMANDEPIECE DROP COLUMN excludeCutOff; 1 ALTER TABLE COMMANDEPIECE DROP COLUMN excludeCutOff; Il est possible que l’as400 nous renvoie une erreur car nous n’avons pas la permission de supprimer une colonne.Il suffit d’ajouter l’instruction suivante pour obtenir les droits : Shell CALL QSYS.QCMDEXC ('CHGJOB INQMSGRPY(*SYSRPYL)', 0000000026.00000); 1 CALL QSYS.QCMDEXC ('CHGJOB INQMSGRPY(*SYSRPYL)',...

Read More

Gestion des certificats auto-signés

Récupération d’un certificat Avec OpenSSL Aprés avoir installé et lancé le programme, on peut récupérer des certificats pour différents protocoles : http s_client -connect smtp.gmail.com:465 ftp avec tls s_client -connect qlf-ftpssl.pci.aw.atosorigin.com:20001 -starttls ftp smtp avec tls s_client -connect smtp.gmail.com:587 -starttls smtp Création du certificat crt Après avoir exécuté la commande, il faut copier les lignes depuis la ligne BEGIN CERTIFICATE (comprise) jusqu’à la ligne (END CERTIFICATE) puis un saut de ligne. Il faut ensuite convertir le fichier obtenu en UTF-8 vec Notepad++. Génération d’un keyStore Java (JKS) C:\Program Files\Java\jdk1.8.0_121\bin>keytool -importcert -trustcacerts -alias intermediate -file C:\FTP\myCert.crt -keystore C:\FTP\keystore.jks Lister les certificats présents dans un keyStore keytool -v -list -keystore keystore.jks Ajouter un certificat à un keyStore existant keytool -import -alias "myCert" -file myCert.crt -keystore keystore.jks   Chargement du fichier JKS dans un objet KeyStore KeyStore ks = KeyStore.getInstance("JKS"); Resource jks = new ClassPathResource("keystore.jks"); ks.load(jks.getInputStream(), "password_choisi_lors_de_la_creation_du_jks".toCharArray()); Utilisation avec RestTemplate pour des connexions SSL en REST @Bean public RestTemplate restTemplate() throws Exception {     KeyStore ks = ...     SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(         new SSLContextBuilder().loadTrustMaterial(null, new TrustSelfSignedStrategy())             .loadKeyMaterial(ks, passwordJks.toCharArray()).build(), NoopHostnameVerifier.INSTANCE);     HttpClient httpClient = HttpClients.custom().setSSLSocketFactory(socketFactory).build();     ClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory(httpClient);     return new RestTemplate(requestFactory);...

Read More

JUNIT tester les log d’erreur

Il peut arriver des situations, ou l’on a envie de s’assurer qu’un log.error() est bien effectué lorsqu’on rentre dans une condition. Exemple de classe à tester : Java @Component public class VendeurUtil { private static final Logger LOGGER = LoggerFactory.getLogger(VendeurUtil.class); // ... private void ajouterNouveauCompte(@Nonnull final Marchand vendeur, final PaymentInfoDTO paymentInfoDTO, @Nonnull final Devise devise, final TypeEtatKYC typeEtatHistoKYC, final Utilisateur currentUser, @Nonnull final Marketplace marketplace) { if (!(paymentInfoDTO instanceof IbanBankAccountInformation)) { LOGGER.error( "Les informations bancaire du vendeur {} de la marketplace {} n'est pas un 'IBAN' et n'est pas géré. Aucune infos bancaire ajoutées pour le vendeur.", vendeur.getIdShop(), marketplace.getCodeClient()); return; } } 12345678910111213141516 @Componentpublic class VendeurUtil {  private static final Logger LOGGER = LoggerFactory.getLogger(VendeurUtil.class); // ... private void ajouterNouveauCompte(@Nonnull final Marchand vendeur, final PaymentInfoDTO paymentInfoDTO,                                    @Nonnull final Devise devise, final TypeEtatKYC typeEtatHistoKYC, final Utilisateur currentUser,                                    @Nonnull final Marketplace marketplace) {      if (!(paymentInfoDTO instanceof IbanBankAccountInformation)) {      LOGGER.error(              "Les informations bancaire du vendeur {} de la marketplace {} n'est pas un 'IBAN' et n'est pas géré. Aucune infos bancaire ajoutées pour le vendeur.",              vendeur.getIdShop(), marketplace.getCodeClient());      return;    } } Et dans le teste on peut tester cela comme ceci :   Java import ch.qos.logback.classic.Level; import ch.qos.logback.classic.spi.ILoggingEvent; import ch.qos.logback.core.read.ListAppender; import org.assertj.core.groups.Tuple; import static org.assertj.core.api.Assertions.assertThat; @RunWith(MockitoJUnitRunner.class)<br />public class VendeurUtilTest { @Before<br />public void init() { // log Logger logger = (Logger) LoggerFactory.getLogger(CantonnementService.class); logAppender = new ListAppender<>(); logAppender.start(); logger.addAppender(logAppender); } @Test public void createVendeurFromShopMarketplace_withoutBank_shouldAlertSupport() { //GIVEN : a non supported payment info myShop.setPayment_info(new UKBankAccountInformation()); //WHEN Marchand vendeur = instance.createVendeurFromShopMarketplace(myShop, marketplace, null, EUR, histoKYC, user, null); //THEN assertLogContains(logAppender, Level.ERROR, "Les informations bancaire du vendeur 1 de la marketplace CASTO n'est pas un 'IBAN' et n'est pas géré. Aucune infos bancaire ajoutées pour le vendeur.", null); } 123456789101112131415161718192021222324252627282930 import ch.qos.logback.classic.Level;import ch.qos.logback.classic.spi.ILoggingEvent;import ch.qos.logback.core.read.ListAppender;import org.assertj.core.groups.Tuple;import static org.assertj.core.api.Assertions.assertThat; @RunWith(MockitoJUnitRunner.class)<br />public class VendeurUtilTest { @Before<br />public void init() { // log    Logger logger = (Logger) LoggerFactory.getLogger(CantonnementService.class);     logAppender = new ListAppender<>();    logAppender.start();     logger.addAppender(logAppender);} @Testpublic void createVendeurFromShopMarketplace_withoutBank_shouldAlertSupport() {   //GIVEN : a non supported payment infomyShop.setPayment_info(new UKBankAccountInformation()); //WHEN Marchand vendeur = instance.createVendeurFromShopMarketplace(myShop, marketplace, null, EUR, histoKYC, user, null); //THENassertLogContains(logAppender, Level.ERROR,                    "Les informations bancaire du vendeur 1 de la marketplace CASTO n'est pas un 'IBAN' et n'est pas géré. Aucune infos bancaire ajoutées pour le vendeur.",                   null);} Shell private assertLogContains(@Nonnull ListAppender&lt;ILoggingEvent&gt; logAppender, @Nonnull Level level, @Nonnull String formattedMessage, @Nullable<br /> Throwable throwable) {<br /> List&lt;Tuple&gt; expectedLogLines = logAppender.list.stream()<br /> .map(l -&gt; new Tuple(l.getLevel(), l.getFormattedMessage(), l.getThrowableProxy() == null ? null : l.getThrowableProxy().getClassName(),<br /> l.getThrowableProxy() == null ? null : l.getThrowableProxy().getMessage()))<br /> .collect(toList());<br /><br /> assertThat(expectedLogLines).contains(<br /> new Tuple(level, formattedMessage, throwable == null ? null : throwable.getClass().getCanonicalName(),<br...

Read More

Mapper une liste de DTO avec mapstruct

Imaginons que nous avons une entité « phone » avec un shemas strucuturé et un phoneDto qui met à plat cette donnée. Si on veut pouvoir mapper proprement avec mapstruct on peut faire comme ceci : Un PhoneMapper Java @Mapper public interface PhoneMapper { @Mapping(source = "indicator.indicator", target = "indicator") @Mapping(source = "type", target = "phoneType") @Mapping(source = "number", target = "number") InnerPhoneNumber mapToKafka(Phone phone); @Mapping(source = "indicator", target = "code") PhoneDto mapFromKafka(InnerPhoneNumber phone); @Named("phoneListToInnerPhoneNumberList") List<InnerPhoneNumber> mapListToKafka(List<Phone> phones); @Named("InnerPhoneNumberListToPhoneDto") List<InnerPhoneNumber> mapListFromKafka(List<Phone> phones); } 1234567891011121314151617 @Mapperpublic interface PhoneMapper {   @Mapping(source = "indicator.indicator", target = "indicator")  @Mapping(source = "type", target = "phoneType")  @Mapping(source = "number", target = "number")  InnerPhoneNumber mapToKafka(Phone phone);   @Mapping(source = "indicator", target = "code")  PhoneDto mapFromKafka(InnerPhoneNumber phone);   @Named("phoneListToInnerPhoneNumberList")  List<InnerPhoneNumber> mapListToKafka(List<Phone> phones);   @Named("InnerPhoneNumberListToPhoneDto")  List<InnerPhoneNumber> mapListFromKafka(List<Phone> phones);}   ensuite on peut réutiliser dans un autre mapper, par exemple CustomerMapper Java @Mapper(uses = {PhoneMapper.class}) public interface CustomerMapper { @Mapping(target = ID_CUSTOMER_WPS, source = TECHNICAL_CODE) @Mapping(target = "phoneNumbers", source = "phoneNumberList", qualifiedByName = "InnerPhoneNumberListToPhoneDto") CustomerUpdateDto mapUpdateArtemis(CustomerUpdatedFromArtemis customerFromArtemis); } 12345678 @Mapper(uses = {PhoneMapper.class})public interface CustomerMapper { @Mapping(target = ID_CUSTOMER_WPS, source = TECHNICAL_CODE)@Mapping(target = "phoneNumbers", source = "phoneNumberList", qualifiedByName = "InnerPhoneNumberListToPhoneDto")CustomerUpdateDto mapUpdateArtemis(CustomerUpdatedFromArtemis customerFromArtemis); } Après on peut tester ça très rapidement avec assertj.   Bonne...

Read More

Lancer tomcat en debug

Souvent il m’arrive d’avoir a me connecter en debug sur la plateforme de recette. Dans mon cas la machine est sous windows, dans tomcat/bin, copier/coller startup.bat en debug.bat modifier le fichier, après la ligne : set "EXECUTABLE=%CATALINA_HOME%\bin\catalina.bat" ajouter : set JAVA_OPTS=%JAVA_OPTS% -Xdebug...

Read More

Faire une recherche case insensitive mariadb

Parfois il nous arrive de vouloir faire une recherche sur un champ en ignorant la case. La mauvaise façon de le faire serait : SELECT * FROM table WHERE upper(champ) = upper(‘morgan’); Faire ceci est catastrophique en terme de performance, et en plus, si jamais on met un index sur le champ, il ne pourra pas fonctionner car les index sont sensible a la case. Heureusement les sgbd modernes viennent avec des solutions. Pour mariaDB/Mysql on peut simplement utiliser un collate différent. Les collates finissant par _bin sont case sensitive et _ci sont case insensitive. SELECT * FROM table WHERE champ = ‘morgan’ COLLATE utf8mb4_unicode_ci;  ...

Read More

Release d’une librairie au file de l’eau pour jenkins et maven

En ce moment je suis sur des problèmatiques de release avec mon projet maven. Je voudrais que mon job jenkins soit capable de releaser automatiquement une version et mettre à jour les projets qui l’utilise comme dépendance. Pour cela il y a deux petites commandes cli très utile. Mais d’abord, étudions comment structurer sont pom.xml <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion> <groupId>com.wps.invoicing</groupId><artifactId>mp-invoicing</artifactId><version>6.1.1-SNAPSHOT</version><packaging>jar</packaging> <name>Marketplace Invoicing</name><url>http://maven.apache.org</url> <properties><majeur.version>6.1</artemis.version><patch.version>1</patch.version> </properties> </project> Ici, la version majeur est variabilité et ne seras changé que sur les branches de releases. Par contre, la version patch va être incrémenter programmatiquement via le JenkinsFile.   Première commande, mettre le projet en version définitive : Shell mvn versions:set -DnewVersion='${majeur.version}.${patch.version}' 1 mvn versions:set -DnewVersion='${majeur.version}.${patch.version}' puis commiter les changements Shell mvn versions:commit 12 mvn versions:commit  Ensuite, il faut deploy la version sur nexus. Maintenant que notre version N a été publier, il ne reste plus qu’a incrémenter la version patch. Shell def pom = readMavenPom file: 'pom.xml' def incrementMinor = pom.properties['patch.version'].toInteger() +1 123 def pom = readMavenPom file: 'pom.xml'def incrementMinor = pom.properties['patch.version'].toInteger() +1  Ensuite, il faut updater la propriété (toujours dans le jenkinsFile) Shell bat "mvn versions:set-property -Dproperty=patch.version -DnewVersion=${incrementMinor}" bat "mvn versions:commit" 12 bat "mvn versions:set-property -Dproperty=patch.version -DnewVersion=${incrementMinor}"bat "mvn versions:commit" Puis créer la nouvelle version snapshot, commit et deploy pour que tous les nouveaux projet l’ai Shell mvn versions:set -DnewVersion='${majeur.version}.${patch.version}-SNAPSHOT' </code><br /><code>mvn versions:commit </code><br /><code>mvn deploy 123 mvn versions:set -DnewVersion='${majeur.version}.${patch.version}-SNAPSHOT'</code><br /><code>mvn versions:commit</code><br /><code>mvn...

Read More

Mettre en place un environement de dev pour rust

Installer rust et les outils tiers curl https://sh.rustup.rs -sSf | sh installer les sources rustup component add rust-src Installer racer pour l’autocompletion cargo install racer installer raincorn pour le parsing cargo install --git https://github.com/RustDT/Rainicorn --tag version_1.x rustfmt pour le formattage Shell [crayon-65f9086742e9e424449440 lang="sh" decode="true" inline="1" ]cargo install rustfmt-nightly 1 [crayon-65f9086742e9e424449440   lang="sh" decode="true" inline="1"  ]cargo install rustfmt-nightly [/crayon] Configurer eclipse :   Directory : ~/.cargo rust src directory : $(rustc --print sysroot)/lib/rustlib/src/rust/src Racer : ~/.cargo/bin/racer...

Read More