why does spring security ignore request interception

Viewed 121

I have a question: Why is it that when getAttributes() returns null, every subsequent request doesn't go through the MyFilterSecurityInterceptor class and it doesn't intercept for the next request or every request after that?

MyFilterSecurityInterceptor

@Service
public class MyFilterSecurityInterceptor extends AbstractSecurityInterceptor implements Filter {

    @Autowired
    private FilterInvocationSecurityMetadataSource securityMetadataSource;

    @Autowired
    public void setMyAccessDecisionManager(MyAccessDecisionManager myAccessDecisionManager) {
        super.setAccessDecisionManager(myAccessDecisionManager);
    }


    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {

        FilterInvocation fi = new FilterInvocation(request, response, chain);
        invoke(fi);
    }

    public void invoke(FilterInvocation fi) throws IOException, ServletException {
        //There is a blocked url in fi
        //Call the getAttributes(Object object) method of MyInvocationSecurityMetadataSource to get all the permissions corresponding to fi
        //Call the decide method of MyAccessDecisionManager to verify whether the user's permissions are sufficient
        InterceptorStatusToken token = super.beforeInvocation(fi);
        try {
            //Execute the next interceptor
            fi.getChain().doFilter(fi.getRequest(), fi.getResponse());
        } finally {
            super.afterInvocation(token, null);
        }
    }


    @Override
    public void destroy() {

    }

    @Override
    public Class<?> getSecureObjectClass() {
        return FilterInvocation.class;

    }

    @Override
    public SecurityMetadataSource obtainSecurityMetadataSource() {
        return this.securityMetadataSource;
    }
}

MyFilterSecurityMetadataSource

public class MyFilterSecurityMetadataSource implements FilterInvocationSecurityMetadataSource {

    @Override
    public List<ConfigAttribute> getAttributes(Object object) {
        FilterInvocation fi = (FilterInvocation) object;
        HttpServletRequest request = fi.getRequest();
        HttpMethod httpMethod = HttpMethod.valueOf(fi.getRequest().getMethod());

        // Bypassing Security check for /js, /css and /images url
        if (new AntPathRequestMatcher("/js/**").matches(request)
                || new AntPathRequestMatcher("/css/**").matches(request)
                || new AntPathRequestMatcher("/images/**").matches(request)
                || new AntPathRequestMatcher("/login").matches(request)
                || new AntPathRequestMatcher("/").matches(request)
                || new AntPathRequestMatcher("/h2/**").matches(request)) {
            return SecurityConfig.createList(new String[] { "Allow" });
        }

        try {
            Collection<? extends GrantedAuthority> authorities = SecurityContextHolder.getContext().getAuthentication()
                    .getAuthorities();
            for (GrantedAuthority grantedAuthority : authorities) {
                if(new AntPathRequestMatcher(grantedAuthority.toString()).matches(request)) {
                    return SecurityConfig.createList(new String[] { "Allow" });
                }
            }
        } catch (Exception e) {
            return SecurityConfig.createList(new String[] { "Deny" });
        }

        return null;
    }

    public Collection<ConfigAttribute> getAllConfigAttributes() {
        return null;
    }

    public boolean supports(Class<?> clazz) {
        return FilterInvocation.class.isAssignableFrom(clazz);
    }
}

MyAccessDecisionManager

public class MyAccessDecisionManager implements AccessDecisionManager {

    @Override
    public void decide(Authentication authentication, Object object, Collection<ConfigAttribute> configAttributes)
            throws AccessDeniedException, InsufficientAuthenticationException {

        if (configAttributes == null || configAttributes.size() == 0) {
            return;
        }
        Iterator<ConfigAttribute> ite = configAttributes.iterator();
        if(ite.next().toString().equalsIgnoreCase("Allow")) {
            return;
        }
        else {
            System.out.println("Access is denied");
            throw new AccessDeniedException("Access is denied");
        }
    }

    @Override
    public boolean supports(ConfigAttribute attribute) {
        return true;
    }

    @Override
    public boolean supports(Class<?> clazz) {
        return true;
    }
}

config security

public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private MyFilterSecurityInterceptor myFilterSecurityInterceptor;

    @Override
    protected void configure(HttpSecurity http) throws Exception {

        http.authorizeRequests()
                .antMatchers("/h2/**").permitAll()
                .anyRequest().authenticated()
                .and().httpBasic()
                .and().formLogin()
                .addFilterBefore(myFilterSecurityInterceptor, FilterSecurityInterceptor.class);
    }
}

and I have set a breakpoint in debug to check, it really only stops on the first request, and after return null is returned incoming requests are not stopped

Debug info

1 Answers

So, I think it is because your checked exception in your filter. Returning null is not enough significant.

If I were you, I will use a RuntimeException which will stop the workflow at that moment, add these exception inside the webapplication exception handler and make a custom webpage to display a message for these exception or for all requests with 403 http status code (not authorized).

Did you add your custom interceptor inside your Spring application config ? Inside the main file : SpringWebapplication.java as a Bean :

@Bean(name="securityInterceptor")
public MyFilterSecurityInterceptor securityInterceptor() {
    return new MyFilterSecurityInterceptor();
}

Or inside WebConfig.java :

private MyFilterSecurityInterceptor securityInterceptor;
//...
@Override
public void addInterceptors(InterceptorRegistry registry) {
    registry.addInterceptor(securityInterceptor);
    registry.addInterceptor(localeChangeInterceptor);
}
Related