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

Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • simpl/simpl-open/development/iaa/users-roles
1 result
Show changes
Commits on Source (28)
Showing
with 1855 additions and 172 deletions
# Users & Roles
This document outlines the environment variables required to configure the application's connections to PostgreSQL, Redis, and other services. These variables are crucial for ensuring that the application connects properly to its backend services within a Kubernetes environment.
You can override this configuration changing the values.yaml
## Overview
The environment variables listed below are used to define the connection details and credentials for PostgreSQL, Redis, and other services. The values are templated using Helm, allowing for customization based on the namespace and other values provided in the Helm chart.
## Configuration Details
### DataSource Configuration
- `SPRING_DATASOURCE_URL`: The URL for the datasource connection.
- Value is derived from `db.url` specified in the Helm values.
- `SPRING_DATASOURCE_USERNAME`: The username for the datasource.
- Value is derived from `db.username` specified in the Helm values.
- `SPRING_DATASOURCE_PASSWORD`: The password for the datasource.
- Value is derived from `db.password` specified in the Helm values.
### Redis Configuration
- `SPRING_DATA_REDIS_HOST`: The host address for the Redis service.
- Value is derived from `redis.host` specified in the Helm values.
- `SPRING_DATA_REDIS_PORT`: The port on which Redis is running.
- Value is derived from `redis.port` specified in the Helm values.
- `SPRING_DATA_REDIS_USERNAME`: The username for connecting to Redis.
- Value is derived from `redis.username` specified in the Helm values.
- `SPRING_DATA_REDIS_PASSWORD`: The password for connecting to Redis.
- Value is derived from `redis.password` specified in the Helm values.
### Keycloak Configuration
- `KEYCLOAK_URL`: The URL for the Keycloak authentication service.
- This value is generated using the `microservices.backend.url` Helm template and points to the `/auth` endpoint of the Keycloak service.
- `KEYCLOAK_APP_REALM`: The realm to be used for the application within Keycloak.
- Value is derived from the `global.profile` specified in the Helm values.
- `KEYCLOAK_MASTER_USER`: The username to be used for the master realm in keycloak.
- Value is derived from the `keycloak.master.user` specified in the Helm values.
- `KEYCLOAK_MASTER_PASSWORD`: The password to be used for the master realm in keycloak.
- Value is derived from the `keycloak.master.password` specified in the Helm values.
### Client Authority Configuration
- `CLIENT_AUTHORITY_URL`: The URL for the client authority service.
- This value is generated using the `tls.gateway.url` Helm template.
- `CLIENT_CERTIFICATE_PASSWORD`: The password for the client certificate.
- Value is derived from `global.keystore.password` specified in the Helm values.
## Usage
To use this `ConfigMap`, include it in your Helm chart and provide the necessary values in the `values.yaml` file. The `ConfigMap` will be generated based on the namespace and other settings you define.
### Example `values-common.yaml`
```yaml
global:
profile: authority
hostBe: participant.be.aruba-simpl.cloud
hostTls: tls.authority.aruba-simpl.cloud
keystore:
password: "your-keystore-password"
```
### Example `values.yaml`
```yaml
db:
url: "jdbc:postgresql://postgresql.{{ .Release.Namespace }}.svc.cluster.local:5432/usersroles"
username: "usersroles"
password: "usersroles"
redis:
host: "redis-master.{{ .Release.Namespace }}.svc.cluster.local"
port: "6379"
username: "default"
password: "admin"
keycloak:
master:
user: "user"
password: "admin"
microservices:
identityProviderUrl: http://identity-provider.{{ .Release.Namespace }}.svc.cluster.local:8080
```
......@@ -18,8 +18,8 @@ data:
KEYCLOAK_MASTER_PASSWORD: "{{ .Values.keycloak.master.password }}"
CLIENT_AUTHORITY_URL: "{{- include "tls.gateway.url" . }}"
CLIENT_CERTIFICATE_PASSWORD: "{{ .Values.global.keystore.password }}"
{{- if eq .Values.global.profile "authority" }}
MICROSERVICE_IDENTITY_PROVIDER_URL: "{{ .Values.microservices.identityProviderUrl }}"
{{- end }}
\ No newline at end of file
{{- end }}
MICROSERVICE_AUTHENTICATION_PROVIDER_URL: "{{ .Values.microservices.authenticationProviderUrl }}"
......@@ -38,7 +38,7 @@ spec:
imagePullPolicy: {{ .Values.image.pullPolicy }}
ports:
- name: http
containerPort: {{ .Values.services.port }}
containerPort: {{ .Values.service.port }}
protocol: TCP
{{- with .Values.envFrom }}
envFrom:
......
{{- if .Values.ingress.enabled -}}
{{- $fullName := include "microservices.fullname" . -}}
{{- $svcPort := .Values.services.port -}}
{{- $svcPort := .Values.service.port -}}
{{- if and .Values.ingress.className (not (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion)) }}
{{- if not (hasKey .Values.ingress.annotations "kubernetes.io/ingress.class") }}
{{- $_ := set .Values.ingress.annotations "kubernetes.io/ingress.class" .Values.ingress.className}}
......
......@@ -125,4 +125,5 @@ keycloak:
password: "admin"
microservices:
identityProviderUrl: http://identity-provider.{{ .Release.Namespace }}.svc.cluster.local:8080
\ No newline at end of file
identityProviderUrl: http://identity-provider.{{ .Release.Namespace }}.svc.cluster.local:8080
authenticationProviderUrl: http://authentication-provider.{{ .Release.Namespace }}.svc.cluster.local:8080
\ No newline at end of file
This diff is collapsed.
......@@ -3,9 +3,11 @@ 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.common.exchanges.authenticationprovider.KeyPairExchange;
import com.aruba.simpl.usersroles.exchanges.PublicKeyExchange;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.JdkClientHttpRequestFactory;
import org.springframework.web.client.RestClient;
import org.springframework.web.client.support.RestClientAdapter;
import org.springframework.web.service.invoker.HttpServiceProxyFactory;
......@@ -13,15 +15,28 @@ import org.springframework.web.service.invoker.HttpServiceProxyFactory;
@Configuration
public class ClientConfig {
private final MicroserviceProperties properties;
public ClientConfig(final MicroserviceProperties properties) {
this.properties = properties;
}
@Bean
@Authority
public PublicKeyExchange publicKeyExchange(
MicroserviceProperties properties, RestClient.Builder restClientBuilder) {
public PublicKeyExchange publicKeyExchange(RestClient.Builder restClientBuilder) {
return buildExchange(properties.identityProvider().url(), restClientBuilder, PublicKeyExchange.class);
}
@Bean
public KeyPairExchange keyPairExchange(RestClient.Builder restClientBuilder) {
return buildExchange(properties.authenticationProvider().url(), restClientBuilder, KeyPairExchange.class);
}
private <E> E buildExchange(String baseurl, RestClient.Builder restClientBuilder, Class<E> clazz) {
var restClient = restClientBuilder.baseUrl(baseurl).build();
var restClient = restClientBuilder
.baseUrl(baseurl)
.requestFactory(new JdkClientHttpRequestFactory())
.build();
var adapter = RestClientAdapter.create(restClient);
var factory = HttpServiceProxyFactory.builderFor(adapter)
.customArgumentResolver(new PageableArgumentResolver())
......
......@@ -3,7 +3,9 @@ package com.aruba.simpl.usersroles.configurations;
import org.springframework.boot.context.properties.ConfigurationProperties;
@ConfigurationProperties(prefix = "microservice")
public record MicroserviceProperties(IdentityProvider identityProvider) {
public record MicroserviceProperties(IdentityProvider identityProvider, AuthenticationProvider authenticationProvider) {
public record IdentityProvider(String url) {}
public record AuthenticationProvider(String url) {}
}
package com.aruba.simpl.usersroles.configurations;
package com.aruba.simpl.usersroles.configurations.keycloak;
import org.keycloak.OAuth2Constants;
import org.keycloak.admin.client.Keycloak;
......
package com.aruba.simpl.usersroles.configurations;
package com.aruba.simpl.usersroles.configurations.keycloak;
import org.springframework.boot.context.properties.ConfigurationProperties;
......
package com.aruba.simpl.usersroles.configurations;
package com.aruba.simpl.usersroles.configurations.mtls;
import com.aruba.simpl.common.exchanges.mtls.AuthorityExchange;
import com.aruba.simpl.common.exchanges.mtls.ParticipantExchange;
import com.aruba.simpl.common.utils.CredentialUtil;
import com.aruba.simpl.usersroles.services.CredentialService;
import com.aruba.simpl.usersroles.services.KeyPairService;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.security.KeyStore;
......@@ -19,26 +20,28 @@ public class MtlsClientBuilder {
private final MtlsClientFactory mtlsClientFactory;
private final CredentialService credentialService;
private final MtlsClientProperties mtlsClientProperties;
private final KeyPairService keyPairService;
public MtlsClientBuilder(
MtlsClientFactory mtlsClientFactory,
CredentialService credentialService,
MtlsClientProperties mtlsClientProperties) {
MtlsClientProperties mtlsClientProperties,
KeyPairService keyPairService) {
this.mtlsClientFactory = mtlsClientFactory;
this.credentialService = credentialService;
this.mtlsClientProperties = mtlsClientProperties;
this.keyPairService = keyPairService;
}
public AuthorityExchange buildAuthorityClient()
throws IOException, CertificateException, KeyStoreException, NoSuchAlgorithmException {
return mtlsClientFactory.buildAuthorityClient(
mtlsClientProperties.authority().url(), readKeyStore(), mtlsClientProperties.certificatePassword());
mtlsClientProperties.authority().url(), readKeyStore());
}
public ParticipantExchange buildParticipantClient(String url)
throws CertificateException, KeyStoreException, IOException, NoSuchAlgorithmException {
return mtlsClientFactory.buildParticipantClient(
url, readKeyStore(), mtlsClientProperties.certificatePassword());
return mtlsClientFactory.buildParticipantClient(url, readKeyStore());
}
private KeyStore readKeyStore() {
......@@ -46,8 +49,8 @@ public class MtlsClientBuilder {
log.error("No credential found");
throw new IllegalStateException("No credential found");
}
return CredentialUtil.loadCredential(
new ByteArrayInputStream(credentialService.getCredential()),
mtlsClientProperties.certificatePassword());
new ByteArrayInputStream(credentialService.getCredential()), keyPairService.getPrivateKey());
}
}
package com.aruba.simpl.usersroles.configurations;
package com.aruba.simpl.usersroles.configurations.mtls;
import com.aruba.simpl.client.SimplClient;
import com.aruba.simpl.client.adapters.EphemeralProofAdapter;
......@@ -8,6 +8,7 @@ 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.aruba.simpl.common.utils.CredentialUtil;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.IOException;
import java.security.KeyStore;
......@@ -43,44 +44,32 @@ public class MtlsClientFactory {
this.objectMapper = objectMapper;
}
public AuthorityExchange buildAuthorityClient(String url, KeyStore keyStore, String password)
public AuthorityExchange buildAuthorityClient(String url, KeyStore keyStore)
throws CertificateException, KeyStoreException, IOException, NoSuchAlgorithmException {
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 FEIGN -> buildClient(feignSimplClient.builder(), keyStore).target(AuthorityExchange.class, url);
case OKHTTP -> {
var client = buildClient(okHttpSimplClient.builder(), keyStore, password);
var client = buildClient(okHttpSimplClient.builder(), keyStore);
yield new OkHttpAuthorityExchange(
client.build(), clientProperties.authority().url(), objectMapper);
}
};
}
public ParticipantExchange buildParticipantClient(String url, KeyStore keyStore, String password)
public ParticipantExchange buildParticipantClient(String url, KeyStore keyStore)
throws CertificateException, KeyStoreException, IOException, NoSuchAlgorithmException {
return buildAuthorityClient(url, keyStore, password);
return buildAuthorityClient(url, keyStore);
}
private <T> T buildClient(SimplClient.Builder<T> clientBuilder, KeyStore keyStore, String password)
private <T> T buildClient(SimplClient.Builder<T> clientBuilder, KeyStore keyStore)
throws CertificateException, KeyStoreException, IOException, NoSuchAlgorithmException {
var trustStore = buildTrustStore(keyStore);
var trustStore = CredentialUtil.buildTrustStore(keyStore);
return clientBuilder
.setSslInfoSupplier(() -> new SslInfo(keyStore, password, trustStore))
.setSslInfoSupplier(() -> new SslInfo(keyStore, null, trustStore))
.setAuthorizationHeaderSupplier(tokenPropagator)
.setEphemeralProofAdapter(ephemeralProofAdapter)
.setAuthorityUrlSupplier(() -> clientProperties.authority().url())
.build();
}
private static KeyStore buildTrustStore(KeyStore keyStore)
throws KeyStoreException, CertificateException, IOException, NoSuchAlgorithmException {
var alias = keyStore.aliases().nextElement();
var chain = keyStore.getCertificateChain(alias);
var rootCa = chain[chain.length - 1];
var trustStore = KeyStore.getInstance("PKCS12");
trustStore.load(null, null);
trustStore.setCertificateEntry("rootCA", rootCa);
return trustStore;
}
}
package com.aruba.simpl.usersroles.configurations;
package com.aruba.simpl.usersroles.configurations.mtls;
import org.springframework.boot.context.properties.ConfigurationProperties;
@ConfigurationProperties(prefix = "client")
public record MtlsClientProperties(AuthorityProperties authority, String certificatePassword, Type type) {
public record MtlsClientProperties(AuthorityProperties authority, Type type) {
public record AuthorityProperties(String url) {}
enum Type {
public enum Type {
FEIGN,
OKHTTP
}
......
package com.aruba.simpl.usersroles.configurations;
package com.aruba.simpl.usersroles.configurations.mtls;
import com.aruba.simpl.client.feign.DaggerFeignSimplClientFactory;
import com.aruba.simpl.client.feign.FeignSimplClient;
......
package com.aruba.simpl.usersroles.configurations;
package com.aruba.simpl.usersroles.configurations.mtls;
import com.aruba.simpl.common.exchanges.mtls.AuthorityExchange;
import com.aruba.simpl.usersroles.model.event.InvalidateMtls;
......
package com.aruba.simpl.usersroles.configurations;
package com.aruba.simpl.usersroles.configurations.mtls;
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.ParticipantDTO;
import com.aruba.simpl.common.model.dto.ParticipantWithIdentityAttributesDTO;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
......@@ -39,13 +40,14 @@ public class OkHttpAuthorityExchange implements AuthorityExchange {
}
@Override
public void sendTierOnePublicKey(String tierOnePublicKey) {
public ParticipantDTO 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()) {
return objectMapper.readValue(response.body().byteStream(), ParticipantDTO.class);
} catch (IOException e) {
throw new RuntimeWrapperException(e);
}
......@@ -64,7 +66,7 @@ public class OkHttpAuthorityExchange implements AuthorityExchange {
}
@Override
public List<IdentityAttributeDTO> getIdentityAttributesByCertificateIdInUri(String certificateId) {
public List<IdentityAttributeDTO> getIdentityAttributesByCredentialIdInUri(String certificateId) {
var json = doGet("/sap-api/mtls/identity-attribute/" + certificateId);
return convert(json, new TypeReference<List<IdentityAttributeDTO>>() {});
}
......
......@@ -89,9 +89,9 @@ public class AgentController {
@ApiResponse(responseCode = "401", description = "Access denied"),
@ApiResponse(responseCode = "403", description = "Forbidden: User does not have the required role")
})
@GetMapping("identity-attributes/{certificateId}")
public List<IdentityAttributeDTO> getParticipantIdentityAttributes(@PathVariable String certificateId) {
return agentService.getParticipantIdentityAttributes(certificateId);
@GetMapping("identity-attributes/{credentialId}")
public List<IdentityAttributeDTO> getParticipantIdentityAttributes(@PathVariable String credentialId) {
return agentService.getParticipantIdentityAttributes(credentialId);
}
@Operation(
......
......@@ -8,7 +8,6 @@ import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import java.util.UUID;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.bind.annotation.GetMapping;
......@@ -28,17 +27,13 @@ public class MTLSController {
@Operation(
summary = "Ping the participant",
description = "Performs a ping operation to check the participant's status using its UUID",
description = "Performs a ping operation to check the participant's status using its credential id",
parameters = {
@Parameter(
name = SimplHeaders.PARTICIPANT_ID,
description = "The UUID of the participant",
name = SimplHeaders.CREDENTIAL_ID,
description = "The Public Key Hash of the participant",
required = true,
schema =
@Schema(
type = "string",
format = "uuid",
example = "123e4567-e89b-12d3-a456-426614174000"))
schema = @Schema(type = "string"))
},
responses = {
@ApiResponse(
......@@ -51,8 +46,8 @@ public class MTLSController {
@ApiResponse(responseCode = "404", description = "Participant not found")
})
@GetMapping("ping")
public ParticipantWithIdentityAttributesDTO ping(@RequestHeader(SimplHeaders.PARTICIPANT_ID) UUID participantId) {
return mtlsService.ping(participantId);
public ParticipantWithIdentityAttributesDTO ping(@RequestHeader(SimplHeaders.CREDENTIAL_ID) String credentialId) {
return mtlsService.ping(credentialId);
}
@Operation(
......@@ -60,14 +55,10 @@ public class MTLSController {
description = "Stores the ephemeral proof for a participant identified by their UUID",
parameters = {
@Parameter(
name = SimplHeaders.PARTICIPANT_ID,
description = "The UUID of the participant",
name = SimplHeaders.CREDENTIAL_ID,
description = "The Public Key Hash of the participant",
required = true,
schema =
@Schema(
type = "string",
format = "uuid",
example = "123e4567-e89b-12d3-a456-426614174000"))
schema = @Schema(type = "string"))
},
requestBody =
@io.swagger.v3.oas.annotations.parameters.RequestBody(
......@@ -81,7 +72,7 @@ public class MTLSController {
})
@PostMapping(value = "ephemeral-proof", consumes = MediaType.TEXT_PLAIN_VALUE)
public void storeCallerEphemeralProof(
@RequestHeader(SimplHeaders.PARTICIPANT_ID) UUID participantId, @RequestBody String ephemeralProof) {
mtlsService.insertEphemeralProof(participantId, ephemeralProof);
@RequestHeader(SimplHeaders.CREDENTIAL_ID) String credentialId, @RequestBody String ephemeralProof) {
mtlsService.insertEphemeralProof(credentialId, ephemeralProof);
}
}
......@@ -119,7 +119,7 @@ public class RoleController {
return roleService.update(roleDTO);
}
@PostMapping("/{id}/identity-attributes")
@PutMapping("/{id}/identity-attributes")
@Operation(
summary = "Assign identity attributes to a role",
description = "Assigns a list of identity attribute IDs to a specified role",
......
package com.aruba.simpl.usersroles.controllers;
import com.aruba.simpl.common.model.dto.IdentityAttributeDTO;
import com.aruba.simpl.usersroles.model.dto.TierOneSessionDTO;
import com.aruba.simpl.usersroles.services.KeycloakUserService;
import com.aruba.simpl.usersroles.services.SessionService;
import io.swagger.v3.oas.annotations.Operation;
......@@ -10,8 +11,6 @@ import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import java.util.List;
import java.util.UUID;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.*;
......@@ -32,14 +31,10 @@ public class SessionController {
description = "Fetches the identity attributes associated with the specified participant ID",
parameters = {
@Parameter(
name = "participantId",
description = "The UUID of the participant",
name = "credentialId",
description = "The Public Key Hash of the participant",
required = true,
schema =
@Schema(
type = "string",
format = "uuid",
example = "123e4567-e89b-12d3-a456-426614174000"))
schema = @Schema(type = "string"))
},
responses = {
@ApiResponse(
......@@ -54,9 +49,9 @@ public class SessionController {
@Schema(implementation = IdentityAttributeDTO.class)))),
@ApiResponse(responseCode = "404", description = "Ephemeral proof not found")
})
@GetMapping("{participantId}")
public List<IdentityAttributeDTO> getIdentityAttributesOfParticipant(@PathVariable UUID participantId) {
return sessionService.getIdentityAttributesOfParticipant(participantId);
@GetMapping("{credentialId}")
public List<IdentityAttributeDTO> getIdentityAttributesOfParticipant(@PathVariable String credentialId) {
return sessionService.getIdentityAttributesOfParticipant(credentialId);
}
@Operation(
......@@ -67,9 +62,9 @@ public class SessionController {
@ApiResponse(responseCode = "422", description = "Invalid Tier 1 session")
})
@ResponseStatus(HttpStatus.NO_CONTENT)
@GetMapping("credential")
public void validateTierOneSession(@RequestHeader HttpHeaders headers) {
sessionService.validateTierOneSession(headers);
@PostMapping("credential")
public void validateTierOneSession(@RequestBody TierOneSessionDTO session) {
sessionService.validateTierOneSession(session);
}
@Operation(
......