ulisesbocchio / jasypt-spring-boot

Jasypt integration for Spring boot
MIT License
2.91k stars 522 forks source link

overriding jasypt properties (e.g. jasypt.encryptor.password) not possible #11

Closed hohwille closed 9 years ago

hohwille commented 9 years ago

The whole story about spring-boot application properties is its flexibility. See here: http://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-external-config.html

Now, when I add your jasypt-spring-boot-starter as a dependency I can not start the application without having jasypt.encryptor.password set even if I have no encrypted password configured anywhere. This makes my unit tests fail, etc. So what I did is adding

jasypt.encryptor.password=dummy

To my application.properties that I deliver within the WAR file (in default package). Now I have an external application.properties in tomcat/lib/config/application.properties that defines encrypted passwords for DB, etc. Of course I want to provide the master password somewhere different as having it in the same file would be quite pointless (my plan is that I have a secret master password per environment that is available in one place on the involved machines while I then can have the configs with encrypted passwords stored in VCS but regular developers can not decrypt them without knowing the master password but they can build release packages including the correct configs).

Now, I set the master password on the commandline as a system property. I verified that the system property is actually set and available in tomcat. However, it is not honored and jasypt will use the dummy password instead.

This is totally unexpected as it works for any other spring boot property like this. There might be a technical reason as you need early on bootstrapping and interception. However, a solution is required to externalize the master password from the actual properties file. Any solution or workaround is welcome. Thanks for your great work!

ulisesbocchio commented 9 years ago

Hey jorg. Once you enable jasypt-spring-boot the password property is required as specified in the documentation. Why would you import the library or add the annotation if you don't have any encrypted properties? For test purposes you don't need to add the @enableencryptableproperties annotation. I suggest you create a spring config class for your tests. That's always a better approach than using the full app spring configuration on unit tests. Apart of that matter, there is a test project in jasypt-spring-boot's repository and an example on how to pass the master password as a syste property. Are you running your app within tomcat deploying it as a war? Do you have a sample project where the issue manifests to I can take a look and troubleshoot? Best and thanks for your feedback

hohwille commented 9 years ago

@ulisesbocchio thanks for your response.

I will try if I can provide an isolated project somewhere on github to reproduce the problem. However, time is always short (too many other projects I am involved).

ulisesbocchio commented 9 years ago

Alright buddy, you can add this to your Test Config when you don't want encryptable properties: @EnableAutoConfiguration(exclude = JasyptSpringBootAutoConfiguration.class) To effectively exclude the auto configuration, and you won't get an error. I'll will work in a way of lazily initializing the bean on first use so in case you don't have any encrypted properties in your properties it will never fail if you don't setup the string encryptor correctly. I'm still looking into the issue you mention overriding existing properties, hang on...

ulisesbocchio commented 9 years ago

Alright so I was able to override any of the properties in the jasypt-spring-boot-demo app from either application.yml and encrypted.properties through the command line using JVM args. For instance: -Djasypt.encryptor.poolSize=20 -DitemConfig.items[0].name=NEW_NAME -Dsecret.property=UNENCRPYPTED

I'm not sure why you mean by "But my expectation is (compliant to spring-boot) that I can override the properties as specified"

hohwille commented 9 years ago

Thanks for the hints, mate. I can confirm that it is working properly if I launch the application directly as JAR or bootified WAR with

java -Djasypt.encryptor.password=******************* -jar webapps/demo.war

However if the WAR gets deployed to a tomcat and I add the system property to the tomcat launch then the bug occurrs. I even verified with ps that the system property is really set:

ps aux | grep jasypt | grep -v grep
app     11892  0.5  1.5 3486172 97452 ?       Sl   00:39   3:13 /opt/java/latest8/bin/java -Dnop -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager -Xloggc:logs/gc_log_app_2015-10-15_00-39-10.log -Djava.security.manager -Djava.security.policy=/etc/opt/catalina/app/catalina.policy -Djava.security.debug=failure -Djasypt.encryptor.password=****************** -Djava.awt.headless=true -Dmail.mime.charset=UTF-8 -Djavax.net.ssl.trustStore=/etc/opt/catalina/app/cacerts -Dcatalina.config=file:/etc/opt/catalina/app/catalina.properties -Djava.net.preferIPv4Stack=true -Xms256m -Xmx1024m -Djava.endorsed.dirs=/opt/catalina/latest8/endorsed -classpath /opt/catalina/latest8/bin/bootstrap.jar:/opt/catalina/latest8/bin/tomcat-juli.jar -Dcatalina.base=/home/app -Dcatalina.home=/opt/catalina/latest8 -Djava.io.tmpdir=/home/app/temp org.apache.catalina.startup.Bootstrap -config /etc/opt/catalina/app/server.xml start

Next I will check if that is a general problem so overriding other properties than jasypt ones will work or not. If that also does not work I have found a general "bug" in spring boot when running in tomcat (maybe only in combination with security manager). I will let you know...

ulisesbocchio commented 9 years ago

Alright buddy, I see what the problem is now. How are you passing the properties to tomcat? Yo have some options, but I recommend either use tomcat/conf/catalina.properties or by creating a setenv.sh file in tomcat/bin. Then in setenv.sh you'll do something like this: `export JAVA_OPTS="-Djasypt.encryptor.poolSize=20 -DitemConfig.items[0].name=NEW_NAME -Dsecret.property=UNENCRPYPTED"``

ulisesbocchio commented 9 years ago

I tested passing the password to the jasypt-spring-boot-demo-tomcat-ssl demo app packaging it as a WAR and rewriting SampleTomcatSslApplication with this:

@SpringBootApplication
@EnableEncryptableProperties
public class SampleTomcatSslApplication extends SpringBootServletInitializer {
  public static void main(String[] args) throws Exception {
    System.setProperty("jasypt.encryptor.password", "password");
    SpringApplication.run(SampleTomcatSslApplication.class, args);
  }
  @Override
  protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
    return builder.sources(SampleTomcatSslApplication.class);
  }
}

And I was able to set the password through a system property just fine running tomcat from IntelliJ Idea 13. Under VM options I specified -Djasypt.encryptor.password=password in the run configurations. Internally, IntelliJ is using catalina.sh run and setting environment variable: JAVA_OPTS="-Djasypt.encryptor.password=password". Which is basically one of the two solutions I recommended, and my test confirms it works.

ulisesbocchio commented 9 years ago

Alright, version 1.3 should be in Central soon, I added lazy initialization of the StringEncryptor up until the first encrypted property is decrypted. So in case there are no "ENC(xxxx)" properties not setting any of the required properties won't prevent your application from working.

hohwille commented 9 years ago

I tested passing the password to the jasypt-spring-boot-demo-tomcat-ssl demo app packaging it as a WAR and rewriting SampleTomcatSslApplication with this...

As I said if you run the WAR directly with spring boot there is no problem. The problem only happens when you run a regular tomcat and have the WAR deployed in tomcat/webapps/.

Alright, version 1.3 should be in Central soon, I added lazy initialization of the StringEncryptor...

Awesome. Thanks buddy, that is cool!

hohwille commented 9 years ago

Yo have some options, but I recommend either use tomcat/conf/catalina.properties or by creating a setenv.sh file in tomcat/bin.

For the record I used setenv.sh so that is not the solution.

hohwille commented 9 years ago

Next I will check if that is a general problem so overriding other properties than jasypt ones will work or not. If that also does not work I have found a general "bug" in spring boot when running in tomcat (maybe only in combination with security manager). I will let you know...

I addded this to the config:

JAVA_OPTS="$JAVA_OPTS -Dspring.datasource.url=illegalURL"

Then I started tomcat and got this:

Caused by: java.sql.SQLException: Driver:oracle.jdbc.driver.OracleDriver@38874c24 returned null for URL:illegalURL

So, the default behaviour of spring boot is correct. However setting jasypt.encryptor.password via System-Property does not work when using external tomcat (it seems that it does not even work if there is no default set in application.properties).

ulisesbocchio commented 9 years ago

can you please take a look at at jasypt-spring-boot-demo-tomcat-ssl? I changed the configuration to package it as a WAR. I'm using tomcat tomcat 8.0.9 in Mac. I throw the WAR into $tomcat_home/webapps and the create a file $tomcat_home/bin/setenv.sh with this inside:

export JAVA_OPTS="jasypt.encryptor.password=password

Then, I run tomcat with $tomcat_home/bin/catalina.sh run

You can hit the demo endpoint at http://localhost:8080 to test the decryption. I would really like for you to put a sample project together in Github so I can take a look. From where I stand everything seems to work as expected.

abuabdul commented 7 years ago

Hi @ulisesbocchio just got to know about this wonderful spring boot starter on jasypt. Question is why are we forced to set jasypt.encryptor.password? If I can use a environmentconfig and set the password environment name(not even password) and create my stringencryptor? Really this feels like a restriction on using our custom encryptor.

ulisesbocchio commented 7 years ago

@abuabdul the jasypt.encryptor.password property is only required if you don't provide a custom StringEncryptor. Basically, if you use jasypt-spring-boot out of the box, a StringEncryptor is pre-configured for you, and all you gotta input is the encryption/decryption password.

abuabdul commented 7 years ago

@ulisesbocchio you are correct. I set my custom string encryptor bean, and its working fine now. However i am facing the same issue in the Spring Boot JUnit Tests. Though i have configured the custom bean, it still forcing me to set jasypt.encryptor.password

ulisesbocchio commented 7 years ago

Can you please upload your code to github so I can take a look?

ulisesbocchio commented 7 years ago

@abuabdul Check out this sample project: https://github.com/ulisesbocchio/jasypt-spring-boot-samples/tree/master/jasypt-spring-boot-demo-custom-encryptor Where you can start/test the app with no jasypt.encryptor.password property whatsoever.

abuabdul commented 7 years ago

Hi @ulisesbocchio Thanks for your help. This is where i have hosted my code. https://github.com/B2OPlus/HTMLService. I reverted back to default stringencryptor. Since the way i have structured my code does not allow me to run tests with custom string encryptor (forcing me to set jasypt.encryptor.password for custom string encryptor). Please suggest a solution.

sparkmuse commented 7 years ago

Thanks a lot for this. The custom encryptor fixed all my problems.

In case anyone has issues with this my configuration is as follows:

pom.xml

...
<dependency>
    <groupId>com.github.ulisesbocchio</groupId>
    <artifactId>jasypt-spring-boot-starter</artifactId>
    <version>${jasypt.starter.version}</version>
</dependency>
...

application.yml

jasypt:
  encryptor:
    password: ${APP_ENCRYPTION_PASSWORD}

test: ENC(4DxzpnbrSONISyS4GEtiqQ==)

EncryptorConfig.java

@Configuration
public class EncryptorConfig {

    @Bean
    public static EnvironmentStringPBEConfig environmentVariablesConfiguration() {
        EnvironmentStringPBEConfig config = new EnvironmentStringPBEConfig();
        config.setPasswordEnvName("APP_ENCRYPTION_PASSWORD");
        config.setAlgorithm("PBEWithMD5AndDES");
        config.setKeyObtentionIterations("1000");
        config.setPoolSize("1");
        config.setProviderName("SunJCE");
        config.setSaltGeneratorClassName("org.jasypt.salt.RandomSaltGenerator");
        config.setStringOutputType("base64");
        return config;
    }

    @Bean(name="jasyptStringEncryptor")
    public static PooledPBEStringEncryptor stringEncryptor() {
        PooledPBEStringEncryptor encryptor = new PooledPBEStringEncryptor();
        encryptor.setConfig(environmentVariablesConfiguration());
        return encryptor;
    }
}

TestController.java

@RestController()
public class TestController {

    @Value("${test}")
    private String test;

    @GetMapping("/test")
    public String getTest(){
        return test;
    }
}

Environment variable with the secret export APP_ENCRYPTION_PASSWORD=secretkey

forrestlake commented 6 years ago

Thanks a bunch @fredlo2010 and @ulisesbocchio If I did not find this page, I would have almost abandoned my efforts to try and use jasypt for springboot application. My problem is pretty similar to what was described by @fredlo2010. I am using AWS CodeBuild and CodeCommit to build and deploy my springboot application. All my source code is in GitHub, so AWS CodeBuild pulls the code from GitHub and runs the mvn package and it fails because its unable to decrypt the properties from application.properties. I was finding ways to tell the mvn package how to decrypt the jasypt encrypted passwords. Luckily i found this thread and @fredlo2010 you final comment helped me save a lot of time. Thanks a bunch guyz :)

sparkmuse commented 6 years ago

I am glad I was able to help :)

poornacse commented 6 years ago

I have two place 2 encrypted passwords in application.properties ..how can i do that? How can i maintain 2 different "jasypt.encryptor.algorithm" and "jasypt.encryptor.password" ??

LeenuV commented 5 years ago

Its not work for me.

mzubairahmed commented 4 years ago

Thanks a lot for this. The custom encryptor fixed all my problems.

In case anyone has issues with this my configuration is as follows:

pom.xml

...
<dependency>
  <groupId>com.github.ulisesbocchio</groupId>
  <artifactId>jasypt-spring-boot-starter</artifactId>
  <version>${jasypt.starter.version}</version>
</dependency>
...

application.yml

jasypt:
  encryptor:
    password: ${APP_ENCRYPTION_PASSWORD}

test: ENC(4DxzpnbrSONISyS4GEtiqQ==)

EncryptorConfig.java

@Configuration
public class EncryptorConfig {

  @Bean
  public static EnvironmentStringPBEConfig environmentVariablesConfiguration() {
      EnvironmentStringPBEConfig config = new EnvironmentStringPBEConfig();
      config.setPasswordEnvName("APP_ENCRYPTION_PASSWORD");
        config.setAlgorithm("PBEWithMD5AndDES");
        config.setKeyObtentionIterations("1000");
        config.setPoolSize("1");
        config.setProviderName("SunJCE");
        config.setSaltGeneratorClassName("org.jasypt.salt.RandomSaltGenerator");
        config.setStringOutputType("base64");
      return config;
  }

  @Bean(name="jasyptStringEncryptor")
  public static PooledPBEStringEncryptor stringEncryptor() {
      PooledPBEStringEncryptor encryptor = new PooledPBEStringEncryptor();
      encryptor.setConfig(environmentVariablesConfiguration());
      return encryptor;
  }
}

TestController.java

@RestController()
public class TestController {

  @Value("${test}")
  private String test;

  @GetMapping("/test")
  public String getTest(){
      return test;
  }
}

Environment variable with the secret export APP_ENCRYPTION_PASSWORD=secretkey

Thanks for the efforts, I have following jasypt dependency in my pom: `

org.jasypt jasypt 1.9.2

` Would your code example work with this one?

nicolimo86 commented 4 years ago

For the one that want to test jasypt-spring-boot-demo-tomcat-ssl using the Tomcat docker container: jasypt-spring-boot-demo-tomcat-ssl> mvn clean install docker run -it --rm -p 8080:8080 **--env jasypt.encryptor.password=***** -v $(pwd)/target/jasypt-spring-boot-demo-tomcat-ssl-0.1-SNAPSHOT.war:/usr/local/tomcat/webapps/app.war tomcat:9.0

then browse the webapp at http://localhost:8080/app/

zeeshanwaris commented 4 years ago

I need to encrypt two database passwords at a time.

how can i pass two vm arguments like this -Djasypt.encryptor.password when i am trying to do it , it is giving me error