Code development platform for open source projects from the European Union institutions

Skip to content
Snippets Groups Projects
Commit d1a8a129 authored by Jean Claude Correale's avatar Jean Claude Correale
Browse files

Merge branch 'feature/ok-http-client' into 'develop'

OkHttpAuthorityExchange

See merge request !109
parents c624182f d1eb88ab
No related branches found
No related tags found
4 merge requests!130Release,!129Release,!128fix unit tests - add property,!109OkHttpAuthorityExchange
Pipeline #222404 passed with warnings
PROJECT_VERSION_NUMBER="0.6.0"
\ No newline at end of file
PROJECT_VERSION_NUMBER="0.7.0"
\ No newline at end of file
......@@ -5,7 +5,7 @@
<parent>
<groupId>com.aruba.simpl</groupId>
<artifactId>simpl-parent</artifactId>
<version>0.6.0-RC</version>
<version>0.7.0-RC</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
......@@ -27,6 +27,10 @@
<groupId>com.aruba.simpl</groupId>
<artifactId>simpl-http-client-feign</artifactId>
</dependency>
<dependency>
<groupId>com.aruba.simpl</groupId>
<artifactId>simpl-http-client-okhttp</artifactId>
</dependency>
<dependency>
<groupId>com.aruba.simpl</groupId>
<artifactId>simpl-spring-boot-starter</artifactId>
......
package com.aruba.simpl.usersroles.configurations;
import com.aruba.simpl.client.SimplClient;
import com.aruba.simpl.client.adapters.EphemeralProofAdapter;
import com.aruba.simpl.client.feign.FeignSimplClient;
import com.aruba.simpl.client.okhttp.OkHttpSimplClient;
import com.aruba.simpl.client.ssl.SslInfo;
import com.aruba.simpl.common.exchanges.mtls.AuthorityExchange;
import com.aruba.simpl.common.exchanges.mtls.ParticipantExchange;
import com.aruba.simpl.common.interceptors.TierOneTokenPropagatorInterceptor;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.IOException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import lombok.extern.log4j.Log4j2;
import org.springframework.stereotype.Component;
@Log4j2
@Component
public class MtlsClientFactory {
private final FeignSimplClient simplClient;
private final OkHttpSimplClient okHttpSimplClient;
private final FeignSimplClient feignSimplClient;
private final TierOneTokenPropagatorInterceptor tokenPropagator;
private final MtlsClientProperties clientProperties;
private final EphemeralProofAdapter ephemeralProofAdapter;
private final ObjectMapper objectMapper;
public MtlsClientFactory(
FeignSimplClient simplClient,
OkHttpSimplClient okHttpSimplClient,
FeignSimplClient feignSimplClient,
TierOneTokenPropagatorInterceptor tokenPropagator,
MtlsClientProperties clientProperties,
EphemeralProofAdapter ephemeralProofAdapter) {
this.simplClient = simplClient;
EphemeralProofAdapter ephemeralProofAdapter,
ObjectMapper objectMapper) {
this.okHttpSimplClient = okHttpSimplClient;
this.feignSimplClient = feignSimplClient;
this.tokenPropagator = tokenPropagator;
this.clientProperties = clientProperties;
this.ephemeralProofAdapter = ephemeralProofAdapter;
this.objectMapper = objectMapper;
}
public AuthorityExchange buildAuthorityClient(String url, KeyStore keyStore, String password)
throws CertificateException, KeyStoreException, IOException, NoSuchAlgorithmException {
return build(url, keyStore, password, AuthorityExchange.class);
log.info("Creating MTLS Client of type {}", clientProperties.type());
return switch (clientProperties.type()) {
case FEIGN -> buildClient(feignSimplClient.builder(), keyStore, password)
.target(AuthorityExchange.class, url);
case OKHTTP -> {
var client = buildClient(okHttpSimplClient.builder(), keyStore, password);
yield new OkHttpAuthorityExchange(
client.build(), clientProperties.authority().url(), objectMapper);
}
};
}
public ParticipantExchange buildParticipantClient(String url, KeyStore keyStore, String password)
throws CertificateException, KeyStoreException, IOException, NoSuchAlgorithmException {
return build(url, keyStore, password, ParticipantExchange.class);
return buildAuthorityClient(url, keyStore, password);
}
private <T> T build(String url, KeyStore keyStore, String password, Class<T> clazz)
private <T> T buildClient(SimplClient.Builder<T> clientBuilder, KeyStore keyStore, String password)
throws CertificateException, KeyStoreException, IOException, NoSuchAlgorithmException {
var trustStore = buildTrustStore(keyStore);
return simplClient
.builder(new SslInfo(keyStore, password, trustStore))
return clientBuilder
.setSslInfoSupplier(() -> new SslInfo(keyStore, password, trustStore))
.setAuthorizationHeaderSupplier(tokenPropagator)
.setEphemeralProofAdapter(ephemeralProofAdapter)
.setAuthorityUrlSupplier(() -> clientProperties.authority().url())
.build()
.target(clazz, url);
.build();
}
private static KeyStore buildTrustStore(KeyStore keyStore)
......
......@@ -3,6 +3,12 @@ package com.aruba.simpl.usersroles.configurations;
import org.springframework.boot.context.properties.ConfigurationProperties;
@ConfigurationProperties(prefix = "client")
public record MtlsClientProperties(AuthorityProperties authority, String certificatePassword) {
public record MtlsClientProperties(AuthorityProperties authority, String certificatePassword, Type type) {
public record AuthorityProperties(String url) {}
enum Type {
FEIGN,
OKHTTP
}
}
......@@ -2,6 +2,8 @@ package com.aruba.simpl.usersroles.configurations;
import com.aruba.simpl.client.feign.DaggerFeignSimplClientFactory;
import com.aruba.simpl.client.feign.FeignSimplClient;
import com.aruba.simpl.client.okhttp.DaggerOkHttpSimplClientFactory;
import com.aruba.simpl.client.okhttp.OkHttpSimplClient;
import com.aruba.simpl.common.exchanges.mtls.AuthorityExchange;
import java.io.IOException;
import java.security.KeyStoreException;
......@@ -35,7 +37,12 @@ public class MtlsConfig implements BeanFactoryPostProcessor {
}
@Bean
public FeignSimplClient simplClient() {
public FeignSimplClient feignSimplClient() {
return DaggerFeignSimplClientFactory.create().get();
}
@Bean
public OkHttpSimplClient okHttpSimplClient() {
return DaggerOkHttpSimplClientFactory.create().get();
}
}
package com.aruba.simpl.usersroles.configurations;
import com.aruba.simpl.common.exceptions.RuntimeWrapperException;
import com.aruba.simpl.common.exchanges.mtls.AuthorityExchange;
import com.aruba.simpl.common.model.dto.IdentityAttributeDTO;
import com.aruba.simpl.common.model.dto.IdentityAttributeWithOwnershipDTO;
import com.aruba.simpl.common.model.dto.ParticipantWithIdentityAttributesDTO;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.IOException;
import java.util.List;
import okhttp3.*;
public class OkHttpAuthorityExchange implements AuthorityExchange {
private final OkHttpClient client;
private final String authorityUrl;
private final ObjectMapper objectMapper;
public OkHttpAuthorityExchange(OkHttpClient client, String authorityUrl, ObjectMapper objectMapper) {
this.client = client;
this.authorityUrl = authorityUrl;
this.objectMapper = objectMapper;
}
@Override
public String token() {
var body = RequestBody.create(new byte[0], null);
var request = new Request.Builder()
.post(body)
.url(authorityUrl + "/identity-api/mtls/token")
.build();
try (Response response = client.newCall(request).execute()) {
return response.body().string();
} catch (IOException e) {
throw new RuntimeWrapperException(e);
}
}
@Override
public void sendTierOnePublicKey(String tierOnePublicKey) {
var body = RequestBody.create(tierOnePublicKey.getBytes(), MediaType.parse("text/plain"));
var request = new Request.Builder()
.patch(body)
.url(authorityUrl + "/identity-api/mtls/public-key")
.build();
try (Response response = client.newCall(request).execute()) {
} catch (IOException e) {
throw new RuntimeWrapperException(e);
}
}
@Override
public ParticipantWithIdentityAttributesDTO echo() {
var json = doGet("/identity-api/mtls/echo");
return convert(json, ParticipantWithIdentityAttributesDTO.class);
}
@Override
public List<IdentityAttributeWithOwnershipDTO> getIdentityAttributesWithOwnership() {
var json = doGet("/sap-api/mtls/identity-attribute");
return convert(json, new TypeReference<List<IdentityAttributeWithOwnershipDTO>>() {});
}
@Override
public List<IdentityAttributeDTO> getIdentityAttributesByCertificateIdInUri(String certificateId) {
var json = doGet("/sap-api/mtls/identity-attribute/" + certificateId);
return convert(json, new TypeReference<List<IdentityAttributeDTO>>() {});
}
@Override
public ParticipantWithIdentityAttributesDTO ping() {
var json = doGet("/user-api/mtls/ping");
return convert(json, ParticipantWithIdentityAttributesDTO.class);
}
private String doGet(String path) {
var request = new Request.Builder().get().url(authorityUrl + path).build();
try (Response response = client.newCall(request).execute()) {
return response.body().string();
} catch (IOException e) {
throw new RuntimeWrapperException(e);
}
}
private <T> T convert(String json, Class<T> clazz) {
try {
return objectMapper.readValue(json, clazz);
} catch (JsonProcessingException e) {
throw new RuntimeWrapperException(e);
}
}
private <T> T convert(String json, TypeReference<T> typeReference) {
try {
return objectMapper.readValue(json, typeReference);
} catch (JsonProcessingException e) {
throw new RuntimeWrapperException(e);
}
}
}
......@@ -41,6 +41,7 @@ keycloak:
client-id: frontend-cli
client:
type: FEIGN
certificate-password: [CLIENT_CERTIFICATE_PASSWORD]
authority:
url: [CLIENT_AUTHORITY_URL]
\ No newline at end of file
......@@ -6,13 +6,16 @@ import static org.mockito.Mockito.*;
import com.aruba.simpl.client.SimplClient.Builder;
import com.aruba.simpl.client.adapters.EphemeralProofAdapter;
import com.aruba.simpl.client.feign.FeignSimplClient;
import com.aruba.simpl.client.okhttp.OkHttpSimplClient;
import com.aruba.simpl.common.interceptors.TierOneTokenPropagatorInterceptor;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.security.KeyStore;
import java.security.cert.Certificate;
import java.util.Collections;
import java.util.List;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Answers;
import org.mockito.MockedStatic;
import org.mockito.Mockito;
import org.springframework.beans.factory.annotation.Autowired;
......@@ -25,17 +28,25 @@ import org.springframework.test.context.junit.jupiter.SpringExtension;
@MockBean(
classes = {
TierOneTokenPropagatorInterceptor.class,
MtlsClientProperties.class,
EphemeralProofAdapter.class,
})
public class MtlsClientFactoryTest {
class MtlsClientFactoryTest {
@Autowired
MtlsClientFactory mtlsClientFactory;
@MockBean
@MockBean(answer = Answers.RETURNS_DEEP_STUBS)
private FeignSimplClient simplClient;
@MockBean(answer = Answers.RETURNS_DEEP_STUBS)
private OkHttpSimplClient okHttpSimplClient;
@MockBean
private ObjectMapper objectMapper;
@MockBean
private MtlsClientProperties mtlsClientProperties;
@Test
void buildAuthorityClient_success() throws Exception {
var url = "url";
......@@ -47,6 +58,7 @@ public class MtlsClientFactoryTest {
var simplClientBuilder = mock(Builder.class);
var feignBuilder = mock(feign.Feign.Builder.class);
given(mtlsClientProperties.type()).willReturn(MtlsClientProperties.Type.FEIGN);
given(keyStore.aliases()).willReturn(Collections.enumeration(List.of("keystore_alias")));
given(keyStore.getCertificateChain("keystore_alias")).willReturn(certs);
given(simplClient.builder(any())).willReturn(simplClientBuilder);
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment