Securing Multiple Resources in OAuth2 Resource Server using Spring Security

In my previous blog post I demonstrate how to setup an OAuth2 authorization server using Spring Security. In this post, I will demonstrate how to setup the security configurations in a resource server to secure multiple resources.

The example here uses Spring Boot 1.2.7 and is a standalone OAuth2 resource server which secures multiple resources with their own ids and access rules. To do that, instead of using @EnableResourceServer, we have to define a ResourceServerConfiguration bean for each resource to be secured as shown below

@Configuration
@EnableOAuth2Resource
public class OAuth2ServerConfig {
     @Bean
     protected ResourceServerConfiguration stockesources() {
          ResourceServerConfiguration resource = new ResourceServerConfiguration(){
                // Switch off the Spring Boot @Autowired configurers
                public void setConfigurers(List<ResourceServerConfigurer> configurers) {
                    super.setConfigurers(configurers);
                }
                @Override
                public int getOrder() {
                     return 30;
                }
     };
           resource.setConfigurers(Arrays.<ResourceServerConfigurer> asList(new ResourceServerConfigurerAdapter() {
                 @Override
                 public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
                      resources.resourceId("stock");
                  }
                  @Override
                  public void configure(HttpSecurity http) throws Exception {
                        http.antMatcher("/stock/**").authorizeRequests().anyRequest().access("#oauth2.hasScope('read')");
                  }
             }));
            return resource;
}

To secure the resource “stock”, we first implements a bean of ResourceServerConfiguration by manually setting the configurers by calling the super.setConfigurers() method and then set the order by overriding the getOrder() method. Then, security configuration for the resource can then be set up by using the return ResourceServerConfiguration object (variable resource) by implementing an anonymous ResourceSourceServerConfigurerAdapter.

To secure another resource, just define another bean of ResourceServerConfiguration similar to the above with a different resource id and its own OAuth2 access rules. Also, the order value has to be unique.

Note that I have to override the getOrder() method in the ResourceServerConfiguration here instead of line like

     ResourceServerConfiguration resource = ...
     resource.setOrder(30)
     resource.setConfigurers(...

or spring security will throw exception like below

Caused by: java.lang.IllegalStateException: @Order on WebSecurityConfigurers must be unique. Order of 2147483626 was already used, so it cannot be used on . OAuth2ServerConfig$1@1a40489f too.

 

Writing parameterized Tests with Spring and JUnit 4

This blog will demonstrate how to write parameterized tests with JUnit4 with Spring.

Let say we have the following interface

public interface Logic {
     boolean xor(boolean a, boolean b);
}

and the corresponding implementation annotated as a Spring service component

@Service
public class LogicImpl implements Logic {
      @Override
      public boolean xor(boolean a, boolean b) {
            return a ^ b;
      }
}

To test the above class with different input combinations of arguments a and b, we can write the following parameterized test in JUnit

@RunWith(Parameterized.class) // Note 1
@SpringApplicationConfiguration(classes = BlogApplication.class)
public class LogicImplTest {

     @Autowired
     private LogicImpl logic;

     // Manually config for spring to use Parameterised
     private TestContextManager testContextManager;

     @Parameter(value = 0) // Note 3i
     public boolean a;

     @Parameter(value = 1) // Note 3ii
     public boolean b;

     @Parameter(value = 2) // Note 3iii
     public boolean expected;

     @Parameters // Note 4
     public static Collection<Object[]> data() {
          Collection<Object[]> params = new ArrayList<>();
          params.add(new Object[] { true, true, false});
          params.add(new Object[] { true, false, true});
          params.add(new Object[] { false, true, true});
          params.add(new Object[] { false, false, false});

          return params;
      }

     @Before // Note 2
     public void setUp() throws Exception {
          this.testContextManager = new TestContextManager(getClass());
          this.testContextManager.prepareTestInstance(this);
     }

     @Test // Note 5
     public void testXor() {
          assertThat(logic.xor(a, b), equalTo(expected));
     }

}

A few things to note here:

  1. The test class is to be run with the Parameterized runner, instead of the normal SpringJUnit4ClassRunner class.
  2. We need to manually configure the test context manager as in the @Before method. This is typically done automatically by Spring
  3. Parameters are defined as public members of the class (as in 3i to 3iii) with the @Parameter annotation. Since we have more than 1 parameter, it is also neccessary to set the value attribute. This defines the index of the parameters to use.
  4. Parameter values are set by implementing a static  method and annotate it with @Parameters. In our example, the data() method returns a list of object arrays. Each value of the list params corresponds to a set of parameter values.
  5.  Tests now can use the parameter values.

Running the test class in Eclipse will give you something like this

blogPTest

Note testXor() is run 4 times, each using the parameter set of the values defined in the list returned by the data() method.

 

Setup Spring RestTemplate to accept Self Signed Cert

This is strictly for testing only but may be useful if you need to perform integration tests. For example, the system you develop needs to access another internal or 3rd party test server via https where the server’s certificate is not signed.

PKIX path building failed

By default, if you try to access a server via https with a self signed certificate, for example with the following codes

RestTemplate template = new TestRestTemplate();
template.getForObject(https://<some server>/, String.class);

you will get the following exception:

org.springframework.web.client.ResourceAccessException: I/O error on GET request for "https://<some server>":
sun.security.validator.ValidatorException: PKIX path building failed: 
sun.security.provider.certpath.SunCertPathBuilderException:
unable to find valid certification path to requested target;

HttpClient

To fix the above, update the RestTemplate with a custom HttpClient that accepts self-signed certificate:

      SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(new SSLContextBuilder().loadTrustMaterial(null, new TrustSelfSignedStrategy()).build());

      HttpClient httpClient = HttpClients.custom().setSSLSocketFactory(socketFactory).build();

      RestTemplate template = new TestRestTemplate();
      ((HttpComponentsClientHttpRequestFactory) template.getRequestFactory()).setHttpClient(httpClient);

and add the following dependency if needed

      <dependency>
           <groupId>org.apache.httpcomponents</groupId>
           <artifactId>httpclient</artifactId>
           <scope>test</scope>
      </dependency>

Again this should only be used for testing purpose only.

Configuring Multiple JPA Entity Managers In Spring Boot

This blog will demonstrate how to setup multiple entity managers in Spring to connect to different data sources. The solution here also supports Spring Data.

Update Maven Pom file

Include Spring Boot dependency for Spring Data:

 <dependency>
       <groupId>org.springframework.boot</groupId>
       <artifactId>spring-boot-starter-data-jpa</artifactId>
 </dependency>

Disable DataSourceAutoConfiguration

Since we are setting up the data sources, disable the auto configuration in Spring Boot

@Configuration
@ComponentScan
@EnableAutoConfiguration (exclude = {  DataSourceAutoConfiguration.class })
public class Application {
   ...

Configure Primary Entity Manager

Below is the Java configuration for the primary entity manager

@Profile("!test")          // 1
@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(basePackages = "au.com.myblog.dao", entityManagerFactoryRef = "entityManager", transactionManagerRef = "transactionManager")        // 2
public class PrimaryMysqlDBConfiguration {
     @Bean(name = "dataSource")      // 3
     @Primary
     @ConfigurationProperties(prefix = "primary.datasource.mysql")
     public DataSource mysqlDataSource() {
          return DataSourceBuilder.create().build();
     }
    @PersistenceContext(unitName = "primary")   // 4
     @Primary
     @Bean(name = "entityManager")
     public LocalContainerEntityManagerFactoryBean mySqlEntityManagerFactory(EntityManagerFactoryBuilder builder) {
          return builder.dataSource(mysqlDataSource()).persistenceUnit("primary").properties(jpaProperties())
                    .packages("au.com.myblog.domain").build();
      }
     private Map<String, Object> jpaProperties() {
          Map<String, Object> props = new HashMap<>();
          props.put("hibernate.ejb.naming_strategy", new SpringNamingStrategy());
          return props;
      }
}

Note:

  1. @Profile annotation to use this configuration only for non test profile. This allows me to set a different datasource, e.g. H2, when running tests.
  2. @EnableJpaRepositories is used for Spring Data. Note we are using the default transaction manager setup in Spring
  3. Bean for primary datasource. The @ConfigurationProperties annotation specifies the prefix of the properties to use by this datasource. For the example here, the application.properties file should include properties like below:
    # DB Connection
    primary.datasource.mysql.url=jdbc:log4jdbc:mysql://localhost/bpmn_service
    primary.datasource.mysql.username=root
    primary.datasource.mysql.password=root
    primary.datasource.mysql.driver-class-name=net.sf.log4jdbc.DriverSpy
  4. Persistence unit name should be setup in the EntityManager bean as shown here.

Configure Secondary Entity Manager

Configuration of the secondary entity manager is very similar to that of the primary.The only thing is we have to define a new transaction manager. Make sure a different prefix is set in the configuration properties of the data source. Also, a different persistent unit name should be used.

@Profile("!test")
@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(basePackages = "au.com.myblog.dao", entityManagerFactoryRef = "secondaryMySqlEntityManager", transactionManagerRef = "secondaryTransactionManager")
public class SecondaryMysqlDBConfiguration {
      @Bean
      @ConfigurationProperties(prefix = "secondary.datasource.mysql")
       public DataSource mysqlDataSource() {
            return DataSourceBuilder.create().build();
       }
      @PersistenceContext(unitName = "secondary")
      @Bean(name = "secondaryMySqlEntityManager")
      public LocalContainerEntityManagerFactoryBean mySqlEntityManagerFactory(EntityManagerFactoryBuilder builder) {
           return  builder.dataSource(mysqlDataSource()).properties(jpaProperties()).persistenceUnit("secondary").packages("au.com.myblog.domain").build();
       }
      @Bean(name = "secondaryTransactionManager")
       public PlatformTransactionManager transactionManager(EntityManagerFactoryBuilder builder) {
             JpaTransactionManager tm = new JpaTransactionManager();
             tm.setEntityManagerFactory(mySqlEntityManagerFactory(builder).getObject());
             tm.setDataSource(mysqlDataSource());
             return tm;
       }
       private Map<String, Object> jpaProperties() {
             Map<String, Object> props = new HashMap<>();
            // naming strategy to put underscores instead of camel case
            // as per auto JPA Configuration
            props.put("hibernate.ejb.naming_strategy", new SpringNamingStrategy());
            props.put("hibernate.hbm2ddl.auto", "update");
            return props;
       }

Note the setup above assumes the primary and secondary data sources are not used together in a single transaction. Hence we can use 2 independent transaction managers.

Specify which Entity Manager to use

Finally, make sure that you specify the name of the secondary transaction in the spring @Transactional annotation:

@Transactional(value = "secondaryTransactionManager")

Also, add the @PersistenceContext annotation with the unit name as defined in the configuration when injecting entity managers;

 @PersistenceContext(unitName = "secondary")
 private EntityManager entityManager;

That’s it!

Validating Spring MVC Request Mapping Method parameters

This short post demonstrates how to set up and use JSR-303 Validation for the arguments in Spring MVC request mapping methods for path variable and request parameter arguments. I am using Spring Boot v1.2.5 with Maven 3.

I. MethodValidationPostProcessor

The only configuration needed is adding the MethodValidationPostProcessor (javadoc) bean to the Spring configuration, e.g.

 @Bean
 public MethodValidationPostProcessor methodValidationPostProcessor() {
      return new MethodValidationPostProcessor();
 }

II Add validation to controller request mapping method

First, add the @Validate annotation to the controller class as follows:

@RestController
@Validated
public class HelloController {
     ...

Then add any JSR-303 validation annotation to a request mapping method arguments:

 @RequestMapping("/hi/{name}")
 public String sayHi(@Size(max = 10, min = 3, message = "name should have between 3 and 10 characters") @PathVariable("name") String name) {
      return "Hi " + name;
 }

The example codes above shows how to validate a value in the request path marked by @PathVariable. You can do the same with @RequestParam

III Validation exception handling

A ConstraintViolationException will be thrown if the size of the path variable is not within 3 to 10 characters. You may need to catch this exception and process it using a Spring MVC exception handler, for example to return the error messages in the response:

 @ExceptionHandler(value = { ConstraintViolationException.class })
 @ResponseStatus(value = HttpStatus.BAD_REQUEST)
 public String handleResourceNotFoundException(ConstraintViolationException e) {
      Set<ConstraintViolation<?>> violations = e.getConstraintViolations();
      StringBuilder strBuilder = new StringBuilder();
      for (ConstraintViolation<?> violation : violations ) {
           strBuilder.append(violation.getMessage() + "\n");
      }
      return strBuilder.toString();
 }

Using Netflix servo to monitor Java applications

Netflix servo is a lightweight API for exposing and publishing application metrics. This blog will demonstrate step by step how to use servo in a Java application.

Project set up

I use Maven so the first step is to include the following in the pom file:

 <dependency>
      <groupId>com.netflix.servo</groupId>
      <artifactId>servo-core</artifactId>
      <version>0.8.0</version>
 </dependency>

Adding Metrics to JMX

Adding metrics with servo is simple. For example, the following codes add metrics to a Rest controller for a single end point (/sayhi):

@RestController("testController")
public class TestController {

 @Monitor(name = "requestCounter", type = DataSourceType.COUNTER, description = "Total number of requests", level = DataSourceLevel.INFO)
 private final AtomicInteger requestCounter = new AtomicInteger(0);
 
 @Monitor(name = "aGauge", type = DataSourceType.GAUGE, description = "A random gauge", level = DataSourceLevel.CRITICAL)
 private final AtomicInteger aGauge = new AtomicInteger(0);
 
 @MonitorTags
 private final TagList tags = BasicTagList.of("id", "testController", "class", "au.com.dac.controller.TestController");
 
 @PostConstruct
 public void init() {
      Monitors.registerObject("testController", this);
 }
 
 @RequestMapping(value = "/sayhi", method = RequestMethod.GET )
 public String sayHi(@RequestParam String to) {
      requestCounter.incrementAndGet(); // increment counter
      aGauge.set(RandomUtils.nextInt(0, 100)); // set some random value
      return "hi " + to;
 }
 
}

Two metrics are defined in this class using the @Monitor annotation. There are 3 types of monitors: counter, gauge and informational. Note also the user of @MonitorTags annotation. This is used to add a set of tags as key-value pairs to all the annotated fields in the class. In the example above, two key-value pairs with key “id” and “class” and values “testController” and “au.com.dac.controller.TestController” respectively.

The object needs to be registered with a monitor registry for it to be monitored. This is done with the following line:

Monitors.registerObject("testController", this);

The registerObject method of the class Monitors use the default monitor registry class DefaultMonitorRegistery to register an object. By default, a JMXMonitorRegistry is used.

To update the monitors, use their corresponding API methods:

 requestCounter.incrementAndGet(); // increment counter
 aGauge.set(RandomUtils.nextInt(0, 100)); // set some random value

Now the metrics are available in JMX and can be viewed via JConsole or VisualVM.

Publishing to other sources

Servo provides a simple and yet powerful API for collecting and publishing metrics to other sources. This makes it easy to add monitors to a Java application and expose them to external monitoring system such as Stackdriver and AWS CloudWatch. The following method setup a metrics poller to collect all metrics regularly (once a minute) and publish to the included metric observers.

 private void initMetricsPublishing() {
      PollScheduler scheduler = PollScheduler.getInstance();
      scheduler.start();
      MetricObserver logObserver = new LoggerMetricObserver("logger-observer"); 
      MetricObserver logObserverRate = new LoggerMetricObserver("logger-observer-rate");
      MetricObserver transform = new CounterToRateMetricTransform(logObserverRate, 1, TimeUnit.MINUTES);
      PollRunnable task = new PollRunnable(
           new MonitorRegistryMetricPoller(),
           BasicMetricFilter.MATCH_ALL,
           logObserver, transform);
      scheduler.addPoller(task, 1, TimeUnit.MINUTES);
 }

Note the poller is associated with two MetricObserver instances logObserver and logObserverRate. The later is wrapped by a CounterToRateMetricTransformer which is used to transform any counter values in the observer into rates.

MetricObserver

This is the interface servo uses to publish metrics to. Servo provides a few example implementations, include one for AWS CloudWatch. The following implements a metric observer that logs some metric information

public class LoggerMetricObserver extends BaseMetricObserver {
 private Logger logger = LoggerFactory.getLogger(getClass());

 public LoggerMetricObserver(String name) {
      super(name);
 }
 @Override
 public void updateImpl(List<Metric> metrics) {
      Preconditions.checkNotNull(metrics, "metrics");
      try {
         for (Metric m : metrics) {
              logger.info("{}: name[{}] tags[{}] value[{}]", new LocalDateTime(m.getTimestamp()), m.getConfig()
 .getName(), m.getConfig().getTags(), m.getValue());
         }
       } catch (Throwable t) {
              incrementFailedCount();
              throw Throwables.propagate(t);
       }
 }
}

Running the Application

The complete source codes can be found in here. Running the web application (embedded Tomcat) and sending requests to http://localhost:8080/sayhi?to=Raymond with the browsers should display on the console something like the below every minute:

2015-08-04 23:48:10.119 INFO 952 --- [PollScheduler-3] a.c.m.b.servo.LoggerMetricObserver : 2015-08-04T23:48:10.119: name[requestCounter] tags[class=TestController,COUNTER,id=testController,INFO] value[3]
2015-08-04 23:48:10.119 INFO 952 --- [PollScheduler-3] a.c.m.b.servo.LoggerMetricObserver : 2015-08-04T23:48:10.119: name[aGauge] tags[class=TestController,GAUGE,id=testController,CRITICAL] value[51]
2015-08-04 23:48:10.120 INFO 952 --- [PollScheduler-3] a.c.m.b.servo.LoggerMetricObserver : 2015-08-04T23:48:10.119: name[requestCounter] tags[class=TestController,RATE,id=testController,INFO] value[0.04987697014032054]
2015-08-04 23:48:10.120 INFO 952 --- [PollScheduler-3] a.c.m.b.servo.LoggerMetricObserver : 2015-08-04T23:48:10.119: name[aGauge] tags[class=TestController,GAUGE,id=testController,CRITICAL] value[51]

Note the log messages for the 2 metric observers.