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

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