2

I am quite new to Spring, so sorry if my question sounds silly.

I am trying to add basic HTTP Auth to my Spring based REST API.

I have been following quite a few tutorials and reference documentations for now, but they all seem to indicate the same thing so it seems obvious I must be missing something.

What I want is to define a simple configuration where every request is behind HTTP Auth by default, but then we can define method level security as needed using @PreAuthorize, or by modifying the HttpSecurity configuration.

I have defined a very simple configuration as such:

@Configuration
@EnableWebMvc
@EnableWebSecurity
@ComponentScan(basePackages = "com.app.rest")
public class RESTConfiguration extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .anyRequest().hasAnyRole("USER")
                .and()
                .httpBasic();
    }

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication().withUser("user").password("password").roles("USER");
    }
}

I then have a very simple controller (no service, nothing fancy).

Here is a very basic overview:

@RestController
@RequestMapping("/images")
public class ImagesController {

    @JsonView(View.Basic.class)
    @RequestMapping(value = "/{id}", method = RequestMethod.GET)
    public ObjectXvo getImageByID(@PathVariable String id) throws IOException {

        ObjectXvo result = doThings();
        return result;
    }
}

The only noticeable difference compared to all the online tutorials is the way we load this API. Because we already have a Jetty container running other things, we have decided to reuse it instead of using a WebAppInitializer like most do online.

Here is an extract of how the REST API is defined:

// Creating REST Servlet
ServletContextHandler restHandler = new ServletContextHandler(ServletContextHandler.SESSIONS);
restHandler.setErrorHandler(null);
restHandler.setContextPath("/rest");

AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
context.setConfigLocation("com.app.test");
WebApplicationContext webAppContext = context;

DispatcherServlet dispatcherServlet = new DispatcherServlet(webAppContext);
ServletHolder springServletHolder = new ServletHolder("REST dispatcher", dispatcherServlet);
restHandler.addServlet(springServletHolder, "/");
restHandler.addEventListener(new ContextLoaderListener(webAppContext));

// Creating handler collection
ContextHandlerCollection handlerCollection = new ContextHandlerCollection();
handlerCollection.addHandler(anotherHandler);
handlerCollection.addHandler(restHandler);
handlerCollection.addHandler(yetAnotherHandler);

// Setting server context
server.setHandler(handlerCollection);

The thing is, when running the app, is that I can still access all URLs like if I had not setup any security scheme. When debugging the application, I can see that the RESTConfiguration is being processed as breakpoints inside my configure methods are definitely being hit.

We are quite set on avoiding the usage of XML files as long as we can, as we think annotations are better so far.

Can anyone point me in the right direction as to why this security configuration is not being activated?

EDIT:

Not sure how relevant that is, but if I try to add a @PreAuthorize to a REST method, I get the following error:

HTTP ERROR: 500

Problem accessing /rest/images/I147. Reason:

    An Authentication object was not found in the SecurityContext

There is plenty of info on the internet on how to fix this, but I am wondering if this is not related.

dur
  • 15,689
  • 25
  • 79
  • 125
jlengrand
  • 12,152
  • 14
  • 57
  • 87

1 Answers1

1

You have to register springSecurityFilterChain, see Spring Security Reference:

The next step is to register the springSecurityFilterChain with the war. This can be done in Java Configuration with Spring’s WebApplicationInitializer support in a Servlet 3.0+ environment. Not suprisingly, Spring Security provides a base class AbstractSecurityWebApplicationInitializer that will ensure the springSecurityFilterChain gets registered for you. The way in which we use AbstractSecurityWebApplicationInitializer differs depending on if we are already using Spring or if Spring Security is the only Spring component in our application.

If you don't use AbstractSecurityWebApplicationInitializer you have to register springSecurityFilterChain manually:

webAppContext.getServletContext()
    .addFilter("springSecurityFilterChain", new DelegatingFilterProxy("springSecurityFilterChain"))
    .addMappingForUrlPatterns(EnumSet.of(DispatcherType.REQUEST, DispatcherType.ERROR, DispatcherType.ASYNC), false, "/*");

See also:

dur
  • 15,689
  • 25
  • 79
  • 125