0Day Forums
Custom Authentication Manager with Spring Security and Java Configuration - Printable Version

+- 0Day Forums (https://zeroday.vip)
+-- Forum: Coding (https://zeroday.vip/Forum-Coding)
+--- Forum: FrameWork (https://zeroday.vip/Forum-FrameWork)
+---- Forum: Spring (https://zeroday.vip/Forum-Spring)
+---- Thread: Custom Authentication Manager with Spring Security and Java Configuration (/Thread-Custom-Authentication-Manager-with-Spring-Security-and-Java-Configuration)



Custom Authentication Manager with Spring Security and Java Configuration - ungamboling327182 - 08-02-2023

I am using Spring Security with SpringMVC to create a web application (I will refer to this as the WebApp for clarity) that speaks to an existing application (I will refer to this as BackendApp).

I want to delegate authentication responsibilities to the BackendApp (so that I don't need to synchronise the two applications).

To implement this, I would like the WebApp (running spring security) to communicate to the BackendApp via REST with the username and password provided by the user in a form and authenticate based on whether the BackendApp's response is 200 OK or 401 Unauthorised.

I understand I will need to write a custom Authentication Manager to do this however I am very new to spring and can't find any information on how to implement it.

I believe I will need to do something like this:

public class CustomAuthenticationManager implements AuthenticationManager{

@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {

String username = authentication.getName();
String pw = authentication.getCredentials().toString();

// Code to make rest call here and check for OK or Unauthorised.
// What do I return?

}

}

Do I set authentication.setAuthenticated(true) if successful and false if otherwise and thats it?

Once this is written, how do I configure spring security to use this authentication manager using a java configuration file?

Thanks in advance for any assistance.


RE: Custom Authentication Manager with Spring Security and Java Configuration - limey383594 - 08-02-2023

First you must configure Spring security to use your custom AuthenticationProvider.
So, in your spring-security.xml (or equivalent config file) you must define wich class is implementing this feature. For example:

<authentication-manager alias="authenticationManager">
<authentication-provider ref="myAuthenticationProvider" />
</authentication-manager>

<!-- Bean implementing AuthenticationProvider of Spring Security -->
<beans:bean id="myAuthenticationProvider" class="com.teimas.MyAutenticationProvider">
</beans:bean>

Secondly you must implement AuthenticationProvider as in your example. Specially the method authenticate(Authentication authentication) in which your rest call must be. For example:

public Authentication authenticate(Authentication authentication) throws AuthenticationException {
User user = null;
try {
//use a rest service to find the user.
//Spring security provides user login name in authentication.getPrincipal()
user = userRestService.loadUserByUsername(authentication.getPrincipal().toString());
} catch (Exception e) {
log.error("Error loading user, not found: " + e.getMessage(), e);
}

if (user == null) {
throw new UsernameNotFoundException(String.format("Invalid credentials", authentication.getPrincipal()));
} else if (!user.isEnabled()) {
throw new UsernameNotFoundException(String.format("Not found enabled user for username ", user.getUsername()));
}
//check user password stored in authentication.getCredentials() against stored password hash
if (StringUtils.isBlank(authentication.getCredentials().toString())
|| !passwordEncoder.isPasswordValid(user.getPasswordHash(), authentication.getCredentials().toString()) {
throw new BadCredentialsException("Invalid credentials");
}

//doLogin makes whatever is necesary when login is made (put info in session, load other data etc..)
return doLogin(user);
}




RE: Custom Authentication Manager with Spring Security and Java Configuration - tubiflorales664388 - 08-02-2023

In its most simplest:

@Override
public Authentication authenticate(Authentication auth) throws AuthenticationException {
String username = auth.getName();
String password = auth.getCredentials().toString();
// to add more logic
List<GrantedAuthority> grantedAuths = new ArrayList<>();
grantedAuths.add(new SimpleGrantedAuthority("ROLE_USER"));
return new UsernamePasswordAuthenticationToken(username, password, grantedAuths);
}




RE: Custom Authentication Manager with Spring Security and Java Configuration - boer134 - 08-02-2023

My solution is almost the same as the first answer:

1) You need a class which implements the Authentication Provider

@Service
@Configurable
public class CustomAuthenticationProvider implements AuthenticationProvider {
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
// Your code of custom Authentication
}
}

2) Opposite to the first answer you **don't** need to have following code in your WebSecurityConfiguration if you have only this custom provider.

@Override
protected AuthenticationManager authenticationManager() throws Exception {
return new ProviderManager(Arrays.asList((AuthenticationProvider) new AuthProvider()));
}

The issue is that Spring looks for available providers and use the default if nothing else is found. But as you have the implementation of the AuthenticationProvider - your implementation will be used.


RE: Custom Authentication Manager with Spring Security and Java Configuration - animism742616 - 08-02-2023

Take a look at my sample below. You have to return an UsernamePasswordAuthenticationToken. It contains the principal and the GrantedAuthorities. Hope I could help :)

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

User user = userRepo.findOne(username);
if (user == null) {
throw new BadCredentialsException("1000");
}
if (!encoder.matches(password, user.getPassword())) {
throw new BadCredentialsException("1000");
}
if (user.isDisabled()) {
throw new DisabledException("1001");
}
List<Right> userRights = rightRepo.getUserRights(username);
return new UsernamePasswordAuthenticationToken(username, null, userRights.stream().map(x -> new SimpleGrantedAuthority(x.getName())).collect(Collectors.toList()));
}

PS: userRepo and rightRepo are Spring-Data-JPA Repositories which access my custom User-DB

SpringSecurity JavaConfig:

@Configuration
@EnableWebMvcSecurity
public class MySecurityConfiguration extends WebSecurityConfigurerAdapter {

public MySecurityConfiguration() {
super(false);
}

@Override
protected AuthenticationManager authenticationManager() throws Exception {
return new ProviderManager(Arrays.asList((AuthenticationProvider) new AuthProvider()));
}

}


RE: Custom Authentication Manager with Spring Security and Java Configuration - chemotropism992 - 08-02-2023

This is how I did using component-based configuration (SecurityFilterChain) and new `authorizeHttpRequests`

```java
@Bean
protected SecurityFilterChain filterChain(HttpSecurity httpSecurity) throws Exception {
httpSecurity
.authorizeHttpRequests(auth -> auth
.antMatchers(UNPROTECTED_URLS).permitAll()
.oauth2ResourceServer()
.accessDeniedHandler(restAccessDeniedHandler)
.authenticationEntryPoint(authenticationEntryPoint)
.jwt()
.authenticationManager(new ProviderManager(authenticationProvider)); // this is custom authenticationProvider
return httpSecurity.build();
}
```