Showing posts with label Spring Security. Show all posts
Showing posts with label Spring Security. Show all posts

Saturday, February 11, 2023

Spring Boot: Secure your application with JDBC-Based Authentication

spring framework,spring boot,java,hibernate,spring security,programming,software development,technology
The previous Spring Security tutorial taught us to configure JDBC authentication using the Spring Security recommended database table. The Spring Security Framework is so flexible that we can use our custom database table for JDBC authentication. So in this tutorial, we connect our custom database table with Spring Security for JDBC authentication.


👉 First, we will create a registration service through which we can create a new student. Then configure the student database table for JDBC authentication.

POM.XML

The Spring Boot project's pom.xml is shown below:
<?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.7.7</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>
	<groupId>com.raven</groupId>
	<artifactId>spring-boot-security-authorization-custom-table</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>spring-boot-security-authorization-custom-table</name>
	<description>Spring Boot project to manage user in custom table in Spring Security</description>
	<properties>
		<java.version>11</java.version>
	</properties>
	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-data-jdbc</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-security</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-devtools</artifactId>
			<scope>runtime</scope>
			<optional>true</optional>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-data-jpa</artifactId>
		</dependency>
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<version>8.0.29</version>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
		<dependency>
			<groupId>org.springframework.security</groupId>
			<artifactId>spring-security-test</artifactId>
			<scope>test</scope>
		</dependency>
	</dependencies>

	<build>
		<finalName>spring-boot-security-with-custom-table</finalName>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>

</project>
Spring Boot version 2.7.6 is what we use. This version of Spring Boot, Spring Framework, and Spring Security is 5.3.24 and 5.7.5, respectively. To implement Spring Security in this application, we have added the spring-boot-starter-security dependency.

Entity

Create a model package under the root package. Create the Student entity within this model package:
package com.raven.springbootsecurityauthorizationcustomtable.model;
import javax.persistence.*;

@Entity
@Table(name = "STUDENT")
public class Student {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private long id;

    @Column(name = "full_name", length = 50)
    private String fullName;

    @Column(name = "phone", length = 15)
    private String phone;

    @Column(name = "email", length = 60)
    private String email;

    @Column(name = "pwd", length = 200)
    private String pwd;

    @Column(name = "role", length = 40)
    private String role;

    public Student() {
    }

    public Student(String fullName, String phone, String email, String pwd, String role) {
        this.fullName = fullName;
        this.phone = phone;
        this.email = email;
        this.pwd = pwd;
        this.role = role;
    }

    public long getId() { return id;}

    public String getFullName() { return fullName; }

    public void setFullName(String fullName) { this.fullName = fullName; }

    public String getPhone() { return phone; }

    public void setPhone(String phone) { this.phone = phone; }

    public String getEmail() { return email;}

    public void setEmail(String email) { this.email = email; }

    public String getPwd() { return pwd; }

    public void setPwd(String pwd) { this.pwd = pwd;}

    public String getRole() { return role; }

    public void setRole(String role) { this.role = role; }

    @Override
    public String toString() {
        return "Student{" +
                "id=" + id +
                ", fullName='" + fullName + '\'' +
                ", phone='" + phone + '\'' +
                ", email='" + email + '\'' +
                ", pwd='" + pwd + '\'' +
                ", role='" + role + '\'' +
                '}';
    }
}
So by leveraging the Spring Data JPA Framework, we are creating a database table of the name STUDENT. We use this database table later to configure JDBC authentication. Before that, we will develop a service to save new student details with encrypted credentials.
...
...

You can download the source code from here.
Happy coding!!! 😊
in

Saturday, January 07, 2023

Spring Security: Manage User In Memory and Database

spring framework,spring boot,java,spring security,programming,software development,technology
We configured a static user in the application.properties file in the previous Spring Security tutorial. In reality, however, we must configure a web application so that it can be accessed by multiple users. In this section, we'll look at how to set up multiple users in a Spring Boot web application using the Spring Security Framework.

So, first, we'll create a simple Spring Boot MVC Web application, and then we'll add Spring Security to it.

POM.XML

The Spring Boot project's pom.xml is shown below:
<?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.7.7</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>
	<groupId>com.raven</groupId>
	<artifactId>spring-boot-security-user-management</artifactId>
	<version>1.0.0-SNAPSHOT</version>
	<name>spring-boot-security-user-management</name>
	<description>Spring Boot project to manage user in Spring Security</description>
	<properties>
		<java.version>11</java.version>
	</properties>
	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-security</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-devtools</artifactId>
			<scope>runtime</scope>
			<optional>true</optional>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-jdbc</artifactId>
		</dependency>
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<version>8.0.29</version>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-data-jpa</artifactId>
		</dependency>

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

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

</project>
Spring Boot version 2.7.6 is what we use. This version of Spring Boot, Spring Framework, and Spring Security is 5.3.24 and 5.7.5, respectively. To implement Spring Security in this application, we have added the spring-boot-starter-security dependency.

Controller

Create a package of name controller within the root package. Create two controller classes within this package: WelcomeController and UserController.

The following is a code snippet from the WelcomeController class:
package com.raven.springbootsecurityusermanagement.controller;
// imports are omitted

@RestController
public class WelcomeController {

    @GetMapping("/welcome")
    public String welcome() {
        return "Available courses:" +
                "<ul>" +
                "<li>Learn JAVA : Beginner to Master</li>" +
                "<li>Full Stack JAVA Developer</li>" +
                "<li>Microservices with Spring Boot</li>" +
                "<li>Complete Web Development</li>" +
                "<li>Wordpress for Beginner</li>" +
                "<li>Complete Python Development</li>" +
                "<li>Docker guide : Beginner to Master</li>" +
                "<li>Node.js : Ultimate guide</li>" +
                "</ul>";
    }
}
This class is annotated with @RestController, which tells the Spring Container that it will be used for a REST-based service. The Spring Container is informed by the @GetMapping annotation that the HTTP endpoint /welcome is exposed as a REST service. As a result, when we call this HTTP endpoint from another application or a browser, the welcome() method is invoked.

Here is a code snippet for the UserController class:
package com.raven.springbootsecurityusermanagement.controller;
// imports are omitted

@RestController
public class UserController {

    @GetMapping("/myCourses")
    public String myCourses() {
        return "Enrolled courses:" +
                "<ul>" +
                "<li>Full Stack JAVA Developer (85% done)</li>" +
                "<li>Microservices with Spring Boot (55 % done)</li>" +
                "<li>Docker guide : Beginner to Master (65% done)</li>" +
                "</ul>";
    }
}
This class is also annotated with @RestController and has exposed another HTTP endpoint - /myCourses.

To manage users, Spring Security Framework provides classes such as InMemoryUserDetailsManager, JdbcUserDetailsManager, and LdapUserDetailsManager. These classes can be used to manage users in a variety of situations, such as in memory while the Spring Boot application is running, in the database, or when retrieving user information from LDAP servers.

User Management In Memory

Create another package of name configuration package under the root package. Create a class called SecurityConfiguration inside the configuration package and update it with the following code:
package com.raven.springbootsecurityusermanagement.configuration;
// imports are omitted

@Configuration
public class SecurityConfiguration {
    @Bean
    SecurityFilterChain securityFilterChain(HttpSecurity httpSecurity) throws Exception {
        httpSecurity.authorizeHttpRequests()
                .antMatchers("/myCourses").authenticated()
                .antMatchers("/welcome").permitAll()
                .and().formLogin()
                .and().httpBasic();
        return httpSecurity.build();
    }

    @Bean
    public InMemoryUserDetailsManager configureUsers() {
        UserDetails adminUser = User.withDefaultPasswordEncoder()
                .username("admin")
                .password("admin@321")
                .authorities("admin")
                .build();

        UserDetails normalUser = User.withDefaultPasswordEncoder()
                .username("normal")
                .password("normal@321")
                .authorities("read")
                .build();

        return new InMemoryUserDetailsManager(adminUser, normalUser);
    }
}
We configured the endpoints that need to be secured in the securityFilterChain() method, while others will remain open to all. In the configureUsers() method, we've set up a number of users who can access the secured endpoints.

UserDetails is an interface in the Spring Security Framework. This interface includes abstract methods such as getUsername() and getPassword(). Spring Security also includes a sample implementation class for this interface called User. We can create new users by using the User class. After creating a new object of the class User, we can use the getUsername() method to retrieve the username or the getAuthorities() method to retrieve the authority (role). The UserDetails interface and User class are used in InMemoryUserDetailsManager, JdbcUserDetailsManager, UserDetailsService, and so on.

To create in-memory users, we define a bean of type InMemoryUserDetailsManager. We created two different users by passing credentials and authorities (roles) to the User class. Because we are using plain text as the password, there will be no encoding or hashing, so we have used withDefaultPasswordEncoder(). In the return statement, we passed the user details objects to the constructor of the InMemoryUserDetailsManager class. Then, using the User class, the InMemoryUserDetailsManager will create those users.  

Start the application and try to connect to the endpoints. You can see that the /welcome endpoint does not require authentication, and you can access the /myCourses endpoint using the credentials specified above.

User Management with Database

First, we must create two tables in the database to store and retrieve user details for the Jdbc type of authentication. The SQL script is as follows:
CREATE DATABASE IF NOT EXISTS `spring_security_db`;
USE `spring_security_db`;

CREATE TABLE
  `users` (
    `id` int(11) NOT NULL AUTO_INCREMENT,
    `username` varchar(45) NOT NULL,
    `password` varchar(45) NOT NULL,
    `enabled` int(11) NOT NULL,
    PRIMARY KEY (`id`));
    
INSERT INTO users(username,password,enabled) VALUES ('john', 'john123', '1');

CREATE TABLE
  `authorities` (
    `id` int(11) NOT NULL AUTO_INCREMENT,
    `username` varchar(45) NOT NULL,
    `authority` varchar(45) NOT NULL,
    PRIMARY KEY (`id`));
INSERT INTO authorities(username,authority) VALUES ('john', 'write');

Update our application's SecurityConfiguration class with the following code snippet to enable JDBC authentication:
package com.raven.springbootsecurityusermanagement.configuration;
// imports are omitted

@Configuration
public class SecurityConfiguration {
    @Bean
    SecurityFilterChain securityFilterChain(HttpSecurity httpSecurity) throws Exception {
        httpSecurity.authorizeHttpRequests()
                .antMatchers("/myCourses").authenticated()
                .antMatchers("/welcome").permitAll()
                .and().formLogin()
                .and().httpBasic();
        return httpSecurity.build();
    }

    @Bean
    public JdbcUserDetailsManager userDetailsManager(DataSource dataSource) {
        return new JdbcUserDetailsManager(dataSource);
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return NoOpPasswordEncoder.getInstance();
    }
}
For Jdbc authentication, we've created a bean of type JdbcUserDetailsManager, just like we did for in-memory user management. The data source object is passed to the userDetailsManager() method. We've added a MySQL-related dependency to our classpath, and there are database-related properties in the application.properties file. Spring Boot will automatically configure the data source object within this application based on the application.properties file. The JdbcUserDetailsManager will now use this data source object.

You may have noticed that we define a bean of the type PasswordEncoder. It is best practice to inform Spring Security about how we store passwords in the database. For the sake of simplicity, we keep the passwords in the database as plain text, which is why we used NoOpPasswordEncoder. Spring Security will be notified that our passwords are in plain text format.

Restart the application and try to connect to the endpoints again. You can use the above-configured database credentials to access the /myCourses endpoint.

Because UserDetailsService and JdbcUserDetailsManager have a parent-child relationship, you can also create a bean of the type UserDetailsService instead of JdbcUserDetailsManager.


The source code is available for download here.
Happy coding!!! 😊
in

Wednesday, December 28, 2022

Spring Boot Security: Using SecurityFilterChain

spring framework,spring boot,java,spring security,programming,software development,technology
The goal of this tutorial is to show you how to use SecurityFilterChain to implement Spring Security in a Spring Boot web application.

To secure data and business logic, security is essential for any type of web application. We can secure our web pages and REST APIs with the Spring Security Framework and apply for roles with minimal configuration. We can also employ the Spring Security Framework to protect our Spring Boot applications from security flaws like CSRF and CORS.


So, first, we'll build a simple Spring Boot MVC Web application, and then we'll add Spring Security to it.

POM.XML

The Spring Boot project's pom.xml is shown below:
<?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.7.6</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>
	<groupId>com.raven</groupId>
	<artifactId>spring-boot-security-basic</artifactId>
	<version>1.0.0-SNAPSHOT</version>
	<name>spring-boot-security-basic</name>
	<description>Spring Boot  project to implement Security</description>
	<properties>
		<java.version>11</java.version>
	</properties>
	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-security</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-devtools</artifactId>
			<scope>runtime</scope>
			<optional>true</optional>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
		<dependency>
			<groupId>org.springframework.security</groupId>
			<artifactId>spring-security-test</artifactId>
			<scope>test</scope>
		</dependency>
	</dependencies>

	<build>
		<finalName>spring-boot-security-basic</finalName>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>

</project>
Spring Boot version 2.7.6 is what we use. This version of Spring Boot, Spring Framework, and Spring Security is 5.3.24 and 5.7.5, respectively. We have added the spring-boot-starter-security dependency to implement Spring Security in this application.

Controller

Create a package of name controller within the root package. Create two controller classes within this package: WelcomeController and UserController.

The following is a code snippet from the WelcomeController class:
package com.raven.springbootsecuritybasic.controller;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class WelcomeController {
	@GetMapping("/welcome")
	public String welcome() {
		return "Available courses:" +
				"<ul>" +
				"<li>Learn JAVA : Beginner to Master</li>" +
				"<li>Full Stack JAVA Developer</li>" +
				"<li>Microservices with Spring Boot</li>" +
				"<li>Complete Web Development</li>" +
				"<li>Wordpress for Beginner</li>" +
				"<li>Complete Python Development</li>" +
				"<li>Docker guide : Beginner to Master</li>" +
				"<li>Node.js : Ultimate guide</li>" +
				"</ul>";
	}
}
This class is annotated with @RestController, which tells the Spring Container that it will be used for a REST-based service. The Spring Container is informed by the @GetMapping annotation that the HTTP endpoint /welcome is exposed as a REST service. As a result, when we call this HTTP endpoint from another application or a browser, the welcome() method is invoked.

Here is a code snippet for the UserController class:
package com.raven.springbootsecuritybasic.controller;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class UserController {

	@GetMapping("/myCourses")
	public String myCourses() {
		return "Enrolled courses:" +
				"<ul>" +
				"<li>Full Stack JAVA Developer (85% done)</li>" +
				"<li>Microservices with Spring Boot (55 % done)</li>" +
				"<li>Docker guide : Beginner to Master (65% done)</li>" +
				"</ul>";
	}
}
This class is also annotated with @RestController and has exposed another HTTP endpoint - /myCourses.

The Magic

Run this application now. We'll call /welcome from the browser, so type http://localhost:8080/welcome into your browser. We are automatically redirected to a login page, as you can see. However, we have not created any login pages or written any Java code related to login.

This is one of the Spring Security Framework's out-of-the-box capabilities. Because we added spring-boot-starter-security as a dependency within our application, Spring Security Framework will secure all of our web applications by default. Anyone attempting to access this application's REST services will be prompted for credentials.

The question now is what my username and password are. Don't be concerned. The solution has been provided by Spring Security. The default username is user, and the password can be found in the console of your IDE (Eclipse/STS/IntelliJ/Visual Studio Code). After entering your username and password, simply click the "Sign in" button to be redirected to /welcome. When we run our other endpoint /myCourses, Spring Security will not prompt us to log in. Because Spring Security validates us based on a session id.

👉 But there is one problem with this approach: every time we restart our application, Spring Security generates a new password. To overcome this, we can configure a static username and password within our application.

Static Credentials

In the application.properties file, we can define our own username and password. Make the following changes to the application.properties file:
spring.security.user.name = admin
spring.security.user.password = admin*%#4321

Restart the application, and we can now log in with the aforementioned username and password. If you look at the IDE console, you'll notice that Spring Security doesn't generate a password for the username because we changed the default username and password in the application.properties file.

👉 By default, the Spring Security Framework will secure all of the endpoints defined in our application. If we change the requirement, we want to secure only the /myCourses endpoint, while the /welcome endpoint is open to all without authentication. To meet this requirement, we must customize our application's security configurations.

Custom Security Configuration

The Spring Security version for this application is 5.7.5. Before the 5.7 version, we used the WebSecurityConfigurerAdapter class to implement custom security configuration by overriding its configure method in our application. Spring deprecates the WebSecurityConfigureAdapter class beginning with version 5.7.

👉 To define custom security requirements for Spring Boot applications, we must use the component or bean style as of Spring Security 5.7. A class called SpringBootWebSecurityConfiguration exists within the Spring Security Framework. This class is primarily accountable for the Spring Security Framework's default security configuration. This class includes a SecurityFilterChain method called defaultSecurityFilterChain(HttpSecurity http).

To create our own SecurityFilterChain, we must override defaultSecurityFilterChain(HttpSecurity http) in our application.

Create another package of name configuration package under the root package. Create a class called SecurityConfiguration inside the configuration package and update it with the following code:
package com.raven.springbootsecuritybasic.configuration;
// imports are omitted

@Configuration
public class SecurityConfiguration {

    @Bean
    SecurityFilterChain securityFilterChain(HttpSecurity httpSecurity) throws Exception {
        httpSecurity.authorizeHttpRequests().anyRequest().authenticated();
        httpSecurity.formLogin();
        httpSecurity.httpBasic();

        return httpSecurity.build();
    }
}
We must annotate this class with @Configuration so that Spring Framework recognizes it as a configuration class, and the IoC container will automatically create all of the beans that we have defined within it when we run this application.

You can rename the method defaultSecurityFilterChain to whatever you want. Spring Security will authenticate any request that comes to this application, according to the first line of this method. As a result, when we attempted to access the application's endpoints, Spring Security redirected us to the login page. Then it returns a SecurityFilterChain bean.


When we restart the application and try to access both endpoints: /welcome and /myCourses, we see that you must enter your credentials in both cases. So we've secured every endpoint. But we want some endpoints to be secure while others can be accessed without a username and password. Update the defaultSecurityFilterChain method with the following code snippet to meet the requirement:
package com.raven.springbootsecuritybasic.configuration;
// imports are omitted

@Configuration
public class SecurityConfiguration {
    @Bean
    SecurityFilterChain securityFilterChain(HttpSecurity httpSecurity) throws Exception {
        httpSecurity.authorizeHttpRequests()
                .antMatchers("/myCourses").authenticated()
                .antMatchers("/welcome").permitAll()
                .and().formLogin()
                .and().httpBasic();
        return httpSecurity.build();
    }
}
We mentioned our endpoints in the antMatchers() method. What exactly are antMatchers? It is an Ant-style path pattern implementation. A portion of this mapping code was graciously borrowed from Apache Ant. So we can pass multiple paths, which means multiple endpoints, inside the antMatchers() method. It tells Spring Security to configure httpSecurity based on the endpoints.    

So, in the first antMatchers, we mentioned the endpoint /myCourses and called the authenticated() method, indicating that the /myCourses endpoint will be secured by Spring Security. We specified the endpoint /welcome and invoked a method called permitAll() in the following antMatchers, so Spring Security will no longer authenticate this REST service, and anyone can access it.

Restart the application and try to connect to the endpoints again. You can see that the /welcome endpoint does not require authentication, but you must enter the credentials to access the /myCourses endpoint. This also meets our criteria.


👉 We now want to be able to access all of our application's endpoints without the need for authentication. To accomplish this, add the following code snippet to the defaultSecurityFilterChain() method:
package com.raven.springbootsecuritybasic.configuration;
// imports are omitted

@Configuration
public class SecurityConfiguration {

    @Bean
    SecurityFilterChain securityFilterChain(HttpSecurity httpSecurity) throws Exception {
        httpSecurity.authorizeHttpRequests()
                .anyRequest().permitAll()
                .and().formLogin()
                .and().httpBasic();
        return httpSecurity.build();
    }
}
We've used the permitAll() method on anyRequest(), as you can see. As a result, Spring Security will no longer authenticate requests to the application.


👉 Similarly, if we use anyRequest() to invoke the denyAll() method, all of our application's endpoints will be inaccessible:
package com.raven.springbootsecuritybasic.configuration;
// imports are omitted

@Configuration
public class SecurityConfiguration {

    @Bean
    SecurityFilterChain securityFilterChain(HttpSecurity httpSecurity) throws Exception {
        httpSecurity
          .authorizeHttpRequests()
                .anyRequest().denyAll();
                
        return httpSecurity.build();
    }
}
If you try to access /welcome or /myCourses now, you will receive a 403 error, indicating that you do not have the authorization to view these pages.

The source code is available for download here.
Happy coding!!! 😊
in


Tuesday, September 20, 2022

Spring Security With Jdbc Authentication Using JAVA Configuration

JAVA,Dispatcher Servlet,Spring Framework,Spring Filter,Spring Security,programming,software development,technology,spring boot
In our previous tutorial, we learned how to configure a custom login page with pre-defined hard-cored user credentials in place of the built-in login page of Spring Security. In this tutorial, we'll learn how to secure a Spring MVC application using Jdbc Authentication along with a custom login page. So in this case, user credentials would not be configured in any configuration file, but rather those would be stored in the database table.

In the basic Spring Security tutorial, we configured user credentials and roles in the ApplicationSecutiryConfiguration class. But now we are going to put user credentials and roles in the database. So we need to tell Spring Security to read that information from the database and on the other hand,   Spring Security also can read that information from the database. 

So, we must follow Spring Security's predefined table schema to fulfill our requirement. Now we need to create the appropriate tables in the database, write some JDBC code to read information from the database, and make some configuration, and then Spring Security will do the rest of the work for us.

Create Maven project

So, first, we will create a simple Maven project. To create a project in Eclipse, click on the File menu, then choose New→Maven Project
Then choose the project location and click Next.
Spring Security with Database Authentication using JAVA configuration in Spring

Now enter Group Id and Artifact Id and select packaging type as war (Web Archive) as shown:
Spring Security with Database Authentication using JAVA configuration in Spring

Click Finish to create the project.

Although we've created a maven project for this tutorial, we will use some of the configuration files from our previous tutorial. You can download the source code here.

POM.XML

Update pom.xml with required dependencies:
Spring Framework version is 5.3.21 and Spring Security version is 5.6.6 for this application. We have added Spring MVC, Servlet, JSPSecurity, and MySQL connector for JAVA and DBCP2 connection pool-related dependencies in pom.xml. We are using war as the packaging type, which is why we use the maven-war-plugin to build the application.

Database Tables

As we've discussed earlier, we need to create some database tables. Below is the SQL script snippet to set up tables:

PasswordEncoder

In the previous section, we've used the phrase {noop} in the password column value in the users table - in Spring 5.0 and onward if we want to store passwords in the database table, we've to store them in encoded format. So the format for a password is - {id}encodedPassword - here id is the identifier for the PasswordEncoder.

One of the PasswordEncoder is NoOpPasswordEncoder which is used when we want to store plain text as our password and its id value is noop.

Here are some PasswordEncoders with their id values:
  • id value of NoOpPasswordEncoder is noop
  • id value of BCryptPasswordEncoder is bcrypt
  • id value of SCryptPasswordEncoder is scrypt
  • id value of Pbkdf2PasswordEncoder is pbkdf2
  • id value of StandardPasswordEncoder is sha256
As we're going to store passwords as plain text, that is why we've used {noop} with our password string. So, when Spring gets password value with {noop} phrase, it'll understand that the password is in plain text.

Connect to Database

In the app-db.properties file under the resource directory, we've configured Jdbc connection properties to connect MySQL database, secure_spring_mvc_db_auth:

Application Configuration

From the previous tutorial, we've copied the ApplicationConfiguration class in the config package and this class will act as Spring configuration. Here we're going to define our data source:
Here, we've mapped our app-db.properties file using @PropertySource annotation. So this property file will be automatically copied to classpath during Maven build. We've autowired the Environment class, a Spring Helper class - with it, we can access the property values in the application.

We've also defined a bean using @Bean annotation to configure our datasource using the property values.

This class also contains the configuration of ViewResolver using Java configuration, which is required for Spring Web MVC applications. We are using JSP as our view technology.

Initialize Dispatcher Servlet

The dispatcher servlet is responsible for forwarding/dispatching the request to the appropriate controller method. To initialize our Spring WebMVC application in the Servlet container environment using JAVA configuration, we create the ApplicationDispatherServletInitializer class in the config package which will extend the AbstractAnnotationConfigDispatcherServletInitializer class.

Initialize Application Security

Now, we need to create a security initializer class that will extend AbstractSecurityWebApplicationInitializer. Here is our ApplicationSecurityInitializer class which will reside config package:
AbstractSecurityWebApplicationInitializer helps us to register the DelegatingFilterProxy to use the Spring Security Filter.

Configure Application Security

As we are going to customize the security configuration, we will disable auto security configuration and specify the user name and its password - that is why we need to create a custom security configuration class by extending the WebSecurityConfigurerAdapter class. So, create the ApplicationSecutiryConfiguration class in the config package:
So, first of all, we've injected our jdbcDataSource here, and then in the configure(AuthenticationManagerBuilder auth), we are telling AuthenticationManagerBuilder that we'll use JDBC Authentication and assign our datasource to it. We've also configured HttpSecurity for our custom login page and logout functionality.

Controller

Create a HomeController class in the controller package:
Our showHome() method will return home, and based on our configuration, the view resolver will look for home.jsp (as we are using JSP as our view technology) in /WEB-INF/view/. So we need to create home.jsp in /WEB-INF/view/.

Now create the CustomLoginController class controller package. Here it is:
Our showCustomLoginPage() method will return customLoginForm, and based on our configuration, view resolver will search for customLoginForm.jsp in /WEB-INF/view/. So we need to create customLoginForm.jsp in /WEB-INF/view/.

View Page

To create the view page, first, create a view directory under /WEB-INF. Then create a home.jsp in the view directory:
So this page is the same as our previous tutorial with logout functionality.

Now create a customLoginForm.jsp in the view directory in /WEB-INF/:
OK, this is our custom login page. We've used the Bootstrap framework and some custom CSS to design this page. Along with these we've also used the Spring MVC form tag to POST user credentials. We've mapped /authenticateTheUser with the action value of the form tag - so that the Spring framework will do the rest of the job for us.

Test the Application

Now run this application and put this URL - http://localhost:8080/secure-spring-mvc-db-auth/, in the browser:
Spring Security with JDBC Authentication using JAVA configuration

Now enter admin as username and admin123 as password as we had stored in the database and press LOG IN to submit the page and the request will be redirected to the home page:
Spring Security with JDBC Authentication using JAVA configuration
Here, on the home page, we can see the logout button and you can press the logout button to check the logout functionality.
Spring Security with JDBC Authentication using JAVA configuration

As we've logged out from the application, a logout status message is given to the user.

So in this tutorial, we set up Spring Security recommended DB tables, configure the JDBC data source, and use that data source to authenticate the user.

You can download the source code from here.
Happy coding!!! 😊
in

References


Sunday, September 11, 2022

Spring Security With Custom Login Page Using JAVA Configuration

JAVA,Dispatcher Servlet,Spring Framework,Spring Filter,Spring Security,programming,software development,technology,spring boot
In our previous tutorial, we've learned to configure and implement basic Spring Security to a Spring MVC application and we've seen that application automatically redirected to the login form provided by Spring Security. In this tutorial, we'll learn how to show our custom login form in place of Spring Security's provided login form and also implement a logout facility.

So to implement login, first we've to create a new controller and inside that controller, create a GET method that will return the custom login page name; then bind the controller method in the Spring Security configuration so that Spring Security will automatically call our custom login page; and finally, create a JSP page to design our login form using HTML and CSS.

To implement logout, we'll add a logout button on the home page, do some configuration, and show a logout status message on the login page.

In this tutorial, we'll use our previous tutorial code base. You can download it from here.

POM.XML

Here is our pom.xml of the maven project for this tutorial:
<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>
	<groupId>com.raven</groupId>
	<artifactId>securespringmvccustomlogin</artifactId>
	<version>1.0.0-SNAPSHOT</version>
	<name>secure-spring-mvc-custom-login</name>
	<packaging>war</packaging>

	<properties>
		<springframework.version>5.3.21</springframework.version>
		<springsecurity.version>5.6.6</springsecurity.version>

		<maven.compiler.source>11</maven.compiler.source>
		<maven.compiler.target>11</maven.compiler.target>
	</properties>

	<dependencies>
		<!-- Spring MVC support -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-webmvc</artifactId>
			<version>${springframework.version}</version>
		</dependency>

		<!-- https://mvnrepository.com/artifact/org.springframework.security/spring-security-web -->
		<dependency>
			<groupId>org.springframework.security</groupId>
			<artifactId>spring-security-web</artifactId>
			<version>${springsecurity.version}</version>
		</dependency>

		<!-- https://mvnrepository.com/artifact/org.springframework.security/spring-security-config -->
		<dependency>
			<groupId>org.springframework.security</groupId>
			<artifactId>spring-security-config</artifactId>
			<version>${springsecurity.version}</version>
		</dependency>

		<!-- Servlet support -->
		<dependency>
			<groupId>javax.servlet</groupId>
			<artifactId>javax.servlet-api</artifactId>
			<version>4.0.1</version>
		</dependency>

		<!-- JSP support -->
		<dependency>
			<groupId>javax.servlet.jsp</groupId>
			<artifactId>javax.servlet.jsp-api</artifactId>
			<version>2.3.3</version>
		</dependency>

		<!-- JSTL support -->
		<dependency>
			<groupId>javax.servlet</groupId>
			<artifactId>jstl</artifactId>
			<version>1.2</version>
		</dependency>

		<dependency>
			<groupId>taglibs</groupId>
			<artifactId>standard</artifactId>
			<version>1.1.2</version>
		</dependency>

	</dependencies>

	<build>
		<finalName>secure-spring-mvc-custom-login</finalName>
		<pluginManagement>
			<plugins>
				<plugin>
					<groupId>org.apache.maven.plugins</groupId>
					<artifactId>maven-war-plugin</artifactId>
					<version>3.3.2</version>
				</plugin>
			</plugins>
		</pluginManagement>
	</build>

</project>

Controller

We'll create a CustomLoginController class controller package. Here it is:
package com.raven.securespringmvccustomlogin.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;

@Controller
public class CustomLoginController {

	@GetMapping("/showCustomLoginPage")
	public String showCustomLoginPage() {
		return "customLoginForm";
	}
}
Our showCustomLoginPage() method will return customLoginForm, and based on our configuration, view resolver will search for customLoginForm.jsp (as we are using JSP as our view technology) in /WEB-INF/view/. So we need to create customLoginForm.jsp in /WEB-INF/view/.

Configuration

We have a configuration class named ApplicationSecutiryConfiguration - here we had configured a user for in-memory authentication by overriding configure(AuthenticationManagerBuilder auth) method. Now, we need to override the configure(HttpSecurity http) method to configure HttpSecurity for our application:
package com.raven.securespringmvccustomlogin.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.User.UserBuilder;

@Configuration
@EnableWebSecurity
public class ApplicationSecutiryConfiguration extends WebSecurityConfigurerAdapter {

	@Override
	protected void configure(AuthenticationManagerBuilder auth) throws Exception {
		UserBuilder userBuilder = User.withDefaultPasswordEncoder();
		auth.inMemoryAuthentication()
				.withUser(userBuilder.username("admin")
				.password("admin123")
				.roles("ADMIN"));
	}

	@Override
	protected void configure(HttpSecurity http) throws Exception {
		http.authorizeRequests()
			.anyRequest()
			.authenticated()
			.and()
			.formLogin()
			.loginPage("/showCustomLoginPage")
			.loginProcessingUrl("/authenticateTheUser").permitAll()
			.and()
			.logout().permitAll();
	}
}
But why do we need  HttpSecurity? Let's see what Spring documentation says:
"A HttpSecurity is similar to Spring Security's XML <http> 
  element in the namespace configuration. It allows configuring web based 
  security for specific http requests. By default it will be applied to 
  all requests..." -- spring-security-docs
So, HttpSecurity is used to secure a specific web path or URL. In other words, we are just defining our security policies/rules using HttpSecurity for some specific URL.

In the configure(HttpSecurity http) method, we have specified that any request coming to this application should be authenticated, and as we are using form-based authentication (formlogin()), that is why we have mapped our custom login page to allow users to provide their credentials. After the request is submitted, the request will be processed by /authenticateTheUser. Now Spring Security would check the user credentials that we had submitted.

We've also configured a logout facility using .and().logout().permitAll(). So when a user clicks the logout button, the request will go to the logout URL: /logout. This is actually the default URL for logging out. This logout URL will be managed by the Spring Security Filters. So Spring Security would invalidate a user's HTTP session and remove session cookies, redirect the user to a login page, and add a logout parameter: ?logout with the base URL.

View

Now create a customLoginForm.jsp in the view directory in /WEB-INF/:
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Log In - Secure Spring MVC</title>
<%-- <link rel="stylesheet"
	href="${pageContext.request.contextPath}/css/style.css"> --%>
<style>
@import
	url('https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500;700&display=swap')
	;

html, body {
	height: 100%;
}
body {
	font-family: 'Roboto', sans-serif;
	background-image: linear-gradient(to top, #7028e4 0%, #e5b2ca 100%);
}
.demo-container {
	height: 100%;
	display: flex;
	justify-content: center;
	align-items: center;
}
.btn-lg {
	padding: 12px 26px;
	font-size: 14px;
	font-weight: 700;
	letter-spacing: 1px;
	text-transform: uppercase;
}
::placeholder {
	font-size: 14px;
	letter-spacing: 0.5px;
}
.form-control-lg {
	font-size: 16px;
	padding: 25px 20px;
}
.font-500 {
	font-weight: 500;
}
</style>
<link rel="stylesheet"
	href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.css" />
<link rel="stylesheet"
	href="https://stackpath.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.css" />
<script src="https://code.jquery.com/jquery-3.4.1.slim.js"></script>
<script
	src="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.js"></script>
<script
	src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.16.0/umd/popper.js"></script>
</head>
<body>
	<div class="demo-container">
		<div class="container">
			<div class="row">
				<div class="col-lg-6 col-12 mx-auto">
					<div class="p-5 bg-white rounded shadow-lg">
						<h3 class="mb-2 text-center">Log In</h3>
						<p class="text-center lead">Log In to manage your account</p>
						<form:form
							action="${pageContext.request.contextPath}/authenticateTheUser"
							method="POST">
							<label class="font-500">User name</label>
							<input name="username" placeholder="enter username"
								class="form-control form-control-lg mb-3" type="text">

							<label class="font-500">Password</label>
							<input name="password" placeholder="enter password"
								class="form-control form-control-lg" type="password">

							<div style="margin-top: 20px; margin-top: 20px">
								<button type="submit"
									class="btn btn-primary btn-lg w-100 shadow-lg">LOG IN</button>
							</div>

							<div style="margin-top: 20px; margin-top: 20px">
								<!-- ERROR MESSAGE -->
								<c:if test="${param.error != null}">
									<div class="alert alert-danger col-xs-offset-1 col-xs-10">
										Invalid username and password!</div>
								</c:if>

								<!-- LOGOUT MESSAGE -->
								<c:if test="${param.logout != null}">
									<div class="alert alert-success col-xs-offset-1 col-xs-10">
										You've been successfully logged out!</div>
								</c:if>
							</div>
						</form:form>
					</div>
				</div>
			</div>
		</div>
	</div>

</body>
</html>
OK, this is our custom login page. We've used the Bootstrap framework and some custom CSS to design this page. Along with these we've also used the Spring MVC form tag to POST user credentials. We've mapped /authenticateTheUser with the action value of the form tag - so that the Spring framework will do the rest of the job for us.

We are also checking the error and logout status using JSTL and showing the message to the user.

Now we'll update home.jsp to show the logout button and implement logout functionality. Here it is:
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Home - Spring Security</title>
<style>
body {
	font-family: Arial, Helvetica, sans-serif;
	margin: 0;
}
.header {
	padding: 60px;
	text-align: center;
	background: #1abc9c;
	color: white;
	font-size: 30px;
}
.content {
	padding: 20px;
}
</style>
</head>
<body>
	<div class="header">
		<h1>Spring Security</h1>
		<p>Welcome to Spring Security with custom Login	page!</p>
	</div>

	<div class="content">
		<h1>Home</h1>
		<p>In this tutorial, we'll learn how to show our custom login form
			in-place of Spring Security provided login form and also implement
			logout facility.</p>
		<p>
			<form:form action="${pageContext.request.contextPath}/logout"
				method="POST">
				<input type="submit" value="LOGOUT">
			</form:form>
		</p>
	</div>
</body>
</html>
So this page is the same as our previous tutorial. We've just added a logout button. As we've discussed earlier, we a user presses the logout button, the request is submitted to the logout URL: /logout and then the request is processed by Spring Security itself.

Testing

Now run this application again and put this URL - http://localhost:8080/ssecure-spring-mvc-custom-login/ in the browser:
Spring Security using JAVA configuration in Spring - Custom Login Form

We can see that the application automatically redirected to our custom login page. Now enter admin as username and admin123 as password and press LOG IN to submit the page and the request will be redirected to the home page:
Spring Security using JAVA configuration in Spring - Custom Login Form

Here, on the home page, we can see the logout button and you can press the logout button to check the logout functionality.
Spring Security using JAVA configuration in Spring - Custom Login Form

As we've logged out from the application, a logout status message is given to the user.

So in this tutorial, we've learned how to configure our custom login page in place of Spring Security's in-built login page and logout functionality.

You can download the source code from here.
Happy coding!!! 😊
in

Popular posts