Skip to content

Commit

Permalink
RIPE NCC has merged 73654dc
Browse files Browse the repository at this point in the history
* Revert "Merge branch 'renovate/net.logstash.logback-logstash-logback-encoder-7.x' into 'next'" [aaeab0cf]
* chore(deps): update dependency gradle to v8.2 [2e25abcd]
* Expand sender ignore-list to ignore bad senders [fec56565]
* Test name of ProvisioningException too [aafa1825]
* ^HttpResponseCode^HttpStatusCode [32709f86]
* Merge nested if-statements [067088ec]
* Add ignore list for unknown senders [c28c18fc]
* Wrap provisioning protocol errors with ProvisioningException [22a8fe2c]
* Rename ProvisioningMetricsTest -> ProvisioningMetricsServiceTest [26b358d5]
* chore(deps): update dependency io.freefair.lombok:io.freefair.lombok.gradle.plugin to v8.1.0 [6d13f78a]
* chore(deps): update dependency org.eclipse.jgit:org.eclipse.jgit to v5.13.2.202306221912-r [2e14d64f]
* chore(deps): update dependency commons-codec:commons-codec to v1.16.0 [fcb7334f]
* chore(deps): update dependency net.logstash.logback:logstash-logback-encoder to v7.4 [87a91d26]
  • Loading branch information
RPKI Team at RIPE NCC committed Jul 6, 2023
1 parent bdfd9bf commit 8846100
Show file tree
Hide file tree
Showing 17 changed files with 182 additions and 74 deletions.
2 changes: 1 addition & 1 deletion .gitlab-ci.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
image: gradle:8.1-jdk11
image: gradle:8.2-jdk11

# Explicit version of the Mergerequests-Pipelines workflow, with the main branch
# added.
Expand Down
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ dependencies {

implementation 'com.google.code.gson:gson:2.10.1'
implementation 'com.jamesmurty.utils:java-xmlbuilder:1.3'
implementation 'commons-codec:commons-codec:1.15'
implementation 'commons-codec:commons-codec:1.16.0'
implementation 'commons-io:commons-io:2.13.0'
implementation 'ch.qos.logback.contrib:logback-json-classic:0.1.5'
implementation 'ch.qos.logback.contrib:logback-jackson:0.1.5'
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.0.1'
implementation 'io.freefair.lombok:io.freefair.lombok.gradle.plugin:8.1.0'
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.0.202109080827-r'
implementation 'org.eclipse.jgit:org.eclipse.jgit:5.13.2.202306221912-r'
implementation 'org.sonarqube:org.sonarqube.gradle.plugin:4.2.1.3168'
}
Binary file modified gradle/wrapper/gradle-wrapper.jar
Binary file not shown.
3 changes: 2 additions & 1 deletion gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.1.1-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.2-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
5 changes: 4 additions & 1 deletion gradlew
Original file line number Diff line number Diff line change
Expand Up @@ -130,10 +130,13 @@ location of your Java installation."
fi
else
JAVACMD=java
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
if ! command -v java >/dev/null 2>&1
then
die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
fi

# Increase the maximum file descriptors if we can.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
import lombok.extern.slf4j.Slf4j;
import net.ripe.rpki.commons.provisioning.cms.ProvisioningCmsObject;
import net.ripe.rpki.commons.provisioning.cms.ProvisioningCmsObjectValidator;
import net.ripe.rpki.commons.provisioning.protocol.ResponseExceptionType;
import net.ripe.rpki.commons.provisioning.x509.ProvisioningIdentityCertificate;
import net.ripe.rpki.commons.validation.ValidationOptions;
import net.ripe.rpki.commons.validation.ValidationResult;
Expand Down Expand Up @@ -38,10 +37,10 @@ public void validateProvisioningCmsAndIdentityCertificate(ProvisioningCmsObject
log.info("Rejected up-down payload because of validation failures: {}", validationResult.getFailuresForAllLocations());

if (validationResult.getFailuresForAllLocations().stream().anyMatch(check -> SIGNING_TIME_GREATER_OR_EQUAL.equals(check.getKey()))) {
throw new ProvisioningException(ResponseExceptionType.POTENTIAL_REPLAY_ATTACK);
throw new ProvisioningException.PotentialReplayAttack();
}
// Includes sending bad data when the certificates are expired.
throw new ProvisioningException(ResponseExceptionType.BAD_DATA);
throw new ProvisioningException.BadData();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@

import net.ripe.rpki.commons.provisioning.protocol.ResponseExceptionType;

import java.util.Optional;
import java.util.UUID;

import static java.lang.String.format;

/**
* An error response as described at the end of https://datatracker.ietf.org/doc/html/rfc6492#section-3.2 .
* These will <emph>not</emph> result in CMS signed responses.
Expand All @@ -10,21 +15,89 @@
* <emph>Recall:</emph> <i>@Transactional</i> rolls back on uncaught RuntimeExceptions, but not on checked exceptions.
*/
class ProvisioningException extends RuntimeException {
private static final long serialVersionUID = 1L;
private static final long serialVersionUID = 2L;

private final ResponseExceptionType exceptionType;
private final ResponseExceptionType protocolError;

private ProvisioningException(ResponseExceptionType protocolError) {
super(format("%s: %s", protocolError.name(), protocolError.getDescription()));
this.protocolError = protocolError;
}

public ProvisioningException(ResponseExceptionType exceptionType, Throwable e) {
super(exceptionType.toString(), e);
this.exceptionType = exceptionType;
private ProvisioningException(ResponseExceptionType protocolError, Throwable cause) {
super(format("%s: %s", protocolError.name(), protocolError.getDescription()), cause);
this.protocolError = protocolError;
}

public ProvisioningException(ResponseExceptionType exceptionType) {
super(exceptionType.toString());
this.exceptionType = exceptionType;
public final String getName() {
return protocolError.name();
}

public Optional<String> getSender() {
return Optional.empty();
}

public int getHttpStatusCode() {
return protocolError.getHttpResponseCode();
}

public String getDescription() {
return protocolError.getDescription();
}

static class PotentialReplayAttack extends ProvisioningException {
PotentialReplayAttack() {
super(ResponseExceptionType.POTENTIAL_REPLAY_ATTACK);
}
}

static class BadData extends ProvisioningException {
BadData() {
super(ResponseExceptionType.BAD_DATA);
}

BadData(Throwable cause) {
super(ResponseExceptionType.BAD_DATA, cause);
}
}

static class BadSenderAndRecipient extends ProvisioningException {
private final String sender;

BadSenderAndRecipient(String sender) {
super(ResponseExceptionType.BAD_SENDER_AND_RECIPIENT);
this.sender = sender;
}

@Override
public Optional<String> getSender() {
return Optional.of(sender);
}
}

static class UnknownRecipient extends ProvisioningException {
UnknownRecipient() {
super(ResponseExceptionType.UNKNOWN_RECIPIENT);
}
}

static class UnknownSender extends ProvisioningException {
private final UUID sender;

UnknownSender(UUID sender) {
super(ResponseExceptionType.UNKNOWN_SENDER);
this.sender = sender;
}

@Override
public Optional<String> getSender() {
return Optional.of(sender.toString());
}
}

public ResponseExceptionType getResponseExceptionType() {
return exceptionType;
static class UnknownProvisioningUrl extends ProvisioningException {
UnknownProvisioningUrl() {
super(ResponseExceptionType.UNKNOWN_PROVISIONING_URL);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,15 @@
import net.ripe.rpki.commons.provisioning.payload.PayloadMessageType;
import net.ripe.rpki.commons.provisioning.payload.error.NotPerformedError;
import net.ripe.rpki.commons.provisioning.payload.error.RequestNotPerformedResponsePayload;
import net.ripe.rpki.commons.provisioning.protocol.ResponseExceptionType;
import net.ripe.rpki.commons.validation.ValidationCheck;
import net.ripe.rpki.commons.validation.ValidationResult;
import org.apache.commons.lang3.tuple.Pair;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.annotation.CheckForNull;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

@Slf4j
Expand All @@ -25,13 +26,15 @@ public class ProvisioningMetricsService {
private final ConcurrentHashMap<Pair<String, String>, Counter> validationStatusCounters = new ConcurrentHashMap<>();
private final ConcurrentHashMap<PayloadMessageType, Counter> payloadTypeCounters = new ConcurrentHashMap<>();
private final ConcurrentHashMap<NotPerformedError, Counter> errorPayloadCounters = new ConcurrentHashMap<>();
private final ConcurrentHashMap<ResponseExceptionType, Counter> provisioningExceptionCounters = new ConcurrentHashMap<>();
private final ConcurrentHashMap<String, Counter> provisioningExceptionCounters = new ConcurrentHashMap<>();

private final Counter totalValidationCount;
private final Set<String> ignoredSenders;

@Autowired
public ProvisioningMetricsService(MeterRegistry registry) {
public ProvisioningMetricsService(MeterRegistry registry, @Value("${rfc6492.sender.ignores}") Set<String> ignoredSenders) {
this.meterRegistry = registry;
this.ignoredSenders = Set.copyOf(ignoredSenders);

totalValidationCount = Counter.builder("rpkicore.rfc6492.validation.total")
.description("total number of rpki-commons validation results tracked")
Expand Down Expand Up @@ -103,14 +106,17 @@ public void trackPayload(@CheckForNull AbstractProvisioningPayload payload) {
* @param provisioningException exception to log the cause for
*/
public void trackProvisioningExceptionCause(@CheckForNull ProvisioningException provisioningException) {
if (provisioningException == null || provisioningException.getResponseExceptionType() == null) {
if (provisioningException == null) {
return;
}
if (provisioningException.getSender().map(ignoredSenders::contains).orElse(false)) {
return;
}

provisioningExceptionCounters.computeIfAbsent(provisioningException.getResponseExceptionType(),
provisioningExceptionCounters.computeIfAbsent(provisioningException.getName(),
exceptionName -> Counter.builder("rpkicore.rfc6492.response.exception")
.description("Number of exceptions returned from up-down endpoint by underlying exception")
.tag("type", exceptionName.name())
.tag("type", exceptionName)
.register(meterRegistry)
).increment();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
import net.ripe.rpki.commons.provisioning.payload.issue.request.CertificateIssuanceRequestPayload;
import net.ripe.rpki.commons.provisioning.payload.list.request.ResourceClassListQueryPayload;
import net.ripe.rpki.commons.provisioning.payload.revocation.request.CertificateRevocationRequestPayload;
import net.ripe.rpki.commons.provisioning.protocol.ResponseExceptionType;
import net.ripe.rpki.domain.NonHostedCertificateAuthority;
import net.ripe.rpki.domain.ProductionCertificateAuthority;
import net.ripe.rpki.server.api.dto.CertificateAuthorityData;
Expand Down Expand Up @@ -136,7 +135,7 @@ public static UUID parseSenderAndRecipientUUID(String uuid) {
try {
return UUID.fromString(uuid);
} catch (IllegalArgumentException e) {
throw new ProvisioningException(ResponseExceptionType.BAD_SENDER_AND_RECIPIENT);
throw new ProvisioningException.BadSenderAndRecipient(uuid);
}
}

Expand All @@ -148,7 +147,7 @@ public static UUID parseSenderAndRecipientUUID(String uuid) {
private void validateRecipientIsProductionCA(UUID recipientUUID) {
CertificateAuthorityData recipient = certificateAuthorityViewService.findCertificateAuthorityByTypeAndUuid(ProductionCertificateAuthority.class, recipientUUID);
if (recipient == null || recipient.getType() != CertificateAuthorityType.ROOT) {
throw new ProvisioningException(ResponseExceptionType.UNKNOWN_RECIPIENT);
throw new ProvisioningException.UnknownRecipient();
}
}

Expand Down Expand Up @@ -177,6 +176,6 @@ private NonHostedCertificateAuthorityData getNonHostedCertificateAuthorityWithPr
return result;
}

throw new ProvisioningException(ResponseExceptionType.UNKNOWN_SENDER);
throw new ProvisioningException.UnknownSender(memberUuid);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
import net.ripe.rpki.commons.provisioning.cms.ProvisioningCmsObject;
import net.ripe.rpki.commons.provisioning.cms.ProvisioningCmsObjectParser;
import net.ripe.rpki.commons.provisioning.cms.ProvisioningCmsObjectParserException;
import net.ripe.rpki.commons.provisioning.protocol.ResponseExceptionType;
import net.ripe.rpki.domain.ProvisioningAuditLogEntity;
import net.ripe.rpki.server.api.security.RunAsUser;
import org.springframework.beans.factory.annotation.Autowired;
Expand Down Expand Up @@ -52,7 +51,7 @@ public byte[] processRequest(final byte[] request) throws ProvisioningException

return responseObject.getEncoded();
} catch (ProvisioningException ex) {
log.warn("Not able to process provisioning request, member UUID = {} with the following error: {}", requestObject.getPayload().getSender(), ex.getMessage());
log.warn("Not able to process provisioning request, member UUID = {} with the following error: {}", requestObject.getPayload().getSender(), ex.getName());
throw ex;
}
});
Expand All @@ -76,7 +75,7 @@ ProvisioningCmsObject extractRequestObject(byte[] encodedCmsObject) throws Provi
return cmsParser.getProvisioningCmsObject();
} catch (ProvisioningCmsObjectParserException e) {
log.warn("Could not parse CMS Object: " + e.getMessage());
throw new ProvisioningException(ResponseExceptionType.BAD_DATA, e);
throw new ProvisioningException.BadData(e);
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package net.ripe.rpki.ripencc.provisioning;

import lombok.extern.slf4j.Slf4j;
import net.ripe.rpki.commons.provisioning.protocol.ResponseExceptionType;
import net.ripe.rpki.rest.exception.RequestEntityTooLargeException;
import org.apache.commons.io.IOUtils;

Expand Down Expand Up @@ -54,10 +53,9 @@ protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws I
resp.sendError(HttpServletResponse.SC_REQUEST_ENTITY_TOO_LARGE);
} catch (ProvisioningException e) {
provisioningMetrics.trackProvisioningExceptionCause(e);
final ResponseExceptionType responseExceptionType = e.getResponseExceptionType();
// content-type not set for HTTP 400/503, non-CMS error responses
log.warn("provisioning error, HTTP {}: {}", responseExceptionType.getHttpResponseCode(), responseExceptionType.getDescription());
resp.sendError(responseExceptionType.getHttpResponseCode(), responseExceptionType.getDescription());
log.warn("provisioning error, HTTP {}: {}", e.getHttpStatusCode(), e.getDescription());
resp.sendError(e.getHttpStatusCode(), e.getDescription());
}
}
}
3 changes: 3 additions & 0 deletions src/main/resources/application.yml
Original file line number Diff line number Diff line change
Expand Up @@ -172,3 +172,6 @@ certificate.authority:
# invariant checking can be slow (more than a second), causing some background jobs to run for much longer. Therefore,
# the invariant checking is disabled by default and only enabled when running tests or locally.
invariant.checking.enabled: false

rfc6492:
sender.ignores: []
Loading

0 comments on commit 8846100

Please sign in to comment.