Skip to content

Commit

Permalink
prefix support for CredentialFactory, improve error logging (frankfra…
Browse files Browse the repository at this point in the history
  • Loading branch information
gvanbrakel authored Jul 28, 2021
1 parent 7bf550e commit 4c26329
Showing 7 changed files with 149 additions and 29 deletions.
Original file line number Diff line number Diff line change
@@ -41,13 +41,18 @@ public class AnsibleVaultCredentialFactory extends MapCredentialFactory {
private String vaultFile = "catalina-secure-store.vault";
private String vaultKeyFile = ".secure-vault-keyfile";


public AnsibleVaultCredentialFactory() throws IOException {
super();
}

@Override
public String getPropertyBase() {
return PROPERTY_BASE;
}


private InputStream getInputStream(AppConstants appConstants, String key, String defaultValue, String purpose) throws MalformedURLException, IOException {
private InputStream getInputStream(AppConstants appConstants, String key, String defaultValue, String purpose) throws IOException {
String filename = appConstants.getProperty(key, defaultValue);
if (Misc.isEmpty(filename)) {
throw new IllegalStateException("No property ["+key+"] found for "+purpose);
Original file line number Diff line number Diff line change
@@ -27,9 +27,12 @@ public class CredentialFactory {
protected Logger log = Logger.getLogger(this.getClass().getCanonicalName());

private final String CREDENTIAL_FACTORY_KEY="credentialFactory.class";
private final String CREDENTIAL_FACTORY_OPTIONAL_PREFIX_KEY="credentialFactory.optionalPrefix";
private final String DEFAULT_CREDENTIAL_FACTORY1=FileSystemCredentialFactory.class.getName();
private final String DEFAULT_CREDENTIAL_FACTORY2=WebSphereCredentialFactory.class.getName();

private static String optionalPrefix;

private ICredentialFactory delegate;

private static CredentialFactory self;
@@ -42,6 +45,10 @@ public static CredentialFactory getInstance() {
}

private CredentialFactory() {
optionalPrefix = AppConstants.getInstance().getProperty(CREDENTIAL_FACTORY_OPTIONAL_PREFIX_KEY);
if (optionalPrefix!=null) {
optionalPrefix=optionalPrefix.toLowerCase();
}
String factoryClassName = AppConstants.getInstance().getProperty(CREDENTIAL_FACTORY_KEY);
if (tryFactory(factoryClassName)) {
return;
@@ -75,20 +82,27 @@ private boolean tryFactory(String factoryClassName) {
return false;
}

public static boolean hasCredential(String alias) {
private static String findAlias(String rawAlias) {
if (optionalPrefix!=null && rawAlias!=null && rawAlias.toLowerCase().startsWith(optionalPrefix)) {
return rawAlias.substring(optionalPrefix.length());
}
return rawAlias;
}

public static boolean hasCredential(String rawAlias) {
ICredentialFactory delegate = getInstance().delegate;
return delegate==null || delegate.hasCredentials(alias);
return delegate==null || delegate.hasCredentials(findAlias(rawAlias));
}

public static ICredentials getCredentials(String alias, String defaultUsername, String defaultPassword) {
public static ICredentials getCredentials(String rawAlias, String defaultUsername, String defaultPassword) {
ICredentialFactory delegate = getInstance().delegate;
if (delegate!=null) {
ICredentials result = delegate.getCredentials(alias, defaultUsername, defaultPassword);
ICredentials result = delegate.getCredentials(findAlias(rawAlias), defaultUsername, defaultPassword);
if (result!=null) {
return result;
}
}
return new Credentials(alias, defaultUsername, defaultPassword);
return new Credentials(findAlias(rawAlias), defaultUsername, defaultPassword);
}

}
Original file line number Diff line number Diff line change
@@ -22,38 +22,34 @@
import nl.nn.credentialprovider.util.AppConstants;

public abstract class MapCredentialFactory implements ICredentialFactory {

public final String USERNAME_SUFFIX_PROPERTY=getPropertyBase()+".usernameSuffix";
public final String PASSWORD_SUFFIX_PROPERTY=getPropertyBase()+".passwordSuffix";

public static final String USERNAME_SUFFIX_DEFAULT="/username";
public static final String PASSWORD_SUFFIX_DEFAULT="/password";

private String usernameSuffix;
private String passwordSuffix;

private Map<String,String> aliases;
public MapCredentialFactory() {

public MapCredentialFactory() throws IOException {
AppConstants appConstants = AppConstants.getInstance();

try {
aliases = getCredentialMap(appConstants);
} catch (Exception e) {
throw new IllegalArgumentException(this.getClass().getName()+" cannot get alias map", e);
}

aliases = getCredentialMap(appConstants);
if (aliases == null) {
throw new IllegalArgumentException(this.getClass().getName()+" cannot get alias map");
}

usernameSuffix = appConstants.getProperty(USERNAME_SUFFIX_PROPERTY, USERNAME_SUFFIX_DEFAULT);
passwordSuffix = appConstants.getProperty(PASSWORD_SUFFIX_PROPERTY, PASSWORD_SUFFIX_DEFAULT);
}

public abstract String getPropertyBase();

protected abstract Map<String,String> getCredentialMap(AppConstants appConstants) throws MalformedURLException, IOException;

@Override
public boolean hasCredentials(String alias) {
return aliases.containsKey(alias) || aliases.containsKey(alias+usernameSuffix) || aliases.containsKey(alias+passwordSuffix);
Original file line number Diff line number Diff line change
@@ -4,7 +4,10 @@
import static org.junit.Assume.assumeTrue;

import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Properties;
@@ -24,7 +27,7 @@ public class AnsibleVaultCredentialFactoryTest {
private AnsibleVaultCredentialFactory credentialFactory;

@Before
public void setup() {
public void setup() throws IOException {
String vaultUrl = this.getClass().getResource(ANSIBLE_VAULT_FILE).toExternalForm();
String vaultFile = Paths.get(vaultUrl.substring(vaultUrl.indexOf(":/")+2)).toString();
assumeTrue(Files.exists(Paths.get(vaultFile)));
@@ -39,26 +42,71 @@ public void setup() {
credentialFactory = new AnsibleVaultCredentialFactory();
}

public void setupVault(Properties aliases, String title) throws IOException {
ByteArrayOutputStream credentialData = new ByteArrayOutputStream();
aliases.store(credentialData, title);

System.out.println("Vault data before encryption:\n"+new String(credentialData.toByteArray()));

byte[] encryptedVault = VaultHandler.encrypt(credentialData.toByteArray(), ANSIBLE_VAULT_PASSWORD);

System.out.println("Ansible Vault:\n"+new String(encryptedVault));

}


//@Test
// run this to obtain a fresh ansible vault
public void setupVault() throws IOException {
public void testSetupVault() throws IOException {
Properties aliases = new Properties();
aliases.put("noUsername/password","password from alias");
aliases.put("straight/username","username from alias");
aliases.put("straight/password","password from alias");
aliases.put("singleValue","Plain Credential");

ByteArrayOutputStream credentialData = new ByteArrayOutputStream();
aliases.store(credentialData, "test data for Ansible Vault");
setupVault(aliases, "test data for Ansible Vault");
}

System.out.println("Vault data before encryption:\n"+new String(credentialData.toByteArray()));

byte[] encryptedVault = VaultHandler.encrypt(credentialData.toByteArray(), ANSIBLE_VAULT_PASSWORD);
public void testCreateVaultFromProperties(String resource, String title) throws IOException {
URL urlin = getClass().getResource(resource+".properties");
Properties properties = new Properties();
properties.load(urlin.openStream());

properties.forEach((k,v) -> System.out.println(k+": "+v));
setupVault(properties, "");
}

//@Test
public void testCreateVaultFromProperties() throws IOException {
testCreateVaultFromProperties("","");
}


public void testReadVault(String file, String password) throws IOException {
FileInputStream fis = new FileInputStream(file);

System.out.println("Ansible Vault:\n"+new String(encryptedVault));
ByteArrayOutputStream credentialData = new ByteArrayOutputStream();
VaultHandler.decrypt(fis, credentialData, password);

System.out.println("Decrypted Vault data:\n"+new String(credentialData.toByteArray()));
}


public void decryptFile(String file, String password) throws IOException {
try (FileOutputStream fos = new FileOutputStream(file+".txt")) {
try (FileInputStream fis = new FileInputStream(file+".vault")) {
VaultHandler.decrypt(fis, fos, password);
}
}
}

public void encryptFile(String file, String password) throws IOException {
try (FileOutputStream fos = new FileOutputStream(file+".vault")) {
try (FileInputStream fis = new FileInputStream(file+".txt")) {
VaultHandler.encrypt(fis, fos, password);
}
}
}

@Test
public void testNoAlias() {

Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package nl.nn.credentialprovider;

import static org.junit.Assert.assertEquals;

import org.junit.Ignore;
import org.junit.Test;

@Ignore("Can only run before other tests that use CredentialFactory")
public class CredentialFactoryTest {

@Test
public void testFindAliasNoPrefix() {
// test depends on setting credentialFactory.class=nl.nn.credentialprovider.MockMapCredentialFactory in test/resources/credentialprovider.properties
ICredentials c = CredentialFactory.getCredentials("account", null, null);
assertEquals("fakeUsername", c.getUsername());
assertEquals("fakePassword", c.getPassword());
}

@Test
public void testFindAliasWithPrefix() {
ICredentials c = CredentialFactory.getCredentials("fakePrefix:account", null, null);
assertEquals("fakeUsername", c.getUsername());
assertEquals("fakePassword", c.getPassword());
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package nl.nn.credentialprovider;

import java.io.IOException;
import java.net.MalformedURLException;
import java.util.HashMap;
import java.util.Map;

import nl.nn.credentialprovider.util.AppConstants;

public class MockMapCredentialFactory extends MapCredentialFactory {

public MockMapCredentialFactory() throws IOException {
super();
}

@Override
public String getPropertyBase() {
return "mockCredentiaFactory";
}

@Override
protected Map<String, String> getCredentialMap(AppConstants appConstants) throws MalformedURLException, IOException {
Map<String,String> map = new HashMap<>();
map.put("account/username", "fakeUsername");
map.put("account/password", "fakePassword");
return map;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
credentialFactory.class=nl.nn.credentialprovider.MockMapCredentialFactory
credentialFactory.optionalPrefix=fakePrefix:

0 comments on commit 4c26329

Please sign in to comment.