RiceBunny
RiceBunny

Reputation: 65

Migrating to Spring Security 4 got Access deinied page

Im currently migrating to spring sec 4 but got trouble. These are my setting down below.

My security.xml file

    <?xml version="1.0" encoding="UTF-8"?>  
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
    xmlns:security="http://www.springframework.org/schema/security"  
    xmlns:p="http://www.springframework.org/schema/p"   
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans  
        http://www.springframework.org/schema/beans/spring-beans.xsd  
        http://www.springframework.org/schema/security  
        http://www.springframework.org/schema/security/spring-security.xsd">

    <!-- Exclude all files and folders under resources for security -->
    <security:http pattern="/resources/**" security="none" />

    <security:http  auto-config="true" disable-url-rewriting="false">
        <security:headers disabled="true"/>
        <security:csrf disabled="true"/>
        <security:intercept-url pattern="/login" access="permitAll"/>
        <security:intercept-url pattern="/**" access="hasAnyRole('RS001', 'RS002', 'RS003')"/>      
        <security:form-login login-page="/login"/>
        <security:logout logout-success-url="/login"/> 
    </security:http>

    <bean id="userDetailService" class="vm.security.UserDetailServiceImpl" />

    <!-- For hashing and salting the password -->
    <bean id="encoder" class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder"/>

    <security:authentication-manager>
        <security:authentication-provider ref="authProvider"></security:authentication-provider>        
    </security:authentication-manager> 

    <bean id="authProvider" class="org.springframework.security.authentication.dao.DaoAuthenticationProvider">
        <property name="userDetailsService" ref="userDetailService" />
        <property name="passwordEncoder" ref="encoder" />
    </bean>

    <!-- To load the message properties for overwrite default spring security error message -->
    <bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
        <property name="basename" value="classpath:message"/>
    </bean>

</beans>

Custom UserDetailSevice

        package vm.security;

    import java.util.ArrayList;
    import java.util.Date;
    import java.util.List;

    import org.apache.log4j.Logger;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.security.core.GrantedAuthority;
    import org.springframework.security.core.authority.SimpleGrantedAuthority;
    import org.springframework.security.core.userdetails.User;
    import org.springframework.security.core.userdetails.UserDetails;
    import org.springframework.security.core.userdetails.UserDetailsService;
    import org.springframework.security.core.userdetails.UsernameNotFoundException;

    import vm.data.dto.VmAccount;
    import vm.data.dto.VmSystemResource;
    import vm.exception.VmException;
    import vm.service.AuditLogService;
    import vm.service.UserAccountService;
    import vm.util.PropertiesConstants;

    public class UserDetailServiceImpl implements UserDetailsService {

        private static final Logger logger= Logger.getLogger(UserDetailServiceImpl.class);

        @Autowired
        private AuditLogService auditLogService;

        @Autowired
        private PropertiesConstants propertiesConstants;

        @Autowired
        private UserAccountService userAccountService;

        @Override
        public UserDetails loadUserByUsername(String userid) throws UsernameNotFoundException{
            try{
                VmAccount account = userAccountService.getVmAccountById(userid);
                if(account != null){
                    List<VmSystemResource> systemResourceList = userAccountService.getUserSystemResources(userid);
                    List<GrantedAuthority> roles= new ArrayList<GrantedAuthority>();
                    for(VmSystemResource resource : systemResourceList)
                        roles.add(new SimpleGrantedAuthority(resource.getResourceId()));
                    UserDetails user = new User(account.getUserid(), account.getPwd(), (account.getStatus().equals(propertiesConstants.getCoreStatusActive()) ? true : false), true, true, true, roles);

                    logger.info(roles);
                    auditLogService.addAuditDetails(userid, new Date(), propertiesConstants.getAuthentication(), propertiesConstants.getLoginSucceed());
                    return user;
                }
                throw new UsernameNotFoundException(userid + " not found."); 
            }catch (VmException ce){
                logger.error(ce.getErrorCode(),ce);
                throw new UsernameNotFoundException(ce.getErrorCode() + ":userid object is null");
            }

        }
    }

Login.jsp

<!DOCTYPE html>
<html lang="en">
    <head>      
        <link href="${pageContext.request.contextPath}/resources/css/bootstrap-3.3.4.min.css" rel="stylesheet">
        <style type="text/css">
            /* For nav header not to overlap*/
            body {
                padding-top:150px;  
                background-color: #eee;                 
            }                                   
        </style>                            
    </head>
    <body>              
        <div class="container"> 
            <div class="row">
                <div class="col-xs-6 col-xs-offset-3">
                    <div class="panel panel-primary">

                        <div class="panel-body">
                            <form id="creForm" class="form-horizontal" method="post" action="${pageContext.request.contextPath}/login">
                                <div id="errPanel" class="form-group">
                                    <div class="col-xs-8 col-xs-offset-3">
                                        <span style="color: red;">${sessionScope["SPRING_SECURITY_LAST_EXCEPTION"].message}</span>
                                    </div>
                                </div>
                                <div class="form-group">
                                    <label class="col-xs-4 control-label" for="userid">USERID:</label>
                                    <div class="col-xs-6">
                                        <input name="username" type="text" class="form-control" placeholder="USERID" />
                                    </div>
                                </div>                      
                                <div class="form-group">
                                    <label class="col-xs-4 control-label" for="name">PASSWORD:</label>
                                    <div class="col-xs-6">
                                         <input name="password" type="password" class="form-control" placeholder="PASSWORD" />
                                    </div>
                                </div>
                                <div class="form-group">
                                    <div class="col-xs-6 col-xs-offset-4">                                          
                                        <button type="submit" class="btn btn-primary">SIGN IN</button>
                                    </div>
                                </div>                                                                      
                            </form>
                        </div>
                        <div class="panel-footer"> 
                        </div>
                    </div>
                </div>
            </div>
        </div>              
    </body>
</html>

My problem is when i replace with old version spring security 3.2.7 it is working fine. But spring security 4 always lead me to access denied page. Hope somebody will help me.

Upvotes: 2

Views: 1405

Answers (1)

M. Deinum
M. Deinum

Reputation: 124888

There have been several changes in Spring Security 4 changes to the defaults and also changes to make behavior more consistent. You are running into a change made for consistency (SEC-2578) meaning all hasRole (and it derivates) are now prefixing the incoming parameter with the role prefix which is by default ROLE_ and this wasn't the case before Spring 3.2 (but was so in other places).

To fix you have 3 options

  1. do as described here in the migration guide or
  2. simply prefix your roles with ROLE_ when converting them.
  3. use hasAnyAuthority instead of hasAnyRole

Upvotes: 2

Related Questions