Reputation: 437
I want to use spring security UserDetailsService
together with spring data jpa CrudRepository
interface.
Principal is represented by User
entity which implements UserDetails
:
@Entity
public class User implements UserDetails {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String username;
private String password;
//other methods of UserDetails
I have spring-security.xml config file:
<beans:beans xmlns="http://www.springframework.org/schema/security"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:beans="http://www.springframework.org/schema/beans"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.1.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-4.0.xsd">
<authentication-manager>
<!-- refers to spring data repository bean org.baeldung.SpringDataAuditDemo.dao.repos.UserDao -->
<authentication-provider user-service-ref="userDao" />
</authentication-manager>
</beans:beans>
It refers to bean userDao
of type UserDetailsService
and CrudRepository
:
public interface UserDao extends CrudRepository<User, Long>, UserDetailsService {
// @Override
@Query(value = "select u from User u where u.username=:username")
public UserDetails loadUserByUsername(@Param("username") String username) throws UsernameNotFoundException;
}
Now I want to authenticate User
object programmatically in jUnit tests.
I hope to run UserDao.loadUserByUsername
method when authenticating User
.
For that I wanted to use org.springframework.security.provisioning.UserDetailsManager
but it implements UserDetailsService
interface as well as my UserDao
. Therefore I got exception that two beans of same type exists!!!
Then I tried to use UserDao
instead of UserDetailsManager
but my UserDao
doesn't authenticate User
, but only loads it from db. In this case spring-security.xml
is not needed.
How to programmatically authenticate User
with spring security default DaoAuthenticationProvider
and use my UserDetailsServie
implementation?
EDIT
When I tried to autowire my UserDao
with @Qualifier
and UserDetailsManager
without it, I got this exception :
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [org.springframework.security.provisioning.UserDetailsManager] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoSuchBeanDefinitionException(DefaultListableBeanFactory.java:1118)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:967)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:862)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:494)
... 28 more
Upvotes: 0
Views: 910
Reputation: 21720
You can programmatically authenticate against your custom UserDetailsService by using the AuthenticationManager. For example, the following would work in a JUnit Test:
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
public class SecurityConfigTests {
@Autowired
private AuthenticationManager manager;
@Before
public void setup() {
SecurityContext context = SecurityContextHolder.createEmptyContext();
Authentication user = manager.authenticate(new UsernamePasswordAuthenticationToken("user", "password"));
context.setAuthentication(user);
SecurityContextHolder.setContext(context);
}
...
}
Any time you have multiple beans of the same type you can use a Qualifier annotation. This means if you are getting an exception that two beans of the same type exists, you can specify which one you want. For example, if you want a UserDetailsService bean by the name of userDao, you can use:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
...
@Qualifier("userDao")
@Autowired
UserDetailsService userDao;
Upvotes: 1