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

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

Related

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

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>

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

determine target url based on roles in spring security 3.1

In spring security 3.0, we are having AuthenticationProcessingFilter class, in which we were using determineTargetUrl() method, which returned the url based on different roles.
Now, we are moving to spring security 3.1.0.RC3 and I am stuck how should I now determine the url based on different roles as AuthenticationProcessingFilter class has been removed from new version. Can anyone please give me steps in brief with some code so that I can implement custom filter to redirect to different pages for different roles.
The best way to determine the target url based upon roles is to specify a target url in your Spring Security configuration as shown below. This will work in Spring 3.0 or 3.1
<http>
...
<form-login login-page="/login" default-target-url="/default"/>
</http>
Then create a controller that processes the default-target-url. The controller should redirect or forward based upon rolls. Below is an example of using Spring MVC, but any type of controller will work (i.e. Struts, a Servlet, etc).
#Controller
public class DefaultController {
#RequestMapping("/default")
public String defaultAfterLogin(HttpServletRequest request) {
if (request.isUserInRole("ROLE_ADMIN")) {
return "redirect:/users/sessions";
}
return "redirect:/messages/inbox";
}
}
The advantages to this approach are it is not coupled to any specific implementation of Security, it is not coupled to any specific MVC implementation, and it works easily with Spring Security namespace configuration. A full example can be found in the SecureMail project I presented at SpringOne this year.
An alternative is that you could create a custom AuthenticationSuccessHandler. The implementation might extend SavedRequestAwareAuthenticationSuccessHandler which is the default AuthenticationSuccessHandler. it could then be wired using the namespace as shown below.
<sec:http>
<sec:form-login authentication-success-handler-ref="authSuccessHandler"/>
</sec:http>
<bean:bean class="example.MyCustomAuthenticationSuccessHandler"/>
I would not recommend doing this as it is tied to Spring Security API's and it is better to avoid that when possible.
Using Custom Authentication Success Handler to specify the redirection based on user role after successful authentication.
You need to create Custom Authentication Success Handler as the following :
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.web.DefaultRedirectStrategy;
import org.springframework.security.web.RedirectStrategy;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Collection;
public class CustomeAuthenticationSuccessHandler implements AuthenticationSuccessHandler {
private RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();
#Override
public void onAuthenticationSuccess(HttpServletRequest request,
HttpServletResponse response, Authentication authentication) throws IOException {
handle(request, response, authentication);
}
protected void handle(HttpServletRequest request,
HttpServletResponse response, Authentication authentication)
throws IOException {
String targetUrl = determineTargetUrl(authentication);
if (response.isCommitted()) {
return;
}
redirectStrategy.sendRedirect(request, response, targetUrl);
}
protected String determineTargetUrl(Authentication authentication) {
boolean isTeacher = false;
boolean isAdmin = false;
Collection<? extends GrantedAuthority> authorities
= authentication.getAuthorities();
for (GrantedAuthority grantedAuthority : authorities) {
if (grantedAuthority.getAuthority().equals("ROLE_USER")) {
isTeacher = true;
break;
} else if (grantedAuthority.getAuthority().equals("ROLE_ADMIN")) {
isAdmin = true;
break;
}
}
if (isTeacher) {
return "/user/account";
} else if (isAdmin) {
return "/admin/account";
} else {
throw new IllegalStateException();
}
}
public void setRedirectStrategy(RedirectStrategy redirectStrategy) {
this.redirectStrategy = redirectStrategy;
}
protected RedirectStrategy getRedirectStrategy() {
return redirectStrategy;
}
}
Then modify spring security xml file and defined your bean and use it
<bean id="customeAuthenticationSuccessHandler"
class="com.test.CustomeAuthenticationSuccessHandler"/>
<security:http auto-config="true" use-expressions="false">
<security:form-login login-page="/sign-in" login-processing-url="/sign-in" username-parameter="username"
password-parameter="password"
authentication-success-handler-ref="customeAuthenticationSuccessHandler"
always-use-default-target="true"
authentication-failure-url="/sign-in?error=true"/>
<security:logout logout-url="/logout" logout-success-url="/"/>
..
..
</security:http>

Resources