Adding Security to a Partially Exposed Web Service

In my previous post I talked about adding some conditional security to a web service by only exposing certain methods and model representations using the new Conditional annotation and a HandlerInterceptor in a Spring 4 based Spring Boot app. Tonight I decided to add some real Spring Security magic to it.

First, add the Spring Security dependency. I took this right from the Spring Security guide on the website.


Then I added the following new Configuration class to my existing Application.

  static class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {

Next, I modified my HandlerInterceptor and it ended up as follows:

public class PublicHandlerInterceptor extends HandlerInterceptorAdapter {

  public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
    if ( handler instanceof HandlerMethod ) {
      HandlerMethod method = (HandlerMethod)handler;
      if ( method.getMethodAnnotation(Public.class) != null
          && hasAnyRole( (User)principal, method.getMethodAnnotation(Public.class).forRoles())) {
        return true;
    return false;
  private boolean hasAnyRole( User principal, String[] rolesStrings ) {
    if ( rolesStrings == null || rolesStrings.length == 0 ) {
      return true;
    Set<String> roles = Sets.newHashSet(rolesStrings);
    for ( GrantedAuthority auth : principal.getAuthorities() ) {
      if ( roles.contains(auth.getAuthority())) {
        return true;
    return false;

In the previous iteration I was simply looking for the Public annotation. Now I am looking for a parameter on that annotation. The parameter defaults to empty, which behaves just like the previous iteration of the project, but now you can specify that it should only be public for certain roles. Obviously, this necessitated a change to the Public annotation, as follows:

public @interface Public {
  String[] forRoles() default {};

Finally, I modified the usage of the annotation to test out the new functionality:


You should also be able to pass an array of role names to the forRoles parameter of the annotation.

The Spring Security filters are executed before my HandlerInterceptor so the user would have gone through all the authentication checks by that point. Then, in my HandlerInterceptor, rather than let the user know that there is an endpoint at the given location they just have to try harder to hack it, they get a 404 if they are not allowed to access it.

I suspect you could probably get the same by using a custom handler for an AuthorizationException (or whatever spring-security throws) and using a spring security method annotation to check the role and return a 404 from the handler instead of the standard response but I wanted to build on the previous example and keep the conditional behavior.

2 thoughts on “Adding Security to a Partially Exposed Web Service

    1. The question that I still need to answer is, with this change what does the @Public annotation buy me that I couldn’t get with a regular Spring @PreAuthorize annotation. It already takes care of the role-based access control. The only difference would be that I am returning a 404 with the @Public and Spring would be returning a 401. I could probably setup a Spring @ExceptionHandler to even return a 404 in the case of an AuthenticationException or AccessDeniedException. The @Conditional annotations I had in the previous post aren’t all that applicable anymore because I really need to create the beans regardless of deployment environment and the access is now conditional on the role of the caller instead of anything in the environment. I also have an unresolved problem with how to configure the ObjectMapper. Previously, it would configure it once depending on the environment and either apply the view every time, or not. Now, it has to selectively apply the view, so it would probably require creating my own version of the MappingJackson2MessageConverter that would “do the right thing”â„¢

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s