Configurer Retrofit ssl avec un jks
Ajouts des dependences maven :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
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 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 |
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; } } |
Ajouter @Autowired au constructeur générer par lombok
1 |
@RequiredArgsConstructor(onConstructor_ = @Autowired) |
DB2 suppression d’une clonne
Lorsqu’on execute une requete de supression de colonne sur l’as400
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 :
1 |
CALL QSYS.QCMDEXC ('CHGJOB INQMSGRPY(*SYSRPYL)', 0000000026.00000); |
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); } |
|
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 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
@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; } } |
Et dans le teste on peut tester cela comme ceci :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
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); } |
1 |
private assertLogContains(@Nonnull ListAppender<ILoggingEvent> logAppender, @Nonnull Level level, @Nonnull String formattedMessage, @Nullable<br /> Throwable throwable) {<br /> List<Tuple> expectedLogLines = logAppender.list.stream()<br /> .map(l -> 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 /> throwable == null ? null : throwable.getMessage()));<br />} |
Réduire le temps de build maven
L’idée serait de détecter les modules maven impactés par les modifications. Puis de builder ces modules ainsi que les modules qui dépendent de celui-ci au sein du même repo. C’est possible à l’aide des arguments pl et -amd (-also-make-dependents)
exemple:
mvn install -pl artemis-javalib-impayes,artemis-javalib-common -amd
Pour avoir tous les fichiers changés dans une branche
1 |
git whatchanged --name-only --pretty="" origin..HEAD |
Pour avoir tous les modules de premier niveau
1 |
git whatchanged --name-only --pretty="" origin..HEAD | awk "{print $1}" | cut -f1 -d"/" | uniq | tr "\r\n" "\n" | tr "\n" "," | sed "s/,$/\n/" |
Pour builder
1 |
mvn -amd -pl "module list" install |
2 problèmes :
seul le premier niveau est pris en compte
le module maven doit avoir le même nom que le dossier du module
plugin maven qui pourrait permettre d’identifier les modules affectés par une modif:
https://github.com/lesfurets/partial-build-plugin
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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
@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); } |
ensuite on peut réutiliser dans un autre mapper, par exemple CustomerMapper
1 2 3 4 5 6 7 8 |
@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 chance
Read MoreLancer 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 -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=8000
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.
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 :
1 |
mvn versions:set -DnewVersion='${majeur.version}.${patch.version}' |
puis commiter les changements
1 2 |
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.
1 2 3 |
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)
1 2 |
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
1 2 3 |
mvn versions:set -DnewVersion='${majeur.version}.${patch.version}-SNAPSHOT' </code><br /><code>mvn versions:commit </code><br /><code>mvn deploy |