Spring security with password encoding and salting - spring

I am trying to to authenticate user with spring-security with SHA hashing and salting. I have added extra field in users table for extra salt and customize UserDetails with this salt but whenever I try to login it is throwing bad credential exception.
My CustomJdbcDaoImpl class is :
public class CustomJdbcDaoImpl extends JdbcDaoImpl implements IChangePassword {
private Logger logger = LoggerFactory.getLogger(CustomJdbcDaoImpl.class);
#Override
protected UserDetails createUserDetails(String username,UserDetails userFromUserQuery,
List<GrantedAuthority> combinedAuthorities){
String returnUsername = userFromUserQuery.getUsername();
if(!isUsernameBasedPrimaryKey()){
returnUsername = username;
}
logger.info("inside #class CustomJdbcDaoImpl #method createUserDetails USER DETAILS ARE: "+userFromUserQuery.getPassword()+"authritieds: "+combinedAuthorities);
return new SaltedUser(returnUsername,
userFromUserQuery.getPassword(),
userFromUserQuery.isEnabled(),
true,
true,
true,
combinedAuthorities,
((SaltedUser)userFromUserQuery).getSalt());
}
#Override
protected List<UserDetails> loadUsersByUsername(String username) {
return getJdbcTemplate()
.query(getUsersByUsernameQuery(),
new String[] {username},
new RowMapper<UserDetails>() {
public SaltedUser mapRow(ResultSet rs, int rowNum) throws SQLException {
String username = rs.getString(1);
String password = rs.getString(2);
boolean enabled = rs.getBoolean(3);
String salt = rs.getString(4);
SaltedUser saltedUser = new SaltedUser(username, password, enabled,
true,
true,
true,
AuthorityUtils.NO_AUTHORITIES,
salt);
logger.info("inside #class #method loadUsersByUsername salted password is: "+saltedUser.getPassword());
return saltedUser;
}
});
}
#Override
public void changePassword(String username, String password) {
getJdbcTemplate().
update("update users set password = ? where username = ?",password,username);
}
}
for changing password each time with salt my DatabasePasswordSecurerBean class is
public class DatabasePasswordSecurerBean extends JdbcDaoSupport {
#Autowired
private PasswordEncoder passwordEncoder;
#Autowired
private SaltSource saltSource;
#Autowired
private UserDetailsService userDetailsService;
private Logger logger = LoggerFactory.getLogger(DatabasePasswordSecurerBean.class);
public void secureDatabase(){
logger.info("inside #class DatabasePasswordSecurerBean #method secureDatabase entry...");
getJdbcTemplate().query("select username,password from users",new RowCallbackHandler(){
#Override
public void processRow(ResultSet rs) throws SQLException {
String username = rs.getString(1);
String password = rs.getString(2);
UserDetails user = userDetailsService.loadUserByUsername(username);
String encodedPassword = passwordEncoder.encodePassword(password,saltSource.getSalt(user));
getJdbcTemplate().update("update users set password = ? where username = ?",
encodedPassword,username);
logger.info("#class DatabasePasswordSecurerBean #method secureDatabase updating password for user: "+username + "to: "+encodedPassword);
}
});
}
}
security.xml configurations are
<http auto-config="true">
<intercept-url pattern="/*" access="ROLE_USER" />
</http>
<authentication-manager alias="authenticationManager">
<authentication-provider user-service-ref="jdbcUserService">
<password-encoder ref="passwordEncoder" >
<salt-source ref="saltSource" />
</password-encoder>
</authentication-provider>
</authentication-manager>
</beans:beans>
and my application.xml is
<!-- Simple implementation of the standard JDBC DataSource interface,
configuring the plain old JDBC DriverManager via bean properties -->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${db.driverClassName}" />
<property name="url" value="${db.connection.url}" />
<property name="username" value="${db.connection.username}" />
<property name="password" value="${db.connection.password}" />
</bean>
<bean id="jdbcUserService" class="com.petCart.springsecurity.security.CustomJdbcDaoImpl">
<property name="dataSource" ref="dataSource" />
<property name="enableGroups" value="true"></property>
<property name="enableAuthorities" value="false"></property>
<property name="usersByUsernameQuery">
<value>
select username,password,enabled,salt from users where username = ?
</value>
</property>
<property name="groupAuthoritiesByUsernameQuery">
<value>
select r.roleid,r.role_name,p.permissionname from roles r
join userrole ur on ur.roleid = r.roleid
join users u on u.id = ur.userid
join rolepermission rp on r.roleid = rp.roleid
join permissions p on p.permissionid = rp.permissionid
where u.username = ?
</value>
</property>
</bean>
<!-- password encoder -->
<bean class="org.springframework.security.authentication.encoding.ShaPasswordEncoder" id="passwordEncoder"/>
<bean class="com.petCart.springsecurity.security.DatabasePasswordSecurerBean" init-method="secureDatabase" depends-on="dataSource">
<property name="dataSource" ref="dataSource" />
</bean>
<bean class="org.springframework.security.authentication.dao.ReflectionSaltSource" id="saltSource">
<property name="userPropertyToUse" value="username" />
</bean>

Try to change from
<bean class="org.springframework.security.authentication.dao.ReflectionSaltSource" id="saltSource">
<property name="userPropertyToUse" value="username" />
</bean>
to
<bean class="org.springframework.security.authentication.dao.ReflectionSaltSource" id="saltSource">
<property name="userPropertyToUse" value="salt" />
</bean>

Related

spring querydsl I don't want start a transaction

Entity:
package com.test.entity
#Entity
#Table(name="TEST_TABLE")
public class TestTable implements HasMapping, PrimaryKey<Long>, Serializable {
public static final String TABLE_NAME = "TEST_TABLE";
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(name="ID", nullable=false)
private Long id;
#Id
#Column(name="Name", nullable=false)
private String name;
#Temporal(value=TemporalType.TIMESTAMP)
#Column(name="CREATE_TIME", nullable=true)
#CreatedDate
private Date createTime;
#Column(name="CREATE_USER", nullable=true, length=32)
#CreatedBy
private String createUser;
#Temporal(value=TemporalType.TIMESTAMP)
#Column(name="LST_UPD_TIME", nullable=true)
#LastModifiedDate
private Date lstUpdTime;
#Column(name="LST_UPD_USER", nullable=true, length=32)
#LastModifiedBy
private String lstUpdUser;
#Column(name="JPA_VERSION", nullable=false)
#Version
private Integer jpaVersion;
......
}
QPath
package com.test.qpath
#Generated("com.mysema.query.codegen.EntitySerializer")
public class QTestTable extends EntityPathBase<TestTable> {
private static final long serialVersionUID = -1751805455;
public static final QTestTable testTable = new QTestTable("testTable");
public final NumberPath<Long> id = createNumber("id", Long.class);
public final DateTimePath<java.util.Date> createTime = createDateTime("createTime", java.util.Date.class);
public final StringPath createUser = createString("createUser");
public final NumberPath<Integer> jpaVersion = createNumber("jpaVersion", Integer.class);
public final DateTimePath<java.util.Date> lstUpdTime = createDateTime("lstUpdTime", java.util.Date.class);
public final StringPath lstUpdUser = createString("lstUpdUser");
public QTestTable(String variable) {
super(TestTable.class, forVariable(variable));
}
#SuppressWarnings("all")
public QTestTable(Path<? extends TestTable> path) {
super((Class)path.getType(), path.getMetadata());
}
public QTestTable(PathMetadata<?> metadata) {
super(TestTable.class, metadata);
}
......
}
Repository
package com.test.repos
public interface RTestTable extends JpaRepository<TestTable, Long>, QueryDslPredicateExecutor<TestTable> {
}
Service
package com.test.service
#Service
public class TestServiceR() {
#Autowired
private RTestTable rTestTable;
public void handler() {
long id = 1;
TestTable t = rTestTable.findone(id);
}
}
package com.test.service
#Service
public class TestServiceQuery() {
#Autowired
private RTestTable rTestTable;
#PersistenceContext
private EntityManager em;
private QTestTable qTestTable = QTestTable.testTable;
public void handler() {
long id = 1;
JPAQuery query = new JPAQuery(em);
TestTable t = query.from(qTestTable).where(qTestTable.id.eq(id)).singleResult(qTestTable);
}
}
spring config
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close">
<property name="url" value="#{env.jdbcUrl}" />
<property name="username" value="#{env.jdbcUsername}" />
<property name="password" value="#{env.jdbcPassword}" />
<property name="initialSize" value="1" />
<property name="minIdle" value="#{env['jdbcMinIdle'] ?: 2 }" />
<property name="maxActive" value="#{env['jdbcMaxActive'] ?: 20}" />
<property name="minEvictableIdleTimeMillis" value="#{env['jdbcMinEvictableIdleTimeMillis'] ?: 1800000}" />
<property name="validationQuery" value="#{env['jdbcTestSql']}" />
<property name="testWhileIdle" value="#{env['jdbcTestWhileIdle']?: false}" />
<property name="testOnBorrow" value="#{env['jdbcTestOnBorrow']?: true}" />
<property name="testOnReturn" value="#{env['jdbcTestOnReturn']?: false}" />
<property name="poolPreparedStatements" value="false" />
<property name="maxPoolPreparedStatementPerConnectionSize" value="-1" />
<property name="filters" value="mergeStat,slf4j" />
<property name="connectionProperties" value="druid.stat.slowSqlMillis=1500;druid.stat.logSlowSql=true" />
<property name="timeBetweenLogStatsMillis" value="900000" />
</bean>
<bean id="emf"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="persistenceUnitName" value="default" />
<property name="packagesToScan">
<list>
<value>com.sunline.ccs.infrastructure.shared.model</value>
</list>
</property>
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="database" value="#{env['jpaDatabaseType']?:'DEFAULT'}" />
<property name="showSql" value="#{env['jpaShowSql']?:false}" />
</bean>
</property>
</bean>
<bean id="sessionFactory" factory-bean="emf" factory-method="getSessionFactory" />
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="emf" />
</bean>
<tx:annotation-driven mode="aspectj"
transaction-manager="transactionManager" />
<jpa:repositories base-package="com.test.repos" />
I test TestServiceR.handler() and TestServiceQuery.handler().
I think they don't start a transaction.
but class TestServiceR are start a transaction.
why? how can i set TestServiceR.handler() don't start a transaction.
TestServiceR calls RTestTable.findOne which extends JpaRepository, which is implemented by SimpleJpaRepository, which is annotated with #Transactional(readOnly = true). So, the transaction is started by SimpleJpaRepository.
Is there a particular reason why you are worried about the transaction, given that it does not affect the application adversely (at least not much)? See the comment history for this Spring Data JPA JIRA issue if you are not convinced.
If you still want to override the default behaviour, you can initialise JPA repositories as #EnableJpaRepositories(enableDefaultTransactions = false) (Java configuration) or <jpa:repositories enable-default-transactions="false" ... /> (XML configuration) to prevent the default implementation from creating transactions by default. See this Spring Data JPA JIRA issue for more details.

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;
}
}

Transaction support for Discriminator model in Muiti-tenancy with Spring + Hibernate

Our current development based on Discriminator model in Multi-tenancy. Following is the technical stack we are currently engage with,
Spring 3.1.1.RELEASE
Hibernate 4.1.6.Final
We are maintain tenant id by keep one column separately in each table. Tenant id filter when session is created.
Example model class.
#Entity
#FilterDef(name = "tenantFilter", parameters = #ParamDef(name = "tenantIdParam", type = "string"))
#Filters(#Filter(name = "tenantFilter", condition = "tenant_id = :tenantIdParam"))
#Table(name = "assessment")
public class Assessment implements java.io.Serializable, Comparable<Assessment> {
private static final long serialVersionUID = -2231966582754667029L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id", unique = true, nullable = false)
private Long id;
#Column(name = "tenant_id", nullable = false, updatable = false)
private String tenantId;
// rest of the code...
}
This is the configuration of session factory
<!-- create database connection pool -->
<bean id="dataSource" class="com.jolbox.bonecp.BoneCPDataSource" destroy-method="close">
<property name="driverClass" value="${jdbc.driverClassName}" />
<property name="jdbcUrl" value="jdbc:mysql://${jdbc.host}:3306/${jdbc.database}?createDatabaseIfNotExist=true&autoReconnect=true&useUnicode=true&connectionCollation=utf8_general_ci&characterEncoding=UTF-8" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
<property name="idleConnectionTestPeriodInMinutes" value="60"/>
<property name="idleMaxAgeInMinutes" value="240"/>
<property name="maxConnectionsPerPartition" value="30"/>
<property name="minConnectionsPerPartition" value="10"/>
<property name="partitionCount" value="3"/>
<property name="acquireIncrement" value="5"/>
<property name="statementsCacheSize" value="100"/>
<property name="releaseHelperThreads" value="3"/>
</bean>
<!-- Hibernate SessionFactory -->
<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="packagesToScan" value="lk.gov.elg.orm.model"/>
<property name="hibernateProperties">
<value>
hibernate.dialect=${hibernate.dialect}
hibernate.hbm2ddl.auto=update
</value>
</property>
</bean>
<bean id="tenantBasedSessionFactory" class="lk.gov.elg.orm.dao.impl.TenantBasedSessionFactoryImpl">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
<bean id="transactionManager"
class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
Tenant base session factory
public class TenantBasedSessionFactoryImpl implements TenantBasedSessionFactory {
private SessionFactory sessionFactory;
#Override
public Session getTenantBasedSession(Object tenantId) {
Session session = sessionFactory.openSession();
session.enableFilter("tenantFilter").setParameter("tenantIdParam", tenantId);
return session;
}
public void setSessionFactory(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
public Session getAllTenantBasedSession() {
Session session = sessionFactory.openSession();
return session;
}
}
sample Service class
#Service("assessmentService")
public class AssessmentServiceImpl implements AssessmentService {
#Autowired
private AssessmentDao assessmentDao;
public Long saveAssessment(Assessment assessment, Object tenantId) {
return assessmentDao.saveAssessment(assessment, tenantId);
}
}
Sample DAO class
#Repository("assessmentDao")
public class AssessmentDaoImpl implements AssessmentDao {
#Autowired
private TenantBasedSessionFactory tenantBasedSessionFactory;
public Long saveAssessment(Assessment assessment, Object tenantId) {
Session session = tenantBasedSessionFactory.getTenantBasedSession(tenantId);
try {
session.beginTransaction();
session.save(assessment);
session.getTransaction().commit();
return assessment.getId();
} catch (HibernateException e) {
logger.error("Error in persist assessment:", e);
session.getTransaction().rollback();
return null;
} finally {
session.close();
}
}
}
I would like to know is there a way to get the spring transaction support with this Discriminator model for database transactions ?
And the other thing is I would like to know is there any advantage of give transaction handling to spring rather than handling it by our side?
Thanks in advance.
i had similar problem and i have resolved it using aspect instead of customizing sessionfactory, so i can leverage annotation driven transaction support
Below code is for aspect which works on annotation #Tennant
#Aspect
public class TennantAspect {
#Autowired
private SessionFactory sessionFactory;
#Around("#annotation(Tennant)")
public Object enableClientFilter(ProceedingJoinPoint pjp) throws Throwable {
Object obj;
boolean isDAO=(pjp.getTarget() instanceof BaseDAO<?,?>);
try {
if(isDAO){
Authentication auth=SecurityContextHolder.getContext().getAuthentication();
if(auth!=null){
User user=(User) auth.getPrincipal();
this.sessionFactory.getCurrentSession().enableFilter("clientFilter").setParameter("clientId", user.getClientId());
}
}
obj=pjp.proceed();
}finally {
if(isDAO)
this.sessionFactory.getCurrentSession().disableFilter("clientFilter");
}
return obj;
}
}
Hope this solves your problem.
Alternatively you can also look at tenancy support by hiberante & spring
http://docs.jboss.org/hibernate/orm/4.1/devguide/en-US/html/ch16.html
https://github.com/mariofts/spring-multitenancy

Spring security - Get all logged in principals

First of all! Thank you for reading my question.
I have a problem with retreiving all my principal objects. I use Spring version 3.2.1.RELEASE and spring security 3.1.3.RELEASE.
I did my research on the net and I found how to retrieve the principals, but after inserting my own authentication code it doesnt work anymore. Methode to retrieve all principals objects:
#RequestMapping("/loggedinusers")
public String viewAllLoggedInUsers(Model model) {
List<Object> principals = sessionRegistry.getAllPrincipals();
model.addAttribute("size", principals.size());
List<Integer> listOfUserIds = new ArrayList<Integer>();
for (Object principal : principals) {
if (principal instanceof Principal) {
listOfUserIds.add(((Principal) principal).getId());
}
}
return "/logged_in_users";
}
The above code was working before I changed some security configuration. Here is all my configuration:
<!-- bean namespave -->
<security:global-method-security jsr250-annotations="enabled" pre-post-annotations="enabled" secured-annotations="enabled" />
<security:http use-expressions="true" entry-point-ref="loginEntryPoint">
<security:intercept-url pattern="/login" access="permitAll()" />
<!-- ******* Filters ******* -->
<security:custom-filter ref="ipFormLoginFilter" position="FORM_LOGIN_FILTER"/>
<security:logout
delete-cookies="JSESSIONID"
logout-url="/logout"
logout-success-url="/login"
/>
<security:session-management session-fixation-protection="newSession">
<security:concurrency-control session-registry-alias="sessionRegistry" max-sessions="5" error-if-maximum-exceeded="false" />
</security:session-management>
</security:http>
<bean id="loginEntryPoint" class="org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint">
<constructor-arg value="/login"/>
</bean>
<security:authentication-manager alias="authenticationManager">
<security:authentication-provider ref="customUserAuthenticationProvider" />
</security:authentication-manager>
<bean id="ipFormLoginFilter" class="nl.irp.vadp.security.CustomIpUsernamePasswordAuthenticationFilter">
<property name="filterProcessesUrl" value="/authlogin"/>
<property name="authenticationManager" ref="authenticationManager"/>
<property name="usernameParameter" value="username"/>
<property name="passwordParameter" value="password"/>
<property name="authenticationSuccessHandler">
<bean class="org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler">
<property name="defaultTargetUrl" value="/"/>
</bean>
</property>
<property name="authenticationFailureHandler">
<bean class="org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler">
<property name="defaultFailureUrl" value="/login?login_error=true"/>
</bean>
</property>
</bean>
<bean id="passwordEncoder" class="org.springframework.security.authentication.encoding.ShaPasswordEncoder">
<constructor-arg value="512" />
</bean>
</beans>
Code::
Filter class
public final class CustomIpUsernamePasswordAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
#Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
if (request.getMethod().equals("POST")) {
String username = obtainUsername(request);
String password = obtainPassword(request);
UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(username, password);
setDetails(request, authRequest);
return this.getAuthenticationManager().authenticate(authRequest);
}
throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod());
}
}
Code:: Custom Authentication class
#Component
public class CustomUserAuthenticationProvider implements AuthenticationProvider {
#Autowired
UserService userService;
#Autowired
ShaPasswordEncoder shaPasswordEncoder;
public CustomUserAuthenticationProvider() {
}
#Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
final String BAD_CREDENTIALS = "test";
final String BAD_IP_ADDRESS = "test";
List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
UsernamePasswordAuthenticationToken token = (UsernamePasswordAuthenticationToken) authentication;
String email = token.getName();
User user = null;
if (email != null) {
user = userService.findUserByEmail(email);
}
if (user == null) {
throw new UsernameNotFoundException(BAD_CREDENTIALS + "no user found");
}
String password = user.getPassword();
String salt = user.getName();
if (!shaPasswordEncoder.isPasswordValid(password, (String) token.getCredentials(), salt)) {
throw new BadCredentialsException(BAD_CREDENTIALS + "bad password");
}
if (!user.hasIpaddress(request.getRemoteAddr())) {
throw new BadCredentialsException(BAD_IP_ADDRESS + "bad ip adress");
}
authorities.add(new SimpleGrantedAuthority("ROLE_" + user.getRole().getName().toUpperCase()));
Principal principal = new Principal(user.getEmail(), user.getPassword(), authorities, user.getId());
return new UsernamePasswordAuthenticationToken(principal, user.getPassword());
}
#Override
public boolean supports(Class<?> authentication) {
return CustomIpUsernamePasswordAuthenticationToken.class.equals(authentication);
}
}
The following listeners are added:
<!-- Listeners -->
<listener><!-- Starts up the webapp project -->
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<listener><!-- spring security listener -->
<listener-class>org.springframework.security.web.session.HttpSessionEventPublisher</listener-class>
</listener>
<!-- extra toegevoegd voor die ip ... -->
<listener>
<listener-class>
org.springframework.web.context.request.RequestContextListener
</listener-class>
</listener>
As the above code describes, I made my own AuthenticationProvider with an authenticate methode which authenticates the inserted data. This works perfectly (component scan is also done). Authorities in jsp ( for example) seems to work also. I seem not to understand why I cant get the registered principals.
edit:
I removed the "auto-config=true" en the tag before inserting additional information.
Hope someone can help me out.
EDIT 2:
I found out where the problem was. In my own custom filter, there is a property called:sessionAuthenticationStrategy. This field needs to be set.
I inserted the following in my filter and it works:
<property name="sessionAuthenticationStrategy" ref="sessionFixationProtectionStrategy" />
<bean id="sessionFixationProtectionStrategy" class="org.springframework.security.web.authentication.session.SessionFixationProtectionStrategy">
Gtrz,

Why is Spring #Transactional returning old data and how can I get it to return up-to-date data?

I'm using Spring 3.1.0.RELEASE with Hibernate 4.0.1.Final. I'm trying to use the Spring transaction manager but am having an issue where Spring is returning old data for a find method. In my Spring application, I call a save method, and then a find method. After I call save, I can see the changes in the database, but when I call the find, it is returning the old state of the object. Here is the controller methods ...
// method to save
#RequestMapping(method = RequestMethod.POST)
public String saveUserEventFeeds(final HttpServletRequest request,
#ModelAttribute("eventFeeds") final Set<EventFeed> eventFeeds) {
final String nextPage = "user/eventfeeds";
try {
final String[] eventFeedIds = request.getParameterValues("userEventFeeds");
final Set<EventFeed> userEventFeeds = new HashSet<EventFeed>();
if (eventFeedIds != null) {
for (final String eventFeedId : eventFeedIds) {
final EventFeed eventFeed = getEventFeed(eventFeeds, Integer.parseInt(eventFeedId));
userEventFeeds.add(eventFeed);
} // for
} // if
final Registration currentUser = (Registration) securityContextFacade.getContext().getAuthentication().getPrincipal();
userService.saveUserEventFeeds(currentUser.getId(), userEventFeeds);
} catch (Exception exc) {
LOG.error(exc.getMessage(), exc);
} // try
return nextPage;
} // saveUserEventFeeds
// method to retrieve user
#ModelAttribute("user")
public UserDetails getUser() {
final Registration reg = (Registration) securityContextFacade.getContext().getAuthentication().getPrincipal();
final int id = reg.getId();
final Registration foundUser = userService.findUserById(id);
return (UserDetails) foundUser;
} // getUser
and here is the service where i declare everything transactional ...
#Transactional(rollbackFor = Exception.class)
#Component("userService")
public class UserServiceImpl implements UserService {
...
#Override
public void saveUserEventFeeds(Integer userId, Set<EventFeed> eventFeeds) {
final Registration searchUser = new Registration();
searchUser.setId(userId);
final Registration user = usersDao.getUser(searchUser);
if (user != null) {
user.setUserEventFeeds(eventFeeds);
usersDao.saveUser(user);
} else {
throw new RuntimeException("User with id " + userId + " not found.");
} // if
}
#Override
public Registration findUserById(Integer id) {
final Registration searchUser = new Registration();
if (id != null) {
searchUser.setId(id);
} // if
return usersDao.getUser(searchUser);
}
Below is the transaction manager I've declared in my application context file. If you can see how I can configure things differently so that I can get the most current data on my finds, please let me know.
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/myproj"/>
<property name="username" value="myproj"/>
<property name="password" value="password"/>
<property name="maxActive" value="10"/>
<property name="minIdle" value="5"/>
<!-- SELECT 1 is a simple query that returns 1 row in MySQL -->
<property name="validationQuery" value="SELECT 1"/>
</bean>
<bean class="org.springframework.orm.hibernate4.LocalSessionFactoryBean" id="sessionFactory">
<property name="dataSource" ref="dataSource" />
<property name="annotatedClasses">
<list>
<value>com.myco.myproj.domain.Registration</value>
<value>com.myco.myproj.domain.Role</value>
<value>com.myco.myproj.domain.EventFeed</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="show_sql">true</prop>
<prop key="dialect">org.hibernate.dialect.MySQLDialect</prop>
</props>
</property>
</bean>
<bean id="transactionManager"
class="org.springframework.orm.hibernate4.HibernateTransactionManager"
p:sessionFactory-ref="sessionFactory" />
<tx:annotation-driven />

Resources