How to implement custom authentication using Spring 2.5 - spring

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"/>

Related

Automate Login to site using Spring Boot (Spring Security) and LDAP

I am working on a Spring Boot project, which uses LDAP in Spring Security for authentication.
I need to automate the login once the user hits the login page based on the roles in LDAP group provided in Spring Security.
If user has any role in the group mentioned in LDAP, then it must redirect to the corresponding page after login. (i.e page1 in my example).
I have been searching 2 days in a row for this for any online documentation or an example, but in vain. All I could find is using a jdbcDataSource or hard coding the username and password in Controller and later validating it when login or through Spring using web.xml. But not via LDAP. Any help would be much helpful.
This is how my Spring Security XML looks:
<?xml version="1.0" encoding="UTF-8" ?>
<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/security
http://www.springframework.org/schema/security/spring-security.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<http auto-config="true" use-expressions="true">
<intercept-url pattern="/login" access="permitAll" />
<intercept-url pattern="/logout" access="permitAll" />
<intercept-url pattern="/webjars/**" access="permitAll" />
<intercept-url pattern="/page1" access="hasAnyRole('GP1','GP2')" />
<intercept-url pattern="/page2" access="hasAnyRole('GP1','GP2')" />
<intercept-url pattern="/page3" access="hasAnyRole('GP1','GP2')" />
<intercept-url pattern="/**" access="permitAll" />
<form-login default-target-url="/page1" login-page="/login"
always-use-default-target="true" />
<access-denied-handler error-page="/403.html" />
<csrf disabled="true" />
<logout logout-url="/logout" />
</http>
<authentication-manager alias="authenticationManager"
erase-credentials="false">
<authentication-provider ref="ldapAuthProvider" />
</authentication-manager>
<ldap-server id="contextSource" url="ldap://url"
manager-dn="mymanagerdn" manager-password="mymanagerpswd" />
<beans:bean id="ldapAuthProvider"
class="org.springframework.security.ldap.authentication.LdapAuthenticationProvider">
<beans:constructor-arg>
<beans:bean id="bindAuthenticator"
class="org.springframework.security.ldap.authentication.BindAuthenticator">
<beans:constructor-arg ref="contextSource" />
<beans:property name="userSearch" ref="userSearch" />
</beans:bean>
</beans:constructor-arg>
<beans:constructor-arg>
<beans:bean
class="org.springframework.security.ldap.userdetails.DefaultLdapAuthoritiesPopulator">
<beans:constructor-arg ref="contextSource" />
<beans:constructor-arg value="myDCvalues" />
<beans:property name="searchSubtree" value="true" />
<beans:property name="ignorePartialResultException"
value="true" />
<beans:property name="groupSearchFilter" value="(member={0})" />
</beans:bean>
</beans:constructor-arg>
</beans:bean>
<beans:bean id="userSearch"
class="org.springframework.security.ldap.search.FilterBasedLdapUserSearch">
<beans:constructor-arg index="0"
value="myDCvalues" />
<beans:constructor-arg index="1"
value="(sAMAccountName={0})" />
<beans:constructor-arg index="2" ref="contextSource" />
<beans:property name="searchSubtree" value="true" />
</beans:bean>
</beans:beans>
My WebController:
package com.myPackage;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import org.springframework.context.annotation.Bean;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
#Controller
public class WebController extends WebMvcConfigurerAdapter {
#Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/page1").setViewName("page1");
registry.addViewController("/page2").setViewName("page2");
registry.addViewController("/page3").setViewName("page3");
registry.addViewController("/login").setViewName("login");
registry.addViewController("/403").setViewName("error/403");
}
#GetMapping("/page1")
public String page1(HttpSession session) {
return "page1";
}
#GetMapping("/page2")
public String page2(HttpSession session) {
return "page2";
}
#GetMapping("/page3")
public String page3(HttpSession session) {
return "page3";
}
#GetMapping("/login")
public String login() {
return "login";
}
#GetMapping("/403")
public String error403() {
return "error/403";
}
#Bean
public ViewResolver getViewResolver() {
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setPrefix("templates/");
return resolver;
}
#Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable();
}
private String getCredentials() {
String credential = null;
UserDetails userDetails = (UserDetails) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
credential = userDetails.getUsername().toString();
return credential;
}
}
For your convenience, this answer comes with a complete and working sample, including an LDAP server, populated with users and groups and an integration test, so that you can run these tests yourself.
Assume you have the following user in LDAP
dn: cn=marissa,ou=Users,dc=test,dc=com
changetype: add
objectClass: person
objectClass: organizationalPerson
objectClass: inetOrgPerson
cn: marissa
userPassword: koala
uid: 20f459e0-e30b-4d1f-998c-3ded7f769db1
mail: marissa#test.com
sn: Marissa
The username is marissa and the password is koala.
Let's start with the test case:
#Test
#DisplayName("ldap login works")
void doLogin() throws Exception {
mvc.perform(
MockMvcRequestBuilders.post("/login")
.param("username", "marissa")
.param("password", "koala")
.with(csrf())
)
.andExpect(status().is3xxRedirection())
.andExpect(authenticated())
;
}
From this test, we can deduce that
LDAP uses form login, username/password
The form has CSRF protection
So let's configure your Spring Boot application using Java config
The classic sample file, SecurityConfig.java
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
The security configuration doesn't change.
We want users to be fully authenticated
We want to use form login
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.anyRequest()
.fullyAuthenticated()
.and()
.formLogin()
;
}
That's it, next we configure LDAP, again in your SecurityConfig.java we do this by calling the AuthenticationManagerBuilder. This is a bean that Spring Security configures. So we can access it using #Autowired
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth
.ldapAuthentication()
.contextSource()
.url("ldap://localhost:389")
.managerDn("cn=admin,dc=test,dc=com")
.managerPassword("password")
.and()
.userSearchBase("ou=Users,dc=test,dc=com")
.userSearchFilter("cn={0}")
.groupSearchBase("dc=test,dc=com")
.groupSearchFilter("member={0}")
;
}
and that's it. Now, I used some code I wrote from the Cloud Foundry UAA project to create an in memory LDAP server for my integration tests.
So when the mock MVC integration test starts up, it starts an LDAP server to run against.
It really is that simple. You can now expand this sample to map LDAP groups to Spring Security authorities.
The LDAP Sample is available in my community repo: https://github.com/fhanik/spring-security-community.git

How to replicate user from LDAP to application database for handling authorization from application layer

Hi I am not pretty sure about the LDAP and spring security. I have a requirement were as the application authentication has to be carried out by a LDAP and authorization mechanism has to handled by application layer. I am using Jhipster which has spring security implementation. However, I can able to connect to LDAP and authenticate the user.
Now authorization mechanism has to be handled by application layer where I could manage authorities. So I thought of replicating the user information from the LDAP to application layer database if the user is not present just after the user authentication process. So how can I implement this with spring security framework. How to intercept the filter chain or some process to do this.
And finally is this the good approach or is there a better way to handle this.
This is how I implemented LDAP authentication and local Authorization in my project.
Configuration:
<beans:bean id="ldapAuthProvider"
class="org.springframework.security.ldap.authentication.LdapAuthenticationProvider">
<beans:constructor-arg name="authenticator">
<beans:bean
class="org.springframework.security.ldap.authentication.BindAuthenticator">
<beans:constructor-arg ref="contextSource" />
<beans:property name="userSearch">
<beans:bean
class="org.springframework.security.ldap.search.FilterBasedLdapUserSearch">
<beans:constructor-arg name="searchBase"
value="ou=example,dc=springframework,dc=org" />
<beans:constructor-arg name="searchFilter"
value="(uid={0})" />
<beans:constructor-arg name="contextSource"
ref="contextSource" />
</beans:bean>
</beans:property>
</beans:bean>
</beans:constructor-arg>
<beans:constructor-arg name="authoritiesPopulator"
ref="myLDAPAuthPopulator" />
</beans:bean>
<authentication-manager alias="authenticationManager">
<authentication-provider ref="ldapAuthProvider" />
</authentication-manager>
Custom Authorities Populator:
#Component("myLDAPAuthPopulator")
public class MyLdapAuthoritiesPopulator implements LdapAuthoritiesPopulator {
#Autowired
private UserDao userDao;
#Override
public Collection<? extends GrantedAuthority> getGrantedAuthorities(
DirContextOperations userData, String username) {
List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
User user = userDao.searchUser(username);
List<String> roleList = userDao.getRoles(username);
if (!roleList.isEmpty()) {
for (String role : roleList) {
System.out.println(role);
authorities.add(new SimpleGrantedAuthority(role));
}
}
return authorities;
}

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.

Custom Authentication Provider get calls with every request

I am creating a custom authentication provider that authenticates user using a third party system. Username and password are being sent to server in json format. To implement that I have created a custom filter - UsernamePasswordAuthenticationFilter which is called at position FORM_LOGIN_FILTER. After this I created a custom authentication provider to authenticate user using a third party system. But, this authentication filter is being called with every request, which causes third party system to be called with every request. What I am doing wrong?
CustomUsernamePasswordAuthenticationFilter:
#Override
public Authentication attemptAuthentication( HttpServletRequest request, HttpServletResponse response)
{
//Get username password from request
UsernamePasswordAuthenticationToken token =
new UsernamePasswordAuthenticationToken( username, password);
setDetails(request, token);
return this.getAuthenticationManager().authenticate(token);
}
Custom Authentication Provider:
#Override
public Authentication authenticate(Authentication authentication) {
String username = authentication.getName();
String password = authentication.getCredentials().toString();
boolean flag = //use the credentials to try to authenticate against the third party system
if(flag) {
return new UsernamePasswordAuthenticationToken(username, password);
}
else
throw new BadCredentialsException("Bad Credentials");
}
#Override
public boolean supports(Class<?> authentication) {
return true;
}
security-context.xml
<http pattern="/resources/**" security="none"/>
<http auto-config="false" use-expressions="true" access-denied-page="/welcome"
create-session="always" disable-url-rewriting="true" entry-point-ref="customEntryPoint">
<intercept-url pattern="/" access='permitAll'/>
<custom-filter ref="loginFilter" position="FORM_LOGIN_FILTER" />
<intercept-url pattern="/**" access="isAuthenticated()" />
<logout logout-success-url="/" delete-cookies="JSESSIONID" logout-url="/logout" invalidate-session="true" />
</http>
<bean id="loginFilter" class="org.temp.secure.CustomUsernamePasswordAuthenticationFilter">
<beans:property name="requiresAuthenticationRequestMatcher" ref="loginRequestUrlHandler" />
<beans:property name="authenticationManager" ref="authenticationManager" />
<beans:property name="usernameParameter" value="username" />
<beans:property name="passwordParameter" value="password" />
</beans:bean>
<authentication-manager alias="authenticationManager">
<authentication-provider ref="customAuthenticationProvider" />
</authentication-manager>
<bean id="loginRequestUrlHandler" class="org.springframework.security.web.util.matcher.RegexRequestMatcher">
<constructor-arg index="0" value="/login" />
<constructor-arg index="1" value="POST" />
<constructor-arg index="2" value="false" />
</bean>
<bean id="customEntryPoint" class="org.temp.secure.CustomEntryPoint" />
<bean id="customAuthenticationProvider" class="org.temp.secure.MyAuthenticationProvider"/>
Never mind, got it, problem was that I was not setting any roles, so it was showing authentication as false. After setting roles in UsernamePasswordAuthenticationToken, it does not call custom authentication provider any more..
#Override
public Authentication authenticate(Authentication authentication) {
String username = authentication.getName();
String password = authentication.getCredentials().toString();
boolean flag = //use the credentials to try to authenticate against the third party system
if(flag) {
List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
authorities.add(new SimpleGrantedAuthority("ROLE_ONE"));
authorities.add(new SimpleGrantedAuthority("ROLE_TWO"));
return new UsernamePasswordAuthenticationToken(username, password, authorities);
}
else
throw new BadCredentialsException("Bad Credentials");
}
#Override
public boolean supports(Class<?> authentication) {
return true;
}

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>

Resources