Skip to content
This repository has been archived by the owner on Sep 15, 2023. It is now read-only.

Commit

Permalink
Merge pull request #33 from admin-ch/feature/keys-list-up-to
Browse files Browse the repository at this point in the history
Feature/keys list up to
  • Loading branch information
ubhaller authored Jul 21, 2021
2 parents fd9e4ba + f042a01 commit d461881
Show file tree
Hide file tree
Showing 20 changed files with 916 additions and 95 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,19 @@
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<executions>
<execution>
<id>Jar Tests Package</id>
<phase>package</phase>
<goals>
<goal>test-jar</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>

</project>
Original file line number Diff line number Diff line change
Expand Up @@ -50,14 +50,28 @@ public interface VerifierDataService {
/** removes all DSCs signed by a CSCA in the given list that haven't been added manually */
public int removeDscsWithCscaIn(List<String> cscaKidsToRemove);

/** returns the next batch of DSCs after `since` up to `upTo` in the requested format */
public List<ClientCert> findDscs(Long since, CertFormat certFormat, Long upTo);

/**
* returns the next batch of DSCs after `since` but before `importedBefore` in the requested
* format
*
* @deprecated only used in KeyController V1
*/
public List<ClientCert> findDscs(Long since, CertFormat certFormat, Date importedBefore);
@Deprecated(since = "KeyControllerV2", forRemoval = true)
public List<ClientCert> findDscsBefore(Long since, CertFormat certFormat, Date importedBefore);

/** returns a list of key ids of all active DSCs */
public List<String> findActiveDscKeyIds();

/** returns a list of key ids of all active DSCs before a certain timestamp */
public List<String> findActiveDscKeyIds(Date importedBefore);
/**
* returns a list of key ids of all active DSCs before a certain timestamp
*
* @deprecated only used in KeyController V1
*/
@Deprecated(since = "KeyControllerV2", forRemoval = true)
public List<String> findActiveDscKeyIdsBefore(Date importedBefore);

/** returns the highest DSC pk id */
public long findMaxDscPkId();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -157,9 +157,49 @@ private List<Long> findCscaPksForKids(List<String> cscaKids) {
}
}

@Override
public List<ClientCert> findDscs(Long since, CertFormat certFormat, Long upTo) {
List<String> formatSpecificSelectFields;
switch (certFormat) {
case IOS:
formatSpecificSelectFields = List.of("subject_public_key_info");
break;
case ANDROID:
formatSpecificSelectFields = List.of("n", "e");
break;
default:
throw new RuntimeException("unexpected cert format received: " + certFormat);
}

String sql =
"select pk_dsc_id,"
+ " key_id,"
+ " origin,"
+ " use,"
+ " alg,"
+ " crv,"
+ " x,"
+ " y, "
+ String.join(", ", formatSpecificSelectFields)
+ " from t_document_signer_certificate"
+ " where pk_dsc_id > :since"
+ (upTo != null ? " and pk_dsc_id <= :up_to" : "")
+ " order by pk_dsc_id asc"
+ " limit :max_dsc_batch_count";

var params = new MapSqlParameterSource();
params.addValue("since", since);
params.addValue("up_to", upTo);
params.addValue("max_dsc_batch_count", MAX_DSC_BATCH_COUNT);

return jt.query(sql, params, new ClientCertRowMapper(certFormat));
}

/** @deprecated only used in KeyController V1 */
@Override
@Transactional(readOnly = true)
public List<ClientCert> findDscs(Long since, CertFormat certFormat, Date importedBefore) {
@Deprecated(since = "KeyControllerV2", forRemoval = true)
public List<ClientCert> findDscsBefore(Long since, CertFormat certFormat, Date importedBefore) {
String sql =
"select pk_dsc_id,"
+ " key_id,"
Expand All @@ -185,9 +225,19 @@ public List<ClientCert> findDscs(Long since, CertFormat certFormat, Date importe
return jt.query(sql, params, new ClientCertRowMapper(certFormat));
}

@Override
public List<String> findActiveDscKeyIds() {
return jt.queryForList(
"select key_id from t_document_signer_certificate order by pk_dsc_id",
new MapSqlParameterSource(),
String.class);
}

/** @deprecated only used in KeyController V1 */
@Override
@Transactional(readOnly = true)
public List<String> findActiveDscKeyIds(Date importedBefore) {
@Deprecated(since = "KeyControllerV2", forRemoval = true)
public List<String> findActiveDscKeyIdsBefore(Date importedBefore) {
String sql =
"select key_id from t_document_signer_certificate where imported_at < :before order by pk_dsc_id";
MapSqlParameterSource params = new MapSqlParameterSource();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,19 +10,20 @@

package ch.admin.bag.covidcertificate.backend.verifier.data;

import static ch.admin.bag.covidcertificate.backend.verifier.data.util.TestUtil.getDefaultCsca;
import static ch.admin.bag.covidcertificate.backend.verifier.data.util.TestUtil.getEcDsc;
import static ch.admin.bag.covidcertificate.backend.verifier.data.util.TestUtil.getRsaDsc;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue;

import ch.admin.bag.covidcertificate.backend.verifier.model.CertSource;
import ch.admin.bag.covidcertificate.backend.verifier.model.cert.Algorithm;
import ch.admin.bag.covidcertificate.backend.verifier.model.cert.CertFormat;
import ch.admin.bag.covidcertificate.backend.verifier.model.cert.db.DbCsca;
import ch.admin.bag.covidcertificate.backend.verifier.model.cert.ClientCert;
import ch.admin.bag.covidcertificate.backend.verifier.model.cert.db.DbDsc;
import java.time.OffsetDateTime;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
Expand Down Expand Up @@ -105,16 +106,16 @@ void insertDscTest() {
verifierDataService.insertCscas(Collections.singletonList(getDefaultCsca(0, "CH")));
final var cscaId = verifierDataService.findCscas("CH").get(0).getId();
verifierDataService.insertDscs(Collections.emptyList());
assertTrue(verifierDataService.findActiveDscKeyIds(nowPlus1Min()).isEmpty());
final var rsaDsc = getRSADsc(0, "CH", cscaId);
assertTrue(verifierDataService.findActiveDscKeyIds().isEmpty());
final var rsaDsc = getRsaDsc(0, "CH", cscaId);
verifierDataService.insertDscs(Collections.singletonList(rsaDsc));
assertEquals(1, verifierDataService.findActiveDscKeyIds(nowPlus1Min()).size());

List<String> activeDscKeyIds = verifierDataService.findActiveDscKeyIds();
assertEquals(1, activeDscKeyIds.size());
assertEquals(rsaDsc.getKeyId(), activeDscKeyIds.get(0));
assertEquals(
rsaDsc.getKeyId(),
verifierDataService
.findDscs(0L, CertFormat.ANDROID, nowPlus1Min())
.get(0)
.getKeyId());
verifierDataService.findDscs(0L, CertFormat.ANDROID, null).get(0).getKeyId());
}

@Test
Expand All @@ -124,24 +125,24 @@ void removeDscsNotInTest() {
final var cscas = verifierDataService.findCscas("CH");
assertEquals(1, cscas.size());
final var cscaId = cscas.get(0).getId();
final var rsaDsc = getRSADsc(0, "CH", cscaId);
final var rsaDsc = getRsaDsc(0, "CH", cscaId);
verifierDataService.insertDscs(Collections.singletonList(rsaDsc));
verifierDataService.removeDscsNotIn(Collections.emptyList());
assertTrue(verifierDataService.findActiveDscKeyIds(nowPlus1Min()).isEmpty());
assertTrue(verifierDataService.findActiveDscKeyIds().isEmpty());
verifierDataService.removeDscsNotIn(Collections.singletonList("keyid_0"));
final var ecDsc = getECDsc(1, "CH", cscaId);
final var ecDsc = getEcDsc(1, "CH", cscaId);
verifierDataService.insertDscs(List.of(rsaDsc, ecDsc));
verifierDataService.removeDscsNotIn(Collections.singletonList(rsaDsc.getKeyId()));
assertEquals(1, verifierDataService.findActiveDscKeyIds(nowPlus1Min()).size());
assertEquals(1, verifierDataService.findActiveDscKeyIds().size());

// verify manual doesnt get removed
updateSourceForAllDscs(CertSource.MANUAL);
verifierDataService.removeDscsNotIn(Collections.singletonList(ecDsc.getKeyId()));
assertEquals(1, verifierDataService.findActiveDscKeyIds(nowPlus1Min()).size());
assertEquals(1, verifierDataService.findActiveDscKeyIds().size());

updateSourceForAllDscs(CertSource.SYNC);
verifierDataService.removeDscsNotIn(Collections.singletonList(ecDsc.getKeyId()));
assertEquals(0, verifierDataService.findActiveDscKeyIds(nowPlus1Min()).size());
assertEquals(0, verifierDataService.findActiveDscKeyIds().size());
}

@Test
Expand All @@ -153,32 +154,49 @@ void removeDscsWithCscaIn() {
assertEquals(2, cscas.size());
final var cscaId0 = cscas.get(0).getId();
final var cscaId1 = cscas.get(1).getId();
final var rsaDsc = getRSADsc(0, "DE", cscaId0);
final var ecDsc = getECDsc(1, "DE", cscaId1);
final var rsaDsc = getRsaDsc(0, "DE", cscaId0);
final var ecDsc = getEcDsc(1, "DE", cscaId1);
verifierDataService.insertDscs(List.of(rsaDsc, ecDsc));
verifierDataService.removeDscsWithCscaIn(Collections.emptyList());
assertEquals(2, verifierDataService.findActiveDscKeyIds(nowPlus1Min()).size());
assertEquals(2, verifierDataService.findActiveDscKeyIds().size());
verifierDataService.removeDscsWithCscaIn(List.of(cscas.get(0).getKeyId()));
assertEquals(1, verifierDataService.findActiveDscKeyIds(nowPlus1Min()).size());
assertEquals(1, verifierDataService.findActiveDscKeyIds().size());

// verify manual doesnt get removed
updateSourceForAllDscs(CertSource.MANUAL);
verifierDataService.removeDscsWithCscaIn(List.of(cscas.get(1).getKeyId()));
assertEquals(1, verifierDataService.findActiveDscKeyIds(nowPlus1Min()).size());
assertEquals(1, verifierDataService.findActiveDscKeyIds().size());

updateSourceForAllDscs(CertSource.SYNC);
verifierDataService.removeDscsWithCscaIn(List.of(cscas.get(1).getKeyId()));
assertEquals(0, verifierDataService.findActiveDscKeyIds(nowPlus1Min()).size());
assertEquals(0, verifierDataService.findActiveDscKeyIds().size());
}

@Test
@Transactional
void findDscsTest() {

verifierDataService.insertCscas(Collections.singletonList(getDefaultCsca(0, "CH")));
final var cscaId = verifierDataService.findCscas("CH").get(0).getId();
verifierDataService.insertDscs(
List.of(getRSADsc(0, "CH", cscaId), getECDsc(1, "DE", cscaId)));
assertEquals(2, verifierDataService.findDscs(0L, CertFormat.IOS, nowPlus1Min()).size());

List<DbDsc> dscs = List.of(getRsaDsc(0, "CH", cscaId), getEcDsc(1, "DE", cscaId));
verifierDataService.insertDscs(dscs);

assertEquals(dscs.size(), verifierDataService.findDscs(0L, CertFormat.IOS, null).size());

// test upTo
long maxPkBeforeInsert = verifierDataService.findMaxDscPkId();
verifierDataService.insertDscs(List.of(getEcDsc(2, "DE", cscaId)));
assertEquals(
dscs.size() + 1, verifierDataService.findDscs(0L, CertFormat.IOS, null).size());
List<ClientCert> upTo1 =
verifierDataService.findDscs(0L, CertFormat.IOS, maxPkBeforeInsert);
assertEquals(dscs.size(), upTo1.size());
List<String> expectedKeyIds =
dscs.stream().map(DbDsc::getKeyId).collect(Collectors.toList());
List<String> actualKeyIds =
upTo1.stream().map(ClientCert::getKeyId).collect(Collectors.toList());
assertTrue(expectedKeyIds.containsAll(actualKeyIds));
}

@Test
Expand All @@ -187,53 +205,9 @@ void findMaxDscsTest() {
verifierDataService.insertCscas(Collections.singletonList(getDefaultCsca(0, "CH")));
final var cscaId = verifierDataService.findCscas("CH").get(0).getId();
verifierDataService.insertDscs(
List.of(getRSADsc(0, "CH", cscaId), getECDsc(1, "DE", cscaId)));
List.of(getRsaDsc(0, "CH", cscaId), getEcDsc(1, "DE", cscaId)));
final var maxDscPkId = verifierDataService.findMaxDscPkId();
assertTrue(
verifierDataService.findDscs(maxDscPkId, CertFormat.IOS, nowPlus1Min()).isEmpty());
assertEquals(
1,
verifierDataService.findDscs(maxDscPkId - 1, CertFormat.IOS, nowPlus1Min()).size());
}

private DbCsca getDefaultCsca(int idSuffix, String origin) {
var dbCsca = new DbCsca();
dbCsca.setKeyId("keyid_" + idSuffix);
dbCsca.setCertificateRaw("cert");
dbCsca.setOrigin(origin);
dbCsca.setSubjectPrincipalName("admin_ch");
return dbCsca;
}

private DbDsc getRSADsc(int idSuffix, String origin, long fkCsca) {
final var dbDsc = new DbDsc();
dbDsc.setKeyId("keyid_" + idSuffix);
dbDsc.setFkCsca(fkCsca);
dbDsc.setCertificateRaw("cert");
dbDsc.setOrigin(origin);
dbDsc.setUse("sig");
dbDsc.setAlg(Algorithm.RS256);
dbDsc.setN("n");
dbDsc.setE("e");
dbDsc.setSubjectPublicKeyInfo("pk");
return dbDsc;
}

private DbDsc getECDsc(int idSuffix, String origin, long fkCsca) {
final var dbDsc = new DbDsc();
dbDsc.setKeyId("keyid_" + idSuffix);
dbDsc.setFkCsca(fkCsca);
dbDsc.setCertificateRaw("cert");
dbDsc.setOrigin(origin);
dbDsc.setUse("sig");
dbDsc.setAlg(Algorithm.ES256);
dbDsc.setCrv("crv");
dbDsc.setX("x");
dbDsc.setY("y");
return dbDsc;
}

private Date nowPlus1Min() {
return Date.from(OffsetDateTime.now().plusMinutes(1).toInstant());
assertTrue(verifierDataService.findDscs(maxDscPkId, CertFormat.IOS, null).isEmpty());
assertEquals(1, verifierDataService.findDscs(maxDscPkId - 1, CertFormat.IOS, null).size());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/*
* Copyright (c) 2021 Ubique Innovation AG <https://www.ubique.ch>
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*
* SPDX-License-Identifier: MPL-2.0
*/

package ch.admin.bag.covidcertificate.backend.verifier.data.util;

import ch.admin.bag.covidcertificate.backend.verifier.model.cert.Algorithm;
import ch.admin.bag.covidcertificate.backend.verifier.model.cert.db.DbCsca;
import ch.admin.bag.covidcertificate.backend.verifier.model.cert.db.DbDsc;

public class TestUtil {

private TestUtil() {}

public static DbCsca getDefaultCsca(int idSuffix, String origin) {
var dbCsca = new DbCsca();
dbCsca.setKeyId("keyid_" + idSuffix);
dbCsca.setCertificateRaw("cert");
dbCsca.setOrigin(origin);
dbCsca.setSubjectPrincipalName("admin_ch");
return dbCsca;
}

public static DbDsc getRsaDsc(int idSuffix, String origin, long fkCsca) {
final var dbDsc = new DbDsc();
dbDsc.setKeyId("keyid_" + idSuffix);
dbDsc.setFkCsca(fkCsca);
dbDsc.setCertificateRaw("cert");
dbDsc.setOrigin(origin);
dbDsc.setUse("sig");
dbDsc.setAlg(Algorithm.RS256);
dbDsc.setN("n");
dbDsc.setE("e");
dbDsc.setSubjectPublicKeyInfo("pk");
return dbDsc;
}

public static DbDsc getEcDsc(int idSuffix, String origin, long fkCsca) {
final var dbDsc = new DbDsc();
dbDsc.setKeyId("keyid_" + idSuffix);
dbDsc.setFkCsca(fkCsca);
dbDsc.setCertificateRaw("cert");
dbDsc.setOrigin(origin);
dbDsc.setUse("sig");
dbDsc.setAlg(Algorithm.ES256);
dbDsc.setCrv("crv");
dbDsc.setX("x");
dbDsc.setY("y");
return dbDsc;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ public class ActiveCertsResponse {
example = "172800000")
private Duration validDuration = Duration.ofHours(48);

public ActiveCertsResponse() {}

public ActiveCertsResponse(List<String> activeKeyIds) {
if (activeKeyIds == null) {
activeKeyIds = new ArrayList<>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
public class CertsResponse {
private List<ClientCert> certs = new ArrayList<>();

public CertsResponse() {}

public CertsResponse(List<ClientCert> certs) {
if (certs == null) {
certs = new ArrayList<>();
Expand Down
Loading

0 comments on commit d461881

Please sign in to comment.