Spring security Custom hash algorithm - spring

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>

Related

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. :)

How Authentication manager verifies Credentials?

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.

How to Implement security login and logout in spring?

Please go through the following code:
I have been using the following class to authenticate the user:
#Controller
public class AdminLoginController
{
#RequestMapping(value = "/loginForm", method ={RequestMethod.GET,RequestMethod.POST})
public String showForm(ModelMap model)
{
return GlobalConstants.LOGIN_PAGE;}
#RequestMapping(value = "/login" ,method ={RequestMethod.POST, RequestMethod.GET})
public String processForm(#ModelAttribute("loginForm")AdminLoginForm loginForm, BindingResult result , HttpServletRequest request, HttpServletResponse response, ModelMap model)
{
try{
AdminLoginWorker worker=new AdminLoginWorker();
boolean status=worker.validateUser(loginForm);
if(status)
{
if("superAdmin".equalsIgnoreCase(loginForm.getUserType()))
{
dtoBean.setEmp_id(loginForm.getUserName());
session.setAttribute("dtoBean", dtoBean);
return GlobalConstants.SUPERADMIN_HOME_PAGE;
}
if("Admin".equalsIgnoreCase(loginForm.getUserType()))
{
dtoBean.setEmp_id(loginForm.getUserName());
session.setAttribute("dtoBean", dtoBean);
return GlobalConstants.HOME_PAGE;
}
}catch(Exception e){
e.printStackTrace();
}
return GlobalConstants.LOGIN_PAGE;
}
and for the logout:
#RequestMapping(value = "/logout", method ={RequestMethod.GET,RequestMethod.POST})
public ModelAndView logoutForm(HttpServletRequest request)
{
HttpSession session = request.getSession(false);
session.invalidate();
return new ModelAndView( GlobalConstants.LOGIN_PAGE);
}
I called the DAO method to validate from database using:
public class AdminLoginWorker{
public boolean validateUser(AdminLoginForm loginForm){
try{ con=DBConnection.getConnection();
query="select userType from login where emp_id=? and pwd=?";
pstmt.setInt(1,loginForm.getUserName());
pstmt.setString(2,loginForm.getPassword());
if(rs.next()){
loginForm.setUserType(rs.getString(1));
return true;}
so now I wants implement the spring security in my web application so I have tried the following in spring-context.xml:
<http auto-config="true">
<intercept-url pattern="/**" access="isAuthenticated"/> <!-- this means all URL in this app will be checked if user is authenticated -->
<form-login/> <!-- -->
<logout logout-url="/logout" logout-success-url=""/>
</http>
<authentication-manager>
<authentication-provider>
<user-service>
<user name="sachin" password="sachin123" authorities="Admin"/>
</user-service>
</authentication-provider>
In above security-context.xml file I wants to add data source so that the user will be verified using database so I have been using the below DBCOnnection class for connectivity with Mysql:
public class DBConnection {
private static Connection con=null;
public static Connection getConnection()
{
try{
if(con==null){
Class.forName("com.mysql.jdbc.Driver");
con = DriverManager.getConnection("jdbc:mysql://localhost:3306/portal",
"root", "root");
}
}catch(Exception e){
e.printStackTrace();
}
return con;
}
}
Now the question i,
How to put the above datasource in security-context.xml file or
Is there any way i can reference from security-context.xml file to DBConnection class for implementing the spring security login authentication.
does anyone have idea to solve the issue?
It seems to me that you are doing of fair amount of wheel reinvention. Everything you are trying to do manually to can easily be handled by Spring Security without writing code, just using the appropriate configuration.
Check out this and this blog post for more details

How custom authentication-provider works

Good day people.
Please help. Can not understands how my custom authentication-provider should be triggered.
I have:
Spring-context.xml
<security:http pattern="/login" security="none" />
<security:http auto-config="true" use-expressions="true">
<security:form-login login-page="/login"/>
<security:intercept-url pattern="/" access="hasRole('ROLE_USER')"/>
<security:form-login authentication-failure-url="www.google.com"/>
</security:http>
<security:authentication-manager>
<security:authentication-provider user-service-ref="userSecurityService"/>
</security:authentication-manager>
<bean id="webContentDAOImpl" class="demidov.pkg.persistence.WebContentDAOImpl">
<property name="sessionFactory"><ref bean="sessionFactory"/></property>
</bean>
<bean id="userSecurityService" class="demidov.pkg.persistence.UserSecurityService">
<property name="webContentDAOIF" >
<ref bean="webContentDAOImpl"/>
</property>
</bean>
Login Controller:
#Controller
public class LoginController {
#RequestMapping(value="/login", method=RequestMethod.GET)
public String login() {
return "login";
}
#RequestMapping(value="/security/j_spring_security_check", method=RequestMethod.POST)
public String access() {
return "redirect:/";
}
}
Login JSP page:
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<form action="security/j_spring_security_check" method="post">
UserName: <input type="text"/> <br>
Password: <input type="password"/> <br>
<br>
<input type="submit"/>
</form>
</body>
</html>
Custom principal resolver:
public class UserSecurityService implements UserDetailsService{
WebContentDAOIF webContentDAOIF;
public WebContentDAOIF getWebContentDAOIF() {
return webContentDAOIF;
}
public void setWebContentDAOIF(WebContentDAOIF webContentDAOIF) {
this.webContentDAOIF = webContentDAOIF;
}
#Override
public UserDetails loadUserByUsername(String userName)
throws UsernameNotFoundException {
UserDetails userDetails = null;
TheUser theUser = webContentDAOIF.fetchUserByName(userName);
userDetails = new User(theUser.getUserEmale(), theUser.getUserPassword(), true, true, true, true, getAthorities(theUser.getRoleAccess()));
return userDetails;
}
public Collection<GrantedAuthority> getAthorities(String role) {
List<GrantedAuthority> authList = new ArrayList<GrantedAuthority>(2);
authList.add(new SimpleGrantedAuthority(" "));
if ( role.equals("ROLE_USER")) {
authList.add(new SimpleGrantedAuthority("ROLE_USER"));
}
// Return list of granted authorities
return authList;
}
}
I just can not understand how my custom principal resolver should work with security. How it should be triggered and by what??? When I put wrong username and password on login page it seems not work with my UserSecurityService and just simply redirect me on login page again because of my hasRole(ROLE_USER) in spring-context.xml . I believe that j_spring_security_check may do something, but so doubt of it. Please help me to understand.
kindly refer to below mentioned link, may be of some help :-
spring security custom authentication
method loadUserByUsername is having param userName which is having value posted from browser that userName is compared with DB and password is fetched from DB and passed to UserDetail object which is having a password posted from browser so now it will compare the passwords internally and acts accordingly for authentication

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