I have a Spring Boot MVC application which uses LDAP for authentication. This works fine, but now I have to match authenticated user (from LDAP repository)
with users from my database. I created LDAPUser:
import java.util.jar.Attributes.Name;
import org.springframework.ldap.odm.annotations.Attribute;
import org.springframework.ldap.odm.annotations.Entry;
import org.springframework.ldap.odm.annotations.Id;
#Entry(
base="ou=users",
objectClasses = { "person", "inetOrgPerson", "top" })
public class LDAPUser {
#Id
private Name id;
private #Attribute(name = "cn") String username;
private #Attribute(name = "sn") String password;
private boolean rememberme;
}
And LDAPUserRepository:
import org.springframework.data.ldap.repository.LdapRepository;
import org.springframework.stereotype.Repository;
import com.licensewatcher.model.LDAPUser;
#Repository("ldapUserRespository")
public interface LDAPUserRepository extends LdapRepository<LDAPUser>{
LDAPUser findByUsername(String username);
LDAPUser findByUsernameAndPassword(String username, String password);
/*List<LDAPUser> findByUsernameLikeIgnoreCase(String username);*/
}
and AuthUserService:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.licensewatcher.repository.LDAPUserRepository;
#Service("authUserService")
public class AuthUserService {
#Autowired LDAPUserRepository ldapUserRespository;
public boolean authenticate(LDAPUser ldapUser) {
//TODO: implement this!!!
return false;
}
public boolean authorize(LDAPUser ldapUser) {
//TODO: implement this!!!
return false;
}
}
Class WebSecurityConfig (extends WebSecurityConfigurerAdapte) configures application to submit login controller action:
#PostMapping("/login/check")
public String login(Model model, LDAPUser ldapUser, RedirectAttributes redirectAttr) {
//TODO: call authUserService.authenticate(LDAPUser ldapUser);
return "redirect:/login";
}
I want to implement authUserService.authenticate(LDAPUser ldapUser) to check LDAPUserRepository first and if user exists, check up the User from my database. If they match, add user to a session and redirect to the requested page.
Is this a good approach? Do you have any suggestions how this could be implemented in a more elegant way?
Thanks in advance!
Here is my answer based on the link I provided in the comment.
This work using the latest Spring boot version 2.7.1 and Spring security 5.7.2
I'm using Custom Spring Authentication Provider.
class CustomAuthProvider
#Component
public class CustomAuthProvider implements AuthenticationProvider {
#Autowired
RfaUserService rfaUserService;
#Autowired
AuthenticationManager ldapAuthenticationManager;
#Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
Optional<RfaUser> rfaUser = rfaUserService.findByUsername((String) authentication.getPrincipal());
if (rfaUser.isPresent()) {
return ldapAuthenticationManager.authenticate(authentication);
}
return null;
}
#Override
public boolean supports(Class<?> authentication) {
return authentication.equals(UsernamePasswordAuthenticationToken.class);
}
}
class WebSecurityConfig
#Configuration
public class WebSecurityConfig {
#Autowired
private CustomAuthProvider customAuthProvider;
#Bean
public SecurityFilterChain filterChain(HttpSecurity httpSecurity) throws Exception {
httpSecurity
.httpBasic()
.and()
.authorizeRequests()
.anyRequest()
.authenticated()
.and()
.cors()
.and()
.csrf()
.disable().logout();
// here is the important part
httpSecurity.authenticationProvider(customAuthProvider);
return httpSecurity.build();
}
LDAP configuration class
#Configuration
public class LdapSecurityConfig {
#Value("${ldap.urls}")
private String ldapUrls;
#Value("${ldap.base.dn}")
private String ldapBaseDn;
#Value("${ldap.username}")
private String ldapSecurityPrincipal;
#Value("${ldap.password}")
private String ldapPrincipalPassword;
#Value("${ldap.user.dn.pattern}")
private String ldapUserDnPattern;
#Autowired
private CustomAuthoritiesPopulator customAuthoritiesPopulator;
#Autowired
private CustomUserDetailsMapper customUserDetailsMapper;
#Bean
public AuthenticationManager ldapAuthenticationManager(BaseLdapPathContextSource contextSource) {
LdapBindAuthenticationManagerFactory managerFactory = new LdapBindAuthenticationManagerFactory(contextSource);
managerFactory.setUserDnPatterns(ldapUserDnPattern);
managerFactory.setUserDetailsContextMapper(customUserDetailsMapper);
managerFactory.setLdapAuthoritiesPopulator(customAuthoritiesPopulator);
managerFactory.setUserSearchFilter("sAMAccountName={0}");
return managerFactory.createAuthenticationManager();
}
#Bean
public LdapContextSource contextSource() {
LdapContextSource ldapContextSource = new LdapContextSource();
ldapContextSource.setUrl(ldapUrls);
ldapContextSource.setBase(ldapBaseDn);
ldapContextSource.setUserDn(ldapSecurityPrincipal);
ldapContextSource.setPassword(ldapPrincipalPassword);
return ldapContextSource;
}
}
Related
I'm working on the course "Information System" and follow the operation of the prof, but it turns a strange error:
The dependencies of some of the beans in the application context form a cycle:
here's my classes:
#Service
public class UsersService implements UserDetailsService {
#Autowired
private UsersRepository _usersDb;
#Autowired
private BCryptPasswordEncoder _passwordEncoder;
public boolean registerNewUser(String username, String password, Role role) {
Optional<User> oldUser = _usersDb.findByUsername(username);
if(oldUser.isPresent()) {
return false;
}
String encodedPassword = _passwordEncoder.encode(password);
User newUser = new User(null, encodedPassword, username, role);
_usersDb.save(newUser);
return true;
}
public List<User> getAllUsers() {
return _usersDb.findAll();
}
#Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
Optional<User> user = _usersDb.findByUsername(username);
if(!user.isPresent()) {
throw new UsernameNotFoundException("User not found");
}
return user.get();
}
public boolean isAdminNotExists(String adminUsername) {
return _usersDb.findAll((r, q, b) -> b.or(
b.equal(r.get("role"), Role.ADMIN),
b.equal(r.get("username"), adminUsername)
)).isEmpty();
}
then:
#Configuration
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter{
#Autowired
private UsersService _usersService;
#Override
protected void configure(HttpSecurity httpSec) throws Exception {
httpSec.csrf()
.disable()
.authorizeRequests()
.antMatchers("/registration").not().fullyAuthenticated()
.antMatchers("/admin/**").hasRole("ADMIN")
.antMatchers("/dishes/**").hasAnyRole("USER", "MANAGER")
.antMatchers("/", "/resources/**").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.defaultSuccessUrl("/")
.permitAll()
.and()
.logout()
.permitAll()
.logoutSuccessUrl("/");
}
protected void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(_usersService).passwordEncoder(bCryptPasswordEncoder());
}
#Bean
public BCryptPasswordEncoder bCryptPasswordEncoder() {
return new BCryptPasswordEncoder();
}
}
and this:
#Component
public class IsProjectAppDataInitializier implements ApplicationListener<ContextRefreshedEvent>{
private boolean _alreadyInitialized = false;
private final UsersService _usersSvc;
public IsProjectAppDataInitializier(UsersService usersSvc) {
_usersSvc = usersSvc;
}
#Override
public void onApplicationEvent(ContextRefreshedEvent event) {
if(!_alreadyInitialized) {
_alreadyInitialized = true;
this.initializeApp();
}
}
private void initializeApp() {
if (_usersSvc.isAdminNotExists("admin")) {
_usersSvc.registerNewUser("admin", "password", Role.ADMIN);
}
}
#Autowired works in the video of prof, but not works on mine....
Really need guys your help!
Your problem is same as this video tutorial I learned from. Search for the Soham Karmakar's comment. He asked this problem and below this comment it might be your solution as well.
I would tell you solution, but I can not see your UserServiceImplementation class.
Basicly your solution might be here:
remove private UsersRepository _usersDb; (UsersService.class)
change your passwordEncoder.encode(... to new BCryptPasswordEncoder().encode(.. (Your UserServiceImplementation.class)
For your WebSecurityConfig.class change
auth.userDetailsService(_usersService).passwordEncoder(bCryptPasswordEncoder());
to `
auth.userDetailsService(_usersService);
auth.setPasswordEncoder(new BCryptPasswordEncoder());
`
Try, it should work.
I have spring web mvc project with Spring Security 4.1.0.RELEASE
In spring controller i try fetch the user from the context
#RestController
public class Test {
#RequestMapping(value="test", method = RequestMethod.POST)
public ResponseEntity<Void> test() {
ContextUser user = (ContextUser) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
}
}
user is an instance with id = 0, login = null .... It is empty instance.
org.springframework.security.core.Authentication isAuthenticated = true, list of Collection<? extends GrantedAuthority> are correct This behaviour is occurred periodically. It is not every time for this request. I catch this issue only for that request
My configurations
#Configuration
#ComponentScan(basePackages={"com.test.app"},
excludeFilters=#ComponentScan.Filter(type=FilterType.REGEX, pattern={"com.test.app.web.*"}))
#PropertySource(value = { "classpath:application.properties" })
#EnableAspectJAutoProxy
public class AppConfig {
#Autowired
private DataSource dataSource;
//My beans
}
#Component
public class TestUserDetailsService implements UserDetailsService{
#Autowired
private TestUserService service;
#Override
public UserDetails loadUserByUsername(String userName)
throws UsernameNotFoundException {
User user = service.findByLogin(userName);
if (user == null) {
throw new UsernameNotFoundException("Error");
}
return new ContextUser(user);
}
}
public class ContextUser extends User implements UserDetails {
//...
}
#Configuration
#EnableWebSecurity
#EnableAsync
#EnableGlobalMethodSecurity(securedEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter
{
#Autowired
private TestAuthenticationEntryPoint testAuthenticationEntryPoint;
#Autowired
private TestSimpleUrlAuthenticationSuccessHandler testSimpleUrlAuthenticationSuccessHandler;
#Autowired
private TestSimpleUrlAuthenticationFailureHandler testSimpleUrlAuthenticationFailureHandler;
#Autowired
private LogoutSuccessHandler logoutSuccessHandler;
#Autowired
private TestUserDetailsService testUserDetailsService;
#Bean
#Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
#Override
protected void configure(AuthenticationManagerBuilder registry) throws MyException {
registry.userDetailsService(testUserDetailsService).passwordEncoder(new TestEncoder());
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.addFilterBefore(new CorsFilter(), ChannelProcessingFilter.class);
http.csrf()
.disable()
.exceptionHandling()
.authenticationEntryPoint(testAuthenticationEntryPoint)
.and().sessionManagement().sessionFixation().migrateSession().maximumSessions(-1).sessionRegistry(sessionRegistry()).and()
.and()
.authorizeRequests()
.antMatchers("/").access("hasAuthority('TEST')")
.anyRequest().authenticated()
.and()
.formLogin()
.successHandler(testSimpleUrlAuthenticationSuccessHandler)
.failureHandler(testSimpleUrlAuthenticationFailureHandler)
.and()
.logout().logoutSuccessHandler(logoutSuccessHandler)
.and()
.headers().cacheControl().disable().frameOptions().sameOrigin();
}
#Bean
public SessionRegistry sessionRegistry() {
return new SessionRegistryImpl();
}
#Override
public void configure(WebSecurity web) {
web.ignoring().antMatchers("/resources/**");
}
}
Are any ideas why this behaviour is happened?
I struggle to understand how to test the Spring Boot application with the Spring Security layer.
I have asked similar questions How to enforce Spring Security with MockitoJUnit runner? and How to mock customer user service details in Spring Security layer?
I have a custom implementation for UserDetailsService which take data from the database, so naturally, I want to take it from somewhere else during unit-testing phase
I want to test my web-layer to see if Spring Security works and if all other use-cases work as well.
How can I achieve both tasks above?
SecurityConfig class:
#Configuration
#EnableGlobalMethodSecurity(securedEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
private static final String[] AUTH_WHITELIST = {
// -- swagger ui
"/",
"/csrf",
"/swagger-resources",
"/swagger-resources/**",
"/configuration/ui",
"/configuration/security",
"/swagger-ui.html",
"/webjars/**"
};
#Autowired
#Qualifier("customUserDetailsService")
private UserDetailsService userDetailsService;
private final static Integer bCryptEncryptionLevel = 8;
#Bean
public BCryptPasswordEncoder bCryptPasswordEncoder() {
return new BCryptPasswordEncoder(bCryptEncryptionLevel);
}
public SecurityConfig() {
super();
}
#Autowired
public void configureGlobalSecurity(AuthenticationManagerBuilder authManagerBuilder) throws Exception {
authManagerBuilder.authenticationProvider(authenticationProvider());
authManagerBuilder.userDetailsService(userDetailsService)
.passwordEncoder(bCryptPasswordEncoder());
}
#Bean
public DaoAuthenticationProvider authenticationProvider() {
DaoAuthenticationProvider authenticationProvider = new DaoAuthenticationProvider();
authenticationProvider.setUserDetailsService(userDetailsService);
authenticationProvider.setPasswordEncoder(bCryptPasswordEncoder());
return authenticationProvider;
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.authorizeRequests()
.antMatchers(AUTH_WHITELIST).permitAll()
// allow default swagger docket
.regexMatchers("\\A/v2/api-docs\\Z").permitAll()
// require auth for any other swagger docket
.regexMatchers("\\A/v2/api-docs?.*\\Z").authenticated()
.antMatchers("/**").authenticated()
.and()
.httpBasic()
.and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
}
}
CustomUserDetailsService class:
#Service("customUserDetailsService")
#Profile("!test")
public class CustomUserDetailsService implements UserDetailsService {
private final static Logger logger = LoggerFactory.getLogger(CustomUserDetailsService.class);
private StringRedisTemplate redisTemplate;
private RedisProperties redisProperties;
#Autowired
public CustomUserDetailsService(RedisProperties redisProperties, StringRedisTemplate redisTemplate) {
this.redisProperties = redisProperties;
this.redisTemplate = redisTemplate;
}
#Override
public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException {
// Do queries to DB and return user if such user exists
}
}
I also added CustomUserDetailsServiceTest class for the unit-testing purpose only into the same package but under src/test/java:
#Service("customUserDetailsService")
#Profile("test")
public class CustomUserDetailsServiceTest implements UserDetailsService {
#Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
#SuppressWarnings("serial")
Map<Object, Object> entries = new HashMap<Object, Object>(){{
put("username", username);
put("password_hash", "$2a$08$YjMcOsLmbbUB4DYPxqSAxOa3STLjEDovwd2..Uidwp.asyhSi8Y5u");
put("role", "ADMIN");
}};
UserEntity user = new UserEntity(entries);
return new HiccasoftApiUser(user);
}
}
How can I use custom implementation for customUserDetailsService in unit-tests while testing web-layer?
I have a web application with 2 types of resources.
web pages
web services
I want to secure the web pages using one authentication provider (i.e. CAS) and the web services using another authentication provider (i.e. BASIC authentication).
I found a solution which could work here, but it uses XML, and I would prefer to not use XML configuration if possible.
Is there a Java Config solution to this?
Well it took a while to figure out how to do it...
Basically I split up my original security configuration class into 3 separate configuration classes.
This is basically how I did it...
The main security configuration...
#Configuration
#Import({WebPageSecurityConfig.class, WebServiceSecurityConfig.class})
public class SecurityConfig {
}
The security configuration for web pages... (URL does not begin with /service/**)
#Configuration
#Order(200)
#EnableWebMvcSecurity
public class WebPageSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
public void configureGlobal(final AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(casAuthenticationProvider());
}
#Override
public void configure(final HttpSecurity http) throws Exception {
http.csrf().disable();
http.requestMatcher(new RequestMatcher() {
#Override
public boolean matches(final HttpServletRequest request) {
final String url = request.getServletPath() + StringUtils.defaultString(request.getPathInfo());
return !(url.startsWith("/service/"));
}
});
http.addFilter(casAuthenticationFilter()).exceptionHandling().authenticationEntryPoint(casAuthenticationEntryPoint());
http.authorizeRequests().
antMatchers("/securedPage").hasAuthority("ROLE_CAS_USER"). // /securedPage can only be accessed by cas user
anyRequest().permitAll(); // all other pages are unsecured
}
// General Application Security (CAS Authentication)
#Bean
public CasAuthenticationFilter casAuthenticationFilter() throws Exception {
final CasAuthenticationFilter casAuthenticationFilter = new CasAuthenticationFilter();
casAuthenticationFilter.setAuthenticationManager(authenticationManager());
return casAuthenticationFilter;
}
#Bean
public CasAuthenticationEntryPoint casAuthenticationEntryPoint() {
final CasAuthenticationEntryPoint casAuthenticationEntryPoint = new CasAuthenticationEntryPoint();
casAuthenticationEntryPoint.setLoginUrl(env.getRequiredProperty("cas.server.url") + "/login");
casAuthenticationEntryPoint.setServiceProperties(casServiceProperties());
return casAuthenticationEntryPoint;
}
#Bean
public ServiceProperties casServiceProperties() {
final ServiceProperties serviceProperties = new ServiceProperties();
serviceProperties.setService(env.getRequiredProperty("cas.service.url") + "/j_spring_cas_security_check");
serviceProperties.setSendRenew(false);
return serviceProperties;
}
#Bean
public CasAuthenticationProvider casAuthenticationProvider() {
final CasAuthenticationProvider casAuthenticationProvider = new CasAuthenticationProvider();
casAuthenticationProvider.setAuthenticationUserDetailsService(casAuthenticationUserDetailsService());
casAuthenticationProvider.setServiceProperties(casServiceProperties());
casAuthenticationProvider.setTicketValidator(casTicketValidator());
casAuthenticationProvider.setKey("casAuthenticationProviderKey");
casAuthenticationProvider.setStatelessTicketCache(casStatelessTicketCache());
return casAuthenticationProvider;
}
#Bean
public AuthenticationUserDetailsService casAuthenticationUserDetailsService() {
final AbstractCasAssertionUserDetailsService authenticationUserDetailsService = new AbstractCasAssertionUserDetailsService() {
#Override
protected UserDetails loadUserDetails(final Assertion assertion) {
final String username = assertion.getPrincipal().getName();
final List<GrantedAuthority> authorities = new ArrayList<>();
authorities.add(new SimpleGrantedAuthority("ROLE_CAS_USER"));
return new User(username, "notused", authorities);
}
};
return authenticationUserDetailsService;
}
#Bean
public TicketValidator casTicketValidator() {
final Saml11TicketValidator ticketValidator = new Saml11TicketValidator(env.getRequiredProperty("cas.server.url"));
ticketValidator.setTolerance(env.getRequiredProperty("cas.ticket.tolerance", Long.class));
return ticketValidator;
}
#Bean
public StatelessTicketCache casStatelessTicketCache() {
final EhCacheBasedTicketCache ticketCache = new EhCacheBasedTicketCache();
ticketCache.setCache(casCache());
return ticketCache;
}
#Bean(initMethod = "initialise", destroyMethod = "dispose")
public Cache casCache() {
final Cache cache = new Cache("casTickets", 50, true, false, 3600, 900);
return cache;
}
#Autowired
private Environment env;
}
The security configuration for RESTful web services (URL starts with /service/**)
#Configuration
#Order(300)
#EnableWebMvcSecurity
public class WebServiceSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
public void configureGlobal(final AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication().
withUser("admin").password("password").authorities(new SimpleGrantedAuthority("ROLE_WS_USER"));
}
#Override
public void configure(final HttpSecurity http) throws Exception {
http.csrf().disable();
http.
antMatcher("/service/**"). // only process URLs that begin with /service/
sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and(). // RESTful web services are stateless
addFilter(wsAuthenticationFilter()).exceptionHandling().authenticationEntryPoint(wsAuthenticationEntryPoint());
http.authorizeRequests().anyRequest().hasAuthority("ROLE_WS_USER"); // all requests are secured
}
// Web Service Security (BASIC Authentication)
#Bean
public BasicAuthenticationFilter wsAuthenticationFilter() throws Exception {
final BasicAuthenticationFilter wsAuthenticationFilter = new BasicAuthenticationFilter(authenticationManager(), wsAuthenticationEntryPoint());
return wsAuthenticationFilter;
}
#Bean
public BasicAuthenticationEntryPoint wsAuthenticationEntryPoint() {
final BasicAuthenticationEntryPoint wsAuthenticationEntryPoint = new BasicAuthenticationEntryPoint();
wsAuthenticationEntryPoint.setRealmName("My Realm");
return wsAuthenticationEntryPoint;
}
#Autowired
private Environment env;
}
It's explain how to create multiple securities in the docs
http://docs.spring.io/spring-security/site/docs/current/reference/html/jc.html#multiple-httpsecurity
something like this should work
#EnableWebSecurity
public class MultiHttpSecurityConfig {
#Configuration
#Order(1)
public static class ApiWebSecurityConfigurationAdapter extends WebSecurityConfigurerAdapter {
#Resource private UserDetailsService userBasicAuthService;
protected void configure(HttpSecurity http) throws Exception {
http.antMatcher("/api/**")
.userDetailsService(userBasicAuthService)
.authorizeRequests()
.and()
.httpBasic();
}
}
#Configuration
public static class PagesWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {
#Resource private UserDetailsService userCasService;
#Override
protected void configure(HttpSecurity http) throws Exception {
http.antMatcher("/pages/**")
.userDetailsService(userCasService)
.authorizeRequests()
.anyRequest().authenticated()
.and()
.formLogin();
}
}
}
I tried to integrate spring security and spring social. The problem is when I try to create account for him in my system. I would like to avoid creating user with id "anonymousUser".
For expected behaviour when I analyzed code from spring-social-security I expected to call method JdbcUsersConnectionRepository.findUserIdsWithConnection(Connection connection) for creating user and entry in the system. But when I run my code I find out this is not true. Before this action is calling implementation of SocialConfigurer.getUserId(). Great... If we have anonymous user it will be cached... But anyway getUserId is called before anything so authorization doesn't work. So I wrote my own implementation to this thing:
#Configuration
#EnableSocial
public class SocialConfig implements SocialConfigurer {
#Autowired
private DataSource dataSource;
#Autowired
private CustomerService customerService;
#Autowired
private CustomerProviderRepository customerProviderRepository;
#Autowired
private PasswordEncoder passwordEncoder;
#Override
public void addConnectionFactories(ConnectionFactoryConfigurer connectionFactoryConfigurer, Environment environment) {
}
#Override
public UserIdSource getUserIdSource() {
return () -> {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (authentication == null || authentication.getName().equals("anonymousUser")) {
throw new IllegalStateException("Unable to get a ConnectionRepository: no user signed in");
}
return authentication.getName();
};
}
#Override
public UsersConnectionRepository getUsersConnectionRepository(ConnectionFactoryLocator connectionFactoryLocator) {
JdbcUsersConnectionRepository repository = new JdbcUsersConnectionRepository(dataSource, connectionFactoryLocator, Encryptors.noOpText());
repository.setConnectionSignUp(new SocialConnectionSignUpService(customerService, customerProviderRepository, passwordEncoder));
return repository;
}
}
Implementation of SocialCOnnectionSignUpService
public class SocialConnectionSignUpService implements ConnectionSignUp {
private final CustomerService customerService;
private final CustomerProviderRepository customerProviderRepository;
private final PasswordEncoder passwordEncoder;
public SocialConnectionSignUpService(CustomerService customerService, CustomerProviderRepository customerProviderRepository, PasswordEncoder passwordEncoder) {
this.customerService = customerService;
this.passwordEncoder = passwordEncoder;
this.customerProviderRepository = customerProviderRepository;
}
#Override
public String execute(Connection<?> connection) {
ConnectionKey connectionKey = connection.getKey();
UserProfile profile = connection.fetchUserProfile();
Customer customer = customerService.findBy(profile.getEmail());
if(customer == null) {
customer = new Customer();
customer.setEmail(profile.getEmail());
customerService.add(customer);
}
SocialKey key = new SocialKey();
key.setUserId(customer.getId().toString());
key.setProviderUserId(connectionKey.getProviderUserId());
key.setProviderId(connectionKey.getProviderId());
CustomerProvider customerProvider = new CustomerProvider();
customerProvider.setKey(key);
customerProvider.setDisplayName(profile.getName());
customerProviderRepository.save(customerProvider);
return customerProvider.id();
}
}
And configuration of spring security:
#Configuration
#EnableWebSecurity
public class SecurityContext extends WebSecurityConfigurerAdapter {
#Autowired
private DataSource dataSource;
#Autowired
private CustomerRepository customerRepository;
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.formLogin()
.loginPage("/login")
.loginProcessingUrl("/login/authenticate")
.permitAll()
.and()
.rememberMe()
.and()
.authorizeRequests()
.antMatchers("/signup/social").authenticated()
.antMatchers("/**").permitAll()
.and()
.apply(new SpringSocialConfigurer().postLoginUrl("/signup/social").alwaysUsePostLoginUrl(true))
.and()
.csrf().disable();
}
#Bean
public SocialUserDetailsService socialUserDetailsService() {
return new SocialUserDetailsServiceImpl(customerRepository);
}
}
Do you have any workaround or solution how to pass the problem?