Spring Security (+Spring) Custom Authentication Provider

I will continue from where I’ve finished in this post. You can customize my development according to your structure. The previous actions does not necessarily have to be done for Spring Security integration. But if you do, you will have Spring + Spring Security together.

My structure will be like below:
Spring Security

My pom.xml for dependencies is like:

<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>com.mydomain</groupId>
	<artifactId>SampleSpringProject</artifactId>
	<packaging>war</packaging>
	<version>1.0-SNAPSHOT</version>
	<name>SampleSpringProject Maven Webapp</name>
	<url>http://maven.apache.org</url>

	<properties>
		<spring.version>4.0.1.RELEASE</spring.version>
		<spring.security.version>3.2.0.RELEASE</spring.security.version>
		<jack.version>1.9.13</jack.version>
		<jdk.version>1.7</jdk.version>
	</properties>

	<dependencies>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-core</artifactId>
			<version>${spring.version}</version>
		</dependency>

		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-web</artifactId>
			<version>${spring.version}</version>
		</dependency>

		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-webmvc</artifactId>
			<version>${spring.version}</version>
		</dependency>
		
		<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>SampleSpringProject</finalName>
		<plugins>
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-compiler-plugin</artifactId>
				<version>3.1</version>
				<configuration>
					<source>${jdk.version}</source>
					<target>${jdk.version}</target>
				</configuration>
			</plugin>
		</plugins>
	</build>

</project>

My application-servlet.xml file will be like below. mvc:resources tags are not necessary for Spring Security configuration. Serving static files from outside of the classpath is best practice for resources.

<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:mvc="http://www.springframework.org/schema/mvc"
	xmlns:context="http://www.springframework.org/schema/context"
	xsi:schemaLocation="
	http://www.springframework.org/schema/beans     
	http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
	http://www.springframework.org/schema/mvc
        http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd
	http://www.springframework.org/schema/context 
	http://www.springframework.org/schema/context/spring-context-4.0.xsd">

	<!-- Scan for components under this package -->
	<context:component-scan base-package="com.mydomain" />

	<!-- Handles HTTP GET requests for /resources/** by efficiently serving up static resources in the ${webappRoot}/resources directory -->
	<mvc:resources mapping="/js/**" location="/assets/js/" />
	<mvc:resources mapping="/css/**" location="/assets/css/" />
	<mvc:resources mapping="/images/**" location="/assets/images/" />
	<mvc:resources mapping="/**" location="/htmls/" />

</beans>

Then my web.xml file for this structure will be like below. Spring Security related things start from the comment. The rest of the file is about Spring configuration.

<web-app xmlns="http://java.sun.com/xml/ns/javaee"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="
	http://java.sun.com/xml/ns/javaee 
	http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
	version="2.5">

	<display-name>Sample Spring Project Application</display-name>

	<servlet>
		<servlet-name>application-servlet</servlet-name>
		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
		<init-param>
			<param-name>contextConfigLocation</param-name>
			<param-value>/WEB-INF/spring/servlets/application-servlet.xml</param-value>
		</init-param>
		<load-on-startup>1</load-on-startup>
	</servlet>

	<servlet-mapping>
		<servlet-name>application-servlet</servlet-name>
		<url-pattern>/</url-pattern>
	</servlet-mapping>

	<context-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>/WEB-INF/spring/root-context.xml</param-value>
	</context-param>

	<listener>
		<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
	</listener>
	
	<!-- Spring Security -->
	<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>

Then we define Spring Security resources and activate annotation base driven development style of Spring in our root-context.xml file:

<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:mvc="http://www.springframework.org/schema/mvc"
	xmlns:context="http://www.springframework.org/schema/context"
	xsi:schemaLocation="
	http://www.springframework.org/schema/beans     
	http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
	http://www.springframework.org/schema/mvc
        http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd	
	http://www.springframework.org/schema/context 
	http://www.springframework.org/schema/context/spring-context-4.0.xsd">

	<!-- Scan for components under this package -->
	<context:component-scan base-package="com.mydomain" />
	
	<!-- Enables the Spring MVC @Controller programming model -->
	<mvc:annotation-driven />

	<!-- Import spring security configurations -->
	<import resource="classpath:spring/spring-security.xml" />

	<!-- Import Beans -->
	<!-- <import resource="classpath:spring/hibernateBeans.xml" /> -->
	<!-- <import resource="classpath:spring/springBeans.xml" /> -->
</beans>

Then one of other important configuration file is spring-security.xml. In http tag, use-expressions property enables to use ‘hasRole’ expression inside the intercept-url tag. In this tag we define which pages are spring secure and what is our logout url. Then we define our custom authentication provider class. We just reference it from this xml and put @Component annotation to Java file.

<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-4.0.xsd
	http://www.springframework.org/schema/security
	http://www.springframework.org/schema/security/spring-security-3.2.xsd">

	<http auto-config="true" use-expressions="true">
		<intercept-url pattern="/**" access="hasRole('ROLE_USER')" />
		<logout logout-url="/logout" />
	</http>

	<authentication-manager alias="authenticationManager">
		<authentication-provider ref="customAuthenticationProvider" />
	</authentication-manager>
	
</beans:beans>

Now, I will talk about necessary classes. Actually we don’t have to implement all of them but this development style provides us more flexibility which we desire. Below you will see CustomAuthenticationProvider class code. This is the main class for customization. Even if you don’t implement other classes from Spring Security interfaces, this class will be enough for custom authentication system. We must implement AuthenticationProvider interface from Spring Security. Note that @Component annotation and the name of class and name in the spring-security.xml file.

package com.mydomain.security;

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.mydomain.model.User;
import com.mydomain.service.UserService;

@Component
public class CustomAuthenticationProvider implements AuthenticationProvider {

	@Autowired
	private UserService userService;

	@Override
	public Authentication authenticate(Authentication authentication) throws AuthenticationException {
		String username = authentication.getName();
		String password = (String) authentication.getCredentials();

		User user = userService.loadUserByUsername(username);

		if (user == null) {
			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);
	}

	@Override
	public boolean supports(Class<?> arg0) {
		return true;
	}
}

Below, there is a UserService which implements Spring Security UserDetailsService. We need to implement loadUserByUsername method that returns Spring Security UserDetails object. In my development, I implement both UserDetailsService and UserDetails class. I choose to return my own User object from loadUserByUsername method.

package com.mydomain.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 org.springframework.transaction.annotation.Transactional;

import com.mydomain.dao.UserDao;
import com.mydomain.service.UserService;
import com.mydomain.model.User;

@Service
public class UserService implements UserDetailsService {

	@Autowired
	private UserDao userDao;

	@Override
	public User loadUserByUsername(final String username) throws UsernameNotFoundException {
		return userDao.loadUserByUsername(username);
	}
}

In UserDao class, I will create a sample User object for test. Probably you want to access database and get user information from there.

package com.mydomain.dao;

import java.util.ArrayList;
import java.util.List;

import org.springframework.stereotype.Repository;

import com.mydomain.model.Role;
import com.mydomain.model.User;

@Repository
public class UserDao {

	public User loadUserByUsername(final String username) {
		User user = new User();
		user.setFirstName("firstName");
		user.setLastName("lastName");
		user.setUsername("user");
		user.setPassword("1111");
		Role r = new Role();
		r.setName("ROLE_USER");
		List<Role> roles = new ArrayList<Role>();
		roles.add(r);
		user.setAuthorities(roles);
		return user;
	}
}

Below class is a custom User class which is returned by UserService loadUserByUsername method.

package com.mydomain.model;

import java.util.Collection;
import java.util.List;

import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;

public class User implements UserDetails {
	private static final long serialVersionUID = 1L;

	private String username;
	private String password;
	private String email;
	private String firstName;
	private String lastName;

	/* Spring Security fields*/
	private List<Role> authorities;
	private boolean accountNonExpired = true;
	private boolean accountNonLocked = true;
	private boolean credentialsNonExpired = true;
	private boolean enabled = true;

	@Override
	public String getUsername() {
		return username;
	}

	public void setUsername(String username) {
		this.username = username;
	}
	
	@Override
	public String getPassword() {
		return password;
	}

	public void setPassword(String password) {
		this.password = password;
	}

	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 String getEmail() {
		return email;
	}

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

	@Override
	public Collection<? extends GrantedAuthority> getAuthorities() {
		return this.authorities;
	}
	
	public void setAuthorities(List<Role> authorities) {
		this.authorities = authorities;
	}

	@Override
	public boolean isAccountNonExpired() {
		return this.accountNonExpired;
	}
	
	public void setAccountNonExpired(boolean accountNonExpired) {
		this.accountNonExpired = accountNonExpired;
	}

	@Override
	public boolean isAccountNonLocked() {
		return this.accountNonLocked;
	}
	
	public void setAccountNonLocked(boolean accountNonLocked) {
		this.accountNonLocked = accountNonLocked;
	}

	@Override
	public boolean isCredentialsNonExpired() {
		return this.credentialsNonExpired;
	}
	
	public void setCredentialsNonExpired(boolean credentialsNonExpired) {
		this.credentialsNonExpired = credentialsNonExpired;
	}

	@Override
	public boolean isEnabled() {
		return this.enabled;
	}

	public void setEnabled(boolean enabled) {
		this.enabled = enabled;
	}

	@Override
	public String toString() {
		StringBuilder builder = new StringBuilder();
		builder.append("User [username=");
		builder.append(username);
		builder.append(", email=");
		builder.append(email);
		builder.append(", password=");
		builder.append(password);
		builder.append(", firstName=");
		builder.append(firstName);
		builder.append(", lastName=");
		builder.append(lastName);
		builder.append(", authorities=");
		builder.append(authorities);
		builder.append(", accountNonExpired=");
		builder.append(accountNonExpired);
		builder.append(", accountNonLocked=");
		builder.append(accountNonLocked);
		builder.append(", credentialsNonExpired=");
		builder.append(credentialsNonExpired);
		builder.append(", enabled=");
		builder.append(enabled);
		builder.append("]");
		return builder.toString();
	}
}

This class has a Role object which will be used for authorization. Role object implements Spring Security GrantedAuthority interface. getAuthority() method must be overridden for implementation. Role object has a list of privileges. This privileges will help us to evaluate permissions in our development.

package com.mydomain.model;

import java.util.List;

import org.springframework.security.core.GrantedAuthority;

public class Role implements GrantedAuthority {

	private static final long serialVersionUID = 1L;
	private String name;

	private List<Privilege> privileges;

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	@Override
	public String getAuthority() {
		return this.name;
	}

	public List<Privilege> getPrivileges() {
		return privileges;
	}

	public void setPrivileges(List<Privilege> privileges) {
		this.privileges = privileges;
	}

	@Override
	public String toString() {
		StringBuilder builder = new StringBuilder();
		builder.append("Role [name=");
		builder.append(name);
		builder.append(", privileges=");
		builder.append(privileges);
		builder.append("]");
		return builder.toString();
	}
}

Below there is a basic Privilige class code:

package com.dataxpert.model;

public class Privilege {

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	private String name;

	@Override
	public String toString() {
		StringBuilder builder = new StringBuilder();
		builder.append("Privilege [name=");
		builder.append(name);
		builder.append("]");
		return builder.toString();
	}
}

With this configuration and code, everything works fine for me. If you encounter any problem, please let me know and we’ll work together on it.

NOTE: Please consider the below comment from Stacy and cleanup toString() method from sensible information.

If you are using psi-probe to monitor a Tomcat instance (for example), the toString() method will enable the password to be visible in cleartext via the Spring session attribute SPRING_SECURITY_CONTEXT

Developers Rock!!!

This entry was posted in Java and tagged , , , , , , , , , , , , , . Bookmark the permalink.

59 Responses to Spring Security (+Spring) Custom Authentication Provider

  1. PSS says:

    Thanks for the code. This is really helpful.
    Could you please send me the code. Or have you uploaded it to GitHub?

  2. Bobo says:

    Hi, I want to know where have you specified the code or template for Login Screen in project

  3. vrsbrazil says:

    Thank you for the post.

  4. Pingback: REBLOG: Spring Security (+Spring) Custom Authentication Provider | vrsbrazil

  5. kihong says:

    Thanks a lot!

    but, I have a question…..

    How can I get the User parameter on Web page?

    • Aykut Akin says:

      Hi,

      It has been a long time to check my blog. So, I am sorry for the very late answer. In my personal projects, I use Jackson for returning JSON elements to requests. You can supply user information from controller when you making requests with this way. If you are using old way jsp, you can check out this sample. In this example, Mkyong returns “Spring Security Hello World” string as a message. You can return your user information with the same way if you want.

    • zerosourshut says:

      You got it wrong aykut, I am pretty sure he knows how to transfer model to jsp.. He asks about accessing your user object.

      @kihong
      Go to CustomAuthenticationProvider.java, find authenticate method,
      change return line as:

      return new UsernamePasswordAuthenticationToken(user, password, authorities);

      In one of your controller write:

      Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
      User user=null;
      if (principal instanceof User) {
      user = ((User)principal);
      }
      modelandView.addObject(“user”,user);

      Here is your user with all data of it. Use it in view (jsp) like ${user.email}

      • Aykut Akin says:

        Hi,

        You are right, I may have understand question a little bit wrong. Also, this post becomes a little bit old, I need some changes and put user object to security context like you do. Please keep me updated when you see something wrong at blog.

        Thank you.

    • Amit says:

      Hi
      For this we have a spring security tag library tag this tag has access to the currently authenticated
      object (principal).

  6. Santanu says:

    Excellent. Thanks for posting this.

  7. Nsqlg says:

    Thank you! Great posting, very helpful to me.

  8. Robin says:

    How can you have return type “User” from the “loadUserByUsername()”? Mine says it has to be “UserDetails”
    Regards

  9. Jitendra says:

    You have done great Job!!!!!!!! Thanks a lot.

  10. pasemes says:

    Very helpful post, thanks!
    I have a question as a beginner in Spring Security. I wasn’t able to figure out how UserDetails and UserDetailsService interfaces are being used in this example. Put in other words, if I remove them what are the effects? Are they really necessary?

    • Aykut Akin says:

      Hi,

      Like I said, they are only for more customization. If you remove them and return UsernamePasswordAuthenticationToken object from authenticate method in different way, there should be no problem. In my example, I add some different variables like FirstName, Lastname, etc. to User object. In my opinion, both username and first name should be belong to same user object. With this way, I encapsulate all user information in one object.

  11. Boyko says:

    Good example, but…did you know that your controller isn’t invoked at all?
    Just like everything Spring, straightforward and meaningful examples are hard to find. I appreciate sharing the code, but I wasted lots of time trying to find out why your MVC wiring wasn’t working. Please, incorporate my changes and push them to your github, so we save someone else’s frustration. Thanks!
    I had to make to following changes to get the example to work the way I guess it was intended to:
    web.xml:
    change

    application-servlet
    /

    to

    application-servlet
    /*

    application-servlet.xml:

    I needed to add component-scan and its namespace – The controller wasn’t instantiated at all.
    The other change was to do with mapping of the jsps so your controller can hit them as views:

    changed to

    Please, compare and incorporate

    LoginController:

    You really shouldn’t have a value of “/” at Request mapping, unless you expect people to always type that “/” after login so
    @RequestMapping(method = RequestMethod.GET, value=”/”)
    became
    @RequestMapping(method = RequestMethod.GET)

    Thanks!

  12. Akhila Krishnamurthy says:

    I am new to spring and spring security as well. I just wanted to know how does the authentication-provider that referes to customAuthenticationProvoder knows to look into the CustomAuthenticationProvider.java to authenticate.
    And what is the purpose of that text box “enter your name” ?
    Thanks in advance

    • Aykut Akin says:

      Hi,

      In the spring-security.xml we define our custom provider. If you look at the line 20 in the spring-security.xml, you can see that we refer to ‘customAuthenticationProvider’ and Spring search for this class. And the purpose of that input is just filling the page:) There is no action about that box, I just put that box to see css is working.

      Regards.

      • Akhila says:

        Thank you for your reply 🙂 !! Also I am actually trying to implement a 3 step process where the user 1st logs in then gets an authorization code and then with the code gets the token and finally the rest api. Do you know how /oauth/authorize is related to /oauth/confirm_access because when I use your custom log and redirect to /oauth/authorize I am getting a 404 not found I thought the configuration will handle the authorization but I am missing something that I dont understand.

      • Akhila Krishnamurthy says:

        Thank you for your reply. I wanted to know if there is a way in which we can pass one more information along with username and password so that it can identify which database to look into. Or is there a way to do that in configuration itself ?
        Thanks in advance

      • Aykut Akin says:

        Hi,

        I do some researches and found this stackoverflow post. I hope it will help you.

        Regards

  13. Tien Dung says:

    thanks for your post!

  14. sylvain says:

    Hello,
    Great post!!
    Maybe you can help me on my problem!!!

    In my application, there is differents parts. And for each parts, a connected user could have different role. For example, in part1 the user is ADMIN and in part2 he is USER.
    the “simple” hasRole(‘ROLE_ADMIN’) is not enough for me, I would rather a thing like
    hasRole(‘ROLE_ADMIN’, partId) which help me to check if the user has the ROLE_ADMIN for these partId.
    Do you think it is possible ?
    I continue to search, and thank you for your return.
    Regards

    • sylvain says:

      Maybe when the user log-in and go to the part1, i can associate his ROLE at this moment. When he changes to part2, i search his new ROLE and associate it to him.
      By this way, hasROLE(‘ADMIN’) will be correct ???

      • Aykut Akin says:

        Hi,

        I searched a little bit, but I couldn’t find a way to use a function like hasRole(‘ROLE_ADMIN’,partId). I think the best solution for your problem is to assign two different role to the user. As you can see, user do not have to be assigned only one role. You may have PART1_ADMIN and PART2_REGULAR_USER roles and assign each role to the authenticated user. That way you don’t need to worry about anything.

        And about other question: Yes you can change user’s role dynamically and with that way hasRole(‘ADMIN’) will be fine. I tried it and it worked for me.

        Regards.

  15. Hendra says:

    I’m wondering how can I put my custom error message in this setup? Preferrably using message.properties file so I can handle multiple language. In this case, the message will always be “Username not found”. thanks

    • Aykut Akin says:

      Hi,

      I have a post about serving messages from messages.properties file. Here is the link. You can have different messages files like: ‘messages_en.properties’ for English and ‘messages_fr.properties’ for French. When you change the locale property of Java, you will read different messages_XX.properties according to your locale. You can check java.util.Locale for different country codes. After changing static “Username not found” string with this dynamic method, you can easily handle with different languages.

      Regards.

  16. Kelvin Te says:

    Thank you so much, i was having a hard time then i saw this post.

  17. Chet Bil says:

    Thank you so much

  18. sunny says:

    Hi Aykut, thank you for such a wonderful post.
    But i could see one scenario which i believe you could help me .
    I have created a separate index page where it has 2 links called admin and user. Now, you click on the admin and it takes you to the login screen where you type the normal user details and submit the form (not the admin’s username & password). It takes to the 403 access denied page. Now what you do is just go to the index page directly and click on the user link, you could login with out asking for the user name and password. What could be the solution for this. Please let me know.

  19. hung@gmail.com says:

    greate article

  20. nani chowdary ravilla says:

    hi aykut akin,

    Can i provide a base for grouping the functions(functional parts of an application) and authorization users/ user-groups against them. I’m new spring security and even to real time development. Any help would be much appreciated.

    thanks,
    nani

  21. mbeddedsoft says:

    Why do you override User.toString()? I didn’t read anything in Spring Security documentation regarding the need to do so for objects implementing the UserDetails interface. Would this be necessary for web based applications or only for console applications?

    BTW, Thank you great example.

    • Aykut Akin says:

      Hi,

      Overriding User.toString() is not necessary for implementing security using Spring. That is my regular development style to override toString() method for every model object. With that way, I can just pass object to logger or sysout and see the variable values of object. Otherwise you will see class name and memory reference like User@ff2413.

      Regards

      • Stacy Mader says:

        If you are using psi-probe to monitor a Tomcat instance (for example), the toString() method will enable the password to be visible in cleartext via the Spring session attribute SPRING_SECURITY_CONTEXT

      • Aykut Akin says:

        Thanks for the catch. I believe there are now better ways to write this code piece. Therefore, I will not update the code but I’ll put a note at the end of this post.

        Best regards,
        Aykut

  22. jucasiro says:

    Hello Aykut:
    first congratulate you on your blog. I want to ask: How can we customize the tag: , to perform a custom query about LDAP?
    Thanks for you attention.

    • Aykut Akin says:

      Hi,

      Actually there are a lot of changes from defining ldap server to implementing LdapAuthenticationProvider. But, at the end userDetails stays the same. Main thing is to changing where to go for authentication and provider of this service. I believe you can check implementation steps from spring documentation.

      If you are starting from scratch, you could follow this link. It uses Spring Boot and Spring Security. At first Spring Boot seems complicated and you may not want to include a new technology to your base. However, it makes a lot of thing easier when you get used to it.

      Regards,
      Aykut

      • jucasiro says:

        Thanks for your answer. We try to authenticate with Microsoft Active Directory and have problems. I show our configuration, I appreciate you can give us some tips for this. We try to authenticate with a user that are created in a group that is not hanging directly from the domain.
        configuration:

        According to your reconmendación:

        Class:
        public class CustomAuthenticationProvider implements AuthenticationProvider {

        public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        String username = authentication.getName();
        String password = (String) authentication.getCredentials();

        if (username == null) {
        throw new BadCredentialsException(“Username not found.”);
        }

        if (password == null ) {
        throw new BadCredentialsException(“Wrong password.”);
        }

        try {
        LdapContextSource ldapContextSource = new LdapContextSource();
        ldapContextSource.setUrl(“ldap://****************:389/”);
        ldapContextSource.setBase(“dc=***,dc=*****,dc=****”);
        ldapContextSource.setUserDn(username + “@*******”);
        ldapContextSource.setPassword(password);
        try {
        // initialize the context
        ldapContextSource.afterPropertiesSet();
        } catch (Exception e) {
        e.printStackTrace();
        }

        LdapTemplate ldapTemplate = new LdapTemplate(ldapContextSource);

        ldapTemplate.setIgnorePartialResultException(true); // Active Directory doesn’t transparently handle referrals. This fixes that.
        AndFilter filter = new AndFilter();
        filter.and(new EqualsFilter(“sAMAccountName”, username));

        try {
        boolean valido=ldapTemplate.authenticate(DistinguishedName.EMPTY_PATH, filter.toString(), password);
        System.out.println(“valido :”+valido);

        }
        catch(org.springframework.ldap.AuthenticationException ee)
        {
        //userDisplay.setText(“Invalid Username/Password”);
        }
        } catch (Exception e) {
        e.printStackTrace();
        }

        return new UsernamePasswordAuthenticationToken(username,password);

        What is happening is that this class runs twice. The second time through the class “authentication” has the attribute with null password.
        Can you help us please.

      • Aykut Akin says:

        Hi,

        I have never need to implement ldap authentication, however as my search on Spring blog and Stackoverflow you need to make your authentication trusted. To do that, either you call isAuthenticated method by yourself or add a role to UsernamePasswordAuthenticationToken. In my example, I get authorities from user object and pass it to UsernamePasswordAuthenticationToken. You can try below code just to check the problem is this.


        Collection authorities = Collections.singleton(new SimpleGrantedAuthority("ROLE_USER"));
        return new UsernamePasswordAuthenticationToken(username, password, authorities);

        If this does not work, let me know and I will try to implement code by myself.

        Regards,
        Aykut

  23. Yasir Shabbir says:

    Hello I’m following your code and I need web.xml and other xml configuration into Java Config annotation.
    Can you please provide use ?
    Thanks

  24. Srikanth says:

    Hi,
    Thanks for your code. it worked without any issues.
    and it has saved lot of time for me.

  25. Manju says:

    Hi Ayukth, Thanks a bunch for the code and well explanations.
    I tried to configure the application to login to my custom login page. But could not proceed. Please let me know what else needs to be done to achieve the custom page login when login button in a page is clicked.
    My spring-security file looks like this.

    Controller code.
    @Controller
    public class LoginController {

    @Autowired
    private UserService userService;

    @RequestMapping(value=”/login”, method=RequestMethod.GET)
    public String getLoginForm(){
    return “login”;
    }

    @RequestMapping(value=”/logout”, method=RequestMethod.GET)
    public String getLogoutForm(){
    return “logout”;

    }

    @RequestMapping(value=”/secured/test”, method=RequestMethod.POST)
    public String getData(ModelMap model){

    Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();

    User user=null;
    if (principal instanceof User) {
    user = ((User)principal);
    }
    model.addAttribute(“username”, “demouser”);
    model.addAttribute(“message”, “Welcome to the secured page”);
    return “home”;

    }
    }

    Every other code is same as the original.

  26. Puneeth says:

    Gettng Null Pointer Exception on line 28 in Class CustomAuthenticationProvider.

    java.lang.NullPointerException
    com.treatmenttriangle.security.CustomAuthenticationProvider.authenticate(CustomAuthenticationProvider.java:28)
    org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:156)
    org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:177)
    org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter.attemptAuthentication(UsernamePasswordAuthenticationFilter.java:94)
    org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:211)
    org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
    org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:110)
    org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
    org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:50)
    org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
    org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:87)
    org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
    org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:192)
    org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:160)
    org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:344)
    org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:261)

  27. Rishi says:

    Best example for Spring Security….

  28. Anu says:

    Hey, I am working on something similar. I autowired in my CustomAuthenticationProvider but it seems not working. I am not sure what could the problem be. Any suggestions?

  29. Rinky says:

    hi aykytakin,
    I need to integrate my own authentication which takes in username password and returns true or false in return.Can this be included in the the customAuthenticationProvider? I have a web app which needs spring web security integration. Please help as i am new to spring concepts. Also the roles will be provided against a usernames which will be present in a text file name=role.
    Can u please give a head start to implement such requirement.

  30. Neha says:

    Hi Aykut

    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!

Leave a comment