Skip to content

Commit

Permalink
RIPE NCC has merged d13d1d66b
Browse files Browse the repository at this point in the history
* use rpki-commons 1.37 [b509ba55d]
* Fix/refactor tests. [b41f163a7]
* Fix item search [12d3eda96]
* Cleanup imports [74c8184cf]
* Make GDPR end-point unauthorized [31af300e6]
* Revert jdk-17 changes as HSM library fails on jdk-17 [c7e2bbb12]
* Add checks for partOfRegistry [c6dafd599]
* Fix broken test [fe1de272f]
* Address review items [4f4857a70]
* chore(deps): update dependency net.jqwik:jqwik to v1.8.3 [680c6ccbe]
* chore(deps): update dependency io.sentry:sentry-bom to v6.34.0 [fc5f0581f]
* Add more integration tests [998f4501f]
* chore(deps): update dependency io.freefair.lombok:io.freefair.lombok.gradle.plugin to v8.6 [79969c3b3]
* Add integration tests, fixes [ad36a87eb]
* Use Lombok [a3b447ca4]
* Make the test a but fancier [d378f8c83]
* Code smell [707d8810a]
* Naming [40c0526f9]
* Change API to resemble existing CR API [6941b5fb1]
* Add /api/gdpr to return some emails we store [9fcef4181]
* Fix parallel GC option for java-17 [3079d441e]
* Update default `JAVA_HOME` to pick java 17 [c9f4415b4]
* Fix `toList` derived types [4149a7177]
* chore(deps): update dependency commons-io:commons-io to v2.15.1 [580b1831b]
* chore(deps): update dependency org.eclipse.jgit:org.eclipse.jgit to v5.13.3.202401111512-r [054280668]
* Use latest gradle version [c2bc852f7]
* Newest gradle version [e6b2436d7]
* Low-handing Java 17 changes [55ab0558a]
* Toolchain is needed once [33ae3a25f]
* Switch to Java 17 [93ff32071]
* chore(deps): update dependency commons-codec:commons-codec to v1.16.1 [69f1bba79]
* Ensure tag from request is copied to response [341eb31a6]
* Add test cases where publisher request contains a tag [9f0729640]
  • Loading branch information
RPKI Team at RIPE NCC committed Mar 4, 2024
1 parent ac2259e commit 50451ac
Show file tree
Hide file tree
Showing 24 changed files with 431 additions and 77 deletions.
8 changes: 4 additions & 4 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ dependencies {
implementation "org.thymeleaf:thymeleaf:3.1.1.RELEASE"
implementation "org.thymeleaf:thymeleaf-spring5:3.1.1.RELEASE"

implementation platform('io.sentry:sentry-bom:6.28.0')
implementation platform('io.sentry:sentry-bom:6.34.0')
implementation 'io.sentry:sentry-spring-boot-starter'
implementation 'io.sentry:sentry-logback'

Expand All @@ -58,8 +58,8 @@ dependencies {

implementation 'com.google.code.gson:gson:2.10.1'
implementation 'com.jamesmurty.utils:java-xmlbuilder:1.3'
implementation 'commons-codec:commons-codec:1.16.0'
implementation 'commons-io:commons-io:2.14.0'
implementation 'commons-codec:commons-codec:1.16.1'
implementation 'commons-io:commons-io:2.15.1'
implementation 'ch.qos.logback.contrib:logback-json-classic:0.1.5'
implementation 'ch.qos.logback.contrib:logback-jackson:0.1.5'
implementation 'net.logstash.logback:logstash-logback-encoder:7.3'
Expand All @@ -74,7 +74,7 @@ dependencies {
}

testImplementation 'com.github.tomakehurst:wiremock-jre8:2.35.0'
testImplementation 'net.jqwik:jqwik:1.7.4'
testImplementation 'net.jqwik:jqwik:1.8.3'
testImplementation "net.ripe.rpki:rpki-commons:$rpki_commons_version:tests"
testImplementation 'org.assertj:assertj-core'

Expand Down
4 changes: 2 additions & 2 deletions buildSrc/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@ repositories {
}

dependencies {
implementation 'io.freefair.lombok:io.freefair.lombok.gradle.plugin:8.4'
implementation 'io.freefair.lombok:io.freefair.lombok.gradle.plugin:8.6'
implementation('com.gorylenko.gradle-git-properties:com.gorylenko.gradle-git-properties.gradle.plugin:2.4.1') {
exclude group: 'org.eclipse.jgit', module: 'org.eclipse.jgit'
}
implementation 'org.eclipse.jgit:org.eclipse.jgit:5.13.2.202306221912-r'
implementation 'org.eclipse.jgit:org.eclipse.jgit:5.13.3.202401111512-r'
implementation 'org.sonarqube:org.sonarqube.gradle.plugin:4.2.1.3168'
}
4 changes: 2 additions & 2 deletions dependencies.gradle
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
ext {
rpki_commons_version = '1.36'
spring_boot_version = '2.7.16'
rpki_commons_version = '1.37'
spring_boot_version = '2.7.18'
}
2 changes: 1 addition & 1 deletion src/main/dist/rpki-ripe-ncc.sh
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ esac
JAVA_OPTS=(
"-DAPPLICATION_ENVIRONMENT=$APPLICATION_ENVIRONMENT"
"-Dinstance.name=$(hostname)"
"-XX:+UseParallelOldGC"
"-XX:+UseParallelGC"
"-Xlog:gc:$LOG_DIR/gc.log:utctime"
"-XX:+HeapDumpOnOutOfMemoryError" "-XX:HeapDumpPath=$LOG_DIR" "-XX:+ExitOnOutOfMemoryError"
"${ENV_OPTS[@]}"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import javax.persistence.Query;
import javax.security.auth.x500.X500Principal;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.stream.Collectors;

Expand Down Expand Up @@ -127,4 +128,17 @@ public void deleteCommandsForCa(long caId) {
query.setParameter("id", caId);
query.executeUpdate();
}

@Override
@SuppressWarnings("unchecked")
public Map<String, Long> findMentionsInSummary(String item) {
Query query = entityManager.createQuery(
"SELECT ca FROM CommandAudit ca " +
"WHERE commandSummary LIKE :itemSpaces " +
"OR commandSummary LIKE :itemParens");
query.setParameter("itemSpaces", "% " + item + " %");
query.setParameter("itemParens", "%'" + item + "'%");
List<CommandAudit> commands = query.getResultList();
return commands.stream().collect(Collectors.toMap(CommandAudit::getCommandType, c -> 1L, Long::sum));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import net.ripe.rpki.ripencc.provisioning.ProvisioningAuditLogService;
import net.ripe.rpki.server.api.dto.*;
import net.ripe.rpki.server.api.services.read.CertificateAuthorityViewService;
import org.apache.commons.lang3.tuple.Pair;
import org.joda.time.Instant;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
Expand Down Expand Up @@ -148,15 +149,15 @@ public Collection<CaStatEvent> getCaStatEvents() {
}

@Override
public Map<UUID, RepositoryResponse> findNonHostedPublisherRepositories(X500Principal caName) {
public Map<UUID, Pair<PublisherRequest, RepositoryResponse>> findNonHostedPublisherRepositories(X500Principal caName) {
NonHostedCertificateAuthority ca = certificateAuthorityRepository.findByTypeAndName(NonHostedCertificateAuthority.class, caName);
if (ca == null) {
throw new EntityNotFoundException("non-hosted CA '" + caName + "' not found");
}

return ca.getPublisherRepositories().values().stream().collect(Collectors.toMap(
NonHostedPublisherRepository::getPublisherHandle,
NonHostedPublisherRepository::getRepositoryResponse
repository -> Pair.of(repository.getPublisherRequest(), repository.getRepositoryResponse())
));
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,7 @@ private X509Crl createProvisioningIdentityCrl(ProvisioningIdentityCertificate id
X509CrlBuilder crlBuilder = new X509CrlBuilder();

crlBuilder.withIssuerDN(identityCertificate.getSubject());
crlBuilder.withThisUpdateTime(identityCertificate.getValidityPeriod().getNotValidBefore());
crlBuilder.withNextUpdateTime(identityCertificate.getValidityPeriod().getNotValidAfter());
crlBuilder.withValidityPeriod(identityCertificate.getValidityPeriod());
crlBuilder.withNumber(BigInteger.ONE);

crlBuilder.withAuthorityKeyIdentifier(persistedKeyPair.getPublicKey());
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package net.ripe.rpki.domain.alerts;

import com.google.common.collect.Sets;
import lombok.Getter;
import net.ripe.rpki.commons.validation.roa.AnnouncedRoute;
import net.ripe.rpki.commons.validation.roa.RouteValidityState;
import net.ripe.rpki.domain.CertificateAuthority;
Expand Down Expand Up @@ -44,13 +45,15 @@ public class RoaAlertConfiguration extends EntitySupport {
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "roa_alert_conf_seq")
private Long id;

@Getter
@OneToOne(optional=false, fetch=FetchType.EAGER)
@JoinColumn(name = "certificateauthority_id")
private CertificateAuthority certificateAuthority;

@Basic(optional=false)
private String email; // May be empty for no subscription.

@Getter
@Basic(optional=false)
@Column(name = "frequency")
@Enumerated(EnumType.STRING)
Expand Down Expand Up @@ -85,14 +88,6 @@ public Object getId() {
return id;
}

public RoaAlertFrequency getFrequency() {
return frequency;
}

public CertificateAuthority getCertificateAuthority() {
return certificateAuthority;
}

public void clearSubscription() {
email = "";
routeValidityStates = "";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,6 @@ public interface RoaAlertConfigurationRepository {
RoaAlertConfiguration findByCertificateAuthorityIdOrNull(long caId);

void remove(RoaAlertConfiguration entity);

List<RoaAlertConfiguration> findByEmail(String email);
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import net.ripe.rpki.server.api.dto.CommandAuditData;

import java.util.List;
import java.util.Map;

public interface CommandAuditService {

Expand All @@ -25,4 +26,6 @@ public interface CommandAuditService {
* Used when we delete a CA completely.
*/
void deleteCommandsForCa(long caId);

Map<String, Long> findMentionsInSummary(String email);
}
3 changes: 1 addition & 2 deletions src/main/java/net/ripe/rpki/domain/crl/CrlEntity.java
Original file line number Diff line number Diff line change
Expand Up @@ -130,8 +130,7 @@ public void update(ValidityPeriod validityPeriod, ResourceCertificateRepository
X509CrlBuilder builder = newCrlBuilderWithEntries(revokedCertificates);
builder.withAuthorityKeyIdentifier(keyPair.getPublicKey());
builder.withIssuerDN(keyPair.getCurrentIncomingCertificate().getSubject());
builder.withThisUpdateTime(validityPeriod.getNotValidBefore());
builder.withNextUpdateTime(validityPeriod.getNotValidAfter());
builder.withValidityPeriod(validityPeriod);
builder.withNumber(BigInteger.valueOf(getAndIncrementNextNumber()));
builder.withSignatureProvider(keyPair.getSignatureProvider());

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -174,8 +174,7 @@ private ManifestCms buildManifestCms(Collection<PublishedObject> manifestEntries
}
builder.withCertificate(certificate.getCertificate());
builder.withManifestNumber(BigInteger.valueOf(nextNumber));
builder.withThisUpdateTime(certificate.getNotValidBefore());
builder.withNextUpdateTime(certificate.getNotValidAfter());
builder.withValidityPeriod(certificate.getValidityPeriod());
builder.withSignatureProvider(signatureProvider);
return builder.build(eeKeyPair.getPrivate());
}
Expand Down
118 changes: 118 additions & 0 deletions src/main/java/net/ripe/rpki/rest/service/GdprService.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
package net.ripe.rpki.rest.service;

import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.*;
import lombok.extern.slf4j.Slf4j;
import net.ripe.rpki.domain.alerts.RoaAlertConfigurationRepository;
import net.ripe.rpki.domain.audit.CommandAuditService;
import net.ripe.rpki.server.api.dto.RoaAlertSubscriptionData;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.ws.rs.core.MediaType;
import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean;

@Slf4j
@Scope("prototype")
@RestController
@RequestMapping(path = "/api/public/gdpr", produces = MediaType.APPLICATION_JSON)
@Tag(name = "/api/public/gdpr", description = "Return personal data according to GDPR")
public class GdprService {
private final CommandAuditService commandAuditService;
private final RoaAlertConfigurationRepository roaAlertConfigurationRepository;

@Autowired
public GdprService(CommandAuditService commandAuditService,
RoaAlertConfigurationRepository roaAlertConfigurationRepository) {
this.commandAuditService = commandAuditService;
this.roaAlertConfigurationRepository = roaAlertConfigurationRepository;
}

@PostMapping("/investigate")
@Operation(summary = "Search if one or more email addresses are present in RPKI core. Endpoint called by Controlroom.")
public GdprInvestigationResult investigate(@RequestBody GdprRequest req) {
var subscriptionEmails = new HashMap<String, List<String>>();
var reports = new ArrayList<GdprReport>();
var partOfRegistry = new AtomicBoolean(false);

req.emails.stream().distinct().forEach(email -> {
roaAlertConfigurationRepository.findByEmail(email).forEach(rac -> {
RoaAlertSubscriptionData subscriptionOrNull = rac.getSubscriptionOrNull();
if (subscriptionOrNull != null) {
subscriptionOrNull.getEmails().forEach(email1 ->
subscriptionEmails.compute(email1, (e, caNames) -> {
if (caNames == null) {
caNames = new ArrayList<>(1);
}
caNames.add(rac.getCertificateAuthority().getName().getName());
return caNames;
}));
}
});

var caNames = subscriptionEmails.get(email);
if (caNames != null) {
var cas = String.join(", ", caNames);
reports.add(new GdprReport("Subscription",
"Subscribed '" + email + "' for alerts for the CA(s) " + cas, (long) caNames.size()));
}

Map<String, Long> mentionsInSummary = commandAuditService.findMentionsInSummary(email);
if (!mentionsInSummary.isEmpty()) {
partOfRegistry.set(true);
}
mentionsInSummary.forEach((commandType, mentionCount) ->
reports.add(new GdprReport(
commandType,
"'" + email + "' found in the history of commands of type " + commandType,
mentionCount)));
});

if (req.id != null) {
Map<String, Long> mentionsInSummary = commandAuditService.findMentionsInSummary(req.id.toString());
if (!mentionsInSummary.isEmpty()) {
partOfRegistry.set(true);
}
mentionsInSummary.forEach((commandType, mentionCount) ->
reports.add(new GdprReport(
commandType,
"'" + req.id + "' found in the history of commands of type " + commandType,
mentionCount)));
}

return new GdprInvestigationResult(
reports,
reports.stream().anyMatch(r -> r.getOccurrences() > 0),
partOfRegistry.get());
}

@Builder
@Getter
public static class GdprReport {
private final String name;
private final String description;
private final Long occurrences;
}

@Data
@NoArgsConstructor
@AllArgsConstructor
public static class GdprRequest {
private UUID id;
private List<String> emails;
}

@Builder
@Getter
public static class GdprInvestigationResult {
private List<GdprReport> reports;
private Boolean anyMatch;
private Boolean partOfRegistry;
}
}
Loading

0 comments on commit 50451ac

Please sign in to comment.