3

I'm new to Spring, SpringSecurity and Boot - trying to create a webapplication where I have to lookup in a database whether a user has access to a requested URL or not. I've managed to make the authentication work (i.e UserDetailService with loadUserByUsername). In the database I have a table for Users, Groups, Roles and a last one for URLs containing the URLs and Config Attributes (typically equal to the Roles).

So I have this working configuration (by the way, I'm trying to configure everything in Java - not using XML):

@Resource(name="authService")
private UserDetailsService userDetailsService;
@Autowired
public void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.authenticationProvider(customAuthenticationProvider());
}
@Bean
public PasswordEncoder passwordEncoder() {
    return new BCryptPasswordEncoder();
}
@Bean
AuthenticationProvider customAuthenticationProvider() {
    DaoAuthenticationProvider authProvider = new DaoAuthenticationProvider();
    authProvider.setUserDetailsService(userDetailsService);
    authProvider.setPasswordEncoder(passwordEncoder());
    return authProvider;
}
@Override
protected void configure(HttpSecurity http) throws Exception {
    http
    .formLogin()
        .loginPage("/login")
        .loginProcessingUrl("/login")
        .usernameParameter("username")
        .passwordParameter("password")
        .defaultSuccessUrl("/table/list").permitAll()
    .and()
    .logout()
        .logoutUrl("/logout").permitAll()
    .and()
    .authorizeRequests()
    .antMatchers(
        "/home",
        "/images/**",
        "/bootstrap/**",
        "/jquery-ui/**",
        "/jquery-2.1.3.min.js",
        "/error"
    ).permitAll()
    .antMatchers("/user/list").permitAll()
    .antMatchers("/user/create/**").permitAll()
    .antMatchers("/user/created/**").permitAll()
    .antMatchers("/user/update/**").permitAll()
    .antMatchers("/user/updated/**").permitAll()
    .antMatchers("/table/list").hasRole("ADMIN")
    .antMatchers("/table/create").hasRole("USER")
    .antMatchers("/table/created").hasRole("USER")
    .anyRequest().denyAll();

Now I'm trying to replace all above antMatchers with:

        .anyRequest().authenticated()
    .withObjectPostProcessor(new ObjectPostProcessor<MyFilterSecurityMetadataSource>() {
        @Override
        public <O extends MyFilterSecurityMetadataSource> O postProcess(O object) {
            object.getAttributes(object);
            FilterInvocationSecurityMetadataSource metadataSource = new MyFilterSecurityMetadataSource();
            if (object instanceof FilterInvocationSecurityMetadataSource) {
                return (O) metadataSource.getAttributes(object);
            }
            return null;
        }
    }).anyRequest().denyAll();

And MyFilterSecurityMetadataSource is as follows (I'm not doing an actual lookup yet - I have a hard time getting to this filter):

public class MyFilterSecurityMetadataSource implements FilterInvocationSecurityMetadataSource {

public List<ConfigAttribute> getAttributes(Object object) {
    FilterInvocation fi = (FilterInvocation) object;
    String fullRequestUrl = fi.getFullRequestUrl();
    String requestUrl = fi.getRequestUrl();
    String httpMethod = fi.getRequest().getMethod();
    String contextPath = fi.getRequest().getContextPath();
    System.out.println("Full request URL: " + fullRequestUrl);
    System.out.println("Request URL: " + requestUrl);
    System.out.println("HTTP Method: " + httpMethod);
    System.out.println("Context path: " + contextPath);
    List<ConfigAttribute> configAttributes = new ArrayList<ConfigAttribute>(0);
    // Lookup your database (or other source) using this information and populate the
    // list of attributes

    return configAttributes;
}

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

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

Maybe I need to configure a FilterSecurityInterceptor instead of MyFilterSecurityMetadataSource and pass this to the FilterSecurityInterceptor, I don't know. But then I have to use decisionManagers roleVotes bla. bla. I don't get it. It's quite hard to find a working sample regarding this specific subject. Sorry, my programming skills suck :)

  • There are a couple of SO topics but no-one helped: http://stackoverflow.com/questions/10979756/spring-security-how-can-i-define-intercept-url-dynamically-using-database – Salman P. Dar May 24 '15 at 22:19
  • Spring docs http://docs.spring.io/spring-security/site/docs/4.0.2.CI-SNAPSHOT/reference/htmlsingle/#post-processing-configured-objects and http://docs.spring.io/spring-security/site/faq/faq.html#faq-dynamic-url-metadata – Salman P. Dar May 24 '15 at 22:20
  • Couldn't make this work either: http://stackoverflow.com/questions/8381776/dynamic-spring-security-using-sql-query. Maybe because it has one xml conf at the bottom which I didn't know how to use. – Salman P. Dar May 24 '15 at 22:51
  • Could you explain what should be written instead of comments in getAttributes method ? list of urls ?list of roles? mapping between these? and another question is: Can I use this solution to config authorization base on username and password ? – faraa Aug 02 '18 at 19:55

1 Answers1

3

You got the postprocessor on the wrong object. Please rewrite the post processor with the following

.anyRequest().authenticated().withObjectPostProcessor(new ObjectPostProcessor<FilterSecurityInterceptor>() {
                    public <O extends FilterSecurityInterceptor> O postProcess(
                            O fsi) {
                        FilterInvocationSecurityMetadataSource newSource = new MyFilterSecurityMetadataSource();
                        fsi.setSecurityMetadataSource(newSource);
                        return fsi;
                    }
                })
ArunM
  • 2,274
  • 3
  • 25
  • 47
  • 1
    Dear Arun. Thank you SO MUCH for this simple solution. Seriously, I tried everything (even consideren decisionManagers, voters etc.). I just tried your solution and now I can see the URL's being called. I will continue on my original plan looking this up in the database to return valid config attributes. THANK YOU!!! – Salman P. Dar May 26 '15 at 19:17