9

My OAuth integration test before Spring Boot 1.4 looked as follows(updates just to not use deprecated features):

@RunWith(SpringRunner.class)
@SpringBootTest(classes = { ApplicationConfiguration.class }, webEnvironment = WebEnvironment.RANDOM_PORT)
public class OAuth2IntegrationTest {

    @Value("${local.server.port}")
    private int port;

    private static final String CLIENT_NAME = "client";
    private static final String CLIENT_PASSWORD = "123456";

    @Test
    public void testOAuthAccessTokenIsReturned() {
        MultiValueMap<String, String> request = new LinkedMultiValueMap<String, String>();
        request.set("username", "user");
        request.set("password", password);
        request.set("grant_type", "password");
        @SuppressWarnings("unchecked")
        Map<String, Object> token = new TestRestTemplate(CLIENT_NAME, CLIENT_PASSWORD)
            .postForObject("http://localhost:" + port + "/oauth/token", request, Map.class);
        assertNotNull("Wrong response: " + token, token.get("access_token"));
    }
}

I now want to use Autowired TestRestTemplate as stated here http://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-testing.html#boot-features-testing-spring-boot-applications-working-with-random-ports

@RunWith(SpringRunner.class)
@SpringBootTest(classes = {
    ApplicationConfiguration.class }, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class OAuth2IntegrationTest {

    private static final String CLIENT_NAME = "client";
    private static final String CLIENT_PASSWORD = "123456";

    @Autowired
    private TestRestTemplate testRestTemplate;

    @Test
    public void testOAuthAccessTokenIsReturned() {
        MultiValueMap<String, String> request = new LinkedMultiValueMap<String, String>();
        request.set("username", "user");
        request.set("password", password);
        request.set("grant_type", "password");
        @SuppressWarnings("unchecked")

        Map<String, Object> token1 = this.testRestTemplate. //how to add basic auth here
        assertNotNull("Wrong response: " + token, token.get("access_token"));
    }
}

I saw this as the closest way to add auth:

Spring 4.0.0 basic authentication with RestTemplate

I want to use the Autowired testRestTemplate to avoid resolving host and ports in my test. Is there a way to do this?

moffeltje
  • 4,521
  • 4
  • 33
  • 57
Tuhin Kanti Sharma
  • 1,056
  • 2
  • 8
  • 19
  • public TestRestTemplate withBasicAuth(String username, String password) this looks to be only available in spring boot 1.4.1, is this the solution – Tuhin Kanti Sharma Sep 23 '16 at 01:16

5 Answers5

19

This got fixed in Spring Boot 1.4.1 which has an additional method

testRestTemplate.withBasicAuth(USERNAME,PASSWORD)

@Autowired
private TestRestTemplate testRestTemplate;

@Test
public void testOAuthAccessTokenIsReturned() {
    MultiValueMap<String, String> request = new LinkedMultiValueMap<String, String>();
    request.set("username", USERNAME);
    request.set("password", password);
    request.set("grant_type", "password");
    @SuppressWarnings("unchecked")
    Map<String, Object> token = this.testRestTemplate.withBasicAuth(CLIENT_NAME, CLIENT_PASSWORD)
            .postForObject(SyntheticsConstants.OAUTH_ENDPOINT, request, Map.class);
    assertNotNull("Wrong response: " + token, token.get("access_token"));
}
Tuhin Kanti Sharma
  • 1,056
  • 2
  • 8
  • 19
  • 2
    Is there a way to do that in a more central place? This way I would have to repeat the password in every testcase that needs Basic Auth. Can the TestRestTemplate be used to always use basic auth somehow? How can I inject the testRestTemplate as a @Bean? – Robert Jan 11 '17 at 14:03
2

There is a better solution so you don't need to retype withBasicAuth part each time

@Autowired
private TestRestTemplate testRestTemplate;

@BeforeClass
public void setup() {
    BasicAuthorizationInterceptor bai = new BasicAuthorizationInterceptor(CLIENT_NAME, CLIENT_PASSWORD);
    testRestTemplate.getRestTemplate().getInterceptors().add(bai);
}

@Test
public void testOAuthAccessTokenIsReturned() {
    MultiValueMap<String, String> request = new LinkedMultiValueMap<String, String>();
    request.set("username", USERNAME);
    request.set("password", password);
    request.set("grant_type", "password");
    @SuppressWarnings("unchecked")
    Map<String, Object> token = this.testRestTemplate.postForObject(SyntheticsConstants.OAUTH_ENDPOINT, request, Map.class);
    assertNotNull("Wrong response: " + token, token.get("access_token"));
}
celezar
  • 442
  • 3
  • 9
1

Although the accepted answer is correct, in my case I had to replicate the testRestTemplate.withBasicAuth(...) in each test method and class.

So, I tried to define in src/test/java/my.microservice.package a configuration like this:

@Configuration
@Profile("test")
public class MyMicroserviceConfigurationForTest {

    @Bean
    public TestRestTemplate testRestTemplate(TestRestTemplate testRestTemplate, SecurityProperties securityProperties) {
        return testRestTemplate.withBasicAuth(securityProperties.getUser().getName(), securityProperties.getUser().getPassword());
    }

}

That seems to have the effect of overriding the default TestRestTemplate definition, allowing the injection of a credentials-aware TestRestTemplate anywhere in my test classes.

I'm not entirely sure whether this is really a valid solution but you can give it a try...

fabriziocucci
  • 782
  • 8
  • 20
1

I think there is a better solution if you are still using Basic Authentication in your application, with the "user.name" and "user.password" properties set on your application.properties file:

public class YourEndpointClassTest {
    private static final Logger logger = LoggerFactory.getLogger(YourEndpointClassTest.class);  

    private static final String BASE_URL = "/your/base/url";

    @TestConfiguration
    static class TestRestTemplateAuthenticationConfiguration {

        @Value("${spring.security.user.name}")
        private String userName;

        @Value("${spring.security.user.password}")
        private String password;

        @Bean
        public RestTemplateBuilder restTemplateBuilder() {
            return new RestTemplateBuilder().basicAuthentication(userName, password);
        }
    }


    @Autowired
    private TestRestTemplate restTemplate;

//here add your tests...
dcormar
  • 61
  • 4
  • Did not work directly for me but with a separate @Configuration annotated class that implements the shown restTemplateBuilder() method. – yasd Nov 25 '21 at 11:30
1

In single testcase, you can do like this:

@Test
public void test() {
    ResponseEntity<String> entity = testRestTemplate
            .withBasicAuth("username", "password")
            .postForEntity(xxxx,String.class);
    Assert.assertNotNull(entity.getBody());
}

and for every testcase add this method in your test class:

@Before
public void before() {
    // because .withBasicAuth() creates a new TestRestTemplate with the same 
    // configuration as the autowired one.
     testRestTemplate = testRestTemplate.withBasicAuth("username", "password");
}
Fly King
  • 91
  • 1
  • 4