RrdpServiceImpl implements RrdpService { @Override public boolean storeRepository(final RpkiRepository rpkiRepository, final RpkiRepositoryValidationRun validationRun) { Pair<Boolean, Long> timed = Time.timed(() -> { try { return doStoreRepository(rpkiRepository, validationRun); } catch (RrdpException e) { log.warn("Error retrieving RRDP repository at {}: " + e.getMessage(), rpkiRepository.getRrdpNotifyUri()); ValidationCheck validationCheck = new ValidationCheck(rpkiRepository.getRrdpNotifyUri(), ValidationCheck.Status.ERROR, ErrorCodes.RRDP_FETCH, e.getMessage()); validationRun.addCheck(validationCheck); validationRun.setFailed(); } return false; }); log.info("RRDP repository job for {} took {}ms", rpkiRepository.getRrdpNotifyUri(), timed.getRight()); return timed.getLeft(); } @Autowired  RrdpServiceImpl(
            final RrdpClient rrdpClient,
            final RpkiObjects rpkiObjects,
            final RpkiRepositories rpkiRepositories,
            final Storage storage,
            final RrdpMetricsService rrdpMetrics
    ); @Override boolean storeRepository(final RpkiRepository rpkiRepository, final RpkiRepositoryValidationRun validationRun);  }
@Test public void should_parse_notification_use_delta_and_republish_object() { final byte[] certificate = Objects.aParseableCertificate(); final String sessionId = UUID.randomUUID().toString(); final long serial = 3; final Objects.Publish crl = new Objects.Publish("rsync: rrdpClient.add(crl.uri, crl.content); final byte[] snapshotXml = Objects.snapshotXml(serial, sessionId, crl); final Objects.SnapshotInfo snapshot = new Objects.SnapshotInfo(SNAPSHOT_URL, Sha256.hash(snapshotXml)); rrdpClient.add(snapshot.uri, snapshotXml); final Objects.DeltaPublish publishCert = new Objects.DeltaPublish("rsync: final byte[] deltaXml1 = Objects.deltaXml(2, sessionId, publishCert); final Objects.DeltaPublish republishCert = new Objects.DeltaPublish("rsync: final byte[] deltaXml2 = Objects.deltaXml(serial, sessionId, republishCert); final Objects.DeltaInfo deltaInfo1 = new Objects.DeltaInfo("https: final Objects.DeltaInfo deltaInfo2 = new Objects.DeltaInfo("https: rrdpClient.add(deltaInfo1.uri, deltaXml1); rrdpClient.add(deltaInfo2.uri, deltaXml2); final String notificationUri = RRDP_RIPE_NET_NOTIFICATION_XML; rrdpClient.add(notificationUri, Objects.notificationXml(3, sessionId, snapshot, deltaInfo1, deltaInfo2)); final TrustAnchor trustAnchor = TestObjects.newTrustAnchor(); wtx0(tx -> this.getTrustAnchors().add(tx, trustAnchor)); final RpkiRepository rpkiRepository = makeRpkiRepository(sessionId, notificationUri, trustAnchor); Ref<RpkiRepository> rpkiRepositoryRef = rtx(tx -> this.getRpkiRepositories().makeRef(tx, rpkiRepository.key())); final RrdpRepositoryValidationRun validationRun = wtx(tx -> this.getValidationRuns().add(tx, new RrdpRepositoryValidationRun(rpkiRepositoryRef))); subject.storeRepository(rpkiRepository, validationRun); assertEquals(0, validationRun.getValidationChecks().size()); final List<RpkiObject> objects = rtx(tx -> this.getRpkiObjects().values(tx)); assertEquals(1, objects.size()); }
@Test public void should_parse_notification_use_delta_non_contiguous_delta_fallback_to_snapshot() { final byte[] certificate = Objects.aParseableCertificate(); final String sessionId = UUID.randomUUID().toString(); final Objects.Publish crl = new Objects.Publish("rsync: rrdpClient.add(crl.uri, crl.content); final byte[] snapshotXml = Objects.snapshotXml(4, sessionId, crl); final Objects.SnapshotInfo emptySnapshot = new Objects.SnapshotInfo(SNAPSHOT_URL, Sha256.hash(snapshotXml)); rrdpClient.add(emptySnapshot.uri, snapshotXml); final Objects.DeltaPublish publishCert = new Objects.DeltaPublish("rsync: final byte[] deltaXml1 = Objects.deltaXml(2, sessionId, publishCert); final Objects.DeltaPublish republishCert = new Objects.DeltaPublish("rsync: final byte[] deltaXml2 = Objects.deltaXml(4, sessionId, republishCert); final Objects.DeltaInfo deltaInfo1 = new Objects.DeltaInfo("https: final Objects.DeltaInfo deltaInfo2 = new Objects.DeltaInfo("https: rrdpClient.add(deltaInfo1.uri, deltaXml1); rrdpClient.add(deltaInfo2.uri, deltaXml2); final String notificationUri = RRDP_RIPE_NET_NOTIFICATION_XML; rrdpClient.add(notificationUri, Objects.notificationXml(4, sessionId, emptySnapshot, deltaInfo1, deltaInfo2)); final TrustAnchor trustAnchor = TestObjects.newTrustAnchor(); wtx0(tx -> this.getTrustAnchors().add(tx, trustAnchor)); final RpkiRepository rpkiRepository = makeRpkiRepository(sessionId, notificationUri, trustAnchor); Ref<RpkiRepository> rpkiRepositoryRef = rtx(tx -> this.getRpkiRepositories().makeRef(tx, rpkiRepository.key())); final RrdpRepositoryValidationRun validationRun = wtx(tx -> this.getValidationRuns().add(tx, new RrdpRepositoryValidationRun(rpkiRepositoryRef))); subject.storeRepository(rpkiRepository, validationRun); System.out.println(validationRun.getValidationChecks()); assertEquals(1, validationRun.getValidationChecks().size()); final ValidationCheck validationCheck = validationRun.getValidationChecks().get(0); assertEquals(ErrorCodes.RRDP_SERIAL_MISMATCH, validationCheck.getKey()); assertEquals(ValidationCheck.Status.WARNING, validationCheck.getStatus()); assertEquals(rpkiRepository.getRrdpNotifyUri(), validationCheck.getLocation()); assertEquals("Serials of the deltas are not contiguous: found 2 and 4 after it", validationCheck.getParameters().get(0)); final List<RpkiObject> objects = rtx(tx -> this.getRpkiObjects().values(tx)); assertEquals(1, objects.size()); final RpkiObject rpkiObject = objects.get(0); assertEquals(RpkiObject.Type.CRL, rpkiObject.getType()); rtx0(tx -> assertEquals(Sets.newHashSet("rsync: }
@Test public void should_parse_notification_use_delta_the_last_delta_serial_is_not_matching_fallback_to_snapshot() { final byte[] certificate = Objects.aParseableCertificate(); final String sessionId = UUID.randomUUID().toString(); final Objects.Publish crl = new Objects.Publish("rsync: rrdpClient.add(crl.uri, crl.content); final byte[] snapshotXml = Objects.snapshotXml(4, sessionId, crl); final Objects.SnapshotInfo emptySnapshot = new Objects.SnapshotInfo(SNAPSHOT_URL, Sha256.hash(snapshotXml)); rrdpClient.add(emptySnapshot.uri, snapshotXml); final Objects.DeltaPublish publishCert = new Objects.DeltaPublish("rsync: final byte[] deltaXml1 = Objects.deltaXml(2, sessionId, publishCert); final Objects.DeltaPublish republishCert = new Objects.DeltaPublish("rsync: final byte[] deltaXml2 = Objects.deltaXml(3, sessionId, republishCert); final Objects.DeltaInfo deltaInfo1 = new Objects.DeltaInfo("https: final Objects.DeltaInfo deltaInfo2 = new Objects.DeltaInfo("https: rrdpClient.add(deltaInfo1.uri, deltaXml1); rrdpClient.add(deltaInfo2.uri, deltaXml2); final String notificationUri = RRDP_RIPE_NET_NOTIFICATION_XML; rrdpClient.add(notificationUri, Objects.notificationXml(4, sessionId, emptySnapshot, deltaInfo1, deltaInfo2)); final TrustAnchor trustAnchor = TestObjects.newTrustAnchor(); wtx0(tx -> this.getTrustAnchors().add(tx, trustAnchor)); final RpkiRepository rpkiRepository = makeRpkiRepository(sessionId, notificationUri, trustAnchor); Ref<RpkiRepository> rpkiRepositoryRef = rtx(tx -> this.getRpkiRepositories().makeRef(tx, rpkiRepository.key())); final RrdpRepositoryValidationRun validationRun = wtx(tx -> this.getValidationRuns().add(tx, new RrdpRepositoryValidationRun(rpkiRepositoryRef))); subject.storeRepository(rpkiRepository, validationRun); assertEquals(1, validationRun.getValidationChecks().size()); final ValidationCheck validationCheck = validationRun.getValidationChecks().get(0); assertEquals(ErrorCodes.RRDP_SERIAL_MISMATCH, validationCheck.getKey()); assertEquals(ValidationCheck.Status.WARNING, validationCheck.getStatus()); assertEquals(rpkiRepository.getRrdpNotifyUri(), validationCheck.getLocation()); assertEquals("The last delta serial is 3, notification file serial is 4", validationCheck.getParameters().get(0)); final List<RpkiObject> objects = rtx(tx -> this.getRpkiObjects().values(tx)); assertEquals(1, objects.size()); final RpkiObject rpkiObject = objects.get(0); assertEquals(RpkiObject.Type.CRL, rpkiObject.getType()); rtx0(tx -> assertEquals(Sets.newHashSet("rsync: }
@Test public void should_parse_notification_use_delta_mismatching_delta_hash_fallback_to_snapshot() { final byte[] certificate = Objects.aParseableCertificate(); final String sessionId = UUID.randomUUID().toString(); final Objects.Publish crl = new Objects.Publish("rsync: rrdpClient.add(crl.uri, crl.content); final byte[] snapshotXml = Objects.snapshotXml(3, sessionId, crl); final Objects.SnapshotInfo emptySnapshot = new Objects.SnapshotInfo(SNAPSHOT_URL, Sha256.hash(snapshotXml)); rrdpClient.add(emptySnapshot.uri, snapshotXml); final Objects.DeltaPublish publishCert = new Objects.DeltaPublish("rsync: final byte[] deltaXml1 = Objects.deltaXml(3, sessionId, publishCert); final Objects.DeltaInfo deltaInfo1 = new Objects.DeltaInfo("https: rrdpClient.add(deltaInfo1.uri, deltaXml1); final String notificationUri = RRDP_RIPE_NET_NOTIFICATION_XML; rrdpClient.add(notificationUri, Objects.notificationXml(3, sessionId, emptySnapshot, deltaInfo1)); final TrustAnchor trustAnchor = TestObjects.newTrustAnchor(); wtx0(tx -> this.getTrustAnchors().add(tx, trustAnchor)); final RpkiRepository rpkiRepository = makeRpkiRepository(sessionId, notificationUri, trustAnchor); Ref<RpkiRepository> rpkiRepositoryRef = rtx(tx -> this.getRpkiRepositories().makeRef(tx, rpkiRepository.key())); final RrdpRepositoryValidationRun validationRun = wtx(tx -> this.getValidationRuns().add(tx, new RrdpRepositoryValidationRun(rpkiRepositoryRef))); subject.storeRepository(rpkiRepository, validationRun); assertEquals(1, validationRun.getValidationChecks().size()); final ValidationCheck validationCheck = validationRun.getValidationChecks().get(0); assertEquals(ErrorCodes.RRDP_WRONG_DELTA_HASH, validationCheck.getKey()); assertEquals(ValidationCheck.Status.WARNING, validationCheck.getStatus()); assertEquals(rpkiRepository.getRrdpNotifyUri(), validationCheck.getLocation()); assertTrue(validationCheck.getParameters().get(0).startsWith("Hash of the delta file")); assertTrue(validationCheck.getParameters().get(0).contains("is " + Hex.format(Sha256.hash(deltaXml1)) + ", but notification file says FFFFFFFF")); final List<RpkiObject> objects = rtx(tx -> this.getRpkiObjects().values(tx)); assertEquals(1, objects.size()); final RpkiObject rpkiObject = objects.get(0); assertEquals(RpkiObject.Type.CRL, rpkiObject.getType()); rtx0(tx -> assertEquals(Sets.newHashSet("rsync: }
@Test public void should_parse_notification_and_snapshot() { final Objects.Publish cert = new Objects.Publish("rsync: final Objects.Publish crl = new Objects.Publish("rsync: rrdpClient.add(cert.uri, cert.content); rrdpClient.add(crl.uri, crl.content); final int serial = 1; final String sessionId = UUID.randomUUID().toString(); final byte[] snapshotXml = Objects.snapshotXml(serial, sessionId, cert, crl); final Objects.SnapshotInfo snapshot = new Objects.SnapshotInfo(SNAPSHOT_URL, Sha256.hash(snapshotXml)); rrdpClient.add(snapshot.uri, snapshotXml); final byte[] notificationXml = Objects.notificationXml(serial, sessionId, snapshot); rrdpClient.add(RRDP_RIPE_NET_NOTIFICATION_XML, notificationXml); final TrustAnchor trustAnchor = TestObjects.newTrustAnchor(); wtx0(tx -> this.getTrustAnchors().add(tx, trustAnchor)); final Ref<TrustAnchor> trustAnchorRef = rtx(tx -> this.getTrustAnchors().makeRef(tx, trustAnchor.key())); RpkiRepository rpkiRepository = wtx(tx -> this.getRpkiRepositories().register(tx, trustAnchorRef, RRDP_RIPE_NET_NOTIFICATION_XML, RpkiRepository.Type.RRDP)); rpkiRepository.setRrdpSerial(BigInteger.valueOf(serial)); final RrdpRepositoryValidationRun validationRun = wtx(tx -> { Ref<RpkiRepository> ref = this.getRpkiRepositories().makeRef(tx, rpkiRepository.key()); return this.getValidationRuns().add(tx, new RrdpRepositoryValidationRun(ref)); }); subject.storeRepository(rpkiRepository, validationRun); final List<RpkiObject> objects = rtx(tx -> this.getRpkiObjects().values(tx)); assertEquals(2, objects.size()); rtx0(tx -> { assertTrue(objects.stream().anyMatch(o -> cert.uri.equals(getLocations(tx, o).first()))); assertTrue(objects.stream().anyMatch(o -> crl.uri.equals(getLocations(tx, o).first()))); }); }
@Test public void should_parse_notification_verify_snapshot_hash() { final Objects.Publish cert = new Objects.Publish("rsync: final Objects.Publish crl = new Objects.Publish("rsync: rrdpClient.add(cert.uri, cert.content); rrdpClient.add(crl.uri, crl.content); final int serial = 1; final String sessionId = UUID.randomUUID().toString(); final byte[] snapshotXml = Objects.snapshotXml(serial, sessionId, cert, crl); final Objects.SnapshotInfo snapshot = new Objects.SnapshotInfo(SNAPSHOT_URL, Hex.parse("FFFFFF")); rrdpClient.add(snapshot.uri, snapshotXml); final byte[] notificationXml = Objects.notificationXml(serial, sessionId, snapshot); rrdpClient.add(RRDP_RIPE_NET_NOTIFICATION_XML, notificationXml); final TrustAnchor trustAnchor = TestObjects.newTrustAnchor(); wtx0(tx -> this.getTrustAnchors().add(tx, trustAnchor)); final Ref<TrustAnchor> trustAnchorRef = rtx(tx -> this.getTrustAnchors().makeRef(tx, trustAnchor.key())); RpkiRepository rpkiRepository = wtx(tx -> this.getRpkiRepositories().register(tx, trustAnchorRef, RRDP_RIPE_NET_NOTIFICATION_XML, RpkiRepository.Type.RRDP)); rpkiRepository.setRrdpSerial(BigInteger.valueOf(serial)); Ref<RpkiRepository> rpkiRepositoryRef = rtx(tx -> this.getRpkiRepositories().makeRef(tx, rpkiRepository.key())); final RrdpRepositoryValidationRun validationRun = new RrdpRepositoryValidationRun(rpkiRepositoryRef); subject.storeRepository(rpkiRepository, validationRun); final List<RpkiObject> objects = rtx(tx -> this.getRpkiObjects().values(tx)); assertEquals(0, objects.size()); assertEquals(1, validationRun.getValidationChecks().size()); final ValidationCheck validationCheck = validationRun.getValidationChecks().get(0); assertEquals(ErrorCodes.RRDP_FETCH, validationCheck.getKey()); assertEquals(ValidationCheck.Status.ERROR, validationCheck.getStatus()); assertEquals("Hash of the snapshot file " + SNAPSHOT_URL + " is " + Hex.format(Sha256.hash(snapshotXml)) + ", but notification file says FFFFFF", validationCheck.getParameters().get(0)); assertEquals(rpkiRepository.getRrdpNotifyUri(), validationCheck.getLocation()); }
@Test public void should_parse_notification_use_delta() { final byte[] certificate = Objects.aParseableCertificate(); final long serial = 2; final String sessionId = UUID.randomUUID().toString(); final byte[] emptySnapshotXml = Objects.snapshotXml(serial, sessionId); final Objects.SnapshotInfo emptySnapshot = new Objects.SnapshotInfo(SNAPSHOT_URL, Sha256.hash(emptySnapshotXml)); rrdpClient.add(emptySnapshot.uri, emptySnapshotXml); final Objects.DeltaPublish publishCert = new Objects.DeltaPublish("rsync: final byte[] deltaXml = Objects.deltaXml(serial, sessionId, publishCert); final Objects.DeltaInfo deltaInfo = new Objects.DeltaInfo("https: rrdpClient.add(deltaInfo.uri, deltaXml); rrdpClient.add(RRDP_RIPE_NET_NOTIFICATION_XML, Objects.notificationXml(serial, sessionId, emptySnapshot, deltaInfo)); final TrustAnchor trustAnchor = TestObjects.newTrustAnchor(); wtx0(tx -> this.getTrustAnchors().add(tx, trustAnchor)); final Ref<TrustAnchor> trustAnchorRef = rtx(tx -> this.getTrustAnchors().makeRef(tx, trustAnchor.key())); RpkiRepository rpkiRepository = wtx(tx -> this.getRpkiRepositories().register(tx, trustAnchorRef, RRDP_RIPE_NET_NOTIFICATION_XML, RpkiRepository.Type.RRDP)); Ref<RpkiRepository> rpkiRepositoryRef = rtx(tx -> this.getRpkiRepositories().makeRef(tx, rpkiRepository.key())); rpkiRepository.setRrdpSerial(BigInteger.valueOf(serial - 1)); rpkiRepository.setRrdpSessionId(sessionId); wtx0(tx -> this.getRpkiRepositories().update(tx, rpkiRepository)); final RrdpRepositoryValidationRun validationRun = wtx(tx -> this.getValidationRuns().add(tx, new RrdpRepositoryValidationRun(rpkiRepositoryRef))); subject.storeRepository(rpkiRepository, validationRun); assertEquals(0, validationRun.getValidationChecks().size()); final List<RpkiObject> objects = rtx(tx -> this.getRpkiObjects().values(tx)); assertEquals(1, objects.size()); }
@Test public void should_parse_notification_use_decline_delta_with_different_session_id_and_fallback_to_snapshot() { final byte[] certificate = Objects.aParseableCertificate(); final long serial = 2; final String sessionId = UUID.randomUUID().toString(); final String wrongSessionId = UUID.randomUUID().toString(); final Objects.Publish crl = new Objects.Publish("rsync: rrdpClient.add(crl.uri, crl.content); final byte[] snapshotXml = Objects.snapshotXml(serial, sessionId, crl); final Objects.SnapshotInfo snapshot = new Objects.SnapshotInfo(SNAPSHOT_URL, Sha256.hash(snapshotXml)); rrdpClient.add(snapshot.uri, snapshotXml); final Objects.DeltaPublish publishCert = new Objects.DeltaPublish("rsync: final byte[] deltaXml = Objects.deltaXml(serial, wrongSessionId, publishCert); final Objects.DeltaInfo deltaInfo = new Objects.DeltaInfo("https: rrdpClient.add(deltaInfo.uri, deltaXml); rrdpClient.add(RRDP_RIPE_NET_NOTIFICATION_XML, Objects.notificationXml(serial, sessionId, snapshot, deltaInfo)); final TrustAnchor trustAnchor = TestObjects.newTrustAnchor(); wtx0(tx -> this.getTrustAnchors().add(tx, trustAnchor)); final Ref<TrustAnchor> trustAnchorRef = rtx(tx -> this.getTrustAnchors().makeRef(tx, trustAnchor.key())); RpkiRepository rpkiRepository = wtx(tx -> this.getRpkiRepositories().register(tx, trustAnchorRef, RRDP_RIPE_NET_NOTIFICATION_XML, RpkiRepository.Type.RRDP)); Ref<RpkiRepository> rpkiRepositoryRef = rtx(tx -> this.getRpkiRepositories().makeRef(tx, rpkiRepository.key())); rpkiRepository.setRrdpSerial(BigInteger.valueOf(serial - 1)); rpkiRepository.setRrdpSessionId(sessionId); wtx0(tx -> this.getRpkiRepositories().update(tx, rpkiRepository)); final RrdpRepositoryValidationRun validationRun = wtx(tx -> this.getValidationRuns().add(tx, new RrdpRepositoryValidationRun(rpkiRepositoryRef))); subject.storeRepository(rpkiRepository, validationRun); assertEquals(1, validationRun.getValidationChecks().size()); final ValidationCheck validationCheck = validationRun.getValidationChecks().get(0); assertEquals(ErrorCodes.RRDP_WRONG_DELTA_SESSION, validationCheck.getKey()); assertEquals(ValidationCheck.Status.WARNING, validationCheck.getStatus()); assertEquals(rpkiRepository.getRrdpNotifyUri(), validationCheck.getLocation()); assertTrue(validationCheck.getParameters().get(0).contains("Session id of the delta")); assertTrue(validationCheck.getParameters().get(0).contains("is not the same as in the notification file: " + sessionId)); final List<RpkiObject> objects = rtx(tx -> this.getRpkiObjects().values(tx)); assertEquals(1, objects.size()); RpkiObject rpkiObject = objects.get(0); assertEquals(RpkiObject.Type.CRL, rpkiObject.getType()); rtx0(tx -> assertEquals(Sets.newHashSet("rsync: }
@Test public void should_parse_notification_use_delta_and_fail_to_use_it() { final byte[] certificate = Objects.aParseableCertificate(); final String sessionId = UUID.randomUUID().toString(); final byte[] emptySnapshotXml = Objects.snapshotXml(3, sessionId); final Objects.SnapshotInfo emptySnapshot = new Objects.SnapshotInfo(SNAPSHOT_URL, Sha256.hash(emptySnapshotXml)); rrdpClient.add(emptySnapshot.uri, emptySnapshotXml); final Objects.DeltaPublish publishCert = new Objects.DeltaPublish("rsync: final byte[] deltaXml1 = Objects.deltaXml(2, sessionId, publishCert); final Objects.DeltaPublish republishCert = new Objects.DeltaPublish("rsync: final byte[] deltaXml2 = Objects.deltaXml(3, sessionId, republishCert); final Objects.DeltaInfo deltaInfo2 = new Objects.DeltaInfo("https: final Objects.DeltaInfo deltaInfo3 = new Objects.DeltaInfo("https: rrdpClient.add(deltaInfo2.uri, deltaXml1); rrdpClient.add(deltaInfo3.uri, deltaXml2); rrdpClient.add(RRDP_RIPE_NET_NOTIFICATION_XML, Objects.notificationXml(3, sessionId, emptySnapshot, deltaInfo2, deltaInfo3)); final TrustAnchor trustAnchor = TestObjects.newTrustAnchor(); wtx0(tx -> this.getTrustAnchors().add(tx, trustAnchor)); RpkiRepository rpkiRepository = makeRpkiRepository(sessionId, RRDP_RIPE_NET_NOTIFICATION_XML, trustAnchor); Ref<RpkiRepository> rpkiRepositoryRef = rtx(tx -> this.getRpkiRepositories().makeRef(tx, rpkiRepository.key())); final RrdpRepositoryValidationRun validationRun = wtx(tx -> this.getValidationRuns().add(tx, new RrdpRepositoryValidationRun(rpkiRepositoryRef))); subject.storeRepository(rpkiRepository, validationRun); assertEquals(0, validationRun.getValidationChecks().size()); final List<RpkiObject> objects = rtx(tx -> this.getRpkiObjects().values(tx)); assertEquals(1, objects.size()); rtx0(tx -> assertEquals(Sets.newHashSet("rsync: assertEquals(1, objects.size()); }