java.io.NotSerializableException when implementing UserDetailsService - spring

I am working with spring-security-oauth2 and I faced with such exception:
Caused by: java.io.NotSerializableException: com.samsung.diary.security.UserDetailsServiceImpl
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1180)
at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1528)
at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1493)
at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1416)
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1174)
In my config file i have:
<beans:bean id="clientDetailsUserService" class="org.springframework.security.oauth2.provider.client.ClientDetailsUserDetailsService">
<beans:constructor-arg ref="clientDetails" />
</beans:bean>
<authentication-manager id="clientAuthenticationManager" >
<authentication-provider user-service-ref="clientDetailsUserService" />
</authentication-manager>
<authentication-manager alias="authenticationManager">
<authentication-provider user-service-ref="userDetailsService">
</authentication-provider>
</authentication-manager>
If I change it to:
<beans:bean id="clientDetailsUserService" class="org.springframework.security.oauth2.provider.client.ClientDetailsUserDetailsService">
<beans:constructor-arg ref="clientDetails" />
</beans:bean>
<authentication-manager id="clientAuthenticationManager" >
<authentication-provider user-service-ref="clientDetailsUserService" />
</authentication-manager>
<authentication-manager alias="authenticationManager">
<authentication-provider>
<user-service>
<user name="2" password="2" authorities="ROLE_USER" />
</user-service>
</authentication-provider>
</authentication-manager>
everething works perfect.
My UserDetailsService implementation:
public class UserDetailsServiceImpl implements UserDetailsService {
#Autowired
#Qualifier("usersDAO")
private UsersDAO dao;
#Transactional(readOnly = true)
public UserDetails loadUserByUsername(String username)
throws UsernameNotFoundException, DataAccessException {
final com.samsung.diary.domain.User userEntity = dao.findByLogin(username);
if (userEntity == null)
throw new UsernameNotFoundException("user not found");
String login = userEntity.getLogin();
String password = userEntity.getPassword();
boolean enabled = userEntity.getEnabled().equals("true");
boolean accountNonExpired = enabled;
boolean credentialsNonExpired = enabled;
boolean accountNonLocked = enabled;
GrantedAuthority auth = new GrantedAuthority() {
private static final long serialVersionUID = 1L;
public String getAuthority() {
return userEntity.getAuthority();
}
};
Set<GrantedAuthority> set = new HashSet<GrantedAuthority>();
set.add(auth);
UserDetails details = new User(login, password, enabled, accountNonExpired, credentialsNonExpired, accountNonLocked,
set);
return details;
}
}
As I understand there is something connected with Serializable interface but I can't figure out how to solve it.
EDIT: I made UserDetailsServiceImpl and UsersDAO Serializable and now it works. But I still don't understand where my UserDetailsServiceImpl is being written in a stream.
If someone give me a hint I would be very appreciated.

Related

Multiple authentication with spring security

I have an application that contains two fields : admin and candidate.
i have implemented spring security in the section candidate and it works but when i want to implement another security in the authentification for the admin, it doesn't work.
i have two authentification pages
there is my security code :
<security:http use-expressions="true" auto-config="true"
access-denied-page="/404.xhtml" >
<security:intercept-url access="hasAnyRole('candidat')"
pattern="/candidat.xhtml" />
<security:intercept-url access="hasAnyRole('candidat')"
pattern="/aproposdemoi.xhtml" />
<security:intercept-url access="hasAnyRole('candidat')"
pattern="/chargermoncv.xhtml" />
<security:intercept-url access="hasAnyRole('candidat')"
pattern="/completermonprofil.xhtml" />
<security:intercept-url access="hasAnyRole('candidat')"
pattern="/maphotodeprofil.xhtml" />
<security:intercept-url access="hasAnyRole('candidat')"
pattern="/mescompetences.xhtml" />
<security:intercept-url access="hasAnyRole('candidat')"
pattern="/mesexperiences.xhtml" />
<security:intercept-url access="hasAnyRole('candidat')"
pattern="/meslangues.xhtml" />
<security:intercept-url access="hasAnyRole('candidat')"
pattern="/moncompte.xhtml" />
<security:intercept-url access="hasAnyRole('candidat')"
pattern="/supprimercompte.xhtml" />
<security:form-login login-processing-url="/j_spring_security_check"
login-page="/carrieres?login_error=1" always-use-default-target="true"
default-target-url="/candidat.xhtml" />
<security:logout logout-success-url="/carrieres.xhtml" />
<security:remember-me key="uniqueAndSecret"/>
<security:form-login login-processing-url="/j_spring_security_check"
login-page="/adminzone?login_error=1" always-use-default-target="true"
default-target-url="/tableaudebord.xhtml" />
<security:logout logout-success-url="/adminzone.xhtml" />
<security:remember-me key="uniqueAndSecret"/>
</security:http>
<security:authentication-manager>
<security:authentication-provider>
<security:password-encoder hash="md5" />
<security:jdbc-user-service id="jdbcMemoryAP"
data-source-ref="dataSource"
users-by-username-query="
select email_candidat,mot_de_passe_candidat,enabled
from candidat where email_candidat=?"
authorities-by-username-query="
select u.email_candidat, ur.autorite from candidat u, role_candidat ur
where u.id_candidat = ur.candidat and u.email_candidat =? " />
</security:authentication-provider>
</security:authentication-manager>
<security:authentication-manager >
<security:authentication-provider>
<security:password-encoder hash="md5" />
<security:jdbc-user-service id="jdbcMemoryAP"
data-source-ref="dataSource"
users-by-username-query="
select email_admin,mot_de_passe,enabled
from administrateur where email_admin=?"
authorities-by-username-query="
select u.email_admin, ur.autorite from administrateur u, role_administrateur ur
where u.idAdmin = ur.administrateur and u.email_admin =? " />
</security:authentication-provider>
</security:authentication-manager>
So, Any time you have to login via two tables, both the Model classes of the tables should implement UserDetails. Per table, you will need one LoginService.
Security-applicationContext.xml :
// The 2 providers mentioned below are each for different datbase tables. Please //note, tables will be checked sequentially.
<security:authentication-manager alias="authenticationManager">
<security:authentication-provider ref="daoAuthenticationProvider"/>
<security:authentication-provider ref="hostAuthenticationProvider"/>
</security:authentication-manager>
<beans:bean id="encoder"
class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder">
<beans:constructor-arg name="strength" value="strengthInInteger you want, default 6" />
</beans:bean>
<beans:bean id="daoAuthenticationProvider"
class="org.springframework.security.authentication.dao.DaoAuthenticationProvider">
//Below is the first LoginServiceImpl, a java bean I have declared in //applicationContext.xml, not here.
<beans:property name="userDetailsService" ref="LoginServiceImpl"/>
<beans:property name="passwordEncoder" ref="encoder"/>
</beans:bean>
<beans:bean id="hostAuthenticationProvider"
class="org.springframework.security.authentication.dao.DaoAuthenticationProvider">
//Below is the second Login implementation, a java bean I have declared in //applicationContext.xml, not here.
<beans:property name="userDetailsService" ref="HostLoginServiceImpl"/>
<beans:property name="passwordEncoder" ref="encoder"/>
</beans:bean>
Now,
// Notice that first LoginServiceImpl implements UserDetailsService. This file is responsible to check if there is any student with the given username in db. If yes, then we build a User object which Spring-security understands, for which I will paste code after this file.
#Transactional
#Service("userDetailsService")
public class LoginServiceImpl implements UserDetailsService{
#Autowired private StudentDAO studentDAO;
#Autowired private Assembler assembler;
private static final GrantedAuthority USER_AUTH = new SimpleGrantedAuthority("ROLE_STUDENT");
#Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException,DataAccessException {
Student student = this.studentDAO.findStudentByUsername(username);
if(student == null) { throw new UsernameNotFoundException("Wrong username or password");}
return assembler.buildUserFromUserEntity(student);
}
}
Now, when user is found, then only we call this.
#Service("assembler")
public class Assembler {
#Transactional(readOnly = true)
User buildUserFromUserEntity(Student userEntity){
String username = userEntity.getUsername();
String password = userEntity.getPassword();
// Long id = userEntity.getId();
// boolean enabled = userEntity.isActive();
boolean enabled = true;
boolean accountNonExpired = userEntity.isAccountNonExpired();
boolean credentialsNonExpired = userEntity.isCredentialsNonExpired();
boolean accountNonLocked = userEntity.isAccountNonLocked();
Collection<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
authorities.add(new SimpleGrantedAuthority("ROLE_STUDENT"));
User user = new User(username,password,enabled,accountNonExpired,credentialsNonExpired,accountNonLocked,authorities);
return user;
}
}
In a similar fashion, I have 2nd i.e HostLoginService :
#Transactional
#Service("hostuserDetailsService")
public class HostLoginService implements UserDetailsService{
#Autowired
private HostDAO hostDAO;
#Autowired
private HostAssembler assembler;
private static final GrantedAuthority USER_AUTH = new SimpleGrantedAuthority("ROLE_HOST");
#Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException,DataAccessException {
Host host = this.hostDAO.findHostByUsername(username);
if(host == null) { throw new UsernameNotFoundException("Wrong username or password");}
return assembler.buildUserFromUserEntity(host);
}
}
For brevity, I am avoiding the assembler for it.
Now you can see the roles are different. For proper redirection, you have to crearte a controller method for the default-target-url of Spring-Security, check who is currently authenticated, admin or candidate by querying Spring-security. Then you can redirect.
If any doubt, let me know.

How redirect based on role after authentication with spring security

I use spring security, spring, hibernate and jsf
authentication work correctly but it always redirects me to the page home.jsf
I want to manage the access of users after authentication
I want to manage the access of users after authentication
if authority = ROLE_ADMIN redirect ves homeadmin.jsf
if authority = ROLE_RH redirect ves homerh.jsf
if authority = ROLE_EXCUTIVE redirect ves homeex.jsf
if authority = ROLE_MANAGER redirect ves homem.jsf
if authority = ROLE_GP redirect ves homegp.jsf
The autority field in the Collaborateur table
the Colaborateur Class is
private Integer idColaborateur;
private Rolecol rolecol;
private String matriculeColaborateur;
private String nomColaborateur;
private String prenomColaborateur;
private String mailColaborateur;
private String pwdColaboratuer;
private String loginColaborateur;
private String adresseColaborateur;
private Boolean flgSuspendu;
private Set<HistoriqueNoteObjctif> historiqueNoteObjctifs = new HashSet<HistoriqueNoteObjctif>(
0);
private Set<Note> notes = new HashSet<Note>(0);
private Set<NoteObjectifs> noteObjectifses = new HashSet<NoteObjectifs>(0);
private Set<CompagneDevaluation> compagneDevaluations = new HashSet<CompagneDevaluation>(
0);
private Set<ColaborateurHierarchique> colaborateurHierarchiques = new HashSet<ColaborateurHierarchique>(
0);
private String authority;
//getter and seter
Datasource configuration is in the file applicationContext.xml
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="user" value="root" />
<property name="driverClass" value="com.mysql.jdbc.Driver" />
<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/modulevsql" />
<property name="password" value="root" />
<property name="maxStatementsPerConnection" value="0" />
<property name="maxAdministrativeTaskTime" value="0" />
<property name="maxConnectionAge" value="0" />
<property name="maxIdleTime" value="0" />
<property name="maxIdleTimeExcessConnections" value="0" />
<property name="maxPoolSize" value="0" />
<property name="maxStatements" value="0" />
</bean>
the User Class is
public class User implements UserDetails {
private static final long serialVersionUID = 1L;
private String name;
private String password;
private Colaborateur user;
public void setUser(Colaborateur user) {
this.user = user;
}
public User(String name) {
FacesContext fc=FacesContext.getCurrentInstance();
UserBean userBean=(UserBean) fc.getApplication().createValueBinding("#{UserBean}").getValue(fc);
userBean.chargerUtilisateur(name);
user = userBean.getUtilisateur();
System.err.println("USERS >>> "+user);
PasswordSupport pswdSupport = new PasswordSupport();
if (user!=null){
System.out.println("User.getLogin() :"+user.getLoginColaborateur());
System.out.println("user.getPwd() :"+user.getPwdColaboratuer());
this.name=user.getMatriculeColaborateur();
this.password=user.getPwdColaboratuer();
System.err.println(pswdSupport.getMD5Hash("1"));
}
}
public Collection<GrantedAuthority> getAuthorities() {
List<GrantedAuthority> grantedAuthorities = new ArrayList<GrantedAuthority>();
System.out.println("GrantedAuthorityImpl 1");
System.out.println("GrantedAuthorityImpl 2");
System.out.println("GrantedAuthorityImpl 3");
System.out.println("GrantedAuthorityImpl 4");
grantedAuthorities.add(new GrantedAuthorityImpl("ROLE_VISITEUR"));
return grantedAuthorities;
}
//getter and setter
and this is applicationContext-security.xml file
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/security"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-3.1.xsd">
<global-method-security secured-annotations="enabled">
</global-method-security>
<http pattern="/modules/members/**" access-denied-page="/modules/members/accessDenied.jsf" authentication-manager-ref="MembersAuthenticationManager">
<intercept-url pattern="/modules/members/secure/**" access="ROLE_VISITEUR" />
<intercept-url pattern="/modules/members/secure/homeadmin.jsf" access="ROLE_ADMIN" />
<intercept-url pattern="/**" access="IS_AUTHENTICATED_ANONYMOUSLY" />
<form-login login-page="/modules/members/login.jsf"
default-target-url="/modules/members/secure/home.jsf"
login-processing-url="/modules/members/j_spring_security_check"
authentication-failure-url="/modules/members/login.jsf" />
<logout logout-url="/modules/members/secure/logout"
logout-success-url="/modules/members/login.jsf" delete-cookies="true" />
</http>
<authentication-manager alias="MembersAuthenticationManager">
<authentication-provider user-service-ref="securityManager">
<password-encoder hash="md5" />
</authentication-provider>
</authentication-manager>
<beans:bean id="securityManager" class="tn.com.security.SecurityManager" />
</beans:beans>
Implement an AuthenticationSuccessHandler and redirect based on the collection of GrantedAuthority objects that's contained within the Authentication that you get passed in.
public class CustomAuthenticationSuccessHandler implements AuthenticationSuccessHandler {
#Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authResult) throws IOException, ServletException {
/* Redirect on the successful authentication of the user */
logger.info("Hit the AuthSuccessHandler");
String redirectAddress = null;
Collection<? extends GrantedAuthority> auths = authResult.getAuthorities();
if(auths.contains("ROLE_ADMIN"){
response.sendRedirect(response.encodeURL("homeadmin.jsf");
}
etc etc etc.
You could even add your roles to an Enum and write a switch statement to determine the redirect location.
Make sure you declare your AuthenticationSuccessHandler in your Security Config
<beans:bean id="customAuthenticationSuccessHandler" class="foo.bar.CustomAuthenticationSuccessHandler" />
<form-login login-page="/LoginView"
authentication-success-handler-ref="customAuthenticationSuccessHandler"
authentication-failure-url="/FailedLogin" />
The answer given by JamesENL is correct but with one mention:
You need to iterate over the collection of GrantedAuthority and only afterwards check for the ROLE:
Collection<? extends GrantedAuthority> authorities = authResult.getAuthorities();
for (GrantedAuthority grantedAuthority : authorities) {
if (grantedAuthority.getAuthority().equals("ROLE_USER")) {
response.sendRedirect("/userHome);
return;
} else if (grantedAuthority.getAuthority().equals("ROLE_ADMIN")) {
response.sendRedirect("/adminHome);
return;
}
}

How to implement custom authentication using Spring 2.5

We are using spring 2.5. We have common web services to authenticate user, which takes a user name and password as input and returns true or false after validating the password. How and where should we implement this web service call? Please reply. Thanks
Right now we have following spring configuration. we want to incorporate webservice call into it.
<intercept-url pattern="/service/**" access="ROLE_ANONYMOUS, ROLE_LEARNER,ROLE_TRAININGADMINISTRATOR,ROLE_LMSADMINISTRATOR,ROLE_REGULATORYANALYST,ROLE_INSTRUCTOR"/>
<logout invalidate-session="true" logout-success-url="/login.do"/>
<anonymous /> <http-basic /> <remember-me />
</http>
<b:bean id="authenticationProcessingFilterEntryPoint" class="org.springframework.security.ui.webapp.AuthenticationProcessingFilterEntryPoint">
<b:property name="loginFormUrl" value="/login.do"/>
<b:property name="forceHttps" value="false" />
</b:bean>
<authentication-manager alias='authenticationManagerAlias'/>
<b:bean id="myAuthenticationProcessingFilter" class="org.springframework.security.ui.webapp.AuthenticationProcessingFilter">
<b:property name="defaultTargetUrl" value="/interceptor.do"/>
<b:property name="authenticationFailureUrl" value="/login.do"/>
<b:property name="authenticationManager" ref="authenticationManagerAlias"/>
<b:property name="authenticationDetailsSource" ref="vu360UserAuthenticationDetailsSource"/>
<b:property name="alwaysUseDefaultTargetUrl" value="true"/>
<custom-filter position="AUTHENTICATION_PROCESSING_FILTER"/>
</b:bean>
<b:bean class="org.springframework.security.providers.dao.DaoAuthenticationProvider">
<b:property name="userDetailsService" ref="userDetailsService"/>
<b:property name="passwordEncoder" ref="passwordEncoder"/>
<b:property name="saltSource" ref="saltSource"/>
<custom-authentication-provider/>
</b:bean>
<b:bean class="org.springframework.security.providers.dao.DaoAuthenticationProvider">
<b:property name="userDetailsService" ref="userDetailsService"/>
<custom-authentication-provider/>
</b:bean>
Implements one CustomAuthenticationProvider like:
import com.google.common.collect.Lists;
import java.util.List;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.GrantedAuthority;
public class CustomAuthenticationProvider implements AuthenticationProvider {
public final static Logger log = LogManager.getLogger(CustomAuthenticationProvider.class.getName());
#Override
public Authentication authenticate(Authentication authentication)
throws AuthenticationException {
List<GrantedAuthority> AUTHORITIES = Lists.newArrayList();
AUTHORITIES.add(new GrantedAuthority() {
#Override
public String getAuthority() {
return "ROLE_ADMIN";
}
});
return new UsernamePasswordAuthenticationToken(authentication.getName(), authentication.getCredentials(), AUTHORITIES);
}
#Override
public boolean supports(Class<? extends Object> authentication) {
return authentication.equals(UsernamePasswordAuthenticationToken.class);
}
}
and
<authentication-manager>
<authentication-provider ref="customAuthenticationProvider" >
</authentication-provider>
</authentication-manager>
<beans:bean id="customAuthenticationProvider" class="com.xkey.principal.CustomAuthenticationProvider"/>
If you want to control the authentication yourself you can create your own AuthenticationManager that calls the web service and inject it into the AuthenticationProcessingFilter. Here's an example custom AuthenticationManager, obviously you'll need to replace the example service call with whatever code you use to call your actual service.
public class CustomWebServiceAuthenticationManager implements AuthenticationManager {
public Authentication authenticate(Authentication credentials) throws AuthenticationException {
String username = credentials.getName();
String password = (String)credentials.getCredentials();
// change this to your actual web service call
boolean successfulAuthentication = myWebService.authenticate(username, password);
if(successfulAuthentication) {
// do whatever you need to do to get the correct roles for the user, this is just an example of giving every user the role "ROLE_LEARNER"
List<GrantedAuthority> roles = Collections.singletonList(new SimpleGrantedAuthority("ROLE_LEARNER"));
return new UsernamePasswordAuthenticationToken(username, password, roles);
} else {
throw new AuthenticationException("Authentication failed, invalid username or password");
}
}
}
Then add the CustomWebServiceAuthenticationManager to your spring configuration and reference it in the AuthenticationProcessingFilter.
<b:bean id="customWebServiceAuthenticationManager" class="CustomWebServiceAuthenticationManager"/>
<b:bean id="myAuthenticationProcessingFilter" class="org.springframework.security.ui.webapp.AuthenticationProcessingFilter">
<b:property name="defaultTargetUrl" value="/interceptor.do"/>
<b:property name="authenticationFailureUrl" value="/login.do"/>
<b:property name="authenticationManager" ref="customWebServiceAuthenticationManager"/>
<b:property name="authenticationDetailsSource" ref="vu360UserAuthenticationDetailsSource"/>
<b:property name="alwaysUseDefaultTargetUrl" value="true"/>
<custom-filter position="AUTHENTICATION_PROCESSING_FILTER"/>

check if user subscription for trial period is expire or not using spring MVC

I am using spring MVC and want to check if user's trial period has expired.
I am getting user detail using spring security using the following method
public User getUserDetail() {
Authentication auth = SecurityContextHolder.getContext()
.getAuthentication();
Object principal = auth.getPrincipal();
if(principal instanceof User){
User user = (User) principal;
return user;
}
return null;
}
User object contains the date when he logged in first.
I am checking the user subscription using following code
UserBean userLoggedIn = (UserBean) userService.getUserDetail();
Date dt = userLoggedIn.getUserCreationDate();
DateTime userCreated = new DateTime(dt).plusDays(TRIAL_PERIOD);
DateTime currentDateTime = new DateTime();
if(currentDateTime.compareTo(userCreated) > 0 && userLoggedIn.getPackageType() == 0){
return new ModelAndView("pricing","user",userLoggedIn);
}
Now my problem is I don't want to write the above code repeatedly in each controller. So is there any common place where I can check the user trial period expire or not and redirect him to pricing page.
I have CustomUserDetail class where I am accessing user details from database and put it in spring security session. So I think this should be the best place to check if users trial period is expire or not but I don't know how I can redirect user from this class to pricing page.
My CustomUserDetail class is
#Service
#Transactional(readOnly = true)
public class CustomUserDetailsService implements UserDetailsService {
static final Logger logger = Logger.getLogger(CustomUserDetailsService.class);
#Resource(name="userService")
private UserService userService;
/* (non-Javadoc)
* #see org.springframework.security.core.userdetails.UserDetailsService#loadUserByUsername(java.lang.String)
*/
#Override
public UserDetails loadUserByUsername(String email)
throws UsernameNotFoundException, DataAccessException {
try {
boolean enabled = true;
boolean accountNonExpired = true;
boolean credentialsNonExpired = true;
boolean accountNonLocked = true;
UserBean domainUser = userService.getUserByName(email);
domainUser.isEnabled();
domainUser.isAccountNonExpired();
domainUser.isCredentialsNonExpired();
domainUser.isAccountNonLocked();
//Collection<? extends GrantedAuthority> roles = getAuthorities((long) domainUser.getRoleId());
return domainUser;
} catch (Exception e) {
logger.error("Invalid Login.",e);
throw new RuntimeException(e);
}
}
---updated---
My spring-security.xml is
<form-login login-page="/login.htm"
authentication-failure-url="/loginfailed.htm"
authentication-failure-handler-ref="exceptionMapper"
default-target-url="/index.htm"
always-use-default-target="true"/>
<access-denied-handler error-page="/logout.htm"/>
<logout invalidate-session="true"
logout-url="/logout.htm"
success-handler-ref="userController"/>
<remember-me user-service-ref="customUserDetailsService" key="89dqj219dn910lsAc12" use-secure-cookie="true" token-validity-seconds="466560000"/>
<session-management session-authentication-strategy-ref="sas"/>
</http>
<authentication-manager>
<authentication-provider user-service-ref="customUserDetailsService">
<password-encoder ref="customEnocdePassword" >
<salt-source user-property="email"/>
</password-encoder>
</authentication-provider>
</authentication-manager>
<beans:bean id="customEnocdePassword" class="com.mycom.myproj.utility.CustomEnocdePassword" />
<beans:bean id="exceptionMapper" class="org.springframework.security.web.authentication.ExceptionMappingAuthenticationFailureHandler" >
<beans:property name="exceptionMappings">
<beans:map>
<beans:entry key="your.package.TrialPeriodExpiredException" value="/pricing"/>
</beans:map>
</beans:property>
</beans:bean>
<beans:bean id="sas"
class="org.springframework.security.web.authentication.session.ConcurrentSessionControlStrategy">
<beans:constructor-arg name="sessionRegistry" ref="sessionRegistry" />
<beans:property name="maximumSessions" value="3" />
---update----
Now what I did is
<beans:bean id="authenticationProvider" class="org.springframework.security.authentication.dao.DaoAuthenticationProvider">
<beans:property name="userDetailsService" ref="customUserDetailsService"/>
<beans:property name="passwordEncoder" ref="customEnocdePassword"/>
<beans:property name="preAuthenticationChecks" ref="expirationChecker"/>
</beans:bean>
<authentication-manager>
<authentication-provider user-service-ref="authenticationProvider">
<password-encoder ref="customEnocdePassword" >
<salt-source user-property="email"/>
</password-encoder>
</authentication-provider>
</authentication-manager>
<!-- <authentication-manager>
<authentication-provider user-service-ref="customUserDetailsService">
<password-encoder ref="customEnocdePassword" >
<salt-source user-property="email"/>
</password-encoder>
</authentication-provider>
</authentication-manager> -->
<beans:bean id="expirationChecker" class="com.mycom.myproj.utility.UserTrialPeriodExpirationChecker" />
<beans:bean id="customEnocdePassword" class="com.mycom.myproj.utility.CustomEnocdePassword" />
now I am getting below error
"Cannot convert value of type [org.springframework.security.authentication.dao.DaoAuthenticationProvider]
to required type [org.springframework.security.core.userdetails.UserDetailsService]
for property 'userDetailsService': no matching editors or conversion strategy found"
You could set a custom UserDetailsChecker on the DaoAuthenticationProvider that verifies the expiration date before authenticating the user.
The <authentication-provider> element in your config generates a DaoAuthenticationProvider, but there is no attribute on that element that would allow you to set its preAuthenticationChecks property. In order to work around this limitation of the namespace configuration, you will have to fall back to defining that provider as a normal bean:
<bean id="authenticationProvider" class="org.springframework.security.authentication.dao.DaoAuthenticationProvider">
<property name="userDetailsService" ref="customUserDetailsService"/>
<property name="passwordEncoder" ref="customEnocdePassword"/>
<property name="preAuthenticationChecks" ref="expirationChecker"/>
</bean>
and refer to it by the id in the <authentication-manager> config:
<security:authentication-manager>
<security:authentication-provider ref="authenticationProvider"/>
</security:authentication-manager>
The above referenced expirationChecker bean must implement UserDetailsChecker which is a call-back interface receiving the UserDetails object, where you could throw a specific exception if the user's trial period has expired:
public class UserTrialPeriodExpirationChecker implements UserDetailsChecker {
#Override
public void check(UserDetails user) {
if( /* whatever way you check expiration */ ) {
throw new TrialPeriodExpiredException();
}
if (!user.isAccountNonLocked()) {
throw new LockedException("User account is locked");
}
if (!user.isEnabled()) {
throw new DisabledException("User is disabled");
}
if (!user.isAccountNonExpired()) {
throw new AccountExpiredException("User account has expired");
}
}
}
Note that the last three checks are not related to the expiration checking, but you have to have them here, as the default implementation (which is AbstractUserDetailsAuthenticationProvider.DefaultPreAuthenticationChecks) is now overridden by this class. Since the default implementation is a private inner class, you cannot simply extend it, but need to copy the code from there to prevent locked/disabled/etc. users from logging in.
Once you have all that in place, configure an ExceptionMappingAuthenticationFailureHandler that maps your TrialPeriodExpiredException to the URL of the pricing page, where the user should land.
<form-login authentication-failure-handler-ref="exceptionMapper" ... />
...
<bean id="exceptionMapper" class="org.springframework.security.web.authentication.ExceptionMappingAuthenticationFailureHandler" >
<property name="exceptionMappings">
<map>
<entry key="your.package.TrialPeriodExpiredException" value="/pricing"/>
</map>
</property>
</bean>

Spring: remember me cookie not set

I can't seem to get a cookie of spring that remembers the session, nor is the persistent_logins table of the dataSource getting populated. Why isn't the cookie received by the client?
Application context xml file :
<?xml version="1.0" encoding="UTF-8"?>
<bean:beans>
<http>
...
<remember-me data-source-ref="dataSource"
user-service-ref="userService" />
</http>
<authentication-manager alias="authenticationManager">
<authentication-provider user-service-ref="userService">
<password-encoder hash="md5" ref="passwordEncoder">
<salt-source ref="saltSource" />
</password-encoder>
</authentication-provider>
</authentication-manager>
...
</bean:beans>
login method:
#Service
public class AServiceImpl extends RemoteServiceServlet implements AService {
#Override
public boolean login(String username, String password, boolean remember) {
Collection<GrantedAuthority> auths = userDetailsService.getGrantedAuthorities(user);
auth = new UsernamePasswordAuthenticationToken(username, password, auths);
Authentication result = authenticationManager.authenticate(auth);
SecurityContextHolder.getContext().setAuthentication(result);
getThreadLocalRequest().getSession().setAttribute(HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY,SecurityContextHolder.getContext());
rememberMeServices.loginSuccess(getThreadLocalRequest(),getThreadLocalResponse(), auth);
}
}

Resources