Spring EnableEncryptableProperties with Jasypt

EnableEncryptableProperties – Jasypt

Spring EnableEncryptableProperties with Jasypt shows an example how to avoid clear text password for database connection’s credentials in properties file. Jasypt means Java simplified encryption. Here I am going to use Spring Boot with Jasypt (Java simplified encryption). Here I am also going to use Spring Data JPA to perform the data layer activities with database.

If you put clear text password in properties file then everybody including people, who should not see password, would gain access to your database and may change database table values, table structure or even may delete data from database table without your consent. So it is always better to put the password in an encrypted format to avoid such unwanted issues.

Jasypt Spring Boot provides Encryption support for property sources in Spring Boot Applications.

There are three ways to integrate Jasypt in your spring boot project:

  • Simply adding the starter jar jasypt-spring-boot-starter to your classpath if you are using @SpringBootApplication or @EnableAutoConfiguration will enable encryptable properties across the entire Spring Environment.
  • Adding jasypt-spring-boot-starter to your classpath and adding @EnableEncryptableProperties to your main Configuration class to enable encryptable properties across the entire Spring Environment.
  • Adding jasypt-spring-boot-starter to your classpath and declaring individual encryptable property sources with @EncrytablePropertySource.

Prerequisites

Java 1.8+/12/19, Gradle 6.5.1 – 6.8.3, Maven 3.6.3/3.8.5, Spring Boot 2.3.1 – 2.4.4/2.7.5/3.1.4, Jasypt 3.0.3/3.0.4/3.0.5

Here I will show you an example by adding jasypt-spring-boot-starter to classpath and adding @EnableEncryptableProperties to Configuration class to enable encryptable properties.

Project Setup

Create gradle or maven based project called spring-jasypt-enableencryptableproperties in your favorite IDE or tool.

For spring boot version 3 you can use the following pom.xml file:

<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>

	<groupId>com.roytuts</groupId>
	<artifactId>spring-jasypt-enableencryptableproperties</artifactId>
	<version>0.0.1-SNAPSHOT</version>

	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<maven.compiler.source>19</maven.compiler.source>
		<maven.compiler.target>19</maven.compiler.target>
	</properties>

	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>3.1.4</version>
	</parent>

	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-data-jpa</artifactId>
		</dependency>

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

		<dependency>
			<groupId>com.mysql</groupId>
			<artifactId>mysql-connector-j</artifactId>
		</dependency>
	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>
</project>

For spring boot version 2 you can use the following build.gradle script or pom.xml file:

Modify your build.gradle script with the following content in order to add required dependencies and configurations.

buildscript {
	ext {
		springBootVersion = '2.3.1.RELEASE' //to 2.4.4
	}
	
    repositories {
    	mavenCentral()
    }
    
    dependencies {
    	classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
    }
}

plugins {
    id 'java-library'
    id 'org.springframework.boot' version "${springBootVersion}"
}

sourceCompatibility = 12
targetCompatibility = 12

repositories {
    mavenCentral()
}

dependencies {
	implementation "org.springframework.boot:spring-boot-starter:${springBootVersion}"
    implementation("org.springframework.boot:spring-boot-starter-data-jpa:${springBootVersion}")
    implementation('com.github.ulisesbocchio:jasypt-spring-boot-starter:3.0.3')
    runtime("mysql:mysql-connector-java:8.0.17") //to 8.0.22
	
	//required for jdk 9 or above
	runtimeOnly('javax.xml.bind:jaxb-api:2.4.0-b180830.0359')
}

For maven based project you can use the following pom.xml file:

<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>

	<groupId>com.roytuts</groupId>
	<artifactId>spring-jasypt-enableencryptableproperties</artifactId>
	<version>0.0.1-SNAPSHOT</version>

	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<maven.compiler.source>12</maven.compiler.source>
		<maven.compiler.target>12</maven.compiler.target>
	</properties>

	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.4.4/2.7.5</version>
	</parent>

	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter</artifactId>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-data-jpa</artifactId>
		</dependency>

		<dependency>
			<groupId>com.github.ulisesbocchio</groupId>
			<artifactId>jasypt-spring-boot-starter</artifactId>
			<version>3.0.3/3.0.4</version>
		</dependency>

		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
		</dependency>

		<!--required only if jdk 9 or higher version is used -->
		<dependency>
			<groupId>javax.xml.bind</groupId>
			<artifactId>jaxb-api</artifactId>
		</dependency>
	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>
</project>

Config File

Create application.properties file under classpath directory src/main/resources with the following content.

In this file I have basically put the MySQL database configurations. You need to change according to your database host, port, service name, username and password or you can use database of your choice.

Here you see I have added ENC() method to let spring know that I am setting encrypted password and it needs to be decrypted while Spring tries to establish the connection with database. This is where the example shows how Spring EnableEncryptableProperties with Jasypt (Java simplified encryption) works.

Now check I have added another line jasypt.encryptor.password=test (you can have other values as per your choice) and it is required to decrypt your encrypted password. This value was used while I encrypted the database password and passed the encrypted password into ENC() method.

Now while spring tries to connect to database, it first decrypts the encrypted password using jasypt.encryptor.password (here the value is ‘test’) and connects to database. If you do not want to keep this jasypt.encryptor.password in application.properties file then you can pass this as VM argument -Djasypt.encryptor.password=test, while you are running the application.

If you want you can encrypt every key/value pair of the application.properties file but only the password field is sensitive so I have encrypted only password here.

By default the Jasypt uses PBEWITHMD5ANDDES algorithm for encrypting/decrypting value before version 3.0.0.

The default encryption/decryption algorithm has changed to PBEWITHHMACSHA512ANDAES_256 from version 3.0.0 of jasypt-spring-boot. So you have to add another line in application.properties file:

jasypt.encryptor.iv-generator-classname=org.jasypt.iv.NoIvGenerator

The complete application.properties file is given below:

spring.datasource.url=jdbc:mysql://localhost/roytuts
spring.datasource.username=root
spring.datasource.password=ENC(ZbkVUeL0Z7/ZbiGV9dh6mA==)
spring.datasource.driverClassName=com.mysql.cj.jdbc.Driver
jasypt.encryptor.algorithm=PBEWithMD5AndDES
jasypt.encryptor.password=test
jasypt.encryptor.iv-generator-classname=org.jasypt.iv.NoIvGenerator

#disable schema generation from Hibernate
spring.jpa.hibernate.ddl-auto=none

Entity Class

Suppose I have a user table that stores all users information and I have the following entity class with the below attributes and corresponding columns in the user table.

I have removed the getters and setters and you can always generate from option in Eclipse.

@Entity
@Table(name = "user")
public class User implements Serializable {
	private static final long serialVersionUID = 1L;

	@Id
	@Column(name = "id")
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	private Integer id;

	@Column(name = "name")
	private String name;

	@Column(name = "email")
	private String email;

	@Column(name = "phone")
	private String phone;

	@Column(name = "address")
	private String address;

	//getters and setters

	@Override
	public String toString() {
		return "User [id=" + id + ", name=" + name + ", email=" + email + ", phone=" + phone + ", address=" + address
				+ "]";
	}

}

Config Class

Note that the following configuration class is required only for spring boot version 2 and you do not need to create this configuration file for spring boot version 3.

I will use annotation based configurations, so I need following configuration class in order to use Spring EnableEncryptableProperties annotation along with DataSource configuration for database.

I am using Spring Data JPA to perform query on database, so I have defined spring beans EntityManagerFactory and DataSource.

I have configured JPA Repositories using annotation EnableJpaRepositories.

I have also let spring know where entity class is kept using factory.setPackagesToScan("com.roytuts.spring.jasypt.enableencryptableproperties.model").

@Configuration
@EnableEncryptableProperties
@EnableJpaRepositories(basePackages = "com.roytuts.spring.jasypt.enableencryptableproperties.repository")
public class Config {

	@Autowired
	private Environment environment;

	@Bean
	public DataSource dataSource() {
		DriverManagerDataSource ds = new DriverManagerDataSource();
		ds.setDriverClassName(environment.getRequiredProperty("spring.datasource.driverClassName"));
		ds.setUrl(environment.getRequiredProperty("spring.datasource.url"));
		ds.setUsername(environment.getRequiredProperty("spring.datasource.username"));
		ds.setPassword(environment.getRequiredProperty("spring.datasource.password"));
		return ds;
	}

	@Bean
	public EntityManagerFactory entityManagerFactory(DataSource dataSource) {
		HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
		vendorAdapter.setDatabase(Database.MYSQL);
		LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
		factory.setJpaVendorAdapter(vendorAdapter);
		factory.setPackagesToScan("com.roytuts.spring.jasypt.enableencryptableproperties.model");
		factory.setDataSource(dataSource);
		factory.afterPropertiesSet();
		return factory.getObject();
	}

}

JPA Repository

Create below JPA repository interface that extends Spring’s JpaRepository interface to get advantages of the Spring’s built-in functionalities.

public interface UserJpaRepository extends JpaRepository<User, Integer> {

}

Service Class

This service class is responsible for fetching data from JPA repository and performing any business logic if required and communicates with controller.

The below service class gets all users from the data layer and process any business logic and finally sends to controller layer.

@Service
public class UserService {

	@Autowired
	private UserJpaRepository repository;

	public List<User> getUserList() {
		return repository.findAll();
	}

}

Spring Boot Main Class

Create below main class to startup the Spring Boot application example Spring EnableEncryptableProperties with Jasypt (Java simplified encryption).

You need to scan the base packages to let spring know where you have put all of your controller, service, repository, entity, configuration classes.

@SpringBootApplication
public class JasyptEnableEncryptablePropertiesApp implements CommandLineRunner {

	@Autowired
	private UserService service;

	public static void main(String[] args) {
		SpringApplication.run(JasyptEnableEncryptablePropertiesApp.class, args);
	}

	@Override
	public void run(String... args) throws Exception {
		System.out.println(service.getUserList());
	}

}

Testing Jasypt

Running the above main class will give you the following output:

[User [id=1, name=Soumitra Roy, email=sroy@gmail.com, phone=2147483647, address=Earth], User [id=2, name=Rahul Kumar, email=rahul@gmail.com, phone=34256780, address=Mars]]

That’s all. Hope you got idea how to use Jasypt (Java simplified encryption) by going through example Spring EnableEncryptableProperties with Jasypt (Java simplified encryption).

Source Code

Download

Leave a Reply

Your email address will not be published. Required fields are marked *