How Authentication manager verifies Credentials? - spring

I am using spring security in my web application.
Here we have authentication-manager & authentication-provider where we are providing authenticate user details directly or by an service.
Like:
<authentication-manager>
<authentication-provider user-service-ref="loginService" />
</authentication-manager>
How it is internally performing the verifications. Where is the verification logic present ?
What is going on internally ?
Can anyone suggest with explanation.

Spring security Javadoc is your friend !
AuthenticationManager is an interface. The default implementation is ProviderManager that gets a list of AuthenticationProvider. Each AuthenticationProvider is tried in sequence until one can decide for the authentication credentials proposed.
Here, the <authentication-provider user-service-ref="loginService" /> declares a DaoAuthenticationProvider. The DaoAuthenticationProvider loads user information from the UserDetailsService (here loginService) and compares the username/password combination with the values supplied at login. If all is fine, it populates an AuthenticationToken with the values retrieved from loginService and passes id back to the AuthenticationManager. If credentials are wrong, it throws an AuthenticationException

It goes like this :
Security-application-context.xml :
<security:authentication-manager alias="authenticationManager">
<security:authentication-provider user-service-ref="LoginServiceImpl">
<security:password-encoder ref="encoder"/>
</security:authentication-provider>
</security:authentication-manager>
<beans:bean id="encoder"
class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder">
<beans:constructor-arg name="strength" value="11" />
</beans:bean>
<beans:bean id="daoAuthenticationProvider"
class="org.springframework.security.authentication.dao.DaoAuthenticationProvider">
<beans:property name="userDetailsService" ref="LoginServiceImpl"/>
<beans:property name="passwordEncoder" ref="encoder"/>
</beans:bean>
In the above code, you can see authentication manager indicates user-service-ref is LoginServiceImpl and use BCrypt encode with 11 rounds for encryption. Then It looks for Classes with LoginServiceImpl, mentioned below :
#Transactional
#Service("userDetailsService")
public class LoginServiceImpl implements UserDetailsService{
#Autowired private PersonDAO personDAO;
#Autowired private Assembler assembler;
#Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException,DataAccessException {
Person person = personDAO.findPersonByUsername(username.toLowerCase());
if(person == null) { throw new UsernameNotFoundException("Wrong username or password");}
return assembler.buildUserFromUserEntity(person);
}
public LoginServiceImpl() {
}
}
As you see it calls a database method by searching in the database for the user. If found, then a new person is build based upon UserDetails class, as below, I am doing it in assembler :
#Service("assembler")
public class Assembler {
#Transactional(readOnly = true)
User buildUserFromUserEntity(Person userEntity){
String username = userEntity.getUsername().toLowerCase();
String password = userEntity.getPassword();
boolean enabled = userEntity.isEnabled();
boolean accountNonExpired = userEntity.isAccountNonExpired();
boolean credentialsNonExpired = userEntity.isCredentialsNonExpired();
boolean accountNonLocked = userEntity.isAccountNonLocked();
Collection<GrantedAuthority> authorities = new ArrayList<>();
authorities.add(new SimpleGrantedAuthority("ROLE_USER"));
return new User(username,password,enabled,accountNonExpired,credentialsNonExpired,accountNonLocked,authorities);
}
}
These other guys indicate if account is not expired, not locked, and other details. I hope you followed the procedure.

Related

Letting Spring security pick implementation of class implementing custom authentication provider

We have a webapp which implements custom authentication via AuthenticationProvider.
This works fine now. But we want to provide an option for customer to implement their own authentication class implementing AuthenticationProvider. So they will delete our jar from app and add their jar to classpath.
It appears in security xml we need to specify only class implementing AuthenticationProvider but can't tell spring to pick any class implementing interface AuthenticationProvider
Current XML and Class implementation
<authentication-manager alias="authenticationManager">
<authentication-provider ref="customAuthenticationProvider"/>
</authentication-manager>
<beans:bean id="customAuthenticationProvider" class="w.x.y.z.CustomAuthenticationProvider"></beans:bean
#Component
public class CustomAuthenticationProvider implements AuthenticationProvider {
#Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
//Implementation
}
#Override
public boolean supports(Class<?> arg0) {
return true;
}
}
Is there anyway I can tell spring to pick any class implementing AuthenticationProvider?
Maybe you can do it by using type autowiring and factory method:
1-The CustomAuthenticationProvider it will be injected by type autowiring defined only in the jar added by your client and the deleted jar(it must be exactly one instance of AuthenticationProvider).
2-And then use a factory method to inject this provider into the authentication-manager.
1-first step
public class AuthenticationProviderFactory {
#Autowired
private AuthenticationProvider authProvider;
public AuthenticationProvider getAuthenticationProvider() {
return authProvider;
}
}
2-second step
<bean name="authenticationProviderFactory"
class="w.x.y.z..AuthenticationProviderFactory"></bean>
<bean name="authenticationProvider" factory-bean="authenticationProviderFactory"
factory-method="getAuthenticationProvider">
</bean>
<authentication-manager alias="authenticationManager">
<authentication-provider ref="authenticationProvider"/>
</authentication-manager>
!!!! The deleted jar and the new jar must have the same applicationContext.xml name(where the AuthenticationProvider is declared) to make the replace working.
<import resource="applicationContextAuthProvider.xml"/>

Spring Security with hibernate : hasRole() is not working in config

I am trying to implement Spring Security for my Spring + Hibernate project.
But the hasRole('SUPER_ADMIN') that i write in the intercept-url tag is not working.
Please find the config that i have done below.
springSecurity.xml
<http auto-config="true" use-expressions="true">
<intercept-url pattern="/admin**" access="hasRole('SUPER_ADMIN')" />
<!-- access denied page -->
<access-denied-handler error-page="/403" />
<form-login login-page="/login" default-target-url="/welcome" authentication-failure-url="/login?error" username-parameter="username"
login-processing-url="/loginCheck" password-parameter="password" />
<logout logout-success-url="/login?logout" />
<!-- enable csrf protection -->
<csrf />
</http>
<authentication-manager>
<authentication-provider user-service-ref="myUserDetailsServices">
<password-encoder hash="bcrypt" />
</authentication-provider>
</authentication-manager>
I am using the following auth provider
public class MyUserDetailsServices implements UserDetailsService {
private UserDao userDao;
#Override
#Transactional
public UserDetails loadUserByUsername(final String username) throws UsernameNotFoundException {
User user = userDao.findByEmail(username);
if (user == null) {
throw new UsernameNotFoundException("User " + username + " not found");
}
List<GrantedAuthority> authorities = buildUserAuthority(user.getRoles());
return buildUserForAuthentication(user, authorities);
}
private org.springframework.security.core.userdetails.User buildUserForAuthentication(User user, List<GrantedAuthority> authorities) {
return new org.springframework.security.core.userdetails.User(user.getEmail(), user.getPassword(), true, true, true, true, authorities);
}
private List<GrantedAuthority> buildUserAuthority(Set<Role> userRoles) {
Set<GrantedAuthority> setAuths = new HashSet<GrantedAuthority>();
for (Role userRole : userRoles) {
setAuths.add(new SimpleGrantedAuthority(userRole.getRoleName()));
}
List<GrantedAuthority> Result = new ArrayList<GrantedAuthority>(setAuths);
return Result;
}
public UserDao getUserDao() {
return userDao;
}
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
}
The The above code is working fine. I am able to get the correct role and buildUserForAuthentication() method is returned with the SUPER_ADMIN role added in the authorities.
But still the hasRole('SUPER_ADMIN') is not working. I am not able to access the page http://127.0.0.1:8080/myproj/admin. The user is getting authenticated and logged in. But the above url is getting redirected to /403 (Access Denied).
Am i missing something? Please help.!
The hasRole is working well. What is not working in your code is your wildcard on your springSecurity.xml.
Change this
<intercept-url pattern="/admin**" access="hasRole('SUPER_ADMIN')" />
to
<intercept-url pattern="/admin/**" access="hasRole('SUPER_ADMIN')" />
Not sure why and how, but spring seems to add a leading slash why validating your url.
so having /admin/** will have the same effect as your intended /admin**.
Got this rectified by adding 'ROLE_' to the rolename. Made it as ROLE_SUPER_ADMIN and it started working. I am assuming that every role should be prefixed with 'ROLE_' for spring security to work properly.
Thanks #storm_buster for the tip. :)

Spring security Custom hash algorithm

I have a Spring Project that has been authenticated using Spring Security.
Spring Security code snippet :
<authentication-manager>
<authentication-provider>
<password-encoder hash="md5"/>
<jdbc-user-service data-source-ref="dataSource"
users-by-username-query="
SELECT users.LOGIN_NAME AS username,
users.PASSWD_HASH AS password , users.status as enabled
FROM RV_USER users
WHERE users.LOGIN_NAME=?"
authorities-by-username-query="
select users.LOGIN_NAME as username, authorities.ROLE_DESC as authority
from RV_ROLE authorities, RV_USER users
where authorities.ROLE_ID=users.ROLE_ID
and users.LOGIN_NAME=?"
/>
</authentication-provider>
</authentication-manager>
I want to use a custom hash algorithm rather than md5 or something else.
You can create your own PasswordEncoder implementation. For example:
import org.springframework.security.crypto.password.PasswordEncoder;
public class CustomPasswordEncoder implements PasswordEncoder {
public String encode(CharSequence rawPassword) {
return null; // TODO implement
}
public boolean matches(CharSequence rawPassword, String encodedPassword) {
return null; // TODO implement
}
}
You can then use CustomPasswordEncoder with password-encoder#ref For example:
<authentication-manager>
<authentication-provider>
<password-encoder ref="customPasswordEncoder/>
...
</authentication-provider>
</authentication-manager>

Passing Dynamic arguments using setter injection in Springs

Iam trying to pass dynamic argument values i.e username from request using spring ioc.But iam unable to seen username value in userdaoimp.
UserDAOImpl.java
public class UserDAOImpl implements UserDAO {
private DataSource dataSource;
private JdbcTemplate jdbctemplate;
private String username;
public void setUsername(String username) {
this.username = username;
}
public DataSource getDataSource() {
return dataSource;
}
public void setDataSource(DataSource dataSource) {
this.dataSource = dataSource;
this.jdbctemplate =new JdbcTemplate (dataSource);
}
public int getUserListSize() {
System.out.println("UserDAOImpl::getUserListSize()"+username);
int count=this.jdbctemplate.queryForInt("SELECT COUNT(*) FROM USER_INFO");
return count;
}
}
epis.dao.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="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-2.5.xsd">
<bean id="userdao" class="com.epis.dao.UserDAO">
<property name="dataSource">
<ref local="dataSource" />
</property>
<property name="username"/>
</bean>
</beans>
UserService
In the XML you can assing properties only to the surrounding bean.
so
will not work, because UserService does not have a filed username and therefor the spring should not start.
You can write it in two different ways:
<bean id="userdao" class="com.epis.dao.UserDAO">
<property name="dataSource" ref="dataSource" />
<property name="username" value="aaa"/>
</bean>
<bean ... class="...UserService">
<property name="userdao" ref="userdao" />
<bean>
or
<bean ... class="...UserService">
<property name="userdao">
<bean class="com.epis.dao.UserDAO">
<property name="dataSource" ref="dataSource" />
<property name="username" value="aaa"/>
</bean>
</property>
<bean>
But you can not mix both styles for one property.
Form the comment
Actually my requirement is the username value is getting based on other business logic in UserService.This username will be forwarded into userdao constructor.How can I forward that value to userdao.
This is not possible or at least not without a lot of handwritten magic. The reason is simple: The objects descriped in the XML file are created when the application starts, and the values are set while starting.
But in general I think you can achieve your aim with some scoped beans. But I have highly doubt that scoped beans can be used for the database connection.
I highly recommend to ask a new question hat focus on the dynamic requirement with the explanation you gave in the comment of this answer. (but without the bugy xml example) )
#See Spring Reference Chapter 3.5 Bean scopes
If you make username a property of the UserDaoImpl then it not longer be thread-safe, i.e. what would happen if two calls come in at the same time? The second call will overwrite the setting of the username property possibly before the getUserListSize() has been called the first time. You'd have to create a new UserDao object for every single call, which is not very efficient.
The easiest way is to use a parameter for your methods:
So in UserDao:
public int getUserListSize(String username);
In UserDaoImpl:
public int getUserListSize(String username) {
logger.debug("UserDAOImpl::getUserListSize():"+username);
int count = this.jdbctemplate.queryForInt(
"SELECT COUNT(*) FROM USER_INFO WHERE USER_NAME = ?", username);
return count;
}
And in UserService:
public int getUserListSize() {
String username = someBusinessLogicObtainsUsername();
return this.userDao.getUserListSize(username);
}

Authentication base64

I am developping an application with Spring roo.
As a first authentication test implying Spring security I used authentication against a table in my database. That work fine :
<authentication-manager alias="authenticationManager">
<authentication-provider>
<jdbc-user-service data-source-ref="dataSource" authorities-by-username-query="select username,authority from users where username=?"/>
</authentication-provider>
</authentication-manager>
Now things get a little more challenging (for me) because the password in the "real" (in the production env) user table is encrypted, I have to first use the hash function md5 and then the base64 encoding as well as iso to deal with special characters.
I have to create a custom jdbc-user-service. What would be the best practices to deal with those operations ?
As suggested, I managed to solve the problem with Spring security build in authentification.
I had first to set the encoding of the security-context.xml to ISO-8859-1
<?xml version="1.0" encoding="ISO-8859-1"?>
then use :
<password-encoder hash="md5" base64="true" ></password-encoder>
The first thing to do is the create a custom password-encoder that will allow me more controle over the authentication process.
In the applicationContext-Security.xml
Create the custom class
public class SnatiPasswordEncoder implements PasswordEncoder {
#Override
public String encodePassword(String arg0, Object arg1)
throws DataAccessException {
// TODO Auto-generated method stub
return null;
}
#Override
public boolean isPasswordValid(String arg0, String arg1, Object arg2)
throws DataAccessException {
// TODO Auto-generated method stub
return false;
}
/**
* #param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
}
}
What should come next ?

Resources