Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

using java configuration for n-factor authentication [closed]

Tags:

In a spring mvc app using spring security, I want to use a custom AuthenticationProvider to check n-number of additional fields beyond the default username and password. I am trying to use Java configuration. How should I set it up?

like image 483
CodeMed Avatar asked Aug 15 '15 00:08

CodeMed


1 Answers

First, some explanation about the interfaces you are working with and the role they play in the authentication process:

  • Authentication - represents the result of authenticating a user. Holds the authorities granted to that user and any additional details that may be needed about the user. As there is no way for the framework to know, what details are going to be needed, the authentication object has a getDetails method that can return any object

  • AuthenticationProvider - object that can create an Authentication object in some way. To make them more reusable, some (or most) of AuthenticationProviders refrain from setting the user details on the Authentication object, as each application may need specific user details. Instead they delegate the process of resolving the user details to a settable UserDetailsService

  • UserDetailsService - a strategy for retrieving the user details required in your application.

So, if you are creating a custom AuthenticationProvider you may not even need to implement it in a way that requires a UserDetailsService. The decission is up to you and depends, on whether you plan on reusing your implementation in other projects.

As for the compilation problems in your code, you are mixing two ways of providing the UserDetailsService. In the CustomAuthenticationProvider you have annotated the userService field with the @Inject annotation .This means, that the container (Spring application context in your case) is to find a suitable implementation and inject it into that field at runtime using reflection. The process of setting this field by the context is called dependency injection. In the SecurityConfig class you are trying to provide the implementation yourself by setting the field through the setUserDetailsService method that does not exist in your class.

To resolve this problem you need to decide to use one of the ways to provide the UserDetails service and either:

  • remove the @Inject annotation and create the setUserDetailsService method, or
  • remove the line when you are calling the non-existant method and declare your implementation of the UserDetailsService as a bean

As for which of the ways should you choose, the dependecy injection way may by better if you can find a way of making your SecurityConfig class reusable in other projects. In that case you could just import it (by using the @Import annotaion) and declare a different UserDetailsSerice implementation as a bean in your next application and have it working.

Usually, classes like the SecurityConfig are not really reusable, so creating the setter and removing the dependency injection would probably be my first choice.

EDIT

A working, albeit a simplistic implementation (based heavily on this blog entry) would be:

public class CustomAuthenticationProvider implements AuthenticationProvider{      @Override     public Authentication authenticate(Authentication authentication) throws AuthenticationException {         String name = authentication.getName();         String password = authentication.getCredentials().toString();         List<GrantedAuthority> grantedAuths = new ArrayList<>();         if (name.equals("admin") && password.equals("system")) {             grantedAuths.add(new SimpleGrantedAuthority("ROLE_ADMIN"));           }          if(pincodeEntered(name)){             grantedAuths.add(new SimpleGrantedAuthority("ROLE_PINCODE_USER"));           }         Authentication auth = new UsernamePasswordAuthenticationToken(name, password, grantedAuths);     }      @Override     public boolean supports(Class<?> authentication) {         return authentication.equals(UsernamePasswordAuthenticationToken.class);     }      private boolean pincodeEntered(String userName){         // do your check here         return true;     } } 

Then in your config class change the following method:

@Bean AuthenticationProvider customAuthenticationProvider() {         return new CustomAuthenticationProvider(); } 
like image 175
Apokralipsa Avatar answered Sep 18 '22 09:09

Apokralipsa