How to encrypt passwords in a Spring Boot project using Jasypt
Welcome, in this tutorial, we will learn how to encrypt passwords in a Spring Boot project using Jasypt. We will see how to secure the file-sensitive information in a spring boot application using the Jasypt dependency.
1. Introduction
Before going further in this tutorial, we will look at the common terminology such as introduction to Spring Boot, Jaspypt, and Lombok.
1.1 Spring Boot
- Spring boot is a module that provides rapid application development feature to the spring framework including auto-configuration, standalone-code, and production-ready code
- It creates applications that are packaged as jar and are directly started using embedded servlet containers (such as Tomcat, Jetty or, Undertow). Thus, no need to deploy the war files
- It simplifies the maven configuration by providing the starter template and helps to resolve the dependency conflicts. It automatically identifies the required dependencies and imports them into the application
- It helps in removing the boilerplate code, extra annotations, and xml configurations
- It provides powerful batch processing and manages the rest endpoints
- It provides an efficient jpa-starter library to effectively connect the application with the relational databases
- It offers a Microservice architecture and cloud configuration that manages all the application related configuration properties in a centralized manner
1.2 Jasypt
- Jasypt stands for Java simplified encryption which is high security and high-performance encryption library to encrypt the sensitive information
- Provides the standard encryption techniques for encryption the passwords, texts, etc
1.3 Lombok
- Lombok is nothing but a small library that reduces the amount of boilerplate Java code from the project
- Automatically generates the getters and setters for the object by using the Lombok annotations
- Hooks in via the Annotation processor API
- Raw source code is passed to Lombok for code generation before the Java Compiler continues. Thus, produces properly compiled Java code in conjunction with the Java Compiler
- Under the
target/classes
folder you can view the compiled class files - Can be used with Maven, Gradle IDE, etc.
1.3.1 Lombok features
Feature | Details |
---|---|
val | Local variables are declared as final |
var | Mutable local variables |
@Slf4J | Creates an SLF4J logger |
@Cleanup | Will call close() on the resource in the finally block |
@Getter | Creates getter methods for all properties |
@Setter | Creates setter for all non-final properties |
@EqualsAndHashCode |
|
@ToString |
|
@NoArgsConstructor |
|
@RequiredArgsContructor |
|
@AllArgsConstructor |
|
@Data |
|
@Builder |
|
@Value |
|
Let us go ahead with the tutorial implementation but before going any further I’m assuming that you’re aware of the Spring boot basics.
2. How to encrypt passwords in a Spring Boot project using Jasypt?
2.1 Tools Used for Spring boot application and Project Structure
We are using Eclipse Kepler SR2, JDK 8, and Maven. In case you’re confused about where you should create the corresponding files or folder, let us review the project structure of the spring boot application.
Let us start building the application!
3. Creating a Spring Boot application
Below are the steps involved in developing the application.
3.1 Maven Dependency
Here, we specify the dependency for the Spring boot (Web and JPA, Spring doc Open API (for swagger interface)), H2 database, Java Faker (to generate the dummy data), Lombok, and Jasypt Spring boot stater. The updated file will have the following code.
pom.xml
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.4.3</version> <relativePath /> <!-- lookup parent from repository --> </parent> <groupId>com.springboot.jasypt</groupId> <artifactId>SpringbootPwdEncryptionUsingJasypt</artifactId> <version>0.0.1-SNAPSHOT</version> <name>SpringbootPwdEncryptionUsingJasypt</name> <description>Pwd encryption in springboot using jasypt</description> <properties> <java.version>1.8</java.version> <jasypt.version>3.0.3</jasypt.version> <javafaker.version>1.0.2</javafaker.version> <spingdoc.openapi.version>1.5.5</spingdoc.openapi.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>com.github.ulisesbocchio</groupId> <artifactId>jasypt-spring-boot-starter</artifactId> <version>${jasypt.version}</version> </dependency> <dependency> <groupId>com.github.javafaker</groupId> <artifactId>javafaker</artifactId> <version>${javafaker.version}</version> </dependency> <dependency> <groupId>org.springdoc</groupId> <artifactId>springdoc-openapi-ui</artifactId> <version>${spingdoc.openapi.version}</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <scope>runtime</scope> <optional>true</optional> </dependency> <dependency> <groupId>com.h2database</groupId> <artifactId>h2</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <configuration> <excludes> <exclude> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </exclude> </excludes> </configuration> </plugin> <plugin> <groupId>com.github.ulisesbocchio</groupId> <artifactId>jasypt-maven-plugin</artifactId> <version>${jasypt.version}</version> </plugin> </plugins> </build> </project>
3.2 Application XML file
Create a new YML file at the location: SpringbootPwdEncryptionUsingJasypt/src/main/resources/
and add the following code where we will define –
- The h2 database connection (such as username, password, and url) and hibernate details.
- The specified username and password is encrypted using the jasypt encryption algorithm defined in the
jcg.jasypt.pwd.generator.EncryptDecryptPwd.java
class - In this tutorial, we are using the database username and password as –
product
andpassword!234#
respectively
- The specified username and password is encrypted using the jasypt encryption algorithm defined in the
- The h2 console details will be accessible at the following URL –
http://localhost:10091/h2-console
in the browser - The Swagger UI path will be accessible at the following URL –
http://localhost:10091/swagger-ui-custom.html
in the browser
You’re free to change the application or the database details as per your wish.
application.yml
server: port: 10091 spring: application: name: springboot-pwd-encryption-using-jasypt datasource: driverClassName: org.h2.Driver password: ENC(G8MWNiqA7QJc6AIcfOL0zvje17vMGaBN) url: 'jdbc:h2:mem:testdb' username: ENC(9Y6SF/ht5/CaU7v8o1WyQQ==) h2: console: enabled: true path: /h2-console jpa: database-platform: org.hibernate.dialect.H2Dialect hibernate: ddl-auto: create-drop properties: hibernate: show_sql: true springdoc: swagger-ui: path: /swagger-ui-custom.html
3.3 Java Classes
Let us write the important java class(es) involved in this application. For brevity, we will skip the following classes –
Product.java
– Entity class that will be persisted in the databaseProductRepository.java
– Repository interface that extends theJpaRepository
interface to perform the SQL operations. The interface also contains a custom method to fetch the product by its reference idProductService.java
– Service class that interact with the DAO layer methodsDefaultProductsLoader.java
– Bootstrap class to populate dummy data to the h2 database once the application is started successfullyFakerConfig.java
– Configuration class to define the Faker bean
3.3.1 Implementation/Main class
Add the following code to the main class to bootstrap the application from the main method. Always remember, the entry point of the spring boot application is the class containing @SpringBootApplication
annotation and the static main method.
SpringbootPwdEncryptionUsingJasyptApplication.java
package com.springboot.jasypt; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import com.ulisesbocchio.jasyptspringboot.annotation.EnableEncryptableProperties; import lombok.extern.slf4j.Slf4j; //lombok annotation @Slf4j //spring annotation @SpringBootApplication //spring jasypt annotation //helps to make the application understand the encryptable properties //across the environment @EnableEncryptableProperties public class SpringbootPwdEncryptionUsingJasyptApplication { public static void main(String[] args) { SpringApplication.run(SpringbootPwdEncryptionUsingJasyptApplication.class, args); log.info("springboot and pwd encryption jasypt application started successfully."); } }
3.3.2 Jasypt Configuration class
Add the following code to the jasypt configuration class where we will define the custom encryptor for the application. The custom encryptor will override the default configuration. The encryptor method will also be used to encrypt the sensitive information using the encryptor’s private key.
JasyptConfig.java
package com.springboot.jasypt.config; import org.jasypt.encryption.StringEncryptor; import org.jasypt.encryption.pbe.PooledPBEStringEncryptor; import org.jasypt.encryption.pbe.config.SimpleStringPBEConfig; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; //spring annotation @Configuration public class JasyptConfig { //common method //used in classes - JasyptConfig.java and EncryptDecryptPwd.java public static SimpleStringPBEConfig getSimpleStringPBEConfig() { final SimpleStringPBEConfig pbeConfig = new SimpleStringPBEConfig(); //can be picked via the environment variablee //TODO - hardcoding to be removed pbeConfig.setPassword("javacodegeek"); //encryptor private key pbeConfig.setAlgorithm("PBEWithMD5AndDES"); pbeConfig.setKeyObtentionIterations("1000"); pbeConfig.setPoolSize("1"); pbeConfig.setProviderName("SunJCE"); pbeConfig.setSaltGeneratorClassName("org.jasypt.salt.RandomSaltGenerator"); pbeConfig.setStringOutputType("base64"); return pbeConfig; } @Bean(name = "jasyptStringEncryptor") public StringEncryptor encryptor() { final PooledPBEStringEncryptor pbeStringEncryptor = new PooledPBEStringEncryptor(); pbeStringEncryptor.setConfig(getSimpleStringPBEConfig()); return pbeStringEncryptor; } }
3.3.3 Controller class
Add the following code to the controller class to specify the different endpoints. The controller methods are annotated with the HTTP GET mapping annotation.
ProductsController.java
package com.springboot.jasypt.controller; import com.springboot.jasypt.model.Product; import com.springboot.jasypt.service.ProductService; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.responses.ApiResponse; import io.swagger.v3.oas.annotations.tags.Tag; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.*; import java.util.List; import java.util.UUID; //NOTE - We are not mapping the Product entity with a Product response dto //you are free to map the Product entity with a Product response dto to //avoid the id in the response //spring annotations @RestController @RequestMapping("/api") //swagger annotation @Tag(name = "Product resource REST endpoints", description = "Shows the product info") public class ProductsController { @Autowired private ProductService service; //swagger annotations @Operation(summary = "Return product list") @ApiResponse(responseCode = "200", description = "The request has succeeded") //spring annotations @GetMapping("/products") @ResponseStatus(HttpStatus.OK) public List<Product> getProducts() { return service.getProducts(); } //swagger annotations @Operation(summary = "Return product by reference id") @ApiResponse(responseCode = "200", description = "The request has succeeded") //spring annotations //NOTE - we are only considering the happy path. //you are free to add the failure case where if product not found //throw an NotFoundException and return HTTP 404 error response //code @GetMapping("/product/{refId}") @ResponseStatus(HttpStatus.OK) public Product getProduct(@PathVariable("refId") final UUID refId) { return service.getProduct(refId); } }
3.4 Encryption/Decryption class
To generate an encrypted key we will use the SimpleStringPBEConfig
specified in the JasyptConfig.java
class.
- We will pass the plain string to the
encrypt(…)
method to generate an encrypted key - In this tutorial, we are using the database username and password as –
product
andpassword!234#
respectively and we’ll encrypt them - Make note that this is class is kept out of the spring scope and this is defined in a different package and can run like a simple java application
EncryptDecryptPwd.java
package jcg.jasypt.pwd.generator; import com.springboot.jasypt.config.JasyptConfig; import lombok.extern.slf4j.Slf4j; import org.jasypt.encryption.pbe.PooledPBEStringEncryptor; import org.jasypt.encryption.pbe.config.SimpleStringPBEConfig; @Slf4j public class EncryptDecryptPwd { private static final String DB_USERNAME = "product"; private static final String DB_PWD = "password!234#"; public static void main(String[] args) { encryptKey(DB_USERNAME); encryptKey(DB_PWD); // decryptKey("9Y6SF/ht5/CaU7v8o1WyQQ=="); // decryptKey("G8MWNiqA7QJc6AIcfOL0zvje17vMGaBN"); } //encrypt the plan text private static void encryptKey(final String plainKey) { final SimpleStringPBEConfig pbeConfig = JasyptConfig.getSimpleStringPBEConfig(); final PooledPBEStringEncryptor pbeStringEncryptor = new PooledPBEStringEncryptor(); pbeStringEncryptor.setConfig(pbeConfig); log.info("Encrypted key = {}", pbeStringEncryptor.encrypt(plainKey)); } //decrypt the encrypted text private static void decryptKey(final String encryptedKey) { final SimpleStringPBEConfig pbeConfig = JasyptConfig.getSimpleStringPBEConfig(); final PooledPBEStringEncryptor pbeStringEncryptor = new PooledPBEStringEncryptor(); pbeStringEncryptor.setConfig(pbeConfig); log.info("Decrypted key = {}", pbeStringEncryptor.decrypt(encryptedKey)); } }
4. Run the Application
To execute the application, right-click on the SpringbootPwdEncryptionUsingJasyptApplication.java
class, Run As -> Java Application
.
5. Project Demo
When the application is started, open the Postman tool to hit the application endpoints. You are free to choose any tool of your choice and for this tutorial, we will use the spring swagger interface (accessible at the following URL – http://localhost:10091/swagger-ui-custom.html
).
Application endpoints
-- HTTP GET endpoints – //Endpoint name – Get all products //URL :: http://localhost:10091/api/products //Endpoint name – Get product by ref id //URL :: http://localhost:10091/api/product/cba49238-dfca-47c7-8fa4-2584951ba8a2
That is all for this tutorial and I hope the article served you whatever you were looking for. Happy Learning and do not forget to share!
6. Summary
In this section, you learned:
- Spring boot and Jasypt introduction
- Steps to implement jasypt password encryption in a spring boot application
You can download the sample application as an Eclipse project in the Downloads section.
7. Download the Project
This was an example to implement jasypt password encryption in a spring boot application.
You can download the full source code of this example here: How to encrypt passwords in a Spring Boot project using Jasypt