Issue
I'm using spring boot and i need to implement spring security with 3 fields authentication process username, password and corporate identifier as a hidden input in a form.
I implemented a custom usernamepasswordauthenticationfilter but it not seems to be enough to setup the security config.
EDIT :
Users don't seem to be authenticated ! because a can access to authenticated request defined in web config
EDIT 2 :
in my custom filter when a enter a valid user it's do execute on succesfulAuthentication. What i'm missing please provide me any help :( Here were i am
@Repository
public class AuthenticationUserDetailsService implements UserDetailsService {
private static final Logger LOGGER = Logger.getLogger(AuthenticationUserDetailsService.class);
@Autowired
private UserRepository users;
private org.springframework.security.core.userdetails.User userdetails;
@Override
public UserDetails loadUserByUsername(String input) throws UsernameNotFoundException {
// TODO Auto-generated method stub
System.out.println(input);
String[] split = input.split(":");
if (split.length < 2) {
LOGGER.debug("User did not enter both username and corporate domain.");
throw new UsernameNotFoundException("no corporate identifier is specified");
}
String username = split[0];
String corporateId = split[1];
System.out.println("Username = " + username);
System.out.println("Corporate identifier = " + corporateId);
boolean enabled = true;
boolean accountNonExpired = true;
boolean credentialsNonExpired = true;
boolean accountNonLocked = true;
com.ubleam.corporate.server.model.User user;
user = checkUserDetail(username, corporateId);
if (user == null)
throw new NotAuthorizedException("Your are not allowed to access to this resource");
LOGGER.info("User email : " + user.getEmail() + "#User corporate : " + user.getCorporateId());
userdetails = new User(user.getEmail(), user.getPassword(), enabled, accountNonExpired, credentialsNonExpired, accountNonLocked, getAuthorities("ROLE_USER"));
return userdetails;
}
/**
*
* @param roles
* roles granted for user
* @return List of granted authorities
*
*/
public List<GrantedAuthority> getAuthorities(String roles) {
List<GrantedAuthority> authList = new ArrayList<GrantedAuthority>();
authList.add(new SimpleGrantedAuthority(roles));
return authList;
}
/**
* User authentication details from database
*
* @param username
* to use for authentication
* @param coporateId
* corporate identifier of user
* @return found user in database
*/
private com.ubleam.corporate.server.model.User checkUserDetail(String username, String corporateId) {
com.ubleam.corporate.server.model.User user = users.findByEmailAndCorporateId(username, corporateId);
return user;
}
My custom filter :
public class PlatformAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
private static final Logger LOGGER = Logger.getLogger(PlatformAuthenticationFilter.class);
private static final String LOGIN_SUCCESS_URL = "{0}/bleamcards/{1}/home";
private static final String LOGIN_ERROR_URL = "{0}/bleamcards/{1}/login?error";
private String parameter = "corporateId";
private String delimiter = ":";
private String corporateId;
@Override
protected String obtainUsername(HttpServletRequest request) {
String username = request.getParameter(getUsernameParameter());
String extraInput = request.getParameter(getParameter());
String combinedUsername = username + getDelimiter() + extraInput;
setCorporateId(extraInput);
LOGGER.info("Combined username = " + combinedUsername);
return combinedUsername;
}
@Override
protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, Authentication authResult) throws IOException, ServletException {
String contextPath = request.getContextPath();
String url = MessageFormat.format(LOGIN_SUCCESS_URL, contextPath, corporateId);
response.sendRedirect(url);
}
@Override
protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException failed) throws IOException, ServletException {
String contextPath = request.getContextPath();
String url = MessageFormat.format(LOGIN_ERROR_URL, contextPath, corporateId);
response.sendRedirect(url);
}
public String getParameter() {
return parameter;
}
public void setParameter(String corporateId) {
this.parameter = corporateId;
}
public String getDelimiter() {
return delimiter;
}
public void setDelimiter(String delimiter) {
this.delimiter = delimiter;
}
public String getCorporateId() {
return corporateId;
}
public void setCorporateId(String corporateId) {
this.corporateId = corporateId;
}
}
And finally the web security config :
@Configuration
@EnableWebMvcSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Inject
private AuthenticationManagerBuilder auth;
@Inject
private UserDetailsService userDS;
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers("/bleamcards/**/login", "/bleamcards/**/forgetpassword", "/bleamcards/**/register", "/css/**", "/js/**", "/images/**", "/webjars/**")
.permitAll().anyRequest().authenticated().and().addFilterBefore(authenticationFilter(), UsernamePasswordAuthenticationFilter.class).formLogin().loginPage("/login")
.defaultSuccessUrl("/").permitAll().and().logout().permitAll();
}
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.eraseCredentials(false);
auth.userDetailsService(userDS).passwordEncoder(new BCryptPasswordEncoder());
}
@Bean
@Override
public AuthenticationManager authenticationManager() throws Exception {
return auth.build();
}
@Bean
public PlatformAuthenticationFilter authenticationFilter() throws Exception {
PlatformAuthenticationFilter authFilter = new PlatformAuthenticationFilter();
authFilter.setRequiresAuthenticationRequestMatcher(new AntPathRequestMatcher("/login", "POST"));
authFilter.setAuthenticationManager(authenticationManager());
authFilter.setUsernameParameter("username");
authFilter.setPasswordParameter("password");
authFilter.setParameter("corporateId");
return authFilter;
}
@Override
protected UserDetailsService userDetailsService() {
return userDS;
}
I want users to be able to connect only to /login /register /forgetpasswod urls for their respective corporate platforms
Solution
Actually i manage to find a solution to my issue.
I added successHandler on successfulAuthentication was missing ! And a failureHandler too on unsuccessfulAuthentication methods.
Here is my new Authentication filter :
public class TwoFactorAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
private static final String LOGIN_SUCCESS_URL = "{0}/bleamcards/{1}/home";
private static final String LOGIN_ERROR_URL = "{0}/bleamcards/{1}/login?error";
private String parameter = "corporateId";
private String delimiter = ":";
private String corporateId;
@Override
protected String obtainUsername(HttpServletRequest request) {
String username = request.getParameter(getUsernameParameter());
String extraInput = request.getParameter(getParameter());
String combinedUsername = username + getDelimiter() + extraInput;
setCorporateId(extraInput);
System.out.println("Combined username = " + combinedUsername);
return combinedUsername;
}
@Override
protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain , Authentication authResult) throws IOException, ServletException {
String contextPath = request.getContextPath();
String url = MessageFormat.format(LOGIN_SUCCESS_URL, contextPath, corporateId);
setAuthenticationSuccessHandler(new SimpleUrlAuthenticationSuccessHandler(url));
super.successfulAuthentication(request, response, chain, authResult);
}
@Override
protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException failed) throws IOException, ServletException {
String contextPath = request.getContextPath();
String url = MessageFormat.format(LOGIN_ERROR_URL, contextPath, corporateId);
setAuthenticationFailureHandler(new SimpleUrlAuthenticationFailureHandler(url));
super.unsuccessfulAuthentication(request, response, failed);
}
public String getParameter() {
return parameter;
}
public void setParameter(String corporateId) {
this.parameter = corporateId;
}
public String getDelimiter() {
return delimiter;
}
public void setDelimiter(String delimiter) {
this.delimiter = delimiter;
}
public String getCorporateId() {
return corporateId;
}
public void setCorporateId(String corporateId) {
this.corporateId = corporateId;
}
}
Answered By - Hassam Abdelillah