3

I have a micro service architecture with spring boot. I decided to add Spring security for each micro service which will authenticate, authorise the user.

So i develop a separate project with has Spring Security authentication.

I have use a Filter which extends AbstractAuthenticationProcessingFilter.

The paths which needs authentication and authorisation are mentioned in my filter class as below,

private AntPathRequestMatcher[] authenticationMatcher = { 
            new AntPathRequestMatcher("//api/myservice1/**"),
            new AntPathRequestMatcher("/api/myservice") 
            };

private AntPathRequestMatcher[] authorizationMatcher = { 
            new AntPathRequestMatcher("/api/myservice") 
            };

So in the filter class doFilter method i check request path and do relevant logics.

My SecurityConfig class configure method just look like below,

@Override
    protected void configure(HttpSecurity http) throws Exception {
        http.addFilterBefore(getMyAuthenticationFilter(), BasicAuthenticationFilter.class); 
    }

So my questions are,

  1. What approach i should do for introduce this module (project) to each micro service?

    What i had in my mind is expose this as a jar file and use it in any micro service. In that case how can i over ride those authenticationMatcher and authorizationMatcher url's which will be specific to each micro services?

    Am i declare those url's in correct place and if so what Object Oriented principles i should apply?

  2. Is there a possibility i can by pass authentication filter if required and enable it when required? Like switching it?

seenukarthi
  • 8,241
  • 10
  • 47
  • 68
Harshana
  • 7,297
  • 25
  • 99
  • 173
  • Why don't you do it in every Microservice itself? Every service has specific paths to secure, so basically with that library you would introduce a dependency from each to each service, which contradicts the purpose of microservices. – dunni Jan 15 '16 at 06:47
  • thanks for the suggestion. But i mean when that library import to a specific micro service, then i need to initialize those AntPathRequestMatcher variables with specific to that micro service request paths only. May be initially that library AntPathRequestMatcher variables can be set to null. So basically what i try to do is, make that library as a service so that any micro service can initialize it specific request paths with in that micro service which need authentication and proceed. Hope you got my point – Harshana Jan 15 '16 at 07:27
  • 1
    Are you using Spring Cloud or any of the Netflix services such as Eureka, Zuul, etc? I implemented a Zuul Edge service with a preauth filter. All the internal microservices are not accessible to external requests. The Zuul service used Spring Session to externalize the authenticated sessions to a Redis database. All the microservices were configured with Spring Session, so all requests have access to the user's authenticated session. You can easily secure paths using annotations on each microservice from there. – Bal Jan 15 '16 at 23:03
  • @Bal Thanks. well i use a aws environment. i think the correct approach would be, in a filter, save the authentication object in security context with relevant authorization details for a given user. Then in each Rest API method, using annotation check authorization. e.g. @PreAuthorize("hasRole('ROLE_USER')"). What you think? – Harshana Jan 16 '16 at 06:43
  • Seems like a lot of work when you could just use Spring Session :) – Bal Jan 16 '16 at 17:19
  • can you please elaborate how can i use spring session along with spring security? May be in an answer – Harshana Jan 16 '16 at 17:43
  • I have found this link which is similar to the problem stated above. Thought might be helpful to you http://stackoverflow.com/questions/31875205/best-way-to-propagate-credentials-between-micro-services-using-spring-session – Shravan Ramamurthy Jan 21 '16 at 23:44

1 Answers1

3

I believe this approach can work like you want and can be done using Spring Boot. In regards to your questions:

  1. In your filter class you can declare something like this which can be populated by bean initialization.

    @Value("${security.checkValues}")
    private String[] checkValues;
    

    Below is an example I used with my own custom filter declared as a bean and passed in to the security configuration. You probably don't need all of it.

    @Configuration
    @Order(3)
    public static class SubscriptionWebSecurityConfigurationAdapter extends WebSecurityConfigurerAdapter {
    
        protected void configure(HttpSecurity http) throws Exception {
            http
                    .requestMatchers().antMatchers("/subscribe**","/subscribe/**").and()
                    .addFilterBefore(applicationSecurityTokenFilter(), UsernamePasswordAuthenticationFilter.class)
                    .authorizeRequests()
                    .anyRequest().authenticated()
                    .and()
                    .httpBasic()
                    .and()
                    .csrf().disable();
        }
    
    
        @Bean
        public ApplicationSecurityTokenFilter applicationSecurityTokenFilter() {
            return new ApplicationSecurityTokenFilter();
        }
    }
    

    Then each application.properties instance in your micro services (assuming they are separate projects) will have a line like below to specify the URLs to use.

    security.checkValues=/api/myservice,/api/myservice2
    
  2. If you include an empty string property like this:

    security.checkValues=
    

    Then the String array will be set to a 0 length array and you can know that it should not be active. I'm not entirely sure this is what your question was referencing so please review.

Let me know if this is what you are looking for. We can flush it out a little further if necessary.

Rob Baily
  • 2,770
  • 17
  • 26