Spring Security using Custom Authentication Provider
Tools and Technologies used
1)Eclipse IDE Mars Release (4.5.0)
2)Java 8
3)Spring framework 4.2.0
4)Spring security 3.2
5)Tomcat 8
Follow steps from the Spring MVC project link to setup a spring maven hello world project.
Project Structure
Then follow below steps to achieve spring security using custom Authentication Provider.
Modify pom.xml as below to have spring security dependencies
- <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 http://maven.apache.org/maven-v4_0_0.xsd">
- <modelVersion>4.0.0</modelVersion>
- <groupId>SpringSecurity</groupId>
- <artifactId>SpringSecurityCustomAuthenticationProvider</artifactId>
- <packaging>war</packaging>
- <version>0.0.1-SNAPSHOT</version>
- <name>SpringSecurityCustomAuthenticationProvider Maven Webapp</name>
- <url>http://maven.apache.org</url>
- <properties>
- <org.springframework.version>4.2.0.RELEASE</org.springframework.version>
- <spring-security.version>3.2.7.RELEASE</spring-security.version>
- </properties>
- <dependencies>
- <dependency>
- <groupId>junit</groupId>
- <artifactId>junit</artifactId>
- <version>3.8.1</version>
- <scope>test</scope>
- </dependency>
- <!-- Spring MVC depends on these modules spring-core, spring-beans, spring-context,
- spring-web -->
- <dependency>
- <groupId>org.springframework</groupId>
- <artifactId>spring-web</artifactId>
- <version>${org.springframework.version}</version>
- </dependency>
- <dependency>
- <groupId>org.springframework</groupId>
- <artifactId>spring-webmvc</artifactId>
- <version>${org.springframework.version}</version>
- </dependency>
- <!-- Spring Security Dependencies -->
- <dependency>
- <groupId>org.springframework.security</groupId>
- <artifactId>spring-security-core</artifactId>
- <version>${spring-security.version}</version>
- </dependency>
- <dependency>
- <groupId>org.springframework.security</groupId>
- <artifactId>spring-security-web</artifactId>
- <version>${spring-security.version}</version>
- </dependency>
- <dependency>
- <groupId>org.springframework.security</groupId>
- <artifactId>spring-security-config</artifactId>
- <version>${spring-security.version}</version>
- </dependency>
- </dependencies>
- <build>
- <finalName>SpringSecurityCustomAuthenticationProvider</finalName>
- <plugins>
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-compiler-plugin</artifactId>
- <version>2.5.1</version>
- <configuration>
- <source>1.8</source>
- <target>1.8</target>
- </configuration>
- </plugin>
- </plugins>
- </build>
- </project>
<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 http://maven.apache.org/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>SpringSecurity</groupId> <artifactId>SpringSecurityCustomAuthenticationProvider</artifactId> <packaging>war</packaging> <version>0.0.1-SNAPSHOT</version> <name>SpringSecurityCustomAuthenticationProvider Maven Webapp</name> <url>http://maven.apache.org</url> <properties> <org.springframework.version>4.2.0.RELEASE</org.springframework.version> <spring-security.version>3.2.7.RELEASE</spring-security.version> </properties> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>3.8.1</version> <scope>test</scope> </dependency> <!-- Spring MVC depends on these modules spring-core, spring-beans, spring-context, spring-web --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> <version>${org.springframework.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>${org.springframework.version}</version> </dependency> <!-- Spring Security Dependencies --> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-core</artifactId> <version>${spring-security.version}</version> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-web</artifactId> <version>${spring-security.version}</version> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-config</artifactId> <version>${spring-security.version}</version> </dependency> </dependencies> <build> <finalName>SpringSecurityCustomAuthenticationProvider</finalName> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>2.5.1</version> <configuration> <source>1.8</source> <target>1.8</target> </configuration> </plugin> </plugins> </build> </project>
Modify web.xml to add spring security filter as below
- <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
- version="3.1">
- <display-name>Archetype Created Web Application</display-name>
- <!-- Spring MVC dispatcher servlet -->
- <servlet>
- <servlet-name>mvc-dispatcher</servlet-name>
- <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
- <init-param>
- <param-name>contextConfigLocation</param-name>
- <param-value>
- /WEB-INF/spring-mvc.xml,
- /WEB-INF/spring-security.xml
- </param-value>
- </init-param>
- <load-on-startup>1</load-on-startup>
- </servlet>
- <servlet-mapping>
- <servlet-name>mvc-dispatcher</servlet-name>
- <url-pattern>/</url-pattern>
- </servlet-mapping>
- <listener>
- <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
- </listener>
- <!-- Loads Spring Security configuration file -->
- <context-param>
- <param-name>contextConfigLocation</param-name>
- <param-value>
- /WEB-INF/spring-mvc.xml,
- /WEB-INF/spring-security.xml
- </param-value>
- </context-param>
- <!-- Spring Security filter -->
- <filter>
- <filter-name>springSecurityFilterChain</filter-name>
- <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
- </filter>
- <filter-mapping>
- <filter-name>springSecurityFilterChain</filter-name>
- <url-pattern>/*</url-pattern>
- </filter-mapping>
- </web-app>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" version="3.1"> <display-name>Archetype Created Web Application</display-name> <!-- Spring MVC dispatcher servlet --> <servlet> <servlet-name>mvc-dispatcher</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value> /WEB-INF/spring-mvc.xml, /WEB-INF/spring-security.xml </param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>mvc-dispatcher</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <!-- Loads Spring Security configuration file --> <context-param> <param-name>contextConfigLocation</param-name> <param-value> /WEB-INF/spring-mvc.xml, /WEB-INF/spring-security.xml </param-value> </context-param> <!-- Spring Security filter --> <filter> <filter-name>springSecurityFilterChain</filter-name> <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class> </filter> <filter-mapping> <filter-name>springSecurityFilterChain</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> </web-app>
Add spring security config file as below
- <beans:beans xmlns="http://www.springframework.org/schema/security"
- xmlns:beans="http://www.springframework.org/schema/beans"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://www.springframework.org/schema/beans
- http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
- http://www.springframework.org/schema/security
- http://www.springframework.org/schema/security/spring-security-3.2.xsd">
- <http auto-config='true'>
- <intercept-url pattern="/secured/*" access="ROLE_USER" />
- </http>
- <authentication-manager>
- <authentication-provider ref="customAuthenticationProvider"/>
- </authentication-manager>
- </beans:beans>
<beans:beans xmlns="http://www.springframework.org/schema/security" xmlns:beans="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.2.xsd"> <http auto-config='true'> <intercept-url pattern="/secured/*" access="ROLE_USER" /> </http> <authentication-manager> <authentication-provider ref="customAuthenticationProvider"/> </authentication-manager> </beans:beans>
Provide Authentication provider reference to our custom class which can handle custom authentication mechanism.
Create controller class as below
- package com.kb.controller;
- import org.springframework.security.core.context.SecurityContextHolder;
- import org.springframework.security.core.userdetails.User;
- import org.springframework.stereotype.Controller;
- import org.springframework.ui.ModelMap;
- import org.springframework.web.bind.annotation.RequestMapping;
- import org.springframework.web.bind.annotation.RequestMethod;
- import com.kb.model.CustomUser;
- @Controller
- public class HomeController {
- @RequestMapping(value="/helloworld", method = RequestMethod.GET)
- public String helloWorld(ModelMap model) {
- model.addAttribute("message", "Welcome to the Hello World page");
- return "helloworld";
- }
- @RequestMapping(value="/secured/home", method = RequestMethod.GET)
- public String securedHome(ModelMap model) {
- Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
- CustomUser user=null;
- if (principal instanceof CustomUser) {
- user = ((CustomUser)principal);
- }
- String name = user.getUsername();
- model.addAttribute("username", name);
- model.addAttribute("message", "Welcome to the secured page");
- return "home";
- }
- }
package com.kb.controller; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.userdetails.User; import org.springframework.stereotype.Controller; import org.springframework.ui.ModelMap; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import com.kb.model.CustomUser; @Controller public class HomeController { @RequestMapping(value="/helloworld", method = RequestMethod.GET) public String helloWorld(ModelMap model) { model.addAttribute("message", "Welcome to the Hello World page"); return "helloworld"; } @RequestMapping(value="/secured/home", method = RequestMethod.GET) public String securedHome(ModelMap model) { Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal(); CustomUser user=null; if (principal instanceof CustomUser) { user = ((CustomUser)principal); } String name = user.getUsername(); model.addAttribute("username", name); model.addAttribute("message", "Welcome to the secured page"); return "home"; } }
Create a custom authentication provider class as below
- package com.kb.authentication.provider;
- import java.util.Collection;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.security.authentication.AuthenticationProvider;
- import org.springframework.security.authentication.BadCredentialsException;
- import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
- import org.springframework.security.core.Authentication;
- import org.springframework.security.core.AuthenticationException;
- import org.springframework.security.core.GrantedAuthority;
- import org.springframework.stereotype.Component;
- import com.kb.model.CustomUser;
- import com.kb.service.CustomUserService;
- @Component
- public class CustomAuthenticationProvider implements AuthenticationProvider{
- @Autowired
- private CustomUserService userService;
- public Authentication authenticate(Authentication authentication) throws AuthenticationException {
- String username = authentication.getName();
- String password = (String) authentication.getCredentials();
- CustomUser user = userService.loadUserByUsername(username);
- if (user == null || !user.getUsername().equalsIgnoreCase(username)) {
- throw new BadCredentialsException("Username not found.");
- }
- if (!password.equals(user.getPassword())) {
- throw new BadCredentialsException("Wrong password.");
- }
- Collection<? extends GrantedAuthority> authorities = user.getAuthorities();
- return new UsernamePasswordAuthenticationToken(user, password, authorities);
- }
- public boolean supports(Class<?> arg0) {
- return true;
- }
- }
package com.kb.authentication.provider; import java.util.Collection; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.authentication.AuthenticationProvider; import org.springframework.security.authentication.BadCredentialsException; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.Authentication; import org.springframework.security.core.AuthenticationException; import org.springframework.security.core.GrantedAuthority; import org.springframework.stereotype.Component; import com.kb.model.CustomUser; import com.kb.service.CustomUserService; @Component public class CustomAuthenticationProvider implements AuthenticationProvider{ @Autowired private CustomUserService userService; public Authentication authenticate(Authentication authentication) throws AuthenticationException { String username = authentication.getName(); String password = (String) authentication.getCredentials(); CustomUser user = userService.loadUserByUsername(username); if (user == null || !user.getUsername().equalsIgnoreCase(username)) { throw new BadCredentialsException("Username not found."); } if (!password.equals(user.getPassword())) { throw new BadCredentialsException("Wrong password."); } Collection<? extends GrantedAuthority> authorities = user.getAuthorities(); return new UsernamePasswordAuthenticationToken(user, password, authorities); } public boolean supports(Class<?> arg0) { return true; } }
Our custom class implements AuthenticationProvider interface provided by spring security
And authenticate method is overridden with our logic.
We will call service class method to load the user based on user name.
If the user is not found or password mismatch then throw an exception , if he is a valid user return the authentication token which is expected by spring security.
Create a user service class to obtain the user details.
- package com.kb.service;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.security.core.userdetails.UserDetailsService;
- import org.springframework.security.core.userdetails.UsernameNotFoundException;
- import org.springframework.stereotype.Service;
- import com.kb.dao.UserDAOImpl;
- import com.kb.model.CustomUser;
- @Service
- public class CustomUserService implements UserDetailsService {
- @Autowired
- private UserDAOImpl userDao;
- public CustomUser loadUserByUsername(String username) throws UsernameNotFoundException {
- return userDao.loadUserByUsername(username);
- }
- }
package com.kb.service; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.stereotype.Service; import com.kb.dao.UserDAOImpl; import com.kb.model.CustomUser; @Service public class CustomUserService implements UserDetailsService { @Autowired private UserDAOImpl userDao; public CustomUser loadUserByUsername(String username) throws UsernameNotFoundException { return userDao.loadUserByUsername(username); } }
Service class calls the DAO layer to obtain the user data based on user name
Create the User DAO class which returns the user based on username supplied.
- package com.kb.dao;
- import java.util.ArrayList;
- import java.util.List;
- import org.springframework.stereotype.Repository;
- import com.kb.model.CustomUser;
- import com.kb.model.Role;
- @Repository
- public class UserDAOImpl {
- public CustomUser loadUserByUsername(final String username) {
- //Write your DB call code to get the user details from DB,But I am just hard coding the user
- CustomUser user = new CustomUser();
- user.setFirstName("kb");
- user.setLastName("gc");
- user.setUsername("kb");
- user.setPassword("1234");
- Role r = new Role();
- r.setName("ROLE_USER");
- List<Role> roles = new ArrayList<Role>();
- roles.add(r);
- user.setAuthorities(roles);
- return user;
- }
- }
package com.kb.dao; import java.util.ArrayList; import java.util.List; import org.springframework.stereotype.Repository; import com.kb.model.CustomUser; import com.kb.model.Role; @Repository public class UserDAOImpl { public CustomUser loadUserByUsername(final String username) { //Write your DB call code to get the user details from DB,But I am just hard coding the user CustomUser user = new CustomUser(); user.setFirstName("kb"); user.setLastName("gc"); user.setUsername("kb"); user.setPassword("1234"); Role r = new Role(); r.setName("ROLE_USER"); List<Role> roles = new ArrayList<Role>(); roles.add(r); user.setAuthorities(roles); return user; } }
Create our own user class as below
- package com.kb.model;
- import java.util.List;
- import org.springframework.security.core.userdetails.UserDetails;
- public class CustomUser implements UserDetails {
- private String username;
- private String password;
- private String email;
- private String firstName;
- private String lastName;
- /* Spring Security related fields*/
- private List<Role> authorities;
- private boolean accountNonExpired = true;
- private boolean accountNonLocked = true;
- private boolean credentialsNonExpired = true;
- private boolean enabled = true;
- public String getUsername() {
- return username;
- }
- public void setUsername(String username) {
- this.username = username;
- }
- public String getPassword() {
- return password;
- }
- public void setPassword(String password) {
- this.password = password;
- }
- public String getEmail() {
- return email;
- }
- public void setEmail(String email) {
- this.email = email;
- }
- public String getFirstName() {
- return firstName;
- }
- public void setFirstName(String firstName) {
- this.firstName = firstName;
- }
- public String getLastName() {
- return lastName;
- }
- public void setLastName(String lastName) {
- this.lastName = lastName;
- }
- public List<Role> getAuthorities() {
- return authorities;
- }
- public void setAuthorities(List<Role> authorities) {
- this.authorities = authorities;
- }
- public boolean isAccountNonExpired() {
- return accountNonExpired;
- }
- public void setAccountNonExpired(boolean accountNonExpired) {
- this.accountNonExpired = accountNonExpired;
- }
- public boolean isAccountNonLocked() {
- return accountNonLocked;
- }
- public void setAccountNonLocked(boolean accountNonLocked) {
- this.accountNonLocked = accountNonLocked;
- }
- public boolean isCredentialsNonExpired() {
- return credentialsNonExpired;
- }
- public void setCredentialsNonExpired(boolean credentialsNonExpired) {
- this.credentialsNonExpired = credentialsNonExpired;
- }
- public boolean isEnabled() {
- return enabled;
- }
- public void setEnabled(boolean enabled) {
- this.enabled = enabled;
- }
- }
package com.kb.model; import java.util.List; import org.springframework.security.core.userdetails.UserDetails; public class CustomUser implements UserDetails { private String username; private String password; private String email; private String firstName; private String lastName; /* Spring Security related fields*/ private List<Role> authorities; private boolean accountNonExpired = true; private boolean accountNonLocked = true; private boolean credentialsNonExpired = true; private boolean enabled = true; public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } public String getFirstName() { return firstName; } public void setFirstName(String firstName) { this.firstName = firstName; } public String getLastName() { return lastName; } public void setLastName(String lastName) { this.lastName = lastName; } public List<Role> getAuthorities() { return authorities; } public void setAuthorities(List<Role> authorities) { this.authorities = authorities; } public boolean isAccountNonExpired() { return accountNonExpired; } public void setAccountNonExpired(boolean accountNonExpired) { this.accountNonExpired = accountNonExpired; } public boolean isAccountNonLocked() { return accountNonLocked; } public void setAccountNonLocked(boolean accountNonLocked) { this.accountNonLocked = accountNonLocked; } public boolean isCredentialsNonExpired() { return credentialsNonExpired; } public void setCredentialsNonExpired(boolean credentialsNonExpired) { this.credentialsNonExpired = credentialsNonExpired; } public boolean isEnabled() { return enabled; } public void setEnabled(boolean enabled) { this.enabled = enabled; } }
Create a class Role
- package com.kb.model;
- import java.util.List;
- import org.springframework.security.core.GrantedAuthority;
- public class Role implements GrantedAuthority{
- private String name;
- public String getName() {
- return name;
- }
- public void setName(String name) {
- this.name = name;
- }
- public String getAuthority() {
- return this.name;
- }
- }
package com.kb.model; import java.util.List; import org.springframework.security.core.GrantedAuthority; public class Role implements GrantedAuthority{ private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } public String getAuthority() { return this.name; } }
Right click on the project and run as Maven install, copy the war file into webapps folder of server and start the server.
Let’s access the public url which is not intercepted by spring security
http://localhost:8080/SpringSecurityCustomAuthenticationProvider/helloworld
Let’s access the secured url which is intercepted by spring security
http://localhost:8080/SpringSecurityCustomAuthenticationProvider/secured/home
Let’s put invalid username and check the output
Let’s put invalid password and check the output
Note : The error messages are coming as we mentioned in our provider class.
Let’s put valid credentials and check the output
Hi
First of all thanks for this post. I am new to spring security and trying to understand use of Authentication provider, I created project as per this post.
I am trying to understand below portion from spring-security.xml file
I understand that authentication happens on first request that comes in. After the user has
been authenticated and tries to access another page, will CustomAuthenticationProvider call authenticate function all over again. If not, how does the application work until user signs out or timeout? If the information store somewhere in applications that the user has been authenticated and is used on request going back and forth
Thanks in advance!
@Component
public class CustomAuthenticationProvider implements AuthenticationProvider{
@Autowired
private CustomUserService userService;
}
in this class always getting “userService” as null.
Please help.
I got below error
No mapping found for HTTP request with URI [/SpringSecurityHelloWorldCustomLogin/login] in DispatcherServlet with name ‘mvc-dispatcher’
Hello,
I am doing something similar but my CustomAuthentcationProvider it not doing any lower level calls (call to DAO to check for the user), I am not sure why.
I Autowired it still it doesn’t work.
Can you help me with this.
Hello. Thank you for a great tutorial! I’ve implemented this in my project and it mostly works. I’m using Postman to test and if I don’t provide any authentication header my custom auth class (CustomAuthenticationProvider) is never called and I am able to access my REST service.
It seems as if Anonymous requests bypass this security. How can I prevent all Anonymous requests?
I should add that I’m using XML configuration.
Hi,
Great, Thank you !!
Do you have an answer for my question?
It seems as if Anonymous requests bypass this security. How can I prevent all Anonymous requests?
< intercept-url pattern="/secured/*" access="ROLE_USER" / >
This line should allow to access only for those users who have ROLE_USER, It should not allow for anonymous as they don’t have this role….Please let me know if its any specific case.
What line? Was there supposed to be code in your last response?
Here is how I have my Spring security xml setup now.
I appreciate the help!
yes. Please check the previous reply.
I could not see any xml in the reply.
It looks like the web site is stripping XML from the comment. I’ll try replacing the with %
The only way I was able to see yours was to view the source for the page.
%http auto-config=’true’%
%intercept-url pattern=”/services/**” access=”ROLE_USER” /%
%csrf disabled=”true”/%
%anonymous enabled=’false’/%
%/http%
I figured it out. My “context-root” wasn’t set right in jboss-web.xml
It was set to “/services”
When I change it to “/” everything works.
Thank you for the help!
Great !!
Hello. Good post.
I would like to know if it is possible to perform several authentication methods with spring security. That is to say, the case of authenticating users through a form or that the same can be authenticated using another means for example with your gmail account through gmail. I know that with spring security there is the possibility of performing encrypted token authentication but I have not seen that it can be done both ways in the same application using spring security.
Good question!!
We can do that in spring security.
For applications to authenticate users through third parties .The best option to use is OAUTH using tokens which is more secure and widely accepted one.
Please check this article on the same.
Thanks for your answer.
I have read the article and it is very clear, excellent. To which also in another project that I was working with spring security I implemented using OAuth2.
But I have not yet managed to perform an authentication integrating both: authentication using credentials user and password, or, when it is authentication using a third party login for example through facebook, but this within the same application. That is, in case of using the authentication of my app will be validated with the records of the DB but in case of the authentication through third party login, authenticate it in my app through a security token.
Thank you again for your attention.
Ok you are welcome 🙂
Karibasappa,
Great tutorial!
I have a small doubt. In the code below, how can I catch the message given in the bad credentials exception in a Spring MVC controller where I call the custom authentication code.
if (user == null || !user.getUsername().equalsIgnoreCase(username)) {
throw new BadCredentialsException(“Username not found.”);
}
if (!password.equals(user.getPassword())) {
throw new BadCredentialsException(“Wrong password.”);
}
Thanks.
Hi Maneesh,
Thank you!!
You can catch the message of any Exception thrown by the Authentication provider in the controller using SPRING_SECURITY_LAST_EXCEPTION session attribute
Its a session attribute set by spring security whenever any exception is thrown in the authentication provider.
So in your controller, you can use the below code and get the exception message
You can add it in the model attribute to send it to JSP page.
That helped. Thanks a lot!
you are welcome !!
Hi,
Interesting post. I have a question. You used AuthenticationProvider to wire-up your code which performs both authentication and authorization. Although this approach is simple to implement but your custom AuthenticationProvider should be doing authentication only and not both.
Hi John,
If you look at my authentication provider, I am not doing any authorization there, I have just taken the user roles and passing it to Spring security using UsernamePasswordAuthenticationToken as below
Authorization will be done by Spring using the Roles passed to this token.
Thanks!!
This is misleading information. on your security xml in above post, you didn’t mention tag but on your downloaded code, you had included it.
Please avoid such mistakes.
Can you tell me which tag you are talking about ?
If you just say tag,i cant understand anything, if you tell me exact piece of code i can correct it after verifying the same.
In download code there is a login form tag in security xml , if you are talking about that, then you are wrong, that is only for using custom login form which is an extra piece of code used for another article.
Please tell me the details where you are finding discrepancy.
Thank you!!
Hi,
I am trying to authenticate my JAX-RS rest APIs using spring authentication . I have created spring filter chain proxy referring this link here http://shazsterblog.blogspot.in/2014/07/spring-security-custom-filterchainproxy.html. I want to have basic authentication for my APIs. I don’t know where to specify basic authentication configuration. I have created CustomAuthenticationProvider and CustomUserDetailsService. When I hit any service URL it says 403 – Access Denied and when I hit /login the request return 200. How do I implement my login service and how to specify the session timeout. Please help me with this.
Hi,
If you want to store the credentials for basic authentication in xml you can put it in the xml file as explained in this post http://javainsimpleway.com/spring-security-hello-world-project/ or if you want to get it from DB then you can use this link http://javainsimpleway.com/spring-security-using-database-authentication/
Then hit the service, it will prompt for authentication and then provide the same credentials.
for session timeout after 15 minutes, you can put below config in web.xml
Thank you!!
nice post,But i want to store roles(like admin,sec user,manage,corp user etc.) in database and based on login i want to fetch that roles from db and display to user in terms of menus
Thanks Iliyas!!
I am just trying to understand your requirement.
When the user provides login credentials and click on login, you need to fetch all the roles of the logged in user and display it in the Menu.
Please correct me If my understanding is incorrect,but assuming its correct, you need to get the roles from below API
Collection< ? extends GrantedAuthority> authorities = (Collection< ? extends GrantedAuthority>) SecurityContextHolder.getContext().getAuthentication().getAuthorities();
and use it wherever you want.
you can see below lines in HomeController.java in this article
we are getting user name from principal and adding inside model attribute
Similalry you can get the roles from principal and add them inside model attribute using
and access them in JSP as below
Thank you!!
I have mail my example project to your mail id .Please go through it and tell me what i need to customize in my project to get roles from database.Thank you.
I did not get access to your project code and requested for access.
i have shared you through google drive .Please confirm and reply back.Thank you
I have checked your code.
You have MainController in your project.
So add below code in that controller
and add below code in your jsp wherever you want to display ex hello.jsp
At the time of login first username and password is validate then based on userid>> roles and privileges(roles are interms of comma seperated like AB,BC,CD etc in single column) of that user get selected ,and based on database roles values menu should be display .Only that menu items are enable which exists in database ,if not then that menu link should be disable.So how i can achieve this requirement.Hope i will get expected solution.Thank you.
In my above previous reply, you can find the solution of how to get the roles and display them in JSP.
You just need to put them in menu using html div and css code.
enable the menu using jquery if roles > 0 else disable it using jquery.
Thanks a lot Karibasappa ,I will go through this and get back to you.
You are welcome!!
I want to use filter for intercept url as shown below.
how to customize “securityMetadataSource” to fetch roles from db.Thank you
when username is not found , i think throw “UsernameNotFoundException” is better.
btw, thanks bro
Completely agree with you, we should do that.
I have just not focused on Exception modularity in this article but good point.
Thanks!!
Hi KB, I liked your post, i have similar integration with siteminder .. i need to read groupmembership header also part of my request for the roles . can you please share some details how to achieve it ?
Hi Jidh,Thanks !!
SiteMinder comes with the filter called “RequestHeaderAuthenticationFilter” which receives only “User”from the request header.
To add anything else into the header and to get it read from the site minder filter,we have to write our own filter class which can extend the “RequestHeaderAuthenticationFilter”.
Inside our own filter , write a logic which will read the group membership from the header.
Inject this custom filter in the place where we inject existing filter.
I was looking for looking for a tutorial on this for a very long time and this somehow hadn’t shown up anywhere. It’s just what I needed and helped me immensely. Thank you very much! 🙂
Thanks and happy learning 🙂
I hope you got it working now after sending the modified files.
Thank you.
Hi,
I have an exact the same issue with Agung.
Can you please teach me how you solved his issue?
Hi Jake , Thanks for reading it!!
His issue was with web.xml where he missed importing some config files.
Please send the error which you are facing along with web.xml and spring config files , will check it and let you know.
Thanks a ton. Would you send me your email address please.
sure… its karibasappagc@gmail.com
an email sent sir.
ya , I checked and replied you !!
thanks you very much for the answer , but it appears an error like this
Severe: Exception while invoking class com.sun.enterprise.web.WebApplication start method
java.lang.Exception: java.lang.IllegalStateException: ContainerBase.addChild: start: org.apache.catalina.LifecycleException: org.springframework.beans.factory.BeanCreationException: Error creating bean with name ‘org.springframework.security.filterChains’: Cannot resolve reference to bean ‘org.springframework.security.web.DefaultSecurityFilterChain#0’ while setting bean property ‘sourceList’ with key [0]; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name ‘org.springframework.security.web.DefaultSecurityFilterChain#0’: Cannot resolve reference to bean ‘org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter#0’ while setting constructor argument with key [3]; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name ‘org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter#0’: Cannot resolve reference to bean ‘org.springframework.security.authentication.ProviderManager#0’ while setting bean property ‘authenticationManager’; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name ‘org.springframework.security.authentication.ProviderManager#0’: Cannot resolve reference to bean ‘org.springframework.security.config.authentication.AuthenticationManagerFactoryBean#0’ while setting constructor argument; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name ‘org.springframework.security.config.authentication.AuthenticationManagerFactoryBean#0’: FactoryBean threw exception on object creation; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name ‘org.springframework.security.authenticationManager’: Cannot resolve reference to bean ‘customAuthenticationProvider’ while setting constructor argument with key [0]; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named ‘customAuthenticationProvider’ is defined
at com.sun.enterprise.web.WebApplication.start(WebApplication.java:138)
at org.glassfish.internal.data.EngineRef.start(EngineRef.java:130)
at org.glassfish.internal.data.ModuleInfo.start(ModuleInfo.java:269)
at org.glassfish.internal.data.ApplicationInfo.start(ApplicationInfo.java:301)
at com.sun.enterprise.v3.server.ApplicationLifecycle.deploy(ApplicationLifecycle.java:461)
at com.sun.enterprise.v3.server.ApplicationLifecycle.deploy(ApplicationLifecycle.java:240)
at org.glassfish.deployment.admin.DeployCommand.execute(DeployCommand.java:389)
at com.sun.enterprise.v3.admin.CommandRunnerImpl$1.execute(CommandRunnerImpl.java:348)
at com.sun.enterprise.v3.admin.CommandRunnerImpl.doCommand(CommandRunnerImpl.java:363)
at com.sun.enterprise.v3.admin.CommandRunnerImpl.doCommand(CommandRunnerImpl.java:1085)
at com.sun.enterprise.v3.admin.CommandRunnerImpl.access$1200(CommandRunnerImpl.java:95)
at com.sun.enterprise.v3.admin.CommandRunnerImpl$ExecutionContext.execute(CommandRunnerImpl.java:1291)
at com.sun.enterprise.v3.admin.CommandRunnerImpl$ExecutionContext.execute(CommandRunnerImpl.java:1259)
at com.sun.enterprise.v3.admin.AdminAdapter.doCommand(AdminAdapter.java:461)
at com.sun.enterprise.v3.admin.AdminAdapter.service(AdminAdapter.java:212)
at com.sun.grizzly.tcp.http11.GrizzlyAdapter.service(GrizzlyAdapter.java:179)
at com.sun.enterprise.v3.server.HK2Dispatcher.dispath(HK2Dispatcher.java:117)
at com.sun.enterprise.v3.services.impl.ContainerMapper$Hk2DispatcherCallable.call(ContainerMapper.java:354)
at com.sun.enterprise.v3.services.impl.ContainerMapper.service(ContainerMapper.java:195)
at com.sun.grizzly.http.ProcessorTask.invokeAdapter(ProcessorTask.java:860)
at com.sun.grizzly.http.ProcessorTask.doProcess(ProcessorTask.java:757)
at com.sun.grizzly.http.ProcessorTask.process(ProcessorTask.java:1056)
at com.sun.grizzly.http.DefaultProtocolFilter.execute(DefaultProtocolFilter.java:229)
at com.sun.grizzly.DefaultProtocolChain.executeProtocolFilter(DefaultProtocolChain.java:137)
at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:104)
at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:90)
at com.sun.grizzly.http.HttpProtocolChain.execute(HttpProtocolChain.java:79)
at com.sun.grizzly.ProtocolChainContextTask.doCall(ProtocolChainContextTask.java:54)
at com.sun.grizzly.SelectionKeyContextTask.call(SelectionKeyContextTask.java:59)
at com.sun.grizzly.ContextTask.run(ContextTask.java:71)
at com.sun.grizzly.util.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:532)
at com.sun.grizzly.util.AbstractThreadPool$Worker.run(AbstractThreadPool.java:513)
at java.lang.Thread.run(Thread.java:745)
Hi Agung,
As per my observation, you have defined the bean customAuthenticationProvider twice,once using @Component annotation in the CustomAuthenticationProvider class and other one is inside spring security xml as below
< beans:bean id="customAuthenticationProvider" class="id.co.iconpln.authentication.CustomAuthenticationProvider">
always XML bean definition takes priority than annotation one which is the issue i think.
Can you please remove the above bean declaration from the spring security config file.
Let me know if that helps, if not send me complete stack trace.
Hi Agung,
Thanks for reading !!
You are getting NULL pointer exception, there is a chance that the object which you are injecting could be NULL.
Please check whether the below CustomUserService you are injecting is defined as spring bean
@Autowired
private CustomUserService userService;
Can you post or email me your CustomUserService class and CustomAuthenticationProvider , i will have a look into it.
thank you for replying , I really appreciate it , I ‘ll send an email, but I do not know your email , can you tell me your email
thank you for replying , I really appreciate it
this my class CustomAuthenticationProvider
import ….
@Component
public class CustomAuthenticationProvider implements AuthenticationProvider {
@Autowired
private CustomUserService userService;
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
String username = authentication.getName();
String password = (String) authentication.getCredentials();
CustomUser user = userService.loadUserByUsername(username);
if (user == null || !user.getUsername().equalsIgnoreCase(username)){
throw new BadCredentialsException(“Username not found.”);
}
if (!password.equals(user.getPassword())) {
throw new BadCredentialsException(“Wrong password.”);
}
Collection authorities = user.getAuthorities();
return new UsernamePasswordAuthenticationToken(user, password, authorities);
}
public boolean supports(Class arg0) {
return true;
}
}
and this my custom user service
@Service
public class CustomUserService implements UserDetailsService {
@Autowired
private UserDAOImpl userDao;
public CustomUser loadUserByUsername(String username) throws UsernameNotFoundException {
return userDao.loadUserByUsername(username);
}
}
i already send my script and my sturcture in email
thanks for your post,
im trying implement but i have problem like this
java.lang.NullPointerException
at CustomAuthenticationProvider.authenticate(CustomAuthenticationProvider.java:32)
CustomUser user = userService.loadUserByUsername(username); <– this line
HTTP Status 500 –
type Exception report
message
descriptionThe server encountered an internal error () that prevented it from fulfilling this request.
exception
java.lang.NullPointerException
note The full stack traces of the exception and its root causes are available in the GlassFish Server Open Source Edition 3.1.2.2 logs.
GlassFish Server Open Source Edition 3.1.2.2
Thank you very much for your post!
But, if I want to add an extra field to login page? For example pinCode?
Since, I am using default login page provided by Spring,we can not achieve it as it is.
But we can add any number of fields in the custom login page and achieve this.
Please refer this post for the same ,there i have added only 2 fields , but yes we can add as many fields as we want. http://javainsimpleway.com/spring/spring-security-using-custom-login-form/
But for this , we need to write custom authentication provider as explained in this post.
I will try to write a new post for the same.
Thanks for this.
Hi Grab,
Have you achieved you requirement, could you please post if you get it.