Skip to content

Commit

Permalink
Enhance accuracy of how get/get versions Azure Key Vault APIs are fak…
Browse files Browse the repository at this point in the history
…ed (#470)

- Changes get and get deleted API endpoints to fail to return disabled entities
- Changes get versions API endpoints to sort versions by natural order of the hashes
- Adds new test cases to UT
- Adds new test cases to E2E
- Improves Gradle build config for Docker module
- Eliminates use of some soon-to-be deprecated properties in root Gradle file
- Avoids release in case of Gradle wrapper update

Resolves #467
{minor}

Signed-off-by: Esta Nagy <nagyesta@gmail.com>
  • Loading branch information
nagyesta authored Feb 15, 2023
1 parent 653ea3b commit c91fa7f
Show file tree
Hide file tree
Showing 19 changed files with 619 additions and 435 deletions.
2 changes: 2 additions & 0 deletions .github/workflows/gradle.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ on:
- 'gradle/verification-metadata-clean.xml'
- 'lowkey-vault-docker/src/docker/Dockerfile'
- 'gradle/wrapper/gradle-wrapper.properties'
- 'gradlew'
- 'gradlew.bat'
- 'config/ossindex/exclusions.txt'

permissions: read-all
Expand Down
8 changes: 4 additions & 4 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -83,10 +83,10 @@ configure(subprojects.findAll({
jacocoTestReport {
reports {
xml.required.set(true)
xml.destination file("$buildDir/reports/jacoco/report.xml")
xml.outputLocation.set(file("$buildDir/reports/jacoco/report.xml"))
csv.required.set(false)
html.required.set(true)
html.destination file("$buildDir/reports/jacoco/html")
html.outputLocation.set(file("$buildDir/reports/jacoco/html"))
}
}

Expand Down Expand Up @@ -145,7 +145,7 @@ configure(subprojects.findAll({
}
jar.dependsOn check

tasks.withType(Checkstyle) {
tasks.withType(Checkstyle).configureEach {
configProperties = [base_dir: rootDir.toString(), cache_file: file("${buildDir}/checkstyle/cacheFile")]
reports {
xml.required.set(false)
Expand Down Expand Up @@ -178,7 +178,7 @@ configure(subprojects.findAll({
}

//Disable metadata publishing and rely on Maven only
tasks.withType(GenerateModuleMetadata) {
tasks.withType(GenerateModuleMetadata).configureEach {
enabled = false
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,9 +106,7 @@ public ResponseEntity<KeyVaultCertificateModel> getWithVersion(
log.info("Received request to {} get certificate: {} with version: {} using API version: {}",
baseUri.toString(), certificateName, certificateVersion, apiVersion());

final ReadOnlyKeyVaultCertificateEntity keyVaultCertificateEntity =
getEntityByNameAndVersion(baseUri, certificateName, certificateVersion);
return ResponseEntity.ok(convertDetails(keyVaultCertificateEntity, baseUri));
return ResponseEntity.ok(getSpecificEntityModel(baseUri, certificateName, certificateVersion));
}

public ResponseEntity<KeyVaultCertificateModel> importCertificate(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ public ResponseEntity<KeyVaultKeyModel> create(

final KeyVaultFake keyVaultFake = getVaultByUri(baseUri);
final VersionedKeyEntityId keyEntityId = createKeyWithAttributes(keyVaultFake, keyName, request);
return ResponseEntity.ok(getModelById(keyVaultFake, keyEntityId, baseUri));
return ResponseEntity.ok(getModelById(keyVaultFake, keyEntityId, baseUri, true));
}

public ResponseEntity<KeyVaultKeyModel> importKey(
Expand All @@ -62,7 +62,7 @@ public ResponseEntity<KeyVaultKeyModel> importKey(

final KeyVaultFake keyVaultFake = getVaultByUri(baseUri);
final VersionedKeyEntityId keyEntityId = importKeyWithAttributes(keyVaultFake, keyName, request);
return ResponseEntity.ok(getModelById(keyVaultFake, keyEntityId, baseUri));
return ResponseEntity.ok(getModelById(keyVaultFake, keyEntityId, baseUri, true));
}

public ResponseEntity<KeyVaultKeyModel> delete(
Expand All @@ -75,7 +75,7 @@ public ResponseEntity<KeyVaultKeyModel> delete(
final KeyEntityId entityId = new KeyEntityId(baseUri, keyName);
keyVaultFake.delete(entityId);
final VersionedKeyEntityId latestVersion = keyVaultFake.getDeletedEntities().getLatestVersionOfEntity(entityId);
return ResponseEntity.ok(getDeletedModelById(keyVaultFake, latestVersion, baseUri));
return ResponseEntity.ok(getDeletedModelById(keyVaultFake, latestVersion, baseUri, true));
}

public ResponseEntity<KeyVaultItemListModel<KeyVaultKeyItemModel>> versions(
Expand Down Expand Up @@ -125,8 +125,7 @@ public ResponseEntity<KeyVaultKeyModel> getWithVersion(
log.info("Received request to {} get key: {} with version: {} using API version: {}",
baseUri.toString(), keyName, keyVersion, apiVersion());

final ReadOnlyKeyVaultKeyEntity keyVaultKeyEntity = getEntityByNameAndVersion(baseUri, keyName, keyVersion);
return ResponseEntity.ok(convertDetails(keyVaultKeyEntity, baseUri));
return ResponseEntity.ok(getSpecificEntityModel(baseUri, keyName, keyVersion));
}

public ResponseEntity<KeyVaultKeyModel> updateVersion(
Expand All @@ -143,7 +142,7 @@ public ResponseEntity<KeyVaultKeyModel> updateVersion(
.ifPresent(operations -> keyVaultFake.setKeyOperations(entityId, operations));
updateAttributes(keyVaultFake, entityId, request.getProperties());
updateTags(keyVaultFake, entityId, request.getTags());
return ResponseEntity.ok(getModelById(keyVaultFake, entityId, baseUri));
return ResponseEntity.ok(getModelById(keyVaultFake, entityId, baseUri, true));
}

public ResponseEntity<KeyVaultKeyModel> getDeletedKey(
Expand All @@ -155,7 +154,7 @@ public ResponseEntity<KeyVaultKeyModel> getDeletedKey(
final KeyVaultFake keyVaultFake = getVaultByUri(baseUri);
final KeyEntityId entityId = new KeyEntityId(baseUri, keyName);
final VersionedKeyEntityId latestVersion = keyVaultFake.getDeletedEntities().getLatestVersionOfEntity(entityId);
return ResponseEntity.ok(getDeletedModelById(keyVaultFake, latestVersion, baseUri));
return ResponseEntity.ok(getDeletedModelById(keyVaultFake, latestVersion, baseUri, false));
}

public ResponseEntity<KeyVaultKeyModel> recoverDeletedKey(
Expand All @@ -168,7 +167,7 @@ public ResponseEntity<KeyVaultKeyModel> recoverDeletedKey(
final KeyEntityId entityId = new KeyEntityId(baseUri, keyName);
keyVaultFake.recover(entityId);
final VersionedKeyEntityId latestVersion = keyVaultFake.getEntities().getLatestVersionOfEntity(entityId);
return ResponseEntity.ok(getModelById(keyVaultFake, latestVersion, baseUri));
return ResponseEntity.ok(getModelById(keyVaultFake, latestVersion, baseUri, true));
}

public ResponseEntity<Void> purgeDeleted(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ public ResponseEntity<KeyVaultSecretModel> create(

final SecretVaultFake secretVaultFake = getVaultByUri(baseUri);
final VersionedSecretEntityId secretEntityId = createSecretWithAttributes(secretVaultFake, secretName, request);
return ResponseEntity.ok(getModelById(secretVaultFake, secretEntityId, baseUri));
return ResponseEntity.ok(getModelById(secretVaultFake, secretEntityId, baseUri, true));
}

public ResponseEntity<KeyVaultSecretModel> delete(
Expand All @@ -59,7 +59,7 @@ public ResponseEntity<KeyVaultSecretModel> delete(
final SecretEntityId entityId = new SecretEntityId(baseUri, secretName);
secretVaultFake.delete(entityId);
final VersionedSecretEntityId latestVersion = secretVaultFake.getDeletedEntities().getLatestVersionOfEntity(entityId);
return ResponseEntity.ok(getDeletedModelById(secretVaultFake, latestVersion, baseUri));
return ResponseEntity.ok(getDeletedModelById(secretVaultFake, latestVersion, baseUri, true));
}

public ResponseEntity<KeyVaultItemListModel<KeyVaultSecretItemModel>> versions(
Expand Down Expand Up @@ -109,9 +109,7 @@ public ResponseEntity<KeyVaultSecretModel> getWithVersion(
final URI baseUri) {
log.info("Received request to {} get secret: {} with version: {} using API version: {}",
baseUri.toString(), secretName, secretVersion, apiVersion());

final ReadOnlyKeyVaultSecretEntity keyVaultSecretEntity = getEntityByNameAndVersion(baseUri, secretName, secretVersion);
return ResponseEntity.ok(convertDetails(keyVaultSecretEntity, baseUri));
return ResponseEntity.ok(getSpecificEntityModel(baseUri, secretName, secretVersion));
}

public ResponseEntity<KeyVaultSecretModel> updateVersion(
Expand All @@ -126,7 +124,7 @@ public ResponseEntity<KeyVaultSecretModel> updateVersion(
final VersionedSecretEntityId entityId = versionedEntityId(baseUri, secretName, secretVersion);
updateAttributes(secretVaultFake, entityId, request.getProperties());
updateTags(secretVaultFake, entityId, request.getTags());
return ResponseEntity.ok(getModelById(secretVaultFake, entityId, baseUri));
return ResponseEntity.ok(getModelById(secretVaultFake, entityId, baseUri, true));
}

public ResponseEntity<KeyVaultSecretModel> getDeletedSecret(
Expand All @@ -138,7 +136,7 @@ public ResponseEntity<KeyVaultSecretModel> getDeletedSecret(
final SecretVaultFake secretVaultFake = getVaultByUri(baseUri);
final SecretEntityId entityId = new SecretEntityId(baseUri, secretName);
final VersionedSecretEntityId latestVersion = secretVaultFake.getDeletedEntities().getLatestVersionOfEntity(entityId);
return ResponseEntity.ok(getDeletedModelById(secretVaultFake, latestVersion, baseUri));
return ResponseEntity.ok(getDeletedModelById(secretVaultFake, latestVersion, baseUri, false));
}

public ResponseEntity<Void> purgeDeleted(
Expand All @@ -163,7 +161,7 @@ public ResponseEntity<KeyVaultSecretModel> recoverDeletedSecret(
final SecretEntityId entityId = new SecretEntityId(baseUri, secretName);
secretVaultFake.recover(entityId);
final VersionedSecretEntityId latestVersion = secretVaultFake.getEntities().getLatestVersionOfEntity(entityId);
return ResponseEntity.ok(getModelById(secretVaultFake, latestVersion, baseUri));
return ResponseEntity.ok(getModelById(secretVaultFake, latestVersion, baseUri, true));
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,16 @@
import com.github.nagyesta.lowkeyvault.service.EntityId;
import com.github.nagyesta.lowkeyvault.service.common.BaseVaultEntity;
import com.github.nagyesta.lowkeyvault.service.common.BaseVaultFake;
import com.github.nagyesta.lowkeyvault.service.exception.NotFoundException;
import com.github.nagyesta.lowkeyvault.service.vault.VaultFake;
import com.github.nagyesta.lowkeyvault.service.vault.VaultService;
import lombok.NonNull;

import java.net.URI;
import java.util.*;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.function.Function;
import java.util.stream.Collectors;

Expand Down Expand Up @@ -67,13 +71,19 @@ protected GenericEntityController(@NonNull final MC modelConverter,
this.versionedItemConverter = versionedItemConverter;
}

protected M getModelById(final S entityVaultFake, final V entityId, final URI baseUri) {
protected M getModelById(final S entityVaultFake, final V entityId, final URI baseUri, final boolean includeDisabled) {
final E entity = entityVaultFake.getEntities().getReadOnlyEntity(entityId);
if (!includeDisabled && !entity.isEnabled()) {
throw new NotFoundException("Operation get is not allowed on a disabled entity.");
}
return modelConverter.convert(entity, baseUri);
}

protected DM getDeletedModelById(final S entityVaultFake, final V entityId, final URI baseUri) {
protected DM getDeletedModelById(final S entityVaultFake, final V entityId, final URI baseUri, final boolean includeDisabled) {
final E entity = entityVaultFake.getDeletedEntities().getReadOnlyEntity(entityId);
if (!includeDisabled && !entity.isEnabled()) {
throw new NotFoundException("Operation get is not allowed on a disabled entity.");
}
return modelConverter.convertDeleted(entity, baseUri);
}

Expand All @@ -85,7 +95,10 @@ protected KeyVaultItemListModel<I> getPageOfItemVersions(
final URI baseUri, final String name, final int limit, final int offset, final String uriPath) {
final S entityVaultFake = getVaultByUri(baseUri);
final K entityId = entityId(baseUri, name);
final Deque<String> allItems = entityVaultFake.getEntities().getVersions(entityId);
final List<String> allItems = entityVaultFake.getEntities().getVersions(entityId)
.stream()
.sorted()
.collect(Collectors.toList());
final List<I> items = filterList(limit, offset, allItems, v -> {
final E entity = getEntityByNameAndVersion(baseUri, name, v);
return versionedItemConverter.convert(entity, baseUri);
Expand Down Expand Up @@ -115,7 +128,13 @@ protected KeyVaultItemListModel<I> getPageOfDeletedItems(final URI baseUri, fina
protected M getLatestEntityModel(final URI baseUri, final String name) {
final S vaultFake = getVaultByUri(baseUri);
final V entityId = vaultFake.getEntities().getLatestVersionOfEntity(entityId(baseUri, name));
return getModelById(vaultFake, entityId, baseUri);
return getModelById(vaultFake, entityId, baseUri, false);
}

protected M getSpecificEntityModel(final URI baseUri, final String name, final String version) {
final S vaultFake = getVaultByUri(baseUri);
final V entityId = versionedEntityId(baseUri, name, version);
return getModelById(vaultFake, entityId, baseUri, false);
}

protected void updateAttributes(final BaseVaultFake<K, V, ?> vaultFake, final V entityId, final BasePropertiesUpdateModel properties) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -311,6 +311,7 @@ void testVersionsShouldFilterTheListReturnedWhenKeyIsFoundAndHasMoreVersionsThan
final int index = 30;
final LinkedList<String> fullList = IntStream.range(0, 42)
.mapToObj(i -> UUID.randomUUID().toString().replaceAll("-", ""))
.sorted()
.collect(Collectors.toCollection(LinkedList::new));
final KeyEntityId baseUri = new KeyEntityId(HTTPS_LOCALHOST_8443, KEY_NAME_1, null);
final String expectedNextUri = baseUri.asUri(HTTPS_LOCALHOST_8443, "versions?api-version=7.2&$skiptoken=31&maxresults=1")
Expand Down Expand Up @@ -348,6 +349,7 @@ void testVersionsShouldNotContainNextUriWhenLastPageIsReturnedFully() {
//given
final LinkedList<String> fullList = IntStream.range(0, 25)
.mapToObj(i -> UUID.randomUUID().toString().replaceAll("-", ""))
.sorted()
.collect(Collectors.toCollection(LinkedList::new));
final KeyEntityId baseUri = new KeyEntityId(HTTPS_LOCALHOST_8443, KEY_NAME_1, null);
when(keyVaultFake.getEntities())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,7 @@ void testVersionsShouldFilterTheListReturnedWhenSecretIsFoundAndHasMoreVersionsT
final int index = 30;
final LinkedList<String> fullList = IntStream.range(0, 42)
.mapToObj(i -> UUID.randomUUID().toString().replaceAll("-", ""))
.sorted()
.collect(Collectors.toCollection(LinkedList::new));
final SecretEntityId baseUri = new SecretEntityId(HTTPS_LOCALHOST_8443, SECRET_NAME_1, null);
final String expectedNextUri = baseUri.asUri(HTTPS_LOCALHOST_8443, "versions?api-version=7.2&$skiptoken=31&maxresults=1")
Expand Down Expand Up @@ -266,6 +267,7 @@ void testVersionsShouldNotContainNextUriWhenLastPageIsReturnedFully() {
//given
final LinkedList<String> fullList = IntStream.range(0, 25)
.mapToObj(i -> UUID.randomUUID().toString().replaceAll("-", ""))
.sorted()
.collect(Collectors.toCollection(LinkedList::new));
final SecretEntityId baseUri = new SecretEntityId(HTTPS_LOCALHOST_8443, SECRET_NAME_1, null);
when(secretVaultFake.getEntities())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -311,6 +311,7 @@ void testVersionsShouldFilterTheListReturnedWhenKeyIsFoundAndHasMoreVersionsThan
final int index = 30;
final LinkedList<String> fullList = IntStream.range(0, 42)
.mapToObj(i -> UUID.randomUUID().toString().replaceAll("-", ""))
.sorted()
.collect(Collectors.toCollection(LinkedList::new));
final KeyEntityId baseUri = new KeyEntityId(HTTPS_LOCALHOST_8443, KEY_NAME_1, null);
final String expectedNextUri = baseUri.asUri(HTTPS_LOCALHOST_8443, "versions?api-version=7.3&$skiptoken=31&maxresults=1")
Expand Down Expand Up @@ -348,6 +349,7 @@ void testVersionsShouldNotContainNextUriWhenLastPageIsReturnedFully() {
//given
final LinkedList<String> fullList = IntStream.range(0, 25)
.mapToObj(i -> UUID.randomUUID().toString().replaceAll("-", ""))
.sorted()
.collect(Collectors.toCollection(LinkedList::new));
final KeyEntityId baseUri = new KeyEntityId(HTTPS_LOCALHOST_8443, KEY_NAME_1, null);
when(keyVaultFake.getEntities())
Expand Down
Loading

0 comments on commit c91fa7f

Please sign in to comment.