7
votes

I don't know, how to approach a solution for the following scenario.

We have a new requirement to remove DB Password from properties even though it's encrypted with Jasypt library or some other algorithms.

Instead of storing the password in properties or LDAP, we need to fetch it dynamically from Cyberark.

Password may expire in a day or two or in a week or in a month. It totally depends on Password expiration policy.

We have multiple projects. Some are web-based and some are standalone. We want to write a generic solution.

How to override getConnection method of any data source like Spring data source, Apache Basic data source (it support extending class), C3P0, DBCP or HikariCP without impacting their behavior and setting the password before hitting super.getConnection()?

super.getConnection(); // Here max attempt  will be 3

Spring supports method replacement, but I don't know what will be the impact on the connection pooling framework.

Let me know if you need more details.

1
First of all, the requirement is a good one - "encrypting" passwords in source code is a naive solution that adds nothing to security - your encryption password must in in plaintext to decrypt; so well done to your security team.Boris the Spider
As to your current problem, Wrap It!. Create a PasswordRenewalDatasource and wrap the data database's native Datasource - when the password expries (ideally before it does) renew the underlying Datasrouce. Pass the PasswordRenewalDatasource to your connection pool.Boris the Spider
Thanks Boris, Well that's what I am doing currently, But if I want to use above mentioned data connection pooling library then i don't know, how to achieve this or rather what will be impact.Viraj
As I say, simply pass your pool to that pool! For Hikari CP use dataSourceClassName - then configure as normal, you will all need to pass the renewal properties.Boris the Spider
If you load datasource properties from properties file you could use AOP and create aspect for Properties.load(). Aspect will check if property name has password in it (or you could use any other more suitable check) and then go to Cyberark to get actual passwordIvan

1 Answers

0
votes

To solve your problem you can use spring-cloud-context library and its @RefreshScope annotation. Also, it will be needed for you to develop a bit.

1) You need a special watcher bean which will monitor if the password was changed. It will be smth like this:

@Service
public class Watcher {
    private final ContextRefresher refresher;

    public Watcher(ContextRefresher refresher) {
        this.refresher = refresher;
    }

    @Scheduled(fixedDelay = 10000L)
    public void monitor() {
        if (/* smth changed*/) {
            refresher.refresh();
        }
    }
}

So, when you call refresher.refresh(); all beans annotated with @RefreshContext will be disposed and recreated after the first access to them.

2) Annotate your datasource bean with @RefreshContext annotation. 3) You have to provide password to be accessed using @ConfigurationProperties annotation. You will need to create SourceLocator. It will be smth like this

@Order(0)
public class SourceLocator implements PropertySourceLocator {
    @Override
    public PropertySource<?> locate(Environment environment) {
        //Load properties to hash map
        return new MapPropertySource("props", new HashMap<>());
    }
}

Also, create a file spring.factories and put the following data there:

org.springframework.cloud.bootstrap.BootstrapConfiguration=\
com.test.YourSourceLocator

4) Create properties class where your db pass will be held and refreshed.

@RefreshScope
@ConfigurationProperties(prefix="your.prefix")
public class Properties {
    private String dbPassword;
}

Autowire this bean to the configuration where you create your datasource and use password from it.