I am having an issue authenticating to my Spring mvc based web application after declaring two subclasses that inherit from the User Class like the following:
User
package com.vivalio.springmvc.model;
import java.io.Serializable;
import java.util.HashSet;
import java.util.Set;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.OneToOne;
import javax.persistence.Table;
import org.hibernate.validator.constraints.NotEmpty;
@Entity
@Table(name = "USER")
public class User implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private Integer id;
@NotEmpty
@Column(name = "SSO_ID", unique = true, nullable = false)
private String ssoId;
@NotEmpty
@Column(name = "PASSWORD", nullable = false)
private String password;
@NotEmpty
@Column(name = "FIRST_NAME", nullable = false)
private String firstName;
@NotEmpty
@Column(name = "LAST_NAME", nullable = false)
private String lastName;
@NotEmpty
@Column(name = "EMAIL", nullable = false)
private String email;
@Column(name = "DTCREATION", nullable = true)
private String dateCreation;
@Column(name = "JJCREATION", nullable = true)
private String jjCreation;
public String getJjCreation() {
return jjCreation;
}
public void setJjCreation(String jjCreation) {
this.jjCreation = jjCreation;
}
@Column(name = "MMCREATION", nullable = true)
private String mmCreation;
public String getMmCreation() {
return mmCreation;
}
public void setMmCreation(String mmCreation) {
this.mmCreation = mmCreation;
}
@Column(name = "YYCREATION", nullable = true)
private String aaCreation;
public String getAaCreation() {
return aaCreation;
}
public void setAaCreation(String aaCreation) {
this.aaCreation = aaCreation;
}
public String getDateCreation() {
return dateCreation;
}
public void setDateCreation(String dateCreation) {
this.dateCreation = dateCreation;
}
@NotEmpty
@ManyToMany(fetch = FetchType.LAZY)
@JoinTable(name = "USER_USER_PROFILE", joinColumns = { @JoinColumn(name = "USER_ID") }, inverseJoinColumns = {
@JoinColumn(name = "USER_PROFILE_ID") })
private Set<UserProfile> userProfiles = new HashSet<UserProfile>();
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getSsoId() {
return ssoId;
}
public void setSsoId(String ssoId) {
this.ssoId = ssoId;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public Set<UserProfile> getUserProfiles() {
return userProfiles;
}
public void setUserProfiles(Set<UserProfile> userProfiles) {
this.userProfiles = userProfiles;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((id == null) ? 0 : id.hashCode());
result = prime * result + ((ssoId == null) ? 0 : ssoId.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (!(obj instanceof User))
return false;
User other = (User) obj;
if (id == null) {
if (other.id != null)
return false;
} else if (!id.equals(other.id))
return false;
if (ssoId == null) {
if (other.ssoId != null)
return false;
} else if (!ssoId.equals(other.ssoId))
return false;
return true;
}
/*
* DO-NOT-INCLUDE passwords in toString function. It is done here just for
* convenience purpose.
*/
@Override
public String toString() {
return "User [id=" + id + ", ssoId=" + ssoId + ", password=" + password + ", firstName=" + firstName
+ ", lastName=" + lastName + ", email=" + email + "]";
}
}
Docteur
package com.vivalio.springmvc.model;
import java.io.Serializable;
import java.util.HashSet;
import java.util.Set;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.OneToMany;
import javax.persistence.Table;
@Entity
@Table(name = "DOCTEUR")
public class Docteur extends User implements Serializable {
@OneToMany(mappedBy = "doc")
private Set<Patient> patients = new HashSet<Patient>(0);
public Set<Patient> getPatients() {
return patients;
}
public void setPatients(Set<Patient> patients) {
this.patients = patients;
}
}
Patient
package com.vivalio.springmvc.model;
import java.io.Serializable;
import java.util.HashSet;
import java.util.Set;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.Table;
@Entity
@Table(name = "PATIENT")
public class Patient extends User implements Serializable {
@OneToMany(mappedBy = "patient")
private Set<Consultation> consultations = new HashSet<Consultation>(0);
@ManyToOne
@JoinColumn(name = "doc_id")
private Docteur doc;
public Docteur getDoc() {
return doc;
}
public void setDoc(Docteur doc) {
this.doc = doc;
}
}
Consultation
package com.vivalio.springmvc.model;
import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
import org.hibernate.validator.constraints.NotEmpty;
@Entity
@Table(name = "CONSULTATION")
public class Consultation implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "CONSID")
private Integer id;
// poid
@NotEmpty
@Column(name = "PARAM1", nullable = false)
private String param1;
// appetit
@NotEmpty
@Column(name = "PARAM2", nullable = false)
private String param2;
// faiblesse
@NotEmpty
@Column(name = "PARAM3", nullable = false)
private String param3;
// douleur
@NotEmpty
@Column(name = "PARAM4", nullable = false)
private String param4;
// boule
@NotEmpty
@Column(name = "PARAM5", nullable = false)
private String param5;
// fievre
@NotEmpty
@Column(name = "PARAM6", nullable = false)
private String param6;
// Commentaire
@NotEmpty
@Column(name = "COMMENTAIRE", nullable = false)
private String commentaire;
@Column(name = "DTCREATION", nullable = true)
private String dateCreation;
@Column(name = "JJCREATION", nullable = true)
private String jjCreation;
@Column(name = "MMCREATION", nullable = true)
private String mmCreation;
@Column(name = "YYCREATION", nullable = true)
private String aaCreation;
@ManyToOne
@JoinColumn(name = "id")
private Patient patient;
public Patient getPatient() {
return patient;
}
public String getParam1() {
return param1;
}
public void setParam1(String param1) {
this.param1 = param1;
}
public String getParam2() {
return param2;
}
public void setParam2(String param2) {
this.param2 = param2;
}
public String getParam3() {
return param3;
}
public void setParam3(String param3) {
this.param3 = param3;
}
public String getParam4() {
return param4;
}
public void setParam4(String param4) {
this.param4 = param4;
}
public String getParam5() {
return param5;
}
public void setParam5(String param5) {
this.param5 = param5;
}
public String getParam6() {
return param6;
}
public void setParam6(String param6) {
this.param6 = param6;
}
public String getDateCreation() {
return dateCreation;
}
public void setPatient(Patient patient) {
this.patient = patient;
}
public void setDateCreation(String dateCreation) {
this.dateCreation = dateCreation;
}
public String getJjCreation() {
return jjCreation;
}
public void setJjCreation(String jjCreation) {
this.jjCreation = jjCreation;
}
public String getMmCreation() {
return mmCreation;
}
public void setMmCreation(String mmCreation) {
this.mmCreation = mmCreation;
}
public String getAaCreation() {
return aaCreation;
}
public void setAaCreation(String aaCreation) {
this.aaCreation = aaCreation;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getCommentaire() {
return commentaire;
}
public void setCommentaire(String commentaire) {
this.commentaire = commentaire;
}
}
on the database side, i have the following User table that contains User accounts.
Is it normal that the tables Patient and Docteur are not created ?
Iam having the following problem while trying to authenticate :
Aug 03, 2017 8:34:00 PM org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter doFilter SEVERE: An internal error occurred while trying to authenticate the user. org.springframework.security.authentication.InternalAuthenticationServiceException: Object [id=1] was not of the specified subclass [com.vivalio.springmvc.model.User] : Discriminator: at org.springframework.security.authentication.dao.DaoAuthenticationProvider.retrieveUser(DaoAuthenticationProvider.java:126) at org.springframework.security.authentication.dao.AbstractUserDetailsAuthenticationProvider.authenticate(AbstractUserDetailsAuthenticationProvider.java:143) at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:167)
And the image of the error :
**
Security
** CustomUserDetail package com.vivalio.springmvc.security;
import java.util.ArrayList;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.vivalio.springmvc.model.User;
import com.vivalio.springmvc.model.UserProfile;
import com.vivalio.springmvc.service.UserService;
@Service("customUserDetailsService")
public class CustomUserDetailsService implements UserDetailsService{
static final Logger logger = LoggerFactory.getLogger(CustomUserDetailsService.class);
@Autowired
private UserService userService;
@Transactional(readOnly=true)
public UserDetails loadUserByUsername(String ssoId)
throws UsernameNotFoundException {
User user = userService.findBySSO(ssoId);
logger.info("User : {}", user);
if(user==null){
logger.info("User not found");
throw new UsernameNotFoundException("Username not found");
}
return new org.springframework.security.core.userdetails.User(user.getSsoId(), user.getPassword(),
true, true, true, true, getGrantedAuthorities(user));
}
private List<GrantedAuthority> getGrantedAuthorities(User user){
List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
for(UserProfile userProfile : user.getUserProfiles()){
logger.info("UserProfile : {}", userProfile);
authorities.add(new SimpleGrantedAuthority("ROLE_"+userProfile.getType()));
}
logger.info("authorities : {}", authorities);
return authorities;
}
}
SecurityConfig
package com.vivalio.springmvc.security;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationTrustResolver;
import org.springframework.security.authentication.AuthenticationTrustResolverImpl;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.rememberme.PersistentTokenBasedRememberMeServices;
import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;
@Configuration
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
@Autowired
@Qualifier("customUserDetailsService")
UserDetailsService userDetailsService;
@Autowired
PersistentTokenRepository tokenRepository;
@Autowired
public void configureGlobalSecurity(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService);
auth.authenticationProvider(authenticationProvider());
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers("/", "/list")
// .access("hasRole('DOCTEUR') or hasRole('ADMINISTRATEUR') or
// hasRole('PATIENT')")
.access("hasRole('ADMINISTRATEUR') OR hasRole('PATIENT') OR hasRole('DOCTEUR')").antMatchers("/board")
.access("hasRole('ADMINISTRATEUR') ").antMatchers("/newconsultation")
.access("hasRole('PATIENT')").antMatchers("/newuser/**", "/delete-user-*")
.access("hasRole('ADMINISTRATEUR')").antMatchers("/edit-user-*").access("hasRole('ADMINISTRATEUR') ")
.and().formLogin().loginPage("/login").loginProcessingUrl("/login").usernameParameter("ssoId")
.passwordParameter("password").and().rememberMe().rememberMeParameter("remember-me")
.tokenRepository(tokenRepository).tokenValiditySeconds(86400).and().csrf().and().exceptionHandling()
.accessDeniedPage("/Access_Denied");
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
public DaoAuthenticationProvider authenticationProvider() {
DaoAuthenticationProvider authenticationProvider = new DaoAuthenticationProvider();
authenticationProvider.setUserDetailsService(userDetailsService);
authenticationProvider.setPasswordEncoder(passwordEncoder());
return authenticationProvider;
}
@Bean
public PersistentTokenBasedRememberMeServices getPersistentTokenBasedRememberMeServices() {
PersistentTokenBasedRememberMeServices tokenBasedservice = new PersistentTokenBasedRememberMeServices(
"remember-me", userDetailsService, tokenRepository);
return tokenBasedservice;
}
@Bean
public AuthenticationTrustResolver getAuthenticationTrustResolver() {
return new AuthenticationTrustResolverImpl();
}
}
Init
package com.vivalio.springmvc.security;
import org.springframework.security.web.context.AbstractSecurityWebApplicationInitializer;
public class SecurityWebApplicationInitializer extends AbstractSecurityWebApplicationInitializer {
}
In the controller i have the /login service
package com.vivalio.springmvc.controller
@Controller
@RequestMapping("/")
@SessionAttributes("roles")
public class AppController {
@Autowired
UserService userService;
@Autowired
UserProfileService userProfileService;
@Autowired
AppetitService appetitService;
@Autowired
FaiblesseService faiblesseService;
@Autowired
DouleurService douleurService;
@Autowired
BouleService bouleService;
@Autowired
MessageSource messageSource;
@Autowired
PersistentTokenBasedRememberMeServices persistentTokenBasedRememberMeServices;
@Autowired
AuthenticationTrustResolver authenticationTrustResolver;
@Autowired
ConsultationService consultationService;
@Autowired
PatientService patientService;
@Autowired
DocteurService docteurServices;
/**
* This method will list all existing users.
*/
@RequestMapping(value = { "/", "/list" }, method = RequestMethod.GET)
public String listUsers(ModelMap model) {
List<User> users = userService.findAllUsers();
model.addAttribute("users", users);
model.addAttribute("loggedinuser", getPrincipal());
return "userslist";
}
/**
* This method will provide the medium to add a new user.
*/
@RequestMapping(value = { "/newuser" }, method = RequestMethod.GET)
public String newUser(ModelMap model) {
User user = new User();
model.addAttribute("user", user);
model.addAttribute("edit", false);
model.addAttribute("loggedinuser", getPrincipal());
return "registration";
}
/**
* This method will provide the medium to add a new consultation.
*/
@RequestMapping(value = { "/newconsultation" }, method = RequestMethod.GET)
public String newConsultation(ModelMap model) {
Consultation consultation = new Consultation();
model.addAttribute("consultation", consultation);
model.addAttribute("edit", false);
model.addAttribute("loggedinuser", getPrincipal());
return "registrationConsultation";
}
/**
* This method will be called on form submission, handling POST request for
* saving user in database. It also validates the user input
*/
@RequestMapping(value = { "/newuser" }, method = RequestMethod.POST)
public String saveUser(@Valid User user, BindingResult result, ModelMap model) {
if (result.hasErrors()) {
return "registration";
}
/*
* Preferred way to achieve uniqueness of field [sso] should be
* implementing custom @Unique annotation and applying it on field [sso]
* of Model class [User].
*
* Below mentioned peace of code [if block] is to demonstrate that you
* can fill custom errors outside the validation framework as well while
* still using internationalized messages.
*
*/
if (!userService.isUserSSOUnique(user.getId(), user.getSsoId())) {
FieldError ssoError = new FieldError("user", "ssoId", messageSource.getMessage("non.unique.ssoId",
new String[] { user.getSsoId() }, Locale.getDefault()));
result.addError(ssoError);
return "registration";
}
userService.saveUser(user);
Mail.sendMailRegistration("support@xxxx.net", user.getEmail(), "aa.xxxx@gmail.com",
"aa.xxxx@gmail.com", "Creation de compte vivalio", "message");
model.addAttribute("success",
"User " + user.getFirstName() + " " + user.getLastName() + " registered successfully");
model.addAttribute("loggedinuser", getPrincipal());
// return "success";
return "redirect:/list";
}
/* ajouter la consultation du patient */
@RequestMapping(value = "/newconsultation", method = RequestMethod.POST)
public String saveConsultation(@Valid Consultation consultation, BindingResult result, ModelMap model) {
if (result.hasErrors()) {
return "registrationConsultation";
}
Patient patient = (Patient) getUser();
//consultation.setPatient(null);
consultationService.saveConsultation(consultation);
if (consultation != null //&&
//consultation.getPatient() != null
) {
Mail.sendMailAfterConsultation("support@vivalio.net",
//consultation.getPatient().getEmail()
"",
"tux025@gmail.com", "tux025@gmail.com", "Envoi de la consultation a votre medecin : ",
"Votre consultation REF-" + consultation.getId()
+ " a ete envoyee a votre medecin avec succes. Vous serez contacte en cas d'urgence.<br/>Ci dessous un recap de votre consultation :<br/>"
+ "<br/>Poid : " + consultation.getParam1() + "<br/>" + "Appetit :"
+ consultation.getParam2() + "<br/>" + "Faiblesse :" + consultation.getParam3() + "<br/>"
+ "Douleur :" + consultation.getParam4() + "<br/>" + "Boule :" + consultation.getParam5()
+ "<br/>" + "Fievre :" + consultation.getParam6() + "<br/>" + "Commentaire :"
+ consultation.getCommentaire() + "<br/>" + "<br/>L'equipe vivalio Group"
);
}
return "redirect:/list";
}
/**
* This method will provide the medium to update an existing user.
*/
@RequestMapping(value = { "/edit-user-{ssoId}" }, method = RequestMethod.GET)
public String editUser(@PathVariable String ssoId, ModelMap model) {
User user = userService.findBySSO(ssoId);
model.addAttribute("user", user);
model.addAttribute("edit", true);
model.addAttribute("loggedinuser", getPrincipal());
return "registration";
}
@RequestMapping(value = { "/edit-user-{ssoId}" }, method = RequestMethod.POST)
public String updateUser(@Valid User user, BindingResult result, ModelMap model, @PathVariable String ssoId) {
if (result.hasErrors()) {
return "registration";
}
userService.updateUser(user);
Mail.sendMailRegistration("support@xxxx.net", user.getEmail(), "aa.xxxxx@gmail.com",
"aa.xxx@gmail.com", "Modification des informations vivalio",
"Votre utilisateur vivalio a été modifié");
model.addAttribute("success",
"User " + user.getFirstName() + " " + user.getLastName() + " updated successfully");
model.addAttribute("loggedinuser", getPrincipal());
return "redirect:/list";
}
/**
* This method will delete an user by it's SSOID value.
*/
@RequestMapping(value = { "/delete-user-{ssoId}" }, method = RequestMethod.GET)
public String deleteUser(@PathVariable String ssoId) {
userService.deleteUserBySSO(ssoId);
return "redirect:/list";
}
/**
* This method will provide UserProfile list to views
*/
@ModelAttribute("roles")
public List<UserProfile> initializeProfiles() {
return userProfileService.findAll();
}
/**
* This method will provide Docs list to views
*/
@ModelAttribute("docteurs")
public List<User> initializeAllDocs() {
return userService.findAllDocs();
}
/**
* This method handles Access-Denied redirect.
*/
@RequestMapping(value = "/Access_Denied", method = RequestMethod.GET)
public String accessDeniedPage(ModelMap model) {
model.addAttribute("loggedinuser", getPrincipal());
return "accessDenied";
}
/**
* This method handles login GET requests. If users is already logged-in and
* tries to goto login page again, will be redirected to list page.
*/
@RequestMapping(value = "/login", method = RequestMethod.GET)
public String loginPage() {
if (isCurrentAuthenticationAnonymous()) {
return "login";
} else {
return "redirect:/list";
}
}
/**
* This method handles logout requests. Toggle the handlers if you are
* RememberMe functionality is useless in your app.
*/
@RequestMapping(value = "/logout", method = RequestMethod.GET)
public String logoutPage(HttpServletRequest request, HttpServletResponse response) {
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
if (auth != null) {
// new SecurityContextLogoutHandler().logout(request, response,
// auth);
persistentTokenBasedRememberMeServices.logout(request, response, auth);
SecurityContextHolder.getContext().setAuthentication(null);
}
return "redirect:/login?logout";
}
/**
* This method returns the principal[user-name] of logged-in user.
*/
private String getPrincipal() {
String userName = null;
Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
if (principal instanceof UserDetails) {
userName = ((UserDetails) principal).getUsername();
} else {
userName = principal.toString();
}
return userName;
}
@SuppressWarnings("rawtypes")
private User getUser() {
String username = null;
Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
username = ((UserDetails) principal).getUsername();
User usr = userService.findBySSO(username);
return usr;
}
/**
* This method returns true if users is already authenticated [logged-in],
* else false.
*/
private boolean isCurrentAuthenticationAnonymous() {
final Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
return authenticationTrustResolver.isAnonymous(authentication);
}
/**
* This method will redirect to dashboard
*/
@RequestMapping(value = { "/board" }, method = RequestMethod.GET)
public String tableauBord(ModelMap model, HttpSession session) {
return "board";
}
}