8

I'm trying to do an integration test to see what the behavior is like when my Registration Endpoint fails. My Registration endpoint is an API provided by an external source (which is secured by Spring OAuth). The client website is using the client side Spring Oauth to communicate with the API.

What I'm trying to do is mocked the API however, I am getting issues where the request is not going against the mocked endpoints; org.springframework.web.client.ResourceAccessException: I/O error on POST request for "http://localhost:8081/oauth/token":Connection refused: connect; nested exception is java.net.ConnectException: Connection refused: connect. Here's my test below:

 @WebAppConfiguration
 @RunWith(SpringJUnit4ClassRunner.class)
 @ContextConfiguration(locations = {"classpath*:RegistrationControllerIntegrationTest-context.xml"})
 public class RegistrationControllerIntegrationTest {


  @Resource
  RegistrationController registrationController;

  @Resource
  private WebApplicationContext webApplicationContext;

  MockMvc mockMvc;

  @Value("${oauth.accessTokenUri}")
  private String oauthUri;

  private MockRestServiceServer mockRestServiceServer;


  private OAuth2RestTemplate clientCredRest;


  @Resource(name = "clientCredentialRest")
  public void setClientCredRest(OAuth2RestTemplate clientCredRest) {
    this.clientCredRest = clientCredRest;
  }



  @Before
  public void setUp()
  {
    this.mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();

    this.mockRestServiceServer = MockRestServiceServer.createServer(this.clientCredRest);


  }
  @Test
  public void testRegistrationThatReturnsBadRequestWhenUserAlreadyExist()
  {




 this.mockRestServiceServer.expect(MockRestRequestMatchers.requestTo("localhost:8081/oauth/token")).andExpect(MockRestRequestMatchers.method(HttpMethod.POST))
    .andRespond(MockRestResponseCreators.withSuccess().contentType(MediaType.APPLICATION_JSON).body("{\n" +
            "\"access_token\": \"8ecd93d4-2484-46de-922a-652fa79d027d\",\n" +
            "\"token_type\": \"bearer\",\n" +
            "\"expires_in\": 1265\n" +
            "\"scope\": \"read write\"\n" +
            "}"));

      Gson gson = Converters.registerDateTime(new GsonBuilder()).create();
      PodamFactory factory = new PodamFactoryImpl();
      RegistrationDTO dto = factory.manufacturePojo(RegistrationDTO.class);
    dto.setUserName("test");
      String json = gson.toJson(dto);


         this.mockRestServiceServer.expect(MockRestRequestMatchers.requestTo("localhost:8081/public/registration")).andExpect(MockRestRequestMatchers.method(HttpMethod.POST))
            .andRespond(MockRestResponseCreators.withBadRequest().contentType(MediaType.APPLICATION_JSON).body("{\n" +
                    "resource: null\n" +
                    "field: \"user_name\"\n" +
                    "code: \"0\"\n" +
                    "message: \"Username already exist\"\n" +
                    "}"));

      MockHttpServletRequestBuilder requestBuilder = MockMvcRequestBuilders.post("/frontend/register").content(json).header("activate", "true").header("User-Agent","Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.101 Safari/537.36").header("Origin","chrome-extension://hgmloofddffdnphfgcellkdfbfbjeloo").contentType(MediaType.APPLICATION_JSON);

      try {
             this.mockMvc.perform(requestBuilder).andExpect(MockMvcResultMatchers.status().isBadRequest());
      } catch (Exception e) {
          e.printStackTrace();
      }
   }
 }

Note, the reason I setup the two expectation for the mocked web server is due to how Spring Oauth gets an access token before making the request to public/registration endpoint. Let me know if I'm missing anything.

Thanks.

Dean
  • 887
  • 4
  • 16
  • 42
  • It looks like that OAuth2RestTemplate creates an internal RestTemplate to retrieve the token that is not bound by the MockRestServiceServer. I have created an issue at Spring https://github.com/spring-projects/spring-security/issues/4217 – Tuno Feb 16 '17 at 15:41

3 Answers3

7

Setting the accesstoken myself worked for me, this prevents the OAuth2RestTemplate from getting the accesstoken itself:

@Before
public void before() {
    mockServer = MockRestServiceServer.createServer(oAuth2RestTemplate);
    oAuth2RestTemplate.getOAuth2ClientContext().setAccessToken(
            new DefaultOAuth2AccessToken("accesstoken")
    );
}
BRNTZN
  • 564
  • 1
  • 7
  • 21
1

I solved it by overriding UserInfoRestTemplateFactory and making OAuth2RestTemplate a bean. This is available as of Spring Boot 1.5.0.

Example:

@RunWith(SpringRunner.class)
@SpringBootTest
@AutoConfigureMockMvc
public class OAuth2Test {

    @TestConfiguration
    static class OAuth2TestConfiguration {

        @Bean
        UserInfoRestTemplateFactory userInfoRestTemplateFactory(
            ObjectProvider<List<UserInfoRestTemplateCustomizer>> customizers,
            ObjectProvider<OAuth2ProtectedResourceDetails> details,
            ObjectProvider<OAuth2ClientContext> context) {

            return new DefaultUserInfoRestTemplateFactory(customizers, details, context);
        }

        @Bean
        OAuth2RestTemplate oAuth2RestTemplate(UserInfoRestTemplateFactory factory) {
            return factory.getUserInfoRestTemplate();
        }

    }

    @Autowired
    private ResourceServerProperties resourceServerProperties;

    @Autowired
    private MockMvc mockMvc;

    @Autowired
    private OAuth2RestTemplate oAuth2RestTemplate;

    @Before
    public void setUp() throws Exception {
        createServer(oAuth2RestTemplate)
            .expect(requestTo(resourceServerProperties.getUserInfoUri()))
            .andExpect(header(HttpHeaders.AUTHORIZATION, OAuth2AccessToken.BEARER_TYPE + " " +  ACCESS_TOKEN))
            .andRespond(withSuccess("{}", MediaType.APPLICATION_JSON));
    }

    @Test
    public void testProtectedResource() throws Exception {
        mockMvc.perform(get("/protected-resource").with(oauth2Token()))
            .andExpect(status().isNotFound());
    }

    private RequestPostProcessor oauth2Token() {
        return request -> {
            request.addHeader(HttpHeaders.AUTHORIZATION, OAuth2AccessToken.BEARER_TYPE + " " + ACCESS_TOKEN);
            return request;
        };
    }

}
Poly
  • 195
  • 2
  • 8
0

One thing you can do is Mock the OAuth2AccessToken or OAuth2AccessToken

Bharath
  • 1,787
  • 1
  • 20
  • 37