Skip to content

Commit

Permalink
Raise exception when access is denied instead of silently failing (#257)
Browse files Browse the repository at this point in the history
Co-authored-by: saville <[email protected]>
  • Loading branch information
bluesliverx and saville authored Nov 14, 2023
1 parent 44fea4f commit 8dfe406
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 15 deletions.
4 changes: 2 additions & 2 deletions src/main/java/com/datapipe/jenkins/vault/VaultAccessor.java
Original file line number Diff line number Diff line change
Expand Up @@ -227,8 +227,8 @@ public static boolean responseHasErrors(VaultConfiguration configuration, PrintS
}
int status = restResponse.getStatus();
if (status == 403) {
logger.printf("Access denied to Vault Secrets at '%s'%n", path);
return true;
throw new VaultPluginException(
String.format("Access denied to Vault path '%s'", path));
} else if (status == 404) {
if (configuration.getFailIfNotFound()) {
throw new VaultPluginException(
Expand Down
56 changes: 43 additions & 13 deletions src/test/java/com/datapipe/jenkins/vault/VaultBuildWrapperTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,11 @@ public class VaultBuildWrapperTest {
@Test
public void testWithNonExistingPath() throws IOException, InterruptedException {
String path = "not/existing";
TestWrapper wrapper = new TestWrapper(standardSecrets(path));
VaultAccessor mockAccessor = mock(VaultAccessor.class);
doReturn(mockAccessor).when(mockAccessor).init();
LogicalResponse response = getNotFoundResponse();
when(mockAccessor.read(path, 2)).thenReturn(response);
TestWrapper wrapper = new TestWrapper(standardSecrets(path), mockAccessor);
final ByteArrayOutputStream baos = new ByteArrayOutputStream();
PrintStream logger = new PrintStream(baos);
SimpleBuildWrapper.Context context = null;
Expand All @@ -56,11 +60,38 @@ public void testWithNonExistingPath() throws IOException, InterruptedException {
assertThat(e.getMessage(), is("Vault credentials not found for 'not/existing'"));
}

wrapper.verifyCalls();
verify(mockAccessor, times(2)).init();
verify(mockAccessor, times(2)).read(path, 2);
assertThat(new String(baos.toByteArray(), StandardCharsets.UTF_8),
containsString("Vault credentials not found for 'not/existing'"));
}

@Test
public void testWithAccessDeniedPath() throws IOException, InterruptedException {
String path = "not/allowed";
VaultAccessor mockAccessor = mock(VaultAccessor.class);
doReturn(mockAccessor).when(mockAccessor).init();
LogicalResponse response = getAccessDeniedResponse();
when(mockAccessor.read(path, 2)).thenReturn(response);
TestWrapper wrapper = new TestWrapper(standardSecrets(path), mockAccessor);
final ByteArrayOutputStream baos = new ByteArrayOutputStream();
PrintStream logger = new PrintStream(baos);
SimpleBuildWrapper.Context context = null;
Run<?, ?> build = mock(Build.class);
when(build.getParent()).thenReturn(null);
EnvVars envVars = mock(EnvVars.class);
when(envVars.expand(path)).thenReturn(path);

try {
wrapper.run(context, build, envVars, logger);
} catch (VaultPluginException e) {
assertThat(e.getMessage(), is("Access denied to Vault path 'not/allowed'"));
}

verify(mockAccessor).init();
verify(mockAccessor).read(path, 2);
}

private List<VaultSecret> standardSecrets(String path) {
List<VaultSecret> secrets = new ArrayList<>();
VaultSecretValue secretValue = new VaultSecretValue("envVar1", "key1");
Expand All @@ -81,21 +112,25 @@ private LogicalResponse getNotFoundResponse() {
return resp;
}

private LogicalResponse getAccessDeniedResponse() {
LogicalResponse resp = mock(LogicalResponse.class);
RestResponse rest = mock(RestResponse.class);
when(resp.getData()).thenReturn(new HashMap<>());
when(resp.getRestResponse()).thenReturn(rest);
when(rest.getStatus()).thenReturn(403);
return resp;
}

class TestWrapper extends VaultBuildWrapper {

VaultAccessor mockAccessor;
VaultConfiguration vaultConfig = new VaultConfiguration();

public TestWrapper(List<VaultSecret> vaultSecrets) {
public TestWrapper(List<VaultSecret> vaultSecrets, VaultAccessor mockAccessor) {
super(vaultSecrets);

vaultConfig.setVaultUrl("testmock");
vaultConfig.setVaultCredentialId("credId");
vaultConfig.setFailIfNotFound(false);
mockAccessor = mock(VaultAccessor.class);
doReturn(mockAccessor).when(mockAccessor).init();
LogicalResponse response = getNotFoundResponse();
when(mockAccessor.read("not/existing", 2)).thenReturn(response);
setVaultAccessor(mockAccessor);
setConfiguration(vaultConfig);
}
Expand All @@ -104,10 +139,5 @@ public void run(Context context, Run build, EnvVars envVars, PrintStream logger)
this.logger = logger;
provideEnvironmentVariablesFromVault(context, build, envVars);
}

public void verifyCalls() {
verify(mockAccessor, times(2)).init();
verify(mockAccessor, times(2)).read("not/existing", 2);
}
}
}

0 comments on commit 8dfe406

Please sign in to comment.