Need generic solution for Spring based app for any Data source on Password expire
Asked Answered
M

1

7

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.

Mudd answered 13/6, 2018 at 5:24 Comment(6)
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.Johnnajohnnie
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.Johnnajohnnie
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.Mudd
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.Johnnajohnnie
Okay Boris, Let me check, will get back to you on this.Mudd
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 passwordBracey
S
0

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.

Saltern answered 27/6, 2018 at 15:14 Comment(3)
If the question is specific to Spring framework you shouldn't start bringing in Cloud, and by transitive dependencies, boot dependencies. IT will screw you over in the long run. Additionally refresh scope was made for spring cloud config servers. A better solution is wrapping the datasource in another datasource impl to refresh if the call fails and re-attempting with refreshed credentials.Cerumen
@RefreshScope wasn't made only for config servers. Spring-cloud-config just uses the same approach. It is not a good idea to wrap a logic of getting configuration to datasource. Instead it will be better to have the same Watcher, which will monitor changes and will set new password and softReset() the datasource. But you will have to use com.mchange.v2.c3p0.ComboPooledDatasource in this case.Saltern
Thanks for answer Krauchanka, But I wan to fetch password only when new get Connection fails to load connection, then want to try with new password and max attempt 3, so can't go in loop.Mudd

© 2022 - 2024 — McMap. All rights reserved.