Spring EnableEncryptableProperties with Jasypt

Introduction

Spring EnableEncryptableProperties with Jasypt shows an example how to avoid putting clear text password for database connection’s credentials in properties file. Jasypt means Java simplified encryption. Here we are going to use Spring Boot with Jasypt (Java simplified encryption). Here we are 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 without your consent. So it is always better to put the password in an encrypted format to avoid such unwanted issues.

Here we will create Gradle based Spring Boot application with Spring Data JPA and apply Jasypt (Java simplified encryption) to extra layer of security for your password.

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

Eclipse 2020-06, Java at least 1.8, Gradle 6.5.1, Spring Boot 2.3.1, Jasypt 3.0.3

Example

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.

Setting Up Project

Create Gradle project called SpringBootEncryptablePropertiesJasypt in Eclipse and build the blank project. Your project should build fine.

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

buildscript {
	ext {
		springBootVersion = '2.3.1.RELEASE'
	}
	
    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")
	
	//required for jdk 9 or above
	runtimeOnly('javax.xml.bind:jaxb-api:2.4.0-b180830.0359')
}

Creating Config File

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

In this file we 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 we have added ENC() method to let spring know that we are 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 we 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 we 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 we 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 we have a user table that stores all users information and we 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.

package com.roytuts.spring.jasypt.enableencryptableproperties.model;

import java.io.Serializable;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

@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

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

We are using Spring Data JPA to perform query on database, so we have defined spring beans EntityManagerFactory and DataSource.

We have configured JPA Repositories using annotation EnableJpaRepositories.

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

package com.roytuts.spring.jasypt.enableencryptableproperties.config;

import javax.persistence.EntityManagerFactory;
import javax.sql.DataSource;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.vendor.Database;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;

import com.ulisesbocchio.jasyptspringboot.annotation.EnableEncryptableProperties;

@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.

package com.roytuts.spring.jasypt.enableencryptableproperties.repository;

import org.springframework.data.jpa.repository.JpaRepository;

import com.roytuts.spring.jasypt.enableencryptableproperties.model.User;

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.

package com.roytuts.spring.jasypt.enableencryptableproperties.service;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.roytuts.spring.jasypt.enableencryptableproperties.model.User;
import com.roytuts.spring.jasypt.enableencryptableproperties.repository.UserJpaRepository;

@Service
public class UserService {

	@Autowired
	private UserJpaRepository repository;

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

}

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.

package com.roytuts.spring.jasypt.enableencryptableproperties;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

import com.roytuts.spring.jasypt.enableencryptableproperties.service.UserService;

@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 the Application

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

[User [id=1, name=Soumitra Roy, [email protected], phone=2147483647, address=Earth], User [id=2, name=Rahul Kumar, [email protected], 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

Thanks for reading.

Related posts

Leave a Comment