Block 4
Block 4
Block 4
CONFIGURATION
Structure
12.0 Introduction
12.1 Objective
12.2 Introduction to Web Securities
12.2.1 Introduction of Java Cryptography Architecture (JCA)
12.2.2 Introduction of Java Secure Socket Extension (JSSE)
12.3 Issues and Challenges of Web Security
12.4 Spring Security Overview
12.5 Java Based Configuration
12.6 Create Spring Initializer Class
12.7 Create Controller and View
12.8 Run Application
12.9 Summary
12.10 Solutions/Answers to Check Your Progress
12.11 References/Further Reading
12.0 INTRODUCTION
In unit 9, Spring Boot Application and a simple application without any security
considerations are described. This unit will describe security features like
authentication and authorization that create a secured Java Enterprise Application. The
following sections will explain JCA and JSSE to secure our data at various levels.
This unit will also describe how spring security simplifies the security implementation
as compared to non-spring projects.
12.1 OBJECTIVE
Security is one of the topmost concern for any application. It includes many aspects
such as sensitive data safety, robust website against hacking, sql injection, csrf etc. A
different set of tools are used for various aspects of application security. This section
describes how to secure sensitive information on backend applications, i.e. passwords
1
Web Security
in the database, critical records etc. With the emergence of cloud services, security has
become an indispensable requirement for sensitive information on every platform.
2
Spring Security
• java.security Configuration
• java.security.cert
• java.security.spec
• java.security.interfaces
Above defines, packages contain many core classes and interfaces. Some of
thefrequently used ones are as follows:
• Provider
• Cipher
• MessageDigest
• Signature
• Mac
• KeyPairGenerator
• KeyGenerator
• KeyStore
The following sections will give you insights of some frequently used classes and its
feature.
Provider
JCA has a “provider” based architecture. Java SDK provides a default provider.
Default providers may not support the encryption algorithms you want to use. In order
to use a different provider instead of the default, Java Cryptography API provides a
method to set the desired provider. Cryptography provider can be set as below-
Security.addProvider(…)
Cipher
The Cipher (javax.crypto.Cipher) class is the core of JCA framework. This class
provides cryptographic cipher for encryption and decryption. Cipher’s getInstance
method provides cipher object for encryption and decryption. Method getInstance
expects the name of the requested transformation. A transformation can be any form
either "algorithm/mode/padding" or "algorithm".
Cipher instance can be created using getInstnace method as –
package com.ignou;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.security.GeneralSecurityException;
import java.util.Base64;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
publicclassEncryptDecrypt
{
publicstaticbyte[] Encrypt(String secretKey, String plainText)
throwsGeneralSecurityException
{
byte[] keyBytes = secretKey.getBytes(Charset.forName("UTF-8"));
if (keyBytes.length != 16)
{
thrownewIllegalArgumentException("Allowed key size is 16");
}
IvParameterSpecparamSpec = newIvParameterSpec(newbyte[16]);
3
Web Security
SecretKeySpeckeySpec = newSecretKeySpec(keyBytes, "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, keySpec, paramSpec);
byte[] cipherTextBytes = cipher.doFinal(plainText.getBytes(Charset.forName("UTF-8")));
returncipherTextBytes;
}
publicstaticbyte[] Decrypt(String key, byte[] cipherText) throwsGeneralSecurityException
{
byte[] keyBytes = key.getBytes(Charset.forName("UTF-8"));
if (keyBytes.length != 16)
{
thrownewIllegalArgumentException("Allowed key size is 16");
}
IvParameterSpecparamSpec = newIvParameterSpec(newbyte[16]);
SecretKeySpeckeySpec = newSecretKeySpec(keyBytes, "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, keySpec, paramSpec);
byte[] plainTextBytes = cipher.doFinal(cipherText);
returnplainTextBytes;
}
publicstaticvoidmain(String[] args)
{
try
{
String key = "ThisIsASecretKey";
String plainText = "Hello, Good Morning";
byte[] ciphertextbytes = Encrypt(key, plainText);
System.out.println("Cipher Text: " + Base64.getEncoder().encodeToString(ciphertextbytes));
byte[] plaintextbytes = Decrypt(key, ciphertextbytes);
String decryptedPlainText = newString(plaintextbytes, StandardCharsets.UTF_8);
System.out.println("Decrypted Plain Text: "+decryptedPlainText);
}
catch (GeneralSecurityException e)
{
e.printStackTrace();
}
}
}
Output: Program execution will provide the below output. As you can see by
encryption, you are getting encrypted text corresponding to plain text. This Cipher
text is used for confidentiality. This encrypted text has been decrypted to the plain text
using Cipher class in Decrypt mode.
Message Digest
Message digests are a secured one-way hash functions that take arbitrary-sized data
and output fixed-length hash value. A common solution to validate the encrypted data
on the way to you has not been modified is Message Digest. A message digest is a
hash value calculated from message data. Steps to send encrypted data with message
digest and validation of encrypted data is as-
• Calculate the message digest from data before encryption
• Encrypt both data and message digest and send across the wire
• Once encrypted data is received, decrypt it to get the message and message
digest
4
Spring Security
• Calculate message digest for the received message and compare it with the Configuration
received message digest
• If the comparison evaluates to true, there is a high probability (but not a 100%
guarantee) that the data was not modified.
Java provides a class, named MessageDigest which belongs to the package
java.security, to create a message digest for message data. This class supports
algorithms such as SHA-1, SHA-256, SHA-384, SHA-512, MD5 algorithms to
convert an arbitrary-length message to a fixed-length message digest. Sample code to
generate message digest for multiple blocks of data is as –
MessageDigest md = MessageDigest.getInstance("SHA-256");
Mac
The term MAC stands for Message Authentication Code. The integrity of information
transmitted over an unsecured channel can be validated using MAC. A MAC is like a
Message Digest but uses an additional key to encrypt the message digest. Thus, A
MAC is a message digest encrypted with a secret key. MAC from a message can be
created using Java Mac Class. To verify the MAC of a message, it requires the key
along with original data. Hence, a MAC is a more protected way to guard a block of
data from modification than a message digest. Java code to calculate the MAC of a
message data is as –
packagecom.ignou;
importjava.util.Base64;
importjavax.crypto.Mac;
importjavax.crypto.spec.SecretKeySpec;
publicclass MAC
{
publicstaticvoidmain(String[] args) throws Exception
{
Mac mac = Mac.getInstance("HmacSHA256");
byte[] keyBytes = newbyte[]{'T','h','i','s','I','s','A','S','e' ,'c','r','e','t','K','e','y'};
String algo = "RawBytes";
SecretKeySpec key = newSecretKeySpec(keyBytes,algo);
mac.init(key); // MAC instance initialized with key
5
Web Security
Signature
A digital signature is a mathematical technique used to validate the authenticity and
integrity of a message or digital document. Digital signatures provide the added
assurances of evidence of origin, identity and status of an electronic document or
message. It also ensures the non-repudiation, i.e. the author of the message can't later
deny that they were the source. Digital Signatures are based on public-key
cryptography. The signer uses his private key to create the signature and signature can
be authenticated only by the signer public key.
The Signature (java.security.Signature) class is used to create Signature instance in
java. A digital signature is an encrypted message digest with the private key of the
signing authority. The signing authority may be the device, person or organization that
is to sign the data.
To create a Signature instance, you call the Signature.getInstance(...) method.
Signature instance creation is shown below:
package com.ignou;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
public class CreateAndVerifySignature
{
public static void main(String[] args) throws Exception
{
KeyPairGeneratorkeyPairGen = KeyPairGenerator.getInstance("DSA");
// Initializing the key pair generator
keyPairGen.initialize(2048);
// Generate the pair of keys
KeyPair pair = keyPairGen.generateKeyPair();
// Get the private key from the key pair
PrivateKeyprivateKey = pair.getPrivate();
// Get the public key from the key pair
PublicKeypublicKey = pair.getPublic();
// Create signature instance
Signature sign = Signature.getInstance("SHA256withDSA");
// Initialize with private key
sign.initSign(privateKey);
// Data that needs to be signed
byte[] bytes = "This is my digital signed data".getBytes();
// Update signature instance with data to be signed
sign.update(bytes);
// Create the signature
byte[] signature = sign.sign();
// Initiate the signature with public key to verify signature
sign.initVerify(pair.getPublic());
// Update signature instance with data for which signature needs to verify
sign.update(bytes);
// Verify the signature
booleanisValidSignature = sign.verify(signature);
if (isValidSignature)
{
System.out.println("Signature verified");
}
else
{
6
Spring Security
System.out.println("Signature Failed");
Configuration
}
}
}
3) Alice wants to send some confidential data securely to Bob over the network.
Alice uses digital signature to sign the data and did the following where S(m)
= digital signature of m.
• Compute S(m) using her private key
• Send m, S(m) and her public key to Bob
Bob did as below upon receiving the confidential data:
• Bob receive S(m), m and Alice's public key
• Bob verify the S(m) using m and Alice's key.
Alice used private key to digitally sign the confidential data. Yet the above
approach is attack prone. Figure out the possible attack and flaw in the above
approach.
JSSE provides an SSL toolkit for Java applications. In addition to the necessary
classes and interfaces, JSSE provides a handy command-line debugging switch that
you can use to watch the SSL protocol in action. A simple example with the below
code can be executed in debug mode to watch the handshaking details.
packagecom.ignou;
publicclassSecureConnection
{
publicstaticvoidmain(String[] arstring)
{
try
{
new java.net.URL("https://www.google.com").getContent();
}
8
Spring Security
To run the above application in debug mode, we need to turn on SSL debugging. The Configuration
application connects to the secure website https://www.google.com using the SSL
protocol via HTTPS. In the command given below, the first option loads the HTTPS
protocol handler, while the second option, the debug option, causes the program to
print out its behavior.
java -Djava.protocol.handler.pkgs=com.sun.net.ssl.internal.www.protocol -
Djavax.net.debug=sslcom.ignou.SecureConnection
The above SecureConnection program using the java.net.URL class demonstrates the
easiest way to add SSL to your applications. This approach is useful, but it is not
flexible enough to let you create a secure application that uses generic sockets. The
next section describes SSL and its implementation using JSSE.
In simple terms, we can understand that SSL provides a secured connection between
server and client. SSL encrypts the communication between two devices operating
over a network connection to provide a secure channel. Secure communication
between web browsers and web servers is a very common example of SSL. The
following three main information security principles is required for secured
communication over a network, and SSL fulfils these:
• Encryption: Protects the data transmissions between involved entities
• Authentication: Ensures that the server we connect to is actually the intended
server
• Data integrity: guarantee that data exchange between two entities is not
modified by the third party
JSSE API
Java Security API is based on Factory Design Pattern extensively. JSSE provides
many factory methods to instantiate. The following section will outline some
important classes in JSSE API and the use of these classes.
SSLSocketFactory
SSLSocket
9
Web Security
This javax.net.ssl.SSLSocket class extends java.net.Socket class in order to provide
secure socket. SSLSockets are normal stream sockets but with an added layer of
security over a network transport protocol, such as TCP. Since it extends
java.net.Socket class, thus it supports all the standard socket methods and adds
methods specific to secure sockets. SSLSocket instances construct an SSL connection
to a named host at a specified port. This allows binding the client side of the
connection to a given address and port. Few important methods in
javax.net.ssl.SSLSocket are listed below:
• String [] getEnabledCipherSuites()
• String [] getSupportedCipherSuites()
• void setEnabledCipherSuites(String [] suites)
• booleangetEnableSessionCreation()
• void setEnableSessionCreation(boolean flag)
• booleangetNeedClientAuth()
• void setNeedClientAuth(boolean need)
The methods below change the socket from client mode to server mode. This affects
who initiates the SSL handshake and who authenticates first:
• booleangetUseClientMode()
• void setUseClientMode(boolean mode)
Method void startHandshake() forces an SSL handshake. It's possible, but not
common, to force a new handshake operation in an existing connection.
SSLServerSocketFactory
SSLServerSocket
This class is subclass of ServerSockets and provides secure server sockets using
protocols such as the Secure Sockets Layer (SSL) or Transport Layer Security (TLS)
protocols. SSLServerSocket creates SSLSockets by accepting connections.
Example
The class SecureEchoServer uses JSSE API to create a secure server socket. It listens
on the server socket for connections from secure clients. When executing the
SecureEchoServer, you must specify the keystore to use. The keystore contains the
server's certificate.
package com.ignou;
public class SecureEchoServer
{
public static void main(String[] arstring)
{
try
{
SSLServerSocketFactorysslserversocketfactory = (SSLServerSocketFactory)
SSLServerSocketFactory.getDefault();
SSLServerSocketsslserversocket = (SSLServerSocket)
sslserversocketfactory.createServerSocket(8888);
SSLSocketsslsocket = (SSLSocket) sslserversocket.accept();
InputStreaminputstream = sslsocket.getInputStream();
InputStreamReaderinputstreamreader = new InputStreamReader(inputstream);
BufferedReaderbufferedreader = new BufferedReader(inputstreamreader);
String text = null;
10
Spring Security
while ((text = bufferedreader.readLine()) != null)
Configuration
{
System.out.println("Received From Client: "+text);
System.out.flush();
}
}
catch (Exception exception)
{
exception.printStackTrace();
}
}
}
The SecureEchoClient code used JSSE to securely connect to the server. When
running the SecureEchoclient, you must specify the truststore to use, which contains
the list of trusted certificates.
package com.ignou;
public class SecureEchoClient
{
public static void main(String[] arstring)
{
try
{
SSLSocketFactorysslsocketfactory = (SSLSocketFactory)
SSLSocketFactory.getDefault();
SSLSocketsslsocket = (SSLSocket) sslsocketfactory.createSocket("localhost", 8888);
InputStreaminputstream = System.in;
InputStreamReaderinputstreamreader = new InputStreamReader(inputstream);
BufferedReaderbufferedreader = new BufferedReader(inputstreamreader);
OutputStreamoutputstream = sslsocket.getOutputStream();
OutputStreamWriteroutputstreamwriter = new OutputStreamWriter(outputstream);
BufferedWriterbufferedwriter = new BufferedWriter(outputstreamwriter);
String text = null;
System.out.println("Send Text to server");
while ((text = bufferedreader.readLine()) != null)
{
bufferedwriter.write(text + '\n');
bufferedwriter.flush();
}
}
catch (Exception exception)
{
exception.printStackTrace();
}
}
}
Put this generated selfsigned.jks file into the root directory of your source code and
execute the below command to run SecureEchoServer and SecureEchoClient.
java -Djavax.net.ssl.keyStore=selfsigned.jks -
Djavax.net.ssl.keyStorePassword=localhost com.ignou.SecureEchoServer
java -Djavax.net.ssl.trustStore=selfsigned.jks -
Djavax.net.ssl.trustStorePassword=localhost com.ignou.SecureEchoClient
Note:Use the same password you used to create a self-signed certificate in step 3 for
keyStorePassword and trustStorePassword. I used localhost as a password in self-
signed certificate generation;therefore so in the above command, I used the same.
On the client terminal, send some text to the server, and the server will echo the same
text on its terminal.
2) List down the benefits of implementing SSL using JSSE over secure
connection established using java.net.URL
With the advancement of the Web and other technology, the frequent usage of
networks makes web applications vulnerable to a variety of threats. Advancements in
web applications have also attracted malicious hackers and scammers, who are always
coming up with new attack vectors. Hackers and attackers can potentially take various
12
Spring Security
path through the web application to cause risks to your business. Web application Configuration
security deals specifically with the security surrounding websites, web applications
and web services such as APIs.
• SQL injection (SQLi) – SQL Injections are among the most common threat
to data security.SQL injection, also known as SQLi, is a type of injection
attack that exploits the weakness of application security and allows attackers
to execute malicious SQL statements. Malicious SQL statements execution
enable attackers to access or delete records, change an application data-driven
behavior. Attackers can use SQL Injection vulnerabilities to bypass
application security measures. Any website or web application, which uses a
relational database such as MySQL, Oracle, SQL Server etc., can be impacted
by SQL Injection. Attackers use SQLi to gain access to unauthorized
information, modify or create new user permissions, or otherwise manipulate
or destroy sensitive data. Attackers use specially-crafted input to trick an
application into modifying the SQL queries that the application asks the
database to execute. Let us understand it by example.
Suppose that a developer has developed a web page to show the account
number and balance into account for the current user’s ID provided in a URL,
Code snippet in java might be as below:
13
Web Security
String accountBalanceQuery =
"SELECT accountNumber, balance FROM accounts WHERE account_owner_id = "
+ request.getParameter("user_id");
try
{
Statement statement = connection.createStatement();
ResultSetrs = statement.executeQuery(accountBalanceQuery);
while (rs.next())
{
page.addTableRow(rs.getInt("accountNumber"), rs.getFloat("balance"));
}
}
catch (SQLException e) { ... }
The above query is a valid query, and it will return only the intended result to
show the balance for the user id 1234.
Now suppose, an attacker has identified the application security vulnerability
and change the parameter user_id as-
0 OR 1 = 1
When the application asks this query to execute into the database, it will
return the account balance for all the accounts into the database. The attacker
now knows every user’s account numbers and balances.
14
Spring Security
A malicious attacker could try to substitute the id parameter value 7778 with Configuration
other similar values, for example:
https://www.example.com/transaction?id=7778
Authentication
15
Web
b Security
• Acccess Control List (ACL): An ACL speecifies which h users have access
a to a
partticular resourrce. For instaance, if a user wants to acccess a specific file or
fold
der, their userrname or detaails should bee mentioned ini the ACL inn order to
be able
a to accesss certain data.
Various metthods for authhorization aree as follows:
• Acccess controls ffor URLs
• Secure Objects aand methods
• Acccess Control L List (ACL)
Servlet Fillters
16
Spring Security
Configuration
Spring Security
Spring Security Modules
Spring 4 Framework has the following modules to provide Security to the Spring-
Based Applications:
• Spring Security
• Spring Security SAML
• Spring Security OAuth
• Spring Security Kerberos
• Spring Cloud Security
In Spring Framework, “Spring Security” module is the base module for the rest of the
Spring Security modules. The following sections will outline some basics of “Spring
Security” module.
Spring Security is one of the Spring Framework’s security modules. It is a Java
SE/Java EE Security Framework to provide Authentication, Authorization, SSO and
other Security features for Web Applications or Enterprise Applications.
17
Web Security
• Supports Both XML Configuration and Annotations. Very Less or minimal
XML Configuration.
Spring 4.x Security Framework supports the following new features:
• Supports WebSocket Security.
• Supports Spring Data Integration.
• CSRF Token Argument Resolver.
3) Howdoes Authorization (AuthZ) make the system secured and restricted? List
down various methods.
18
Spring Security
12.5 JAVA BASED CONFIGURATION Configuration
Spring security uses Servlet Filter to implement the security in java applications. It
creates a Servlet Filter named as SpringSecurityFilterChain.
SpringSecurityFilterChain takes care of all the security concerns such as validating
submitted username and passwords, application URLs protection, redirecting to the
log in form to unauthenticated users, etc. Spring Security provides an abstract class
AbstractSecurityWebApplicationInitializer that will ensure the
springSecurityFilterChain Filter get registered for every URL in the application.
SpringSecurityFilterChain can be registered into spring application with the
initialization of AbstractSecurityWebApplicationInitializer as:
import org.springframework.security.web.context.*;
With the latest Spring Security and/or Spring Boot versions, Spring Security is
configured by having a class that:
• Is annotated with @EnableWebSecurity.
• Extends WebSecurityConfigurerAdapter, which basically provides a
convenient base class for creating a WebSecurityConfigurer instance. The
implementation allows customization by overriding methods. Here’s what a
typical WebSecurityConfigurerAdapter looks like:
@Configuration
@EnableWebSecurity // (1)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter{ // (1)
@Override
protected void configure(HttpSecurity http) throws Exception { // (2)
http
.authorizeRequests()
.antMatchers("/home").permitAll() // (3)
.anyRequest().authenticated() // (4)
.and()
.formLogin() // (5)
.loginPage("/login") // (5)
.permitAll()
.and()
.logout() // (6)
.permitAll()
.and()
.httpBasic(); // (7)
}
}
19
Web Security
4. All other requests except “/home”, the user to be authenticated first, i.e. the
user needs to login.
5. As described, authentication methods in section 12.4, form login with a
custom loginPage (/login, i.e. not Spring Security’s auto-generated one) is
being used in the configuration. Login page should be accessible to anyone.
Thus “/login” URI has been permitted to all using permitAll().
6. The default spring logout feature is configured and has been permitted to all.
7. Apart from form login, the configuration is also allowing for Basic Auth, i.e.
sending in an HTTP Basic Auth Header to authenticate.
The above configuration creates SpringSecurityFilterChain which is accountable for
security concerns such as validating submitted username and passwords, application
URLs protection, redirecting to the log in form to unauthenticated users, etc. Java
Configuration do the following for our application.
• Register required authentication for every URL
• Creates a login form
• Allow a user to be authenticated using form-based authentication as well as
HTTP Basic Auth.
• Allow to logout
• Prevent from CSRF attack
HTTP Security
20
Spring Security
Form Login Configuration
Based on the features that are enabled in spring security, it generates a login page
automatically. It uses standard values for the URLs such as /login and /logout to
process the submitted login form and logout the user.
protected void configure(HttpSecurity http) throws Exception
{
http.authorizeRequests()
.anyRequest().authenticated()
.and().formLogin()
.loginPage("/login").permitAll();
}
In-Memory Authentication
JDBC Authentication
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth)
throws Exception
{
auth.jdbcAuthentication().dataSource(dataSource)
.withDefaultSchema()
.withUser("user").password(passwordEncoder().encode("password")).roles("USER")
.and()
.withUser("admin").password(passwordEncoder().encode("password")).roles("USER",
"ADMIN");
}
21
Web Security
(
username varchar_ignorecase(50) not null primary key,
password varchar_ignorecase(50) not null,
enabled boolean not null
);
create table authorities
(
username varchar_ignorecase(50) not null,
authority varchar_ignorecase(50) not null,
constraint fk_authorities_users foreign key(username) references users(username)
);
Default Schema will not work for other databases except HSQLDB database. Check
the spring.io website for schema corresponding to a database. The database schema
can be checked at:
https://docs.spring.io/spring-security/site/docs/4.0.x/reference/html/appendix-
schema.html
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth)
throws Exception
{
auth.jdbcAuthentication()
.dataSource(dataSource)
.usersByUsernameQuery("select uuid,password,enabled "
+ "from users "
+ "where uuid= ?")
.authoritiesByUsernameQuery("select uuid,authority "
+ "from authorities "
+ "where uuid= ?");
}
Customization of a search query in spring security is very easy, and two methods for
that has been provided as usersByUsernameQuery and
authoritiesByUsernameQuery.
22
Spring Security
public class AppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer
Configuration
{
@Override
protected Class<?>[] getRootConfigClasses()
{
return new Class<?>[] { RepositoryConfig.class, SecurityConfig.class };
}
@Override
protected Class<?>[] getServletConfigClasses()
{
return new Class<?>[] { WebConfig.class };
}
@Override
protected String[] getServletMappings()
{
return new String[] { "/" };
}
}
If we have a single DispatcherServlet, we can add the WebConfig to the root context
and make the servlet context empty:
public class ServletInitializer extends AbstractAnnotationConfigDispatcherServletInitializer
{
@Override
protected Class<?>[] getRootConfigClasses()
{
return new Class<?>[] { RepositoryConfig.class, SecurityConfig.class,
WebConfig.class };
}
@Override
protected Class<?>[] getServletConfigClasses()
{
return null;
}
@Override
protected String[] getServletMappings()
{
return new String[] { "/" };
}
}
23
Web Security
@Controller //(1)
@RequestMapping(value="/") //(2)
public class HomeController
{
@GetMapping //(3)
public ModelAndViewindex()
{
ModelAndView mv = new ModelAndView();
mv.setViewName("index");
mv.getModel().put("message", "User, Spring Security Implemented Successfully !!");
return mv;
}
}
@Configuration
@EnableWebMvc
@ComponentScan
public class MvcConfiguration extends WebMvcConfigurerAdapter
{
@Override
public void configureViewResolvers(ViewResolverRegistry registry)
{
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setPrefix("/WEB-INF/views/");
resolver.setSuffix(".jsp");
resolver.setViewClass(JstlView.class);
registry.viewResolver(resolver);
}
}
24
Spring Security
Configuration
packagecom.ignou.javabasedspringsecurity;
@SpringBootApplication
publicclassJavaBasedSpringSecurityApplicationextendsSpringBootServletInitializer
{
@Override
protectedSpringApplicationBuilder configure(SpringApplicationBuilderapplication)
{
returnapplication.sources(JavaBasedSpringSecurityApplication.class);
}
publicstaticvoid main(String[] args)
{
Figure 2: Project Folder Structure In Eclipse
SpringApplication.run(JavaBasedSpringSecurityApplication.class, args);
}
}
25
Web Security
Step 3: Spring Security Configuration
packagecom.ignou.javabasedspringsecurity.security;
@EnableWebSecurity
publicclassSecurityConfigextendsWebSecurityConfigurerAdapter
{
@Autowired
PasswordEncoderpasswordEncoder;
@Bean
publicPasswordEncoderpasswordEncoder()
{
returnnewBCryptPasswordEncoder();
}
@Override
protectedvoid configure(AuthenticationManagerBuilderauth) throws Exception
{
auth.inMemoryAuthentication().passwordEncoder(passwordEncoder).withUser("testuser")
.password(passwordEncoder.encode("user@123")).roles("USER").and().withUser("testadmin")
.password(passwordEncoder.encode("admin@123")).roles("USER", "ADMIN");
}
protectedvoid configure(HttpSecurityhttp) throws Exception
{
http.authorizeRequests().anyRequest().authenticated().and().formLogin().and().httpBasic();
}
}
publicclassSecurityInitializerextendsAbstractSecurityWebApplicationInitializer
{
// No Code Needed Here
}
26
Spring Security
Step 6: Controller Class and View Configuration
packagecom.ignou.javabasedspringsecurity.controller;
@Controller
@RequestMapping(value="/")
publicclassHomeController
{
@GetMapping
publicModelAndView index()
{
ModelAndViewmv = newModelAndView();
mv.setViewName("index");
mv.getModel().put("message", "User, Spring Security Implemented Successfully !!");
returnmv;
}
}
spring.mvc.view.prefix=/WEB-INF/views/
spring.mvc.view.suffix=.jsp
Execution Output:
If user tries to access localhost:8080 and user is not logged in, spring will redirect to
user on localhost:8080/login as shown below. This login page is spring security in-
built.
27
Web
b Security
☞Check Your
Y Proggress 4
28
Spring Security
Configuration
4) How to secure the URLs in Spring Security? Explain with available methods
to make URL secure.
12.9 SUMMARY
In this unit, many concepts related to web security have been explained. You got to
know about securing data at-rest and in-transit. In the unit JCA section described
many useful concepts such as Cipher, Message Digest, Message Authentication Code,
Signature. Using JCA API, the authenticity and integrity of the message can be
verified. Further SSL and other useful concepts to secure the data in-transit is
explained. The Spring Security provides a convenient and easy way to incorporate
security in spring applications with minimum configuration. The concept of
Authentication and Authorization has been explained to make application secure.
Various methods such as authenticate(), permitAll(), hasRole(), hasAuthority() have
been written to make URL secure in Spring Security. In-memory authentication and
JDBC authentication has been described with the custom search query to incorporate
user-defined schema for users and authorities.In the last section of this unit, you
learned code to integrate spring security into the spring boot application.
29
Web Security
12.10 SOLUTIONS/ANSWERS TO CHECK YOUR
PROGRESS
It allows you to verify the integrity of the It allows you to verify the integrity
message and the authenticity of the message
Any change to the message will (ideally) Any change to the message or the
result in a different hash being generated. secret key will (ideally) result in a
different MAC being generated.
An attacker that can replace the message and Nobody without access to the secret
digest is fully capable of replacing the should be able to generate a MAC
message and digest with a new valid pair. calculation that verifies the integrity
and authenticity of the message
30
Spring Security
S
☞Check
C Yourr Progress 3 Configu
uration
1)
1 Refer secttion 12.4, Sprring Security has been expplained in detaail.
2)
2 Refer Autthentication inn Section 12.4
3)
3 Refer Autthorization in
n Section 12.44
☞Check
C Yourr Progress 4
1)
1 SecurityF
FilterChain iss a FilterChaain componeent which haas zero or more
m
Security Filters
F in an order.
o
31
Web Security
SQL statements when configuring the AuthenticationManagerBuilder. Two
methods for customization has been provided as usersByUsernameQuery and
authoritiesByUsernameQuery. Refer to Section 12.5 for customizing the
search query.
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth)
throws Exception
{
auth.jdbcAuthentication()
.dataSource(dataSource)
.usersByUsernameQuery("select email,password,enabled "
+ "from users "
+ "where email = ?")
.authoritiesByUsernameQuery("select email,authority "
+ "from authorities "
+ "where email = ?");
}
4) Refer Securing the URLs in section 12.5
32
UNIT 13 CUSTOM LOGIN USING
SECURITY
Structure
13.0 Introduction
13.1 Objectives
13.2 Custom Login form creation
13.3 Spring Config for Custom Login Form
13.4 Create Request mapping and building Custom Login Form
13.5 Testing Custom Login Form
13.5.1 Integration Test in Spring Boot
13.6 Adding Logout Support
13.7 Summary
13.8 Solutions/ Answer to Check Your Progress
13.9 References/Further Reading
13.0 INTRODUCTION
Unit 12 explained how to secure the spring application using spring security. The
built-in login module of Spring Security authenticates the users and provides
accessibility to the application. Default spring security does not require to create new
jsp page for login since built-in login module already has default login page, which is
used to authenticate the user. The default login page provided by spring security is not
suitable for enterprise web application since the developer does not have control on
designing and processing behavior. This unit describes how to customize the login
page into spring security. The default login page, provided by Spring Security, has
been used in the example written in unit 12, section 12.8. In this unit, the example
executed in section 12.8 will be incorporated with a custom login page.
Testing is a very important phase of any application to ensure whether it works as per
expected functionality or not. Integration testing and unit testing play a vital role in
making the application error prone. This unit describes the annotation available in
spring boot for Integration testing. The next unit will explain about unit test
annotation available in spring boot.
Once user finishes all the activity on a web portal, he must be provided with a way to
invalidate the session using logout functionality. Spring logout feature with various
available methods has been explained in this unit.
13.1 OBJECTIVES
After going through this unit, you should be able to:
1
Web Security
13.2 CUSTOM LOGIN FORM CREATION
If no login form is configured into spring security, spring boot provides default login
screen for spring security. Default login screen will be used to authenticate the user,
and user will be allowed to access a resource. In an enterprise application default login
screen is not suitable since enterprise does not have full control over design,
processing URLs etc.
Customized login from creation and configuration is very easy in spring security.
Custom login form in Spring Application is nothing but a simple html or jsp, like
other web pages in java. A custom login form enables an enterprise to customize the
login form as per their choice of design. It provides the developer to have full control
over css and processing URL. A custom login form must be having below artifacts:
• Form action URL where the form is POSTed to trigger the authentication
process
• Username input field for the username
• Password input field for the password
Sample custom login page is shown below. You can put the css styling as per
application requirements. The following written custom login page will be used in the
execution of the application into example.
importorg.springframework.stereotype.Controller;
importorg.springframework.web.bind.annotation.GetMapping;
importorg.springframework.web.bind.annotation.RequestMapping;
@Controller
@RequestMapping(value="/customlogin")
publicclassLoginController
{
@GetMapping
public String login()
{
return"customlogin";
}
}
input[type=text], input[type=password]
2
{
Custom Login Using
width: 100%; Security
padding: 12px 20px;
margin: 8px 0;
display: inline-block;
border: 1px solid #ccc;
box-sizing: border-box;
}
button
{
background-color: #4CAF50;
color: white;
padding: 14px 20px;
margin: 8px 0;
border: none;
cursor: pointer;
width: 100%;
}
button:hover
{
opacity: 0.8;
}
.cancelbtn
{
width: auto;
padding: 10px 18px;
background-color: #f44336;
}
.container
{
padding: 16px;
width: 50%;
margin: auto;
}
.errormsg
{
width: 100%;
color: red;
padding: 12px 0px;
text-align: center;
}
span.psw
{
float: right;
padding-top: 16px;
}
</style>
</head>
<body>
<label for="psw"><b>Password</b></label>
<input type="password" placeholder="Enter Password" name="password" required>
<button type="submit">Login</button>
<label>
<input type="checkbox" checked="checked" name="remember"> Remember me
</label>
</div>
<div class="container">
<button type="button" class="cancelbtn">Cancel</button>
<span class="psw">Forgot <a href="#">password?</a></span>
3
Web Seccurity </div>
</form>
</body>
</html>
The login foorm created abbove has the following rellevant artifactts:
• /siggnin – the UR
RL where thee form is PO OSTed to trig
gger the authhentication
proccess
• userrname – inputt field name for
f the usernaame
• passsword – inputt field name for
f the passwoord
Figuree13.1: Custom
m Login Page iin Spring Secu
urity
13.3 SPRING
S Security
y CONFIG with Spring
S M
MVC
FOR
F CUSSTOM LOGIN
L F
FORM
Once you crreate the custtom login pag ge, you need to configure the custom login
l page
in spring security.
s Theere is a detaailed explanaation regardinng Java-baseed Spring
Security connfiguration inn section 12.5
5. Configuratiion for custom
m login pagee in spring
security is very easy. YYou just need d to set the lloginPage in FormLoginC Configurer
object provided by form mLogin(). Sam mple Spring security conffiguration witth custom
login page is shown beloow.
package com
m.ignou.javab
basedspringse
ecurity.secur
rity;
@EnableWebS
Security
public clas
ss WebSecurit
tyConfig exte
ends WebSecur
rityConfigure
erAdapter
{
d
@Autowired
PasswordEn
ncoderpasswor
rdEncoder;
@Bean
sswordEncoder
public Pas rpasswordEnco
oder()
{
return new BCryptPass
swordEncoder(
();
}
@Override
protected void configu
ure(Authentic
cationManager
rBuilder auth
h) throws Excception
{
auth.inMemoryAuthenti
ication().pas
sswordEncoder
r(passwordEnc
coder)
r("testuser")
.withUser
.password
d(passwordEnc
coder.encode(
("user@123")).roles("USER
R").and()
.withUser
r("testadmin"
").password(p
passwordEncod
der.encode("a
admin@123"))
.roles("U
USER", "ADMIN
N");
}
4
protected void configure(HttpSecurity http) throws Exception
Custom Login Using
{ Security
http.csrf().disable()
.authorizeRequests()
.antMatchers("/customlogin").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/customlogin")
.loginProcessingUrl("/signin")
.defaultSuccessUrl("/", true)
.failureUrl("/customlogin?error=true");
}
}
In the above configuration, in-memory authentication has been configured with two
users as testuser with Role USER and testadmin user with Role as USER, ADMIN
both. Thefollowing section will explain the elements used to create the form login
configuration.
authorizeRequests()
<intercept-url> element with access=”permitAll” configures the authorization
to allow all the requests on that particular path. Thus the requests for which no
authorization is required, can be achieved without disabling the spring security using
permitAll().
formLogin()
There are several methods to configure the behavior of formLogin().
Custom login form must be mapped with controller in order to render the page to the
user. The controller class is responsible for processing the request received from the
dispatcher servlet. Spring provides annotation like @Controller to make a POJO class
a controller in spring mvc application. @RequestMapping can be used at class level to
map the controller which will be responsible for handling the request, and at the
method level to map the method, which will be responsible for handling the requested
URL. In previous code snippet for security configuration in section 13.3,
loginPage("/customlogin") has been used. "/customlogin" should be mapped into a
controller which will be responsible to process it and to return the corresponding
view. Request mapping is shown below for "/customlogin" which return the view
name as customlogin.
Spring view resolver resolves this view name as customlogin.jsp and it renders the jsp
created into section 13.2
package com.ignou.javabasedspringsecurity.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
@RequestMapping(value="/customlogin")
public class LoginController
{
@GetMapping
public String login()
{
return "customlogin";
}
In above code snippet, LoginController is mapped with the URL pattern /customlogin
and login() method is returning view name as cutomlogin. View resolver will resolve
the view and corresponding view will be rendered.
packagecom.ignou.javabasedspringsecurity.security;
@EnableWebSecurity
publicclassSecurityConfigextendsWebSecurityConfigurerAdapter
{
@Autowired
PasswordEncoderpasswordEncoder;
@Bean
publicPasswordEncoderpasswordEncoder()
{
returnnewBCryptPasswordEncoder();
}
@Override
protectedvoidconfigure(AuthenticationManagerBuilderauth) throws Exception
{
auth.inMemoryAuthentication().passwordEncoder(passwordEncoder).withUser("testuser")
.password(passwordEncoder.encode("user@123")).roles("USER").and().withUser("testadmin")
.password(passwordEncoder.encode("admin@123")).roles("USER", "ADMIN");//(1)
}
protectedvoidconfigure(HttpSecurityhttp) throws Exception
{
http.csrf().disable()
.authorizeRequests()
.antMatchers("/customlogin*").permitAll() //(2)
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/customlogin") //(3)
.loginProcessingUrl("/signin") //(4)
.defaultSuccessUrl(“/”, true)
.failureUrl(“/customlogin?error=true”);
}
}
7
Web Security
2) /customlogin URL should be accessible to all. Thus permitAll() will allow all
request to pass.
3) formLogin().loginPage("/customlogin") configures the customlogin page.
Controller must have a mapping corresponding to Url pattern “/customlogin”
to return customlogin page.
4) Custom login form processing URL is configured by
loginProcessingUrl("/signin"). Custom login page form action must be
“/signin”
input[type=text], input[type=password]
{
width: 100%;
padding: 12px 20px;
margin: 8px 0;
8
display: inline-block;
Custom Login Using
border: 1px solid #ccc; Security
box-sizing: border-box;
}
button
{
background-color: #4CAF50;
color: white;
padding: 14px 20px;
margin: 8px 0;
border: none;
cursor: pointer;
width: 100%;
}
button:hover
{
opacity: 0.8;
}
.cancelbtn
{
width: auto;
padding: 10px 18px;
background-color: #f44336;
}
.container
{
padding: 16px;
width: 50%;
margin: auto;
}
.errormsg
{
width: 100%;
color: red;
padding: 12px 0px;
text-align: center;
}
span.psw
{
float: right;
padding-top: 16px;
}
</style>
</head>
<body>
<label for="psw"><b>Password</b></label>
<input type="password" placeholder="Enter Password" name="password" required>
<button type="submit">Login</button>
<label>
<input type="checkbox" checked="checked" name="remember"> Remember me
</label>
</div>
<div class="container">
<button type="button" class="cancelbtn">Cancel</button>
<span class="psw">Forgot <a href="#">password?</a></span>
</div>
</form>
</body>
9
Web Seccurity </html>
Output:
If user tries to access loccalhost:8080 and
a user is noot logged in, spring will reedirect the
user on locaalhost:8080/cuustomlogin and custom loogin page willl be rendered as shown
below in Fig gure 13.2:
Figuree 13.3: Custom
m Login Page In
I Spring Secu
urity
If user provides wrong crredentials, aleert from sprinng security wiill be as show
wn in
Figure 13.4 :
Figure 13.4: Invalid Credentialss Error Messaage
10
Custom Loggin Using
Security
Figure 13.5: Success Screeen After Auth
hentication
13.5
5.1 Integrattion Test in
n Spring Boot
The following seection describbes the integrration test inn the spring boot
b applicattion.
Befoore getting diive into inteegration testinng, let us deefine how inntegration tesst is
different from uniit test.
@RunW
With(SpringR
Runner.class)
)
@SpringBootTest
@Auto
oConfigureMo
ockMvc
class
sJavaBasedSp
pringSecurity
yApplication
nTests
{
@Autowire
ed
privateMo
ockMvcmvc;
}
@Sp pringBootTestt: This annotaation instructts Spring Booot to use mainn class annotated
with @SpringBootApplicationn to start a Spring application conteext. Spring boot b
appliication testing
g requires notthing special to do. It’s ApplicationCoontext that neeeds
to bee available too test Spring Boot applicaation. @RunWith instructts the spring--test
moduule to create an ApplicationContext. SpringBootTe
S est loads com
mplete applicaation
and injects
i all the beans, whichh can be slow.
SecurityMockMvcRequestPostProcessors
There are two ways to run the test cases as a specific User in Spring MVC Test.
The following test will run as a specific user, which need not to exist since we are
mocking the user, with the username "user", the password "password", and the role
"ROLE_USER":
@Test
publicvoidtestAlreadyLoggedInUser() throws Exception
{
mvc.perform(get("/").with(user("user"))).andExpect(authenticated().withUsername("user"))
.andExpect(authenticated().withRoles("USER"))
.andExpect(model().attribute("message",
"User, Spring Security with custom login page implemented Successfully !!"));
}
In the set up MockMvc is autoconfigured as mvc and it is being used to simulate the
HTTP request. Here RequestPostProcessoruser() has been used to modified the
get(“/”) request. User RequestPostProcessor can be customized for password and roles
as –
mvc.perform(get("/").with(user("John").password("pass@123").roles("USER","ADMIN")))
mvc.perform(get("/").with(anonymous()))
12
Custom Login Using
• username: String Security
• authorities: String[]
• password: String
• roles: String[]
SecurityMockMvcRequestBuilders
RequestBuilder interface is provided by Spring MVC Test. These request builders can
be used to create the MockHttpServletRequest into the test. Few implementations of
RequestBuilderhas been provided by Spring Security to make testing easy and
efficient. Spring Security’s ReuestBuilder implementations can be used by static
import of as below:
importstaticorg.springframework.security.test.web.servlet.request.SecurityMockMvcRequest
Builders.*;
Form based authentication can be tested very easily in Spring Boot with the help of
SecurityMockMvcRequestBuilders. Below will submit a POST request to “/login”
with the username as “user”, the password as “password” and valid CSRF token.
mvc.perform(formLogin())
In above configuration a POST request for “/signin” with the username as “testadmin”
and the password as “admin@123” with a valid CSRF token will be submitted.
Parameters name can be customized as follows -
mvc.perform(formLogin("/singin").user("uname","[email protected]").password("password","admin@"))
mvc.perform(logout())
mvc.perfrom(logout(“/signout”))
13
Web Seccurity
Check the folder
fo src/test for unit test cases.
c All unitt test cases caan be executed by right
click on the project -> Ruun As -> Juniit Test as show wn below scrreenshot in Figgure 13.6
Figuree 13.6: UnitCaase Execution From
F Eclipse IDE
Successful execution
e of Unit
U test casee will output thhe following.. As you can sees that
all test casess are passed tthat is shown by green tickk and green prrogress bar inn the
Figure 13.7..
Figgure 13.7: Uniit Test Cases E
Execution Logg
13.6 ADDING
A G LOGOU
UT SUPP
PORT
The basic configuration
c of Spring Loogout functioonality using the logout() method
m is
simple enou
ugh:
@Configurat
tion
@EnableWebS
Security
public clas
ss SecSecurittyConfig exte
ends WebSecur
rityConfigure
erAdapter
{
@Override
protected void
v configur
re(final Http
pSecurity htt
tp) throws Ex
xception
{
tp
htt
//...
/
.logout()
//...
/
}
//...
}
The above configuratioon enables default logoutt mechanism m with processing url:
/logout, whiich used to bee /j_spring_seecurity_logouut before Spriing Security 4.
4 We can
14
Custom Login Using
customize the logout feature in spring security. Let us see the advanced customization Security
of spring logout.
logoutSuccessUrl()
On successfully logout operation, Spring Security will redirect the user to a specified
page. By default, this is the root page (“/”), but this is configurable:
//...
.logout()
.logoutSuccessUrl("/successlogout")
//...
logoutUrl()
Like other defaults in Spring Security, logout mechanism has a default processing
URL as well – /logout. To hide the information regarding which framework has been
used to secure the application, it’s better to change the default value. It can be done as
below:
// ...
.logout()
.logoutUrl("/do_logout")
// ...
//...
.logout()
.logoutUrl("/do_logout")
.invalidateHttpSession(true)
.deleteCookies("JSESSIONID")
// ...
Logout feature can be tested by enabling the logout option for the user. Add the logout
option by doing the changes into index.jsp as shown below.
<!DOCTYPEhtml>
<%@taglibprefix="spring"uri="http://www.springframework.org/tags"%>
<htmllang="en">
<body>
<div>
<div>
<astyle="text‐align: left;" href="/logout">logout</a>
<h1>Spring Boot Security Example</h1>
<h2>Hello ${message}</h2>
</div>
</div>
</body>
</html>
15
Web Seccurity pa
ackagecom.igno ou.javabasedsppringsecurity.
.security;
EnableWebSecur
@E rity
pu
ublicclassWebS SecurityConfiggextendsWebSec
curityConfigur
rerAdapter
{
@Autowired
PasswordEncodderpasswordEnccoder;
@Bean
publicPassworrdEncoderpasswwordEncoder()
{
CryptPasswordE
returnnewBC Encoder();
}
@Override
protectedvoid dconfigure(AutthenticationMa
anagerBuildera
auth) throws E
Exception
{
oryAuthenticat
auth.inMemo tion().passwor
rdEncoder(pass
swordEncoder).
.withUser("tes
stuser")
.password(p
passwordEncodeer.encode("use
er@123")).role
es("USER").and
d().withUser("
"testadmin")
.password(p
passwordEncodeer.encode("adm
min@123")).rol
les("USER", "A
ADMIN");
}
protectedvoiddconfigure(HtttpSecurityhttp
p) throws Exce
eption
{
http.csrf()
).disable()
.authorizeR
Requests()
.antMatcher
rs("/customloggin*").permitA
All()
.anyRequest
t().authenticaated()
.and()
.formLogin()
loginPage("/cu
.l ustomlogin")
.l
loginProcessin ngUrl("/signinn")
.d
defaultSuccess sUrl("/", truee)
.f
failureUrl("/c customlogin?errror=true")
.
.and()
.l
logout();
}
}
Execute thee application and after succcessful loginn you will loogout option as shown
below in Fig
gure 13.8:
Figurre 13.8: Successs Screen with
h Logout Feature
After clickiing logout linnk, user will be logged oout and redireected to loginn page as
shown in Figure 13.9
16
Custom Loggin Using
Security
1)
1 Explain th
he usage of @SpringBootT
@ Test.
2)
2 Write the unit test case to execute it as a user w with RequestPPostProcessorr for
the URL pattern "/" which
w returns model
m a "message" and
attribuute with key as
value as "Hello
" World!!"
3)
3 Write thee unit test casse to execute it as a user with
w Annotattion for the U URL
pattern "/" which returrns model attrribute with kkey as "messaage" and valuue as
"Hello World!!"
W
4)
4 Write Unnit test case to test the custom logiin form havving "/signin"" as
loginProccessingUrl and
d "/" as defauultSuccessUrl.
17
Web Security
13.7 SUMMARY
Default Spring Security login form is not suitable for enterprises application since
developers do not have full control over css and form design. Spring Security provides
a way to configure custom login form in Spring Application. This unit has explained
the configuration of custom login form with an example and its execution.
Unit test plays a vital role to ensure the correctness of code, and it identifies every
defect that may arise before code is integrated with other modules. Many Spring Boot
annotations available for Integration testing, such as @SpringBootTest,
@AutoConfigureMockMvc, @WithMockUser has been explained.
Logout feature is an important feature from security perspective. At the end of this
unit, Spring provided logout support has been explained with configurable properties.
<html>
<body>
<div>
<center>Custom Spring Login Form</center>
<form action="/signin" method="post">
<input name="username" type="text" placeholder="Enter Username" />
<input name="password" type="text" placeholder="Enter password" />
<input type="submit" />
</form>
</div>
<body>
<html>
Configuration for custom login page in spring security is very easy. We just
need to set the loginPage in FormLoginConfigurer object provided by
formLogin(). Sample Spring security configuration with custom login page is
shown below.
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter
{
@Autowired
PasswordEncoderpasswordEncoder;
@Bean
18
Custom Login Using
public PasswordEncoderpasswordEncoder()
Security
{
return new BCryptPasswordEncoder();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception
{
auth.inMemoryAuthentication().passwordEncoder(passwordEncoder).withUser("testuser")
.password(passwordEncoder.encode("user@123")).roles("USER").and().withUser("testadmin")
.password(passwordEncoder.encode("admin@123")).roles("USER", "ADMIN");
}
protected void configure(HttpSecurity http) throws Exception
{
http.csrf().disable()
.authorizeRequests()
.antMatchers("/customlogin").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/customlogin")
.loginProcessingUrl("/signin")
.defaultSuccessUrl("/", true)
.failureUrl("/customlogin?error=true");
}
}
19
Web Security
2) RequestPostProcessor interface is provided by Spring MVC Test. These
request processors can be used to modify the request. Many implementations
of RequestPostProcessorhas been provided by Spring Security to make testing
easy and efficient. Spring Security’s ReuestPostProcessor implementations
can be used by static import of as below:
Importstatic
org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPost
Processors.*;
@ExtendWith(SpringExtension.class)
@SpringBootTest
@AutoConfigureMockMvc
classJavaBasedSpringSecurityApplicationTests
{
@Autowired
privateMockMvcmvc;
@Test
@WithMockUser()
publicvoidtestAlreadyLoggedInUserWithAnnotation() throws Exception
{
mvc.perform(get("/").andExpect(authenticated().withUsername("user"))
.andExpect(authenticated().withRoles("USER"))
.andExpect(model().attribute("message","Hello World!!"));
}
}
20
Custom Login Using
Security
13.9 REFERENCES/FURTHER READING
• Craig Walls, “Spring Boot in action” Manning Publications, 2016.
(https://doc.lagout.org/programmation/Spring%20Boot%20in%20Action.pdf)
• Christian Bauer, Gavin King, and Gary Gregory, “Java Persistence with
Hibernate”,Manning Publications, 2015.
• Ethan Marcotte, “Responsive Web Design”, Jeffrey Zeldman Publication,
2011(http://nadin.miem.edu.ru/images_2015/responsive-web-design-2nd-
edition.pdf)
• Tomcy John, “Hands-On Spring Security 5 for Reactive Applications”,Packt
Publishing,2018
• https://docs.spring.io/spring-
security/site/docs/4.2.19.RELEASE/guides/html5/form-javaconfig.html
• https://www.baeldung.com/spring-security-login
• https://www.baeldung.com/spring-boot-testing
• https://docs.spring.io/spring-
framework/docs/current/reference/html/testing.html
21
UNIT 14 ROLE BASED LOGIN
Structure
14.0 Introduction
14.1 Objectives
14.2 Display User Id and Roles – Overview
14.2.1 User Details in a Controller
14.2.2 Spring view layer security and User Details using JSP Taglibs
14.3 Roles based Login Example
14.4 Restrict Access based on Roles
14.5 Testing the Application
14.5.1 Unit Tests in Spring Boot
14.5.1.1 Data Layer or Repository Layer testing with @DataJpaTest
14.5.1.2 Service Layer and Controller layer testing with @MockBean
14.6 Cross Site Request Forgery (CSRF)
14.7 Summary
14.8 Solutions/ Answer to Check Your Progress
14.9 References/Further Reading
14.0 INTRODUCTION
Role-Based access control (RBAC) allows us to define the accessibility based on
user’s roles and permissions. The roles in RBAC refer to the levels of access that user
has to the resource. Roles and permissions are used to make a resource secured from
unauthorized access. RBAC allows to define what end-users can perform at both
broad and granular levels. While using RBAC, resource access of the users is
analyzed, and users are grouped into roles based on common responsibilities and
needs. Each user into the system is assigned with one or more roles and one or more
permissions to each role. For an example, an admin can have permission to create a
new post and edit the already created post while an editor may have permission to edit
the post which already exists.
This Unit explains how to restrict resource access based on roles using the Spring
security. Most of the applications display the logged in user details. This unit
describes the various approaches to get logged in user details in controllers. It also
describes how to retrieve security related information at view layer in jsp.
The previous unit explained how to write integration test cases using annotations
provided by Spring. Good unit test cases make the codebase auto deployable and
production ready since codebase can be validated with the help of unit test cases. This
unit describes the unit test cases with available annotations in Spring.
Cross site request forgery, also known as CSRF or XSRF, is a type of attack in which
attackers trick a victim to make a request that utilizes their authentication or
authorization. The victim’s level of permission decides the impact of CSRF attack. In
the end of this Unit, Cross Site Request Forgery (CSRF) has been explained with an
example and the solution to avoid CSRF attack.
1
Web Security
14.1 OBJECTIVES
Various core classes and interface available in spring security to get security context
are outlined. Spring Security core components are -
• SecurityContextHolder: A Class which provide access to SecurityContext
• SecurityContext: An Interface having Authentication and defining the
minimum-security information associated with request
• Authentication: Represents the Principal in Spring security-specific way.
The Spring Security Principal can only be retrieved as an Object from
Authentication and needs to be cast to the correct UserDetails instance as –
UserDetailsuserDetails = (UserDetails)
authentication.getPrincipal();
System.out.println("User has authorities: "+
userDetails.getAuthorities());
@Controller
public class UserSecurityController
{
2
Role Based Login
Instead of Principal, Authentication can be used. Authentication allows us to get the
granted authorities using getAuthorities() method while Spring Security principal can
only be retrieved as an Object and needs to be cast to the correct UserDetails instance.
Sample code is as following-
@Controller
public class UserSecurityController
{
@RequestMapping(value = "/username", method = RequestMethod.GET)
@ResponseBody
public String loggeInUserName(Authentication authentication)
{
return authentication.getName();
}
}
14.2.2 Spring view layer security and User Details using JspTaglibs
Spring Security provides its own taglib for basic security support, such as retrieving
security information and applying security constraints at view layer jsp. To use spring
security features in jsp, you need to add the following tag library declaration into jsp-
The tags provided by spring security to access security information and to secure the
view layer of the application are as below:
• Authorize Tag
• Authentication Tag
• Accesscontrollist Tag
• Csrfinput Tag
• CsrfMetaTags Tag
Authorize Tag: This tag supports to secure information based on user’s role or
permission to access a URL. Authorize tag support two types of attributes.
• access
• url
In an application, view layer might need to display certain information based on user’s
role or based on authentication state. An example for the same is shown below.
<security:authorize access="!isAuthenticated()">
Login
</security:authorize>
<security:authorize access="isAuthenticated()">
3
Web Security Logout
</security:authorize>
Further, we can also display certain information based on user role as-
<security:authorize access="hasRole('ADMIN')">
Delete Users
</security:authorize>
Using url attribute in authorize tag, at view layer we can check weather user is
authorized to send request to certain URL:
<security:authorizeurl="/inventoryManagement">
<a href="/inventoryManagement">Manage Inventory</a>
</security:authorize>
Authentication Tag: This tag is not used to implement security but it allows access
to the current Authentication object stored in the security context. It renders a property
of the object directly in the JSP. If the principal property of the Authentication is an
instance of Spring Security’s UserDetails object, then username and roles can be
accessed as –
Accesscontrollist Tag: This tag is used with Spring Security’s ACL module. It
checks list of required permissions for the specified domains. It executes only if
current user has all the permissions.
Csrfinput Tag: For this tag to work, csrf protection should be enabled in spring
application. If csrf is enabled, spring security inserts a csrf hidden form input inside
<form:form> tag. But in case if we want to use html <form></form>, we need to put
csrfinput tag inside <form> to create CSRF token as below –
<form method=”post” action=”/some/action”>
<security:csrfInput />
Name:<input type=”text” name=”username” />
…
</form>
4
Role Based Login
</body>
</html>
This section describes role-based login using Spring Security. Role based login means
redirecting users to different URLs upon successful login according to the assigned
role to the logged-in user. The following section explains an example with three types
of users as Admin, Editor and normal User. Once user successfully logged into the
system, based on role user will be redirected to its own url as –
6
Role Based Login
{
returntrue;
}
returnfalse;
}
privatebooleanisEditor(List<String>roles)
{
if (roles.contains("ROLE_EDITOR"))
{
returntrue;
}
returnfalse;
}
publicvoidsetRedirectStrategy(RedirectStrategyredirectStrategy)
{
this.redirectStrategy = redirectStrategy;
}
protectedRedirectStrategygetRedirectStrategy()
{
returnredirectStrategy;
}
}
Above class overrides the handle method and redirects the user based on his role as
follows –
Role-based access control (RBAC) is a mechanism that restricts system access. RBAC
accomplishes this by assigning one or more "roles" to each user and giving each role
different permissions. To protect sensitive data, mostly large-scale organizations use
role-based access control to provide their employees with varying levels of access
based on their roles and responsibilities.
The previous unit explained to secure the application using authentication and URL
level security along with restrictions based on roles. The following sections explain to
secure the application at service layer. Method-level security is used to restrict access
based on Role. The last of this section explains to add security at view layer i.e.jsp.
Spring allows us to implement the security at the method level. Security applied at the
method level restricts the unauthorized user to access the resource mapped by the
method. How to enable method level security and restrict the method accessed based
on role is explained below.
7
Web Security
@EnableGlobalMethodSecurity
To Enable the method level security in spring we need to enable global method
security as below:
@Configuration
@EnableGlobalMethodSecurity(
prePostEnabled = true,
securedEnabled = true,
jsr250Enabled = true)
public class MethodSecurityConfig
extends GlobalMethodSecurityConfiguration
{
}
@Secured annotation is used to implement method level security based on Role. This
annotation accepts list of allowed roles to be permitted. Hence, a user can access a
method if he/she has been assigned at least one role into the list.
@Secured("ROLE_USER")
public String getUsername()
{
SecurityContextsecurityContext = SecurityContextHolder.getContext();
return securityContext.getAuthentication().getName();
}
User who is having role as ROLE_USER can execute the above method.
@Secured({ "ROLE_USER", "ROLE_ADMIN" })
public booleanisValidUsername(String username)
{
return userRoleRepository.isValidUsername(username);
}
A user having Either "ROLE_USER" OR "ROLE_ADMIN" can invoke above
method.
@RolesAllowed Annotation
The @RolesAllowed annotation is the JSR-250’s equivalent annotation of the
@Secured annotation. Basically, we can use the @RolesAllowed annotation in a
similar way as @Secured.
@RolesAllowed("ROLE_USER")
public String getUsername()
{
//...
}
8
Role Based Login
Both @PreAuthorize and @PostAuthorize annotations provide expression-based
access control. The @PreAuthorize annotation checks the given expression before
entering into the method, whereas, the @PostAuthorize annotation verifies it after the
execution of the method and could alter the result.
@PreAuthorize("hasRole('ROLE_VIEWER')")
public String getUsername()
{
//...
}
@PreAuthorize("hasRole('ROLE_USER') or hasRole('ROLE_ADMIN')")
public booleanisValidUsername(String username)
{
//...
}
@PreAuthorize("#username == authentication.principal.username")
public String getMyRoles(String username)
{
//...
}
Further we can also display certain information based on user role as-
<security:authorize access="hasRole('ADMIN')">
Delete Users
</security:authorize>
1) Describe role-based login. Write the sample code to configure the role-based
login.
…………………………………………………………………………………
…………………………………………………………………………………
…………………………………………………....................................………
…………………………………………………………………………………
………………………………
2) What is Role Based Access Control (RBAC)? Write the sample configuration
code to restrict the URL access based on role.
…………………………………………………………………………………
…………………………………………………………………………………
…………………………………………………....................................………
9
Web Security
…………………………………………………………………………………
………………………………
3) Explain @Secured and @RolesAllowed. What is the difference between
them?
…………………………………………………………………………………
…………………………………………………………………………………
…………………………………………………....................................………
…………………………………………………………………………………
………………………………
4) Which are all spring security annotations allowed to use SpEL?
…………………………………………………………………………………
…………………………………………………………………………………
…………………………………………………....................................………
…………………………………………………………………………………
………………………………
5) What's the difference between @Secured and @PreAuthorize in spring
security?
…………………………………………………………………………………
…………………………………………………………………………………
…………………………………………………....................................………
…………………………………………………………………………………
………………………………
6) Explain spring security tag which restricts the access based on roles in jsp.
…………………………………………………………………………………
…………………………………………………………………………………
…………………………………………………....................................………
…………………………………………………………………………………
………………………………
In units 12 and 13, In-Memory authentication has been configured. Here JDBC
authentication with mysql database has been explained. Tools and software required
10
Role Based Login
to write the code easily, manage the spring dependencies and execute the application
is as -
• Java 8 or above is required
• Maven
• Eclipse IDE
• Mysql
• Hibernate
• JPA
Directory Structure for Spring Project in eclipse is shown below. A few of the code is
shown in Figure 14.1.
Figure 14.1: Project Folder Structure In Eclipse IDE
packagecom.ignou.javabasedspringsecurity.config;
@Component
publicclassCustomSuccessHandlerextendsSimpleUrlAuthenticationSuccessHandler
{
privateRedirectStrategyredirectStrategy = newDefaultRedirectStrategy();
@Override
protectedvoidhandle(HttpServletRequestrequest, HttpServletResponseresponse,
Authentication authentication)throwsIOException
{
String targetUrl = determineTargetUrl(authentication);
if (response.isCommitted())
{
System.out.println("Can't redirect");
return;
}
11
Web Security
redirectStrategy.sendRedirect(request, response, targetUrl);
}
/*
* This method extracts the roles of currently logged‐in user and returns
* appropriate URL according to his/her role.
*/
protected String determineTargetUrl(Authentication authentication)
{
String url = "";
Map<String, String>roleTargetUrlMap = new HashMap<>();
roleTargetUrlMap.put("ROLE_USER", "/home");
roleTargetUrlMap.put("ROLE_ADMIN", "/admin");
roleTargetUrlMap.put("ROLE_Editor", "/editor");
Collection<? extendsGrantedAuthority>authorities =
authentication.getAuthorities();
List<String>roles = newArrayList<String>();
for (GrantedAuthoritya :authorities)
{
roles.add(a.getAuthority());
}
if (isAdmin(roles))
{
url = "/admin";
}
elseif (isEditor(roles))
{
url = "/editor";
}
elseif (isUser(roles))
{
url = "/home";
}
else
{
url = "/accessDenied";
}
returnurl;
}
privatebooleanisUser(List<String>roles)
{
if (roles.contains("ROLE_USER"))
{
returntrue;
}
returnfalse;
}
privatebooleanisAdmin(List<String>roles)
{
if (roles.contains("ROLE_ADMIN"))
{
returntrue;
}
returnfalse;
}
privatebooleanisEditor(List<String>roles)
{
if (roles.contains("ROLE_EDITOR"))
{
returntrue;
}
returnfalse;
}
publicvoidsetRedirectStrategy(RedirectStrategyredirectStrategy)
{
this.redirectStrategy = redirectStrategy;
}
12
Role Based Login
protectedRedirectStrategygetRedirectStrategy()
{
returnredirectStrategy;
}
}
SecurityConfig.java
Complete Security configuration with successHandler(customSuccessHandler) is as
below-
packagecom.ignou.javabasedspringsecurity.config;
@EnableWebSecurity
publicclassSecurityConfigextendsWebSecurityConfigurerAdapter
{
@Autowired
privateUserDetailsServicecustomUserService;
@Autowired
privateCustomSuccessHandlercustomSuccessHandler;
@Autowired
PasswordEncoderpasswordEncoder;
@Bean
publicPasswordEncoderpasswordEncoder()
{
returnnewBCryptPasswordEncoder();
}
@Override
protectedvoidconfigure(AuthenticationManagerBuilderauth) throws Exception
{
auth
.userDetailsService(customUserService)
.passwordEncoder(passwordEncoder);
}
protectedvoidconfigure(HttpSecurityhttp) throws Exception
{
http.csrf().disable()
.authorizeRequests()
.antMatchers("/customlogin*").permitAll()
.antMatchers("/","/home").hasRole("USER")
.antMatchers("/editor/**").hasRole("EDITOR")
.antMatchers("/admin/**").hasRole("ADMIN")
.antMatchers("/edit/**").hasAnyRole("ADMIN","EDITOR")
.antMatchers("/create/**").hasAnyRole("ADMIN")
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/customlogin")
.loginProcessingUrl("/signin")
.successHandler(customSuccessHandler)
.failureUrl("/customlogin?error=true")
.and()
.logout()
.and().exceptionHandling().accessDeniedPage("/accessdenied");;
}
13
Web Security publicclassLoginController
{
@GetMapping
public String login()
{
return"customlogin";
}
}
HomeController.java
packagecom.ignou.javabasedspringsecurity.controller;
@Controller
publicclassHomeController
{
privatestatic Map<Long, String>msgs = new HashMap<>();
privatestaticlongmsgCount = 0;
static
{
msgs.put(new Long(1), "Java Cryptography Architecture (JCA)");
msgs.put(new Long(2), "Java Secure Socket Extension (JSSE)");
msgCount = 2;
}
@RequestMapping(value="/home", method=RequestMethod.GET)
public String user(Model model)
{
model.addAttribute("msgs", msgs);
return"user";
}
@RequestMapping(value="/editor", method=RequestMethod.GET)
public String editor()
{
return"editor";
}
@RequestMapping(value="/admin", method=RequestMethod.GET)
public String admin()
{
return"admin";
}
@RequestMapping(value="/edit", method=RequestMethod.GET)
public String edit(Model model)
{
model.addAttribute("msgs", msgs);
return"edit";
}
@RequestMapping(value="/edit", method=RequestMethod.POST)
public String editPost(@ModelAttributeMsgPostmsgPost, Model model)
{
longmsgId = msgPost.getId();
if (msgs.get(msgId) != null)
{
msgs.put(msgPost.getId(), msgPost.getContent());
}
model.addAttribute("msgs",msgs);
return"edit";
}
@RequestMapping(value="/create", method=RequestMethod.POST)
publicStringcreatePost(@ModelAttributeMsgPostmsgPost, Model model)
{
msgCount += 1;
msgs.put(msgCount, msgPost.getContent());
model.addAttribute("msgs",msgs);
return "edit";
}
14
Role Based Login
}
packagecom.ignou.javabasedspringsecurity.service;
@Service
@Transactional
publicclassUserServiceimplementsUserDetailsService
{
@Autowired
privateUserRepositoryuserRepository;
@Override
publicUserDetailsloadUserByUsername(String email)
throwsUsernameNotFoundException
{
User user = userRepository.findByEmail(email).orElseThrow(()‐
>newUsernameNotFoundException(email + "not found"));
returnneworg.springframework.security.core.userdetails.User(user.getEmail(),
user.getPassword(),getAuthorities(user));
}
privatestatic Collection<? extendsGrantedAuthority>getAuthorities(User user)
{
String[] userRoles = user.getRoles().stream().map((role) ‐>
role.getName()).toArray(String[]::new);
Stream.of(userRoles).forEach(System.out::print);
Collection<GrantedAuthority>authorities =
AuthorityUtils.createAuthorityList(userRoles);
returnauthorities;
}
}
Jsp in WEB-INF/views
Note: customlogin.jsp has been used same as explained in Unit 13.
admin.jsp
<%@tagliburi="http://www.springframework.org/security/tags"prefix="security"%>
<%@pagelanguage="java"contentType="text/html; charset=ISO‐8859‐1"pageEncoding="ISO‐
8859‐1"%>
<html>
<head>
<metahttp‐equiv="Content‐Type"content="text/html; charset=ISO‐8859‐1">
<title>Admin page</title>
</head>
<body>
Dear <strong><security:authenticationproperty="principal.username"/></strong>,
Welcome to Admin Page.
<p>You are having roles as
<strong><security:authenticationproperty="principal.authorities"/></strong>
<p><ahref="/edit">Edit</a>
<p><ahref="/logout">Logout</a>
</body>
</html>
editor.jsp
<%@tagliburi="http://www.springframework.org/security/tags"prefix="security"%>
<%@pagelanguage="java"contentType="text/html; charset=ISO‐8859‐1"pageEncoding="ISO‐
8859‐1"%>
<html>
<head>
<metahttp‐equiv="Content‐Type"content="text/html; charset=ISO‐8859‐1">
<title>Editor page</title>
</head>
15
Web Security <body>
Dear <strong><security:authenticationproperty="principal.username"/></strong>,
Welcome to Editor Page.
<p>You are having roles as
<strong><security:authenticationproperty="principal.authorities"/></strong>
<p><ahref="/edit">Edit</a>
<p><ahref="/logout">Logout</a>
</body>
</html>
user.jsp
<%@tagliburi="http://www.springframework.org/security/tags"
prefix="security"%>
<%@taglibprefix="c"uri="http://java.sun.com/jsp/jstl/core"%>
<%@pagelanguage="java"contentType="text/html; charset=ISO‐8859‐1"
pageEncoding="ISO‐8859‐1"%>
<html>
<head>
<metahttp‐equiv="Content‐Type"content="text/html; charset=ISO‐8859‐1">
<title>Welcome page</title>
<style>
table.border,th.border,td.border
{
margin‐left: auto;
margin‐right: auto;
border: 1px solid black;
}
</style>
</head>
<body>
Dear
<strong><security:authenticationproperty="principal.username"/></strong>,
Welcome to Home Page.
<p>
You are having roles as <strong><security:authentication
property="principal.authorities"/></strong>
<tableclass="border">
<tr>
<thclass="border">Msg Id</th>
<thclass="border">Message</th>
</tr>
<c:forEachitems="${msgs}"var="msg">
<tr>
<tdclass="border">${msg.key}</td>
<tdclass="border">${msg.value}</td>
</tr>
</c:forEach>
</table>
<p>
<ahref="/logout">Logout</a>
</body>
</html>
Execute the project either from eclipse or command line. After successful execution of
the application, security configured application can be accessed using browser on
localhost:8080
The following users are configured for the testing of role-based login example.
If a user tries to access localhost:8080 and the user is not logged in, spring will
redirect to the user on localhost:8080/customlogin as shown in Figure 14.2.
16
Role Based
d Login
Figure 14.22: Spring Secu
urity Custom L
Login Page
Figuree14.3: Admin User Home Screen
On click
c on Edit button
b admin will see the below
b screen (Figure 14.4)). Admin has
only permission too create new messages as explained
e thee feature of eaach user in thee
nning of this section.
begin
Figure14.4: Edit
E and Creatte Screen For Admin User
17
7
Web Security
S
When Editoor logs in, youu will get the below
b screenn (Figure 14.5).
Figgure 14.5: Ediitor Role Userr Home Screen
n
On click on n Edit buttonn, editor can only edit thee already exissting messages. Check
edit.jsp file in which <security:authoorize access="hasRole('A ADMIN')">seecurity tag
has been useed to allow onnly Admin usser to create nnew messagess (Figure 14.66).
Figu
ure14.6: Edit Screen
S from E
Editor Role Usser
When a userr logs in, he/sshe will get thhe below screen(Figure 14.7) as you cann see that
normal userr does not havve any option to edit the message.
F
Figure14.7: General
G User H
Home Screen
14.5.1 Un
nit Tests in Spring Boot
Production-ready code shhould have well-written
w U test casess as well as Inntegration
Unit
Test. Good unit test casees should hav ve code coverrage of 80% or more. Wriiting good
unit test casses is an art, aand sometimees it’s difficuult to write goood code coverage unit
test cases. Spring
S providees an efficiennt way to writee Unit Test caases as well Inntegration
Test cases. In
I Unit 13, vaarious annotattions have beeen described for Integratioon Testing
18
Role Based Login
with examples. @SpringBootTest is used for integration testing, and it is useful when
we need to bootstrap the entire container. This section will describe the best practices
to write unit test cases as well as available annotations will be described.
@SpringBootTest
@SpringBootTest
class StudentEnrollmentUseCaseTest
@Autowired
private EnrollmentServiceenrollmentService;
@Test
void studentEnrollemnt()
assertThat(enrolledStudent.getEnrollmentNo()).isNotNull();
A good test case takes only few milliseconds, but the above code might take 3-4
seconds. The above test case execution takes only a few milliseconds, and the rest of
the 4 seconds is being taken by @SpringBootTest to set up the complete Spring Boot
Application Context. In the above test case complete Spring Boot Application Context
has been set up to autowire the EnrollmentService instance into the test case. Unit test
cases set up time can be reduced a lot with the use of Mock instances and appropriate
annotation instead of @SpringBootTest.
A well-structured web application consists of multiple layer such as Controllers,
Services and Repository. Controllers are responsible to handle the client request
forwarded by dispatcherServlet. The controller uses Service classes for business logic
and Service classes uses Repository classes to interact with databases. Each layer can
be tested independently with Unit test cases. The following section will describe the
important annotations available in Spring to write the good unit test with a few
milliseconds of execution time.
@Autowired
private TestEntityManagerentityManager;
@Autowired
private UserRepositoryuserRepository;
// test cases
}
@DataJpaTest focuses only on JPA components needed for testing the persistence
layer. Instead of initializing the complete Spring Boot Application Context, as in the
case of @SpringBootTest, initializes only the required configuration relevant to JPA
tests. Thus, Unit test case set-up time is very less. @DataJpaTest does the following
configurations.\
@DataJpaTest
publicclassUserRepositoryTest
{
@Autowired
privateTestEntityManagerentityManager;
@Autowired
privateUserRepositoryuserRepository;
@BeforeEach
privatevoidsetUp()
{
User user = newUser();
user.setEmail("[email protected]");
user.setName("Admin");
user.setPassword("admin@123");
entityManager.persist(user);
entityManager.flush();
}
20
Role Based Login
@Test
publicvoidfindByEmailTest()
{
String email = "[email protected]";
// Call userRepository to get user record
Optional<User>found = userRepository.findByEmail(email);
String getUserEmail = found.get().getEmail();
assertThat(getUserEmail).isEqualTo(email);
}
}
21
Web Security
All unit test cases can be executed by right click on the project -> Run As -> Junit
Test as shown below screenshot (Figure 14.8).
Figure 14.8: Unit Test Case Execution From Eclipse IDE
Successful execution of Unit Test case will output the following (Figure 14.9). As you
can see all test cases are passed,which is shown by the green tick and green progress
bar.
Figure14.9: Unit Test Cases Execution Status
22
Role Based Login
amount=100.00&account=1234
Now consider that user authenticate to bank’s website and then, without logging out,
visit an evil website. The evil website contains an HTML page with the following
form:
<form action="https://bank.example.com/transfer" method="post">
<input type="hidden"
name="amount"
value="100.00"/>
<input type="hidden"
name="account"
value="evilsAccountNumber"/>
<input type="submit"
value="Win Money!"/>
</form>
User like to win money, and he clicks on the Win Money! Button. As user clicks on
button, unintentionally he transferred $100 to a malicious user. While evil website can
not see your cookies, but the browser sent the cookie associated with bank along with
the request.
The whole process can be automated using JavaScript, and onPage load script can be
executed to perform CSRF. The most popular method to prevent Cross-site Request
Forgery is to use a randomly generated token that is associated with a particular user
and that is sent as a hidden value in every state-changing form in the web app. This
token, called an anti-CSRF token (often abbreviated as CSRF token) or a synchronizer
token. When a request is submitted, the server must look up the expected value for the
parameter and compare it against the actual value in the request. If the values do not
match, the request should fail.
Spring Security CSRF Protection
The use of proper HTTP verb plays a vital role to protect a website against CSRF
attack. We need to be assured that the application is using PATCH, POST, PUT,
and/or DELETE for anything that modifies state. This is not a limitation of Spring
Security’s support, but instead a general requirement for proper CSRF prevention.
@EnableWebSecurity
public class WebSecurityConfig extends
WebSecurityConfigurerAdapter
{
@Override
protected void configure(HttpSecurity http) throws Exception
{
http
.csrf().disable();
}
}
The last step is to include the CSRF token all PATCH, POST, PUT, and DELETE
methods. Csrfinput Tag is described into section 14.2 and used it in edit.jsp in Section
14.5. In edit.jsp we used two approach to include csrf token as follows-
• <input type="hidden" name="${_csrf.parameterName}"
value="${_csrf.token}" />
• <security:csrfInput/>
Following example will give you experimental and real feel of CSRF attack in the
application executed in Section 14.5. Steps to perform CSRF attack simulation are as
below-
Step 1: To simulate the evil website create a html file with below content. You can
give it any name. Let us assume that filename is as evil.html and save this file to any
location.
<html>
<body>
<form action="http://localhost:8080/edit" method="POST" id="attack">
<input type="hidden" name="id" value="2">
<input type="hidden" name="content" value="Hackers Msg">
<input type="button"
onclick="document.getElementById('attack').submit()" value="Click me to Won
Prize"></input>
</form>
</body>
</html>
Step 2: Start the application tested into Section 14.5 and login as Admin or Editor
user. Here consideration is that Admin user do login into the system (Figure 14.10).
24
Role Based
d Login
Figure 144.10: Admin Role
R User Hom
me Screen
F
Figure 14.11: CSRF Attack
k
As you
y can see in i above screeen that maliicious user hhas edited thee msg. Close the
evil.h
html. From admin
a y will find the
login, click on eddit link, and there also you
modiified msg by malicious
m useer.
Noww we will makke the requireed changes too protect the website
w again
nst CSRF attaacks.
We have
h configurred security inn Security.javva file. You ccan check thaat csrf is disabbled
theree. You can ju ust remove csrf.disable()
c and automattically csrf prrotection will be
enabled. We havee already inclluded token in i jsp so no nneed to makee any changees in
jsp. Perform
P all th
he steps againn, and this tim
me in step 3 yyou will get the below scrreen
(Figuure 14.12) .
F
Figure 14.12: Website
W Proteected Against CSRF Attack
k
25
5
Web Security
As you can see now,the edit is being denied since we have enabled CSRF protection
and the malicious user is unable to edit or create the msg.
You can try to create a new message as a malicious user by disabling csrf protection.
Make the changes in evil.html.
14.7 SUMMARY
In the Unit, you learnt various core components of Spring Security such as
SecurityContextHolder, SecurityContext, Authentication, Principal etc. Next you
26
Role Based Login
learnt how to get logged in user details in controllers using Authentication and
Principal and many more.
Gradually you learnt various Spring Security tags such as authorize, authentication,
csrfInput etc. to secure the view layer jsp and display the user details on jsp using
these tags.
Next you learnt about role-based login. In role-based login you learnt to redirect users
on different URL based on assigned role of the User. You learnt about
AuthenticationSuccessHandler and configuration using successHandler().
This Unit has described how to secure the service layer methods using various
annotations such as @Secured, @RoleAllowed, @PreAuthorize, @PostAuthorize etc.
You executed a complete application in which you learnt how to implement the above
concept programmatically. In the lastof the unit, you learnt how to enable CSRF
protection in Spring application. You got the real feel of CSRF attack with executed
example, and this will enable you to understand CSRF attack easily.
Figure 14.13: Authorities in Authentication object
@Override
protected void configure(final HttpSecurity http) throws Exception
{
http
.authorizeRequests()
// endpoints
.formLogin()
.loginPage("/login.html")
.loginProcessingUrl("/login")
.successHandler(customSuccessHandler())
// other configuration
}
2) For RBAC refer section 14.4. Configuration to restrict the URL access based
on role is as below-
protectedvoidconfigure(HttpSecurityhttp) throws Exception
{
http.csrf().disable()
.authorizeRequests()
.antMatchers("/customlogin*").permitAll()
.antMatchers("/","/home").hasRole("USER")
.antMatchers("/editor/**").hasRole("EDITOR")
.antMatchers("/admin/**").hasRole("ADMIN")
.antMatchers("/edit/**").hasAnyRole("ADMIN","EDITOR")
.antMatchers("/create/**").hasAnyRole("ADMIN")
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/customlogin")
.loginProcessingUrl("/signin")
.successHandler(customSuccessHandler)
.failureUrl("/customlogin?error=true")
.and()
.logout()
.and().exceptionHandling().accessDeniedPage("/accessdenied");;
}
In above configuration
URL pattern “/” and “/home” is accessible only to user which is having role
as ROLE_USER.
URL pattern “/editor/**” is accessible only to user having role as
ROLE_EDITOR
URL pattern “/admin/**” is accessible only to user having role as
ROLE_ADMIN
28
Role Based Login
URL pattern “/edit/**” is accessible to user having role as ROLE_ADMIN or
ROLE_EDITOR
URL pattern “/create/**” is permissible only to user having role as
ROLE_ADMIN
5) If you wanted to do something like access the method only if the user has
Role1 and Role2 the you would have to use @PreAuthorize
@PreAuthorize("hasRole('ROLE_role1') and hasRole('ROLE_role2')") Using
@Secured({"role1", "role2"}) is treated as an OR
Further we can also display certain information based on user role as-
<security:authorize access="hasRole('ADMIN')">
Delete Users
</security:authorize>
2) In the MVC project, Controllers are dependent on Services, and Services are
dependent on Repositories. However, Controllers and Services should be
testable without knowing the complete implementation of dependencies.
@MockBean can be used to mock the required dependency. Spring boot
@MockBean annotation used to add mocks to a Spring ApplicationContext.
• @MockBean allows to mock a class or an interface.
29
Web Security
• @MockBean can be used on fields in either @Configuration classes
or test classes that are @RunWith the SpringRunner as well as a class
level annotation.
@MockBean at field level
@RunWith(SpringRunner.class)
public class LoginControllerTest
{
@MockBean
private LoginServiceloginService;
@RunWith(SpringRunner.class)
@MockBean(LoginService.class)
public class LoginControllerTest
{
@Autowired
private LoginServiceloginservice;
3) For CSRF details, refer Unit 12 section 12.3 and Unit 14 section 14.6.
Necessary condition for CSRF attack to succeed is that that the victim must be
logged in and attacker is able to trick the victim into clicking a link or loading
a web page is done through social engineering or using a malicious link.
30
Role Based Login
• Christian Bauer, Gavin King, and Gary Gregory, “Java Persistence with
Hibernate”,Manning Publications, 2015.
• Ethan Marcotte, “Responsive Web Design”, Jeffrey Zeldman Publication,
2011(http://nadin.miem.edu.ru/images_2015/responsive-web-design-2nd-
edition.pdf)
• Tomcy John, “Hands-On Spring Security 5 for Reactive Applications”,Packt
Publishing,2018
• https://www.baeldung.com/spring_redirect_after_login
• https://digitalguardian.com/blog/what-role-based-access-control-rbac-
examples-benefits-and-more
• https://docs.spring.io/spring-security/site/docs/5.0.x/reference/html/csrf.html
• https://docs.spring.io/spring-
framework/docs/current/reference/html/testing.html
• https://www.baeldung.com/spring-security-csrf
• https://www.baeldung.com/java-spring-mockito-mock-mockbean
31