PreAuthorized("hasRole()") always return false after upgrade spring security from 3.2 to 4.0.2

pre authorized credit
pre authorization hotel
visa pre-authorization rules
mastercard pre-authorization rules
booking.com pre authorisation
pre authorization in medical billing
remove pre authorization debit card
what does pre authorized debit mean

After I upgraded spring-security to version 4.0.2 from version 3.2.x, I am able to login to the web application, but I get the access denied if it tries to access a method that has the @PreAuthorized(hasRole()).

I have tried to inject the 'ROLE_' into the GrantAuthorities list, but the result is the same.

The same configuration works fine in version 3.2.x. Can anyone have any idea what did I do wrong?

Thanks

the security-context.xml

<http pattern="/css/**" security="none" />
<http pattern="/Images/**" security="none" />
<http pattern="/javascript/**" security="none" />

<http auto-config='true' use-expressions="true" create-session="always"
    authentication-manager-ref="tunAuthenticationManager">
    <csrf disabled="true" />

    <intercept-url pattern="/new/**"
        access="hasRole('eu_rw') or hasRole('sp_rw')" />
    <intercept-url pattern="/ajax/**"
        access="hasRole('eu_rw') or hasRole('sp_rw')" />
    <intercept-url pattern="/v2/**"
        access="hasRole('eu_rw') or hasRole('sp_rw')" />

    <intercept-url pattern="/monitoring" access="hasRole('sp_rw')" />
    <intercept-url pattern="/monitoring/**" access="hasRole('sp_rw')" />

    <form-login login-page="/logon.jsp" username-parameter="username"
        password-parameter="password" login-processing-url="/j_spring_security_check"
        authentication-failure-url="/logon.jsp?login_error=1"
        default-target-url="/" always-use-default-target="true" />

    <custom-filter position="FIRST" ref="logoutFilter" />
    <custom-filter after="FIRST" ref="requestLoggingFilter" />
    <custom-filter after="LAST" ref="passwordExpirationCheckFilter" />
    <custom-filter after="SWITCH_USER_FILTER" ref="authorizationAdjustmentFilter" />
    <custom-filter after="EXCEPTION_TRANSLATION_FILTER" ref="ajaxTimeoutRedirectFilter" />
</http>



<authentication-manager id="tunAuthenticationManager">
    <authentication-provider ref="strongDaoAuthenticationProviderProxy" />
    <authentication-provider ref="tunAdAuthenticationProvider" />
</authentication-manager>

<beans:bean id="strongDaoAuthenticationProviderProxy"
    class="local.company.tun.security.DaoAuthenticationProviderProxy">
    <beans:constructor-arg>
        <beans:bean id="strongDaoAuthenticationProvider"
            class="org.springframework.security.authentication.dao.DaoAuthenticationProvider">
            <beans:property name="userDetailsService" ref="jdbcUserDetailsService" />
            <beans:property name="passwordEncoder" ref="strongEncoder" />
            <beans:property name="saltSource" ref="saltSource" />
        </beans:bean>
    </beans:constructor-arg>
</beans:bean>
<beans:bean id="jdbcUserDetailsService"
    class="local.company.tun.security.tunUserDetailsService">
</beans:bean>
<beans:bean id="authenticationService"
    class="local.company.tun.security.service.impl.AuthenticationServiceImpl">
    <beans:qualifier value="authenticationService" />
    <beans:property name="authenticationManager" ref="tunAuthenticationManager" />
</beans:bean>
<beans:bean
    class="local.company.tun.security.DefaultRolesPrefixPostProcessor" />

servlet-context.xml

<mvc:interceptors>
    <!-- Changes the locale when a 'locale' request parameter is sent;
        e.g. /?locale=de -->
        <bean class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor" />
</mvc:interceptors>

<!-- Activate scanning of @Autowired -->
<context:annotation-config />
<!-- Spring Security - enable pre- post- annotations on Spring managed
    MVC components -->
<bean id="expressionHandler" class="org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler" >

</bean>
<security:global-method-security pre-post-annotations="enabled">
    <security:expression-handler ref="expressionHandler" />
</security:global-method-security>

....

You must use ROLE_ prefix in role names and the same in GrantedAuthorities otherwise it won't work unless you have set the prefix as empty.

RoleVoter.setRolePrefix(""); 


@PreAuthorize("hasRole('ROLE_ADMIN')")

new SimpleGrantedAuthority("ROLE_ADMIN")

There is also an idea how to debug. Put a break point in userDetails.getAuthorities() method. Then access the protected resource. Spring will check the actual version of authorities and will be caught. Go up through the stack trace and find the place and values that are compared finding out what is going wrong.

Authorization hold, practice within the banking industry of verifying electronic transactions initiated with a debit card or credit card and rendering this balance as unavailable until either the merchant clears the transaction, also called settlement, or Pre-authorization definition is - prior authorization; especially : authorization (as by an insurer) that is required prior to performance of a health-care service (such as a surgery or prescription of a drug).

I am able to resolve the issue by adding a

<beans:bean
class="local.company.tun.security.DefaultRolesPrefixPostProcessor" />

to security-context.xml and the servlet-context.xml. It looks like it needed for both places. the bean in the security-context.xml will prevent adding the "ROLE_" to the the bean in the servlet-context.xml will prevent adding the "ROLE_" to the method level.

for the reference the DefaultRolePrefixPostProcessor.java is copy from the spring security migration 3 -> 4. here is the source code just for the completeness.

public class DefaultRolesPrefixPostProcessor implements BeanPostProcessor, PriorityOrdered {

@Override
public Object postProcessAfterInitialization(Object bean, String beanName)
        throws BeansException {

    Logger logger = LoggerFactory.getLogger(DefaultRolesPrefixPostProcessor.class);
    // remove this if you are not using JSR-250
    if(bean instanceof Jsr250MethodSecurityMetadataSource) {
        ((Jsr250MethodSecurityMetadataSource) bean).setDefaultRolePrefix(null);
    }

    if(bean instanceof DefaultMethodSecurityExpressionHandler) {
        logger.info("overriding the default Role prefix. set it to null ");
        ((DefaultMethodSecurityExpressionHandler) bean).setDefaultRolePrefix(null);
    }
    if(bean instanceof DefaultWebSecurityExpressionHandler) {
        ((DefaultWebSecurityExpressionHandler) bean).setDefaultRolePrefix(null);
    }
    if(bean instanceof SecurityContextHolderAwareRequestFilter) {
        ((SecurityContextHolderAwareRequestFilter)bean).setRolePrefix("");
    }
    return bean;
}

@Override
public Object postProcessBeforeInitialization(Object bean, String beanName)
        throws BeansException {
    return bean;
}

@Override
public int getOrder() {
    return PriorityOrdered.HIGHEST_PRECEDENCE;
}

}

Pre-authorized debits (PAD) - Canada.ca, your bills. With PAP, you can “set it and forget it.” The money is automatically deducted from your bank account each month like clockwork. The biggest risk is over-billing. (prē'aw-thōr-i-zā'shŭn), A prerequisite, often intended as a rate-limiting or cost-containment step, in the provision of care and treatment to an insured patient.

You can use hasAuthority() instead of hasRole(), hasAuthority() won't append the defaultRolePrefix. Alternatively, you can also add this to your security-context.xml to override the defaultRolePrefix to be null:

<!-- Remove defaultRolePrefix from SecurityExpressionRoot.java to prevent hasRole() call from appending "ROLE_" to role parameters -->
<bean id="defaultWebSecurityExpressionHandler" class="org.springframework.security.web.access.expression.DefaultWebSecurityExpressionHandler">
    <property name="defaultRolePrefix" value=""></property>
</bean>

<bean id="defaultMethodSecurityExpressionHandler" class="org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler">
    <property name="defaultRolePrefix" value=""></property>
</bean>

<security:global-method-security pre-post-annotations="enabled">
    <security:expression-handler ref="defaultMethodSecurityExpressionHandler" />
</security:global-method-security>

Reference article: Why does Spring Security's RoleVoter need a prefix?

Why You Should Think Twice About Pre-Authorized Payment, A pre-authorization is essentially a temporary hold placed by a merchant on a customer's credit card, and reserves funds for a future payment  a song or ode in praise or honor of God, a deity, a nation, etc. a style of popular music for dancing, usually recorded and with complex electronic instrumentation, in which simple, repetitive lyrics are subordinated to a heavy, pulsating, rhythmic beat.

When does the pre-authorization get released from the credit card , A pre-authorization is a temporary hold on funds in a customer's account that lasts around 5 days. Unlike an actual transaction, you aren't moving  Arrangement (such as direct debit payment or standing order) under which a bank is authorized by a customer to debit his or her account for a regular bill's amount or for loan installments.

What Are Pre Authorization Payments and How They Work, The amount may go to the bank to pay a standing fee, but most often goes to a third party. For example, a customer may set up a pre-authorized payment plan to​  Preauthorized Payment Any agreement between a bank and an account holder whereby the account holder gives the bank permission to automatically debit the account by a certain amount every month. The amount may go to the bank to pay a standing fee, but most often goes to a third party.

Pre-Authorization on Credit Card Explained · Tidal Commerce, Definition of preauthorized payment: Arrangement (such as direct debit payment or standing order) under which a bank is authorized by a customer to debit his  Complete another Authorization Agreement for Preauthorized Payments form (SF-5510), and indicate the type of change you want to make on the form. Mail the completed form to the address above. It can take 6 to 8 weeks to change your bank account. You can get a new form at Medicare.gov or by calling 1-800-MEDICARE (1-800-633-4227).

Comments
  • This answer should be marked as correct. Simple and precise.