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

Skip to content
Snippets Groups Projects
Commit 64cb9c0f authored by Marco Amoia's avatar Marco Amoia
Browse files

Merge branch 'feature/cherrypick' into 'develop'

Authority can send public key with internal cluster call

See merge request !112
parents c50d1693 06591778
No related branches found
No related tags found
4 merge requests!130Release,!129Release,!128fix unit tests - add property,!112Authority can send public key with internal cluster call
Pipeline #222672 passed with warnings
Showing with 151 additions and 26 deletions
......@@ -80,4 +80,7 @@ keycloak:
master:
user: "user"
password: "admin"
microservices:
identityProviderUrl: http://identity-provider.{{ .Release.Namespace }}.svc.cluster.local:8080
```
......@@ -18,4 +18,8 @@ data:
KEYCLOAK_MASTER_PASSWORD: "{{ .Values.keycloak.master.password }}"
CLIENT_AUTHORITY_URL: "{{- include "tls.gateway.url" . }}"
CLIENT_CERTIFICATE_PASSWORD: "{{ .Values.global.keystore.password }}"
\ No newline at end of file
CLIENT_CERTIFICATE_PASSWORD: "{{ .Values.global.keystore.password }}"
{{- if eq .Values.global.profile "authority" }}
MICROSERVICES_IDENTITY_PROVIDER_URL: "{{ .Values.microservices.identityProviderUrl }}"
{{- end }}
\ No newline at end of file
......@@ -122,4 +122,7 @@ redis:
keycloak:
master:
user: "user"
password: "admin"
\ No newline at end of file
password: "admin"
microservices:
identityProviderUrl: http://identity-provider.{{ .Release.Namespace }}.svc.cluster.local:8080
\ No newline at end of file
package com.aruba.simpl.usersroles.configurations;
import com.aruba.simpl.common.annotations.Authority;
import com.aruba.simpl.common.argumentresolvers.PageableArgumentResolver;
import com.aruba.simpl.common.argumentresolvers.QueryParamsArgumentResolver;
import com.aruba.simpl.usersroles.exchanges.PublicKeyExchange;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestClient;
import org.springframework.web.client.support.RestClientAdapter;
import org.springframework.web.service.invoker.HttpServiceProxyFactory;
@Configuration
public class ClientConfig {
@Bean
@Authority
public PublicKeyExchange publicKeyExchange(
MicroserviceProperties properties, RestClient.Builder restClientBuilder) {
return buildExchange(properties.identityProvider().url(), restClientBuilder, PublicKeyExchange.class);
}
private <E> E buildExchange(String baseurl, RestClient.Builder restClientBuilder, Class<E> clazz) {
var restClient = restClientBuilder.baseUrl(baseurl).build();
var adapter = RestClientAdapter.create(restClient);
var factory = HttpServiceProxyFactory.builderFor(adapter)
.customArgumentResolver(new PageableArgumentResolver())
.customArgumentResolver(new QueryParamsArgumentResolver())
.build();
return factory.createClient(clazz);
}
}
package com.aruba.simpl.usersroles.configurations;
import org.springframework.boot.context.properties.ConfigurationProperties;
@ConfigurationProperties(prefix = "microservices")
public record MicroserviceProperties(IdentityProvider identityProvider) {
public record IdentityProvider(String url) {}
}
package com.aruba.simpl.usersroles.exchanges;
import com.aruba.simpl.common.model.constants.SimplHeaders;
import java.util.UUID;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.service.annotation.HttpExchange;
import org.springframework.web.service.annotation.PatchExchange;
@HttpExchange
public interface PublicKeyExchange {
@PatchExchange(value = "/mtls/public-key", contentType = MediaType.TEXT_PLAIN_VALUE)
void sendTierOnePublicKey(
@RequestHeader(SimplHeaders.PARTICIPANT_ID) UUID participantId, @RequestBody String tierOnePublicKey);
}
package com.aruba.simpl.usersroles.services.impl;
import com.aruba.simpl.common.security.JwtService;
import com.aruba.simpl.usersroles.configurations.MtlsClientProperties;
import com.aruba.simpl.usersroles.model.event.InvalidateMtls;
import com.aruba.simpl.usersroles.services.KeycloakService;
import org.springframework.context.event.EventListener;
public abstract class AbstractCredentialUpdateEventListener {
private final KeycloakService keycloakService;
private final JwtService jwtService;
protected final MtlsClientProperties mtlsClientProperties;
protected AbstractCredentialUpdateEventListener(
KeycloakService keycloakService, JwtService jwtService, MtlsClientProperties mtlsClientProperties) {
this.keycloakService = keycloakService;
this.jwtService = jwtService;
this.mtlsClientProperties = mtlsClientProperties;
}
@EventListener(InvalidateMtls.class)
public void handleInvalidateCredential(InvalidateMtls event) {
if (event.getNewCredential() != null) {
sendKeycloakPublicKeyToAuthority(event.getNewCredential());
}
}
protected abstract void sendKeycloakPublicKeyToAuthority(byte[] content);
protected String getKeycloakPublicKey() {
var kid = jwtService.getKid();
return keycloakService.getPublicKey(kid);
}
}
package com.aruba.simpl.usersroles.services.impl;
import com.aruba.simpl.common.annotations.Authority;
import com.aruba.simpl.common.security.JwtService;
import com.aruba.simpl.common.utils.CredentialUtil;
import com.aruba.simpl.usersroles.configurations.MtlsClientProperties;
import com.aruba.simpl.usersroles.exchanges.PublicKeyExchange;
import com.aruba.simpl.usersroles.services.KeycloakService;
import java.io.ByteArrayInputStream;
import java.util.UUID;
import org.springframework.stereotype.Component;
@Component
@Authority
public class AuthorityCredentialUpdateEventListener extends AbstractCredentialUpdateEventListener {
private final PublicKeyExchange publicKeyExchange;
public AuthorityCredentialUpdateEventListener(
PublicKeyExchange publicKeyExchange,
KeycloakService keycloakService,
JwtService jwtService,
MtlsClientProperties mtlsClientProperties) {
super(keycloakService, jwtService, mtlsClientProperties);
this.publicKeyExchange = publicKeyExchange;
}
@Override
protected void sendKeycloakPublicKeyToAuthority(byte[] content) {
var keyStore = CredentialUtil.loadCredential(
new ByteArrayInputStream(content), mtlsClientProperties.certificatePassword());
var certificate = CredentialUtil.extractCertificateFromKeystore(keyStore);
var participantId = UUID.fromString(CredentialUtil.getCommonNameFromSubject(certificate));
publicKeyExchange.sendTierOnePublicKey(participantId, getKeycloakPublicKey());
}
}
package com.aruba.simpl.usersroles.services.impl;
import com.aruba.simpl.common.annotations.Participant;
import com.aruba.simpl.common.security.JwtService;
import com.aruba.simpl.common.utils.CredentialUtil;
import com.aruba.simpl.usersroles.configurations.MtlsClientFactory;
import com.aruba.simpl.usersroles.configurations.MtlsClientProperties;
import com.aruba.simpl.usersroles.model.event.InvalidateMtls;
import com.aruba.simpl.usersroles.services.KeycloakService;
import java.io.ByteArrayInputStream;
import lombok.SneakyThrows;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;
@Component
public class CredentialUpdateEventListener {
@Participant
public class ParticipantCredentialUpdateEventListener extends AbstractCredentialUpdateEventListener {
private final MtlsClientProperties mtlsClientProperties;
private final MtlsClientFactory mtlsClientFactory;
private final KeycloakService keycloakService;
private final JwtService jwtService;
public CredentialUpdateEventListener(
public ParticipantCredentialUpdateEventListener(
MtlsClientProperties mtlsClientProperties,
MtlsClientFactory mtlsClientFactory,
KeycloakService keycloakService,
JwtService jwtService) {
this.mtlsClientProperties = mtlsClientProperties;
super(keycloakService, jwtService, mtlsClientProperties);
this.mtlsClientFactory = mtlsClientFactory;
this.keycloakService = keycloakService;
this.jwtService = jwtService;
}
@EventListener(InvalidateMtls.class)
public void handleInvalidateCredential(InvalidateMtls event) {
if (event.getNewCredential() != null) {
sendKeycloakPublicKeyToAuthority(event.getNewCredential());
}
}
@SneakyThrows
private void sendKeycloakPublicKeyToAuthority(byte[] content) {
@Override
protected void sendKeycloakPublicKeyToAuthority(byte[] content) {
var password = mtlsClientProperties.certificatePassword();
var keyStore = CredentialUtil.loadCredential(new ByteArrayInputStream(content), password);
var mtlsClient = mtlsClientFactory.buildAuthorityClient(
mtlsClientProperties.authority().url(), keyStore, password);
mtlsClient.sendTierOnePublicKey(getKeycloakPublicKey());
}
private String getKeycloakPublicKey() {
var kid = jwtService.getKid();
return keycloakService.getPublicKey(kid);
}
}
package com.aruba.simpl.usersroles;
import com.aruba.simpl.common.exchanges.mtls.AuthorityExchange;
import com.aruba.simpl.usersroles.configurations.MicroserviceProperties;
import com.aruba.simpl.usersroles.configurations.RoleInitializer;
import com.aruba.simpl.usersroles.repositories.*;
import java.lang.annotation.ElementType;
......@@ -8,6 +9,7 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.keycloak.admin.client.Keycloak;
import org.mockito.Answers;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.autoconfigure.ssl.SslAutoConfiguration;
......@@ -29,7 +31,8 @@ import org.springframework.boot.test.mock.mockito.MockBeans;
@MockBean(IdentityAttributeRolesRepository.class),
@MockBean(RoleRepository.class),
@MockBean(AuthorityExchange.class),
@MockBean(RoleInitializer.class)
@MockBean(RoleInitializer.class),
@MockBean(value = MicroserviceProperties.class, answer = Answers.RETURNS_DEEP_STUBS)
})
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
......
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