Skip to content

Commit

Permalink
RIPE NCC has merged 953ef97
Browse files Browse the repository at this point in the history
* Pass in exact createdAt value where available [5d4a69c6]
* Use rpki-commons implementation of object time parsing [12750355]
* add PrivateAsnsUsedException [4d64424c]
* Skip stacktrace for two more error situations [79fe45f5]
* Do not log stacktrace for EntityTagDoesNotMatch and PreconditionRequired exceptions [eee53915]
* Fix sonar nit by using Object::toString [f810f7e8]
* Fix broken tests [ec4e8129]
* Address some code smells [5e3997ef]
* Prevent controller from running certain operations. [5c832754]
* This is to change RSNG resource-service monitoring URL [ff2a902d]
* Minimal fix to avoid "wrong button" click in the Ustream CA UI [0e92676f]
* Don't recalculate current time [03f91b3c]
* Update plugin org.springframework.boot to v2.7.18 [1fcdb70d]
* Exclude ncipher/thales from public repositories. [f6e1ce9f]
* Fix location of thymeleaf templates in local profile [47bee4ca]
* Make error message a bit better [9f5eef99]
* Fix tests [17eef53d]
* Fixing more code smells [e67b420f]
* Fix tests [0814b06c]
* Try to cater for sonarcube [c0db3caa]
* Use existing ROA configuration instead of existing ROA objects to validate [c39fea0c]
* Fix server crash when submitting duplicate ROAs. [f6d982bd]
* Code smell [b5733066]
* Remove some code smells. [0c8ab8b4]
* Fix test name [5be56abf]
* Add validation to "stage", fix broken test. [8fd13940]
* Add a comment [711f3089]
* Add validation to "api/publish" REST call [057f3f38]
* Add Utils.validateNoIdenticalROAs [c18156df]
* rename variable and log ASPA when reissuing [aa795c4e]
* Only force configuration check on nonhosted CAs [b9769f23]
* Fix sonarqube warning [cfb6933e]
* Move some validation of updates to command handler [1d5a7593]
* Junit5 API in test case [33aff947]
* Ignore a test [f06fa879]
* Do not issue for AspaConfigurations without providers [3d6f7dac]
* Do not create AspaEntities without providers [8047d022]
* Add failing test for AspaEntity with empty provider AS [2e94165f]
* ASPAs where the ASN was no longer on the certificate were not correctly deleted. [0259e1a3]
* Correctly re-issue ASPAs when they are not parseable [9eadd9e6]
* Copy the providers in the migrations [c721b259]
* Make riswhois dump work in local development [f65e5283]
* Reissue ASPA files when a new profile version is present [8b449b19]
* Support "no providers" ASPA in the API [b0063b70]
* Update for new profile [24e54137]
* With ProviderAS explicitly [ec45854f]
* fix two nits in PublisherRepositoriesService [c9077c8b]
  • Loading branch information
RPKI Team at RIPE NCC committed Jan 16, 2024
1 parent 3afa85c commit f4db4ad
Show file tree
Hide file tree
Showing 48 changed files with 805 additions and 451 deletions.
9 changes: 1 addition & 8 deletions build.gradle
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
plugins {
id 'rpki-ripe-ncc.build-conventions'
id 'org.springframework.boot' version '2.7.16'
id 'org.springframework.boot' version '2.7.18'
id 'distribution'
id 'jacoco'
id "com.google.cloud.tools.jib" version "3.3.2"
Expand Down Expand Up @@ -93,13 +93,6 @@ java {
}

sourceSets {
main {
resources {
srcDir 'public'
// Wicket resources are in src/main/java
srcDir 'src/main/java'
}
}
integration {
java.srcDir 'src/integration/java'
resources.srcDir 'src/integration/resources'
Expand Down
15 changes: 14 additions & 1 deletion buildSrc/src/main/groovy/rpki-ripe-ncc.build-conventions.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,26 @@ group = 'net.ripe.rpki-ripe-ncc'

repositories {
mavenLocal()
mavenCentral()
mavenCentral() {
content {
excludeGroupByRegex "com\\.thales\\.esecurity\\.*"
excludeGroupByRegex "com\\.ncipher\\.nfast\\.*"
}
}

maven {
url = uri('https://oss.sonatype.org/content/repositories/releases')
content {
excludeGroupByRegex "com\\.thales\\.esecurity\\.*"
excludeGroupByRegex "com\\.ncipher\\.nfast\\.*"
}
}
maven {
url = uri('https://oss.sonatype.org/content/repositories/snapshots')
content {
excludeGroupByRegex "com\\.thales\\.esecurity\\.*"
excludeGroupByRegex "com\\.ncipher\\.nfast\\.*"
}
}

maven {
Expand Down
2 changes: 1 addition & 1 deletion dependencies.gradle
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
ext {
rpki_commons_version = '1.34'
rpki_commons_version = '1.36'
spring_boot_version = '2.7.16'
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,12 @@
import net.ripe.rpki.core.events.CertificateAuthorityEventVisitor;
import net.ripe.rpki.domain.ManagedCertificateAuthority;
import net.ripe.rpki.domain.audit.CommandAuditService;
import net.ripe.rpki.rest.exception.PreconditionRequiredException;
import net.ripe.rpki.ripencc.support.event.EventDelegateTracker;
import net.ripe.rpki.ripencc.support.event.EventSubscription;
import net.ripe.rpki.server.api.commands.CertificateAuthorityCommand;
import net.ripe.rpki.server.api.commands.CommandContext;
import net.ripe.rpki.server.api.services.command.CommandService;
import net.ripe.rpki.server.api.services.command.CommandStatus;
import net.ripe.rpki.server.api.services.command.CommandWithoutEffectException;
import net.ripe.rpki.server.api.services.command.*;
import net.ripe.rpki.services.impl.handlers.CommandHandlerMetrics;
import net.ripe.rpki.services.impl.handlers.LockCertificateAuthorityHandler;
import net.ripe.rpki.services.impl.handlers.MessageDispatcher;
Expand Down Expand Up @@ -127,6 +126,10 @@ private CommandStatus executeCommandWithRetries(CertificateAuthorityCommand comm
log.info("Command failed with possibly transient locking exception {}, retry {} in {} ms: {}", e.getClass().getName(), retryCount, sleepForMs, command);
sleepUninterruptibly(sleepForMs, TimeUnit.MILLISECONDS);
}
} catch (EntityTagDoesNotMatchException | PreconditionRequiredException | IllegalResourceException | NotHolderOfResourcesException | PrivateAsnsUsedException e) {
// Do not log these user generated commands: This causes very noisy logs.
log.info("Aborted a (user) command: {} for reason {}", command, e.getMessage());
throw e;
} catch (Exception e) {
log.warn("Error processing command: {}", command, e);
throw e;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,12 @@ public abstract class GenericPublishedObject extends EntitySupport {
@NonNull
protected byte[] content = new byte[0];

/**
* The time at which this object was created.
*
* <emph>Do not parse the object for this value if an approximate value is available</emph> since parsing violates
* abstraction layers.
*/
@Column(name = "created_at", nullable = false)
@Getter
private Instant createdAt;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -338,8 +338,9 @@ private void activatePendingKey(KeyPairEntity newKeyPair) {
* @return false if NO key was activated
*/
public boolean activatePendingKeys(Duration minStagingTime) {
DateTime cutOffTime = new DateTime().minus(minStagingTime);
return findPendingKeyPair()
.filter(pkp -> pkp.getStatusChangedAt(KeyPairStatus.PENDING).isBefore(new DateTime().minus(minStagingTime)))
.filter(pkp -> pkp.getStatusChangedAt(KeyPairStatus.PENDING).isBefore(cutOffTime))
.map(pkp -> {
activatePendingKey(pkp);
return true;
Expand Down
33 changes: 25 additions & 8 deletions src/main/java/net/ripe/rpki/domain/PublishedObject.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import net.ripe.rpki.commons.crypto.ValidityPeriod;
import net.ripe.rpki.domain.manifest.ManifestEntity;
import org.apache.commons.lang3.Validate;
import org.joda.time.Instant;
import org.joda.time.DateTime;

import javax.persistence.*;
import java.net.URI;
Expand Down Expand Up @@ -63,14 +63,15 @@ protected PublishedObject() {
}

public PublishedObject(
@NonNull KeyPairEntity issuingKeyPair,
@NonNull String filename,
byte[] content,
boolean includedInManifest,
@NonNull URI publicationDirectory,
@NonNull ValidityPeriod validityPeriod
@NonNull KeyPairEntity issuingKeyPair,
@NonNull String filename,
byte[] content,
boolean includedInManifest,
@NonNull URI publicationDirectory,
@NonNull ValidityPeriod validityPeriod,
@NonNull DateTime createdAt
) {
super(content, validityPeriod.getNotValidBefore().toInstant());
super(content, createdAt.toInstant());
this.issuingKeyPair = issuingKeyPair;
this.filename = filename;
this.includedInManifest = includedInManifest;
Expand All @@ -79,6 +80,22 @@ public PublishedObject(
this.validityPeriod = new EmbeddedValidityPeriod(validityPeriod);
}

/**
* Construct a PublishedObject with <emph>implicit</emph> createdAt from the validity period.
*
* <emph>Do not use for CMS signed objects or CRLs</emph>
*/
public PublishedObject(
@NonNull KeyPairEntity issuingKeyPair,
@NonNull String filename,
byte[] content,
boolean includedInManifest,
@NonNull URI publicationDirectory,
@NonNull ValidityPeriod validityPeriod
) {
this(issuingKeyPair, filename, content, includedInManifest, publicationDirectory, validityPeriod, validityPeriod.getNotValidBefore());
}

@NonNull
public URI getUri() {
return URI.create(directory).resolve(filename);
Expand Down
57 changes: 16 additions & 41 deletions src/main/java/net/ripe/rpki/domain/aspa/AspaConfiguration.java
Original file line number Diff line number Diff line change
@@ -1,37 +1,19 @@
package net.ripe.rpki.domain.aspa;

import com.google.common.collect.ImmutableSortedSet;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.NonNull;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import net.ripe.ipresource.Asn;
import net.ripe.rpki.domain.ManagedCertificateAuthority;
import net.ripe.rpki.ncc.core.domain.support.EntitySupport;
import net.ripe.rpki.server.api.dto.AspaAfiLimit;
import net.ripe.rpki.server.api.dto.AspaConfigurationData;
import net.ripe.rpki.server.api.dto.AspaProviderData;

import javax.persistence.CollectionTable;
import javax.persistence.Column;
import javax.persistence.ElementCollection;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.MapKeyColumn;
import javax.persistence.OneToOne;
import javax.persistence.OrderBy;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table;
import javax.persistence.*;
import javax.validation.constraints.NotEmpty;
import java.util.Collections;
import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;
import java.util.*;
import java.util.stream.Collectors;

import static net.ripe.rpki.util.Streams.streamToSortedMap;
Expand All @@ -58,46 +40,39 @@ public class AspaConfiguration extends EntitySupport {
private Asn customerAsn;

/**
* Set of provider ASNs with the AFI limit (null allows both IPv4 and IPv6, otherwise only the specified address
* family is allowed).
* Set of provider ASNs.
*/
@ElementCollection(fetch = FetchType.EAGER)
@MapKeyColumn(name = "provider_asn")
@Enumerated(value = EnumType.STRING)
@Column(name = "afi_limit")
@CollectionTable(name = "aspaconfiguration_providers", joinColumns = @JoinColumn(name = "aspaconfiguration_id"))
@OrderBy("provider_asn")
@NotEmpty
private SortedMap<@NonNull Asn, @NonNull AspaAfiLimit> providers = new TreeMap<>();
@ElementCollection(fetch = FetchType.EAGER)
@CollectionTable(name = "aspaconfiguration_providers")
private Set<@NonNull Asn> providers = new TreeSet<>();

public AspaConfiguration(@NonNull ManagedCertificateAuthority certificateAuthority, @NonNull Asn customerAsn, @NonNull Map<Asn, AspaAfiLimit> providers) {
public AspaConfiguration(@NonNull ManagedCertificateAuthority certificateAuthority, @NonNull Asn customerAsn, @NonNull SortedSet<Asn> providers) {
this.certificateAuthority = certificateAuthority;
this.customerAsn = customerAsn;
this.providers.putAll(providers);
this.providers.addAll(providers);
}

public static SortedMap<Asn, SortedMap<Asn, AspaAfiLimit>> entitiesToMaps(SortedMap<Asn, AspaConfiguration> entities) {
public static SortedMap<Asn, SortedSet<Asn>> entitiesToMaps(SortedMap<Asn, AspaConfiguration> entities) {
return streamToSortedMap(
entities.values().stream(),
AspaConfiguration::getCustomerAsn,
AspaConfiguration::getProviders
);
}

public SortedMap<Asn, AspaAfiLimit> getProviders() {
return Collections.unmodifiableSortedMap(providers);
public SortedSet<Asn> getProviders() {
return ImmutableSortedSet.copyOf(providers);
}

public void setProviders(Map<Asn, AspaAfiLimit> providers) {
this.providers = new TreeMap<>(providers);
public void setProviders(SortedSet<Asn> providers) {
this.providers = new TreeSet<>(providers);
}

public AspaConfigurationData toData() {
return new AspaConfigurationData(
getCustomerAsn(),
providers.entrySet().stream()
.map(entry -> new AspaProviderData(entry.getKey(), entry.getValue()))
.collect(Collectors.toList())
List.copyOf(getProviders())
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
public interface AspaConfigurationRepository {
SortedMap<Asn, AspaConfiguration> findByCertificateAuthority(ManagedCertificateAuthority certificateAuthority);

SortedMap<Asn, AspaConfiguration> findConfigurationsWithProvidersByCertificateAuthority(ManagedCertificateAuthority certificateAuthority);

Collection<AspaConfiguration> findAll();

void add(AspaConfiguration aspaConfiguration);
Expand Down
37 changes: 15 additions & 22 deletions src/main/java/net/ripe/rpki/domain/aspa/AspaEntity.java
Original file line number Diff line number Diff line change
@@ -1,33 +1,24 @@
package net.ripe.rpki.domain.aspa;

import com.google.common.collect.ImmutableSortedSet;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import net.ripe.ipresource.Asn;
import net.ripe.rpki.commons.crypto.cms.aspa.AspaCms;
import net.ripe.rpki.commons.crypto.cms.aspa.AspaCmsParser;
import net.ripe.rpki.commons.crypto.cms.aspa.ProviderAS;
import net.ripe.rpki.commons.validation.ValidationResult;
import net.ripe.rpki.domain.OutgoingResourceCertificate;
import net.ripe.rpki.domain.PublishedObject;
import net.ripe.rpki.ncc.core.domain.support.EntitySupport;
import net.ripe.rpki.server.api.dto.AspaAfiLimit;
import net.ripe.rpki.server.api.services.command.UnparseableRpkiObjectException;
import org.apache.commons.lang.Validate;

import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.OneToOne;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table;
import javax.persistence.Transient;
import javax.persistence.*;
import java.net.URI;
import java.util.List;
import java.util.SortedMap;
import java.util.SortedSet;

import static net.ripe.rpki.util.Streams.streamToSortedMap;

Expand All @@ -51,19 +42,25 @@ public class AspaEntity extends EntitySupport {
@Getter
private PublishedObject publishedObject;

@Getter
@Setter
@Column(name = "profile_version", nullable = false)
private Long profileVersion;

@Transient
private AspaCms cms;

public AspaEntity(OutgoingResourceCertificate eeCertificate, AspaCms aspaCms, String filename, URI directory) {
public AspaEntity(OutgoingResourceCertificate eeCertificate, AspaCms aspaCms, String filename, URI directory, long profileVersion) {
super();
Validate.notNull(eeCertificate);
Validate.notNull(aspaCms);
this.certificate = eeCertificate;
this.publishedObject = new PublishedObject(
eeCertificate.getSigningKeyPair(), filename, aspaCms.getEncoded(), true, directory, aspaCms.getValidityPeriod());
eeCertificate.getSigningKeyPair(), filename, aspaCms.getEncoded(), true, directory, aspaCms.getValidityPeriod(), aspaCms.getSigningTime());
this.profileVersion = profileVersion;
}

public static SortedMap<Asn, SortedMap<Asn, AspaAfiLimit>> entitiesToMaps(List<AspaEntity> entities) {
public static SortedMap<Asn, SortedSet<Asn>> entitiesToMaps(List<AspaEntity> entities) {
return streamToSortedMap(
entities.stream(),
AspaEntity::getCustomerAsn,
Expand Down Expand Up @@ -106,11 +103,7 @@ public Asn getCustomerAsn() {
return getAspaCms().getCustomerAsn();
}

public SortedMap<Asn, AspaAfiLimit> getProviders() {
return streamToSortedMap(
getAspaCms().getProviderASSet().stream(),
ProviderAS::getProviderAsn,
providerAS -> AspaAfiLimit.fromOptionalAddressFamily(providerAS.getAfiLimit())
);
public SortedSet<Asn> getProviders() {
return ImmutableSortedSet.copyOf(getAspaCms().getProviderASSet());
}
}
Loading

0 comments on commit f4db4ad

Please sign in to comment.