I am using Jhipster with Oauth2 implementation and mongodb as a database.
I am trying to test a resource with OAuth2. But I got always an error message "Access Denied" and status code 401. I am looking for an JUnit example with OAuth2. Thank you!
Manuel
/**
* Test class for the InvoiceResource REST controller.
*
* #see InvoiceResource
*/
#RunWith(SpringJUnit4ClassRunner.class)
#SpringApplicationConfiguration(classes = Application.class)
#WebAppConfiguration
#IntegrationTest
public class InvoiceResourceIntTest {
...
private MockMvc restInvoiceMockMvcWebApp;
#PostConstruct
public void setup() {
MockitoAnnotations.initMocks(this);
this.restInvoiceMockMvcWebApp = MockMvcBuilders.webAppContextSetup(context).alwaysDo(MockMvcResultHandlers.print())
.apply(SecurityMockMvcConfigurers.springSecurity()).build();
}
#Before
public void initTest() {
// Create currentuser
currentUser = new User();
currentUser.setActivated(CURRENTUSER_ACTIVATED);
currentUser.setFirstName(CURRENTUSER_FIRSTNAME);
currentUser.setLastName(CURRENTUSER_LASTNAME);
currentUser.setEmail(CURRENTUSER_EMAIL);
Set<Authority> authorities = new HashSet<>();
Authority authority = new Authority();
authority.setName(AuthoritiesConstants.ADMIN);
currentUser.setAuthorities(authorities);
currentUser.setPassword(passwordEncoder.encode(CURRENTUSER_PASSWORD));
userRepository.save(currentUser);
}
#Test
// #WithMockUser(username = CURRENTUSER_EMAIL, password = CURRENTUSER_PASSWORD, roles = { "ADMIN" })
public void getAllInvoices() throws Exception {
// Initialize the database
invoice.setDeletedAt(LocalDate.now());
invoiceRepository.save(invoice);
invoice.setId(null);
invoice.setDeletedAt(null);
invoiceRepository.save(invoice);
// Get all the invoices
restInvoiceMockMvcWebApp.perform(get("/api/invoicessort=id,desc")
.with(user(CURRENTUSER_EMAIL).password(CURRENTUSER_PASSWORD.roles("ADMIN")))
.andExpect(status().isOk()).andExpect(content().contentType(MediaType.APPLICATION_JSON)).andExpect(jsonPath("$", hasSize(1)))
}
You can get a token from the token resource, and use that token in your tests, here a complete example.
#RunWith(SpringJUnit4ClassRunner.class)
#SpringApplicationConfiguration(classes = Application.class)
#WebAppConfiguration
public class PermissionTest {
#Autowired
WebApplicationContext context;
#Autowired
FilterChainProxy springSecurityFilterChain;
MockMvc mvc;
#Before
public void setUp() {
mvc = MockMvcBuilders.webAppContextSetup(context)
.addFilter(springSecurityFilterChain).build();
}
#Test
public void shouldHavePermission() throws Exception {
mvc.perform(get("/api/resource")
.header("Authorization", "Bearer " + getAccessToken("user", "123"))
.accept(MediaType.APPLICATION_JSON))
.andExpect(status().isOk());
}
private String getAccessToken(String username, String password) {
MockHttpServletResponse response = mvc
.perform(post("/oauth/token")
.header("Authorization", "Basic "
+ new String(Base64Utils.encode(("appclient:password")
.getBytes())))
.param("username", username)
.param("password", password)
.param("grant_type", "password"))
.andReturn().getResponse();
return new ObjectMapper()
.readValue(response.getContentAsByteArray(), OAuthToken.class)
.accessToken;
}
#JsonIgnoreProperties(ignoreUnknown = true)
private static class OAuthToken {
#JsonProperty("access_token")
public String accessToken;
}
}
Related
i added a mocked user this my class
#TestConfiguration
public class UserDetailsMock {
final String apiAccessGroup = "00000000-0000-0000-0000-000000000000";
#Bean
#Primary
public UserDetailsService userDetailsService() {
User ericssonUser = new User("ericsson-worker", "secret", Arrays.asList());
User msApiUser = new User("msApiUser", "StrongPass", Arrays.asList(new SimpleGrantedAuthority(apiAccessGroup)));
return new InMemoryUserDetailsManager(Arrays.asList(
ericssonUser, msApiUser
));
}
}
and this my test Class any help please!!!!
#SpringBootTest(
classes = UserDetailsMock.class
)
#AutoConfigureMockMvc
public class MuninServiceAuthorizationTest {
#Autowired
MockMvc mockMvc;
List<MockHttpServletRequestBuilder> endpoints;
#BeforeEach
public void setUp() throws IOException {
MockitoAnnotations.openMocks(this);
endpoints = Arrays.asList(
MockMvcRequestBuilders.post("/migrate/foss").with(csrf()),
MockMvcRequestBuilders.get("/swagger/ui/**"));
}
#Test
#WithUserDetails("msApiUser")
void userWithGroupWhichIsAllowedToUseApiShouldGet200() throws Exception {
for (MockHttpServletRequestBuilder mockHttpServletRequestBuilder : endpoints) {
mockMvc.perform(mockHttpServletRequestBuilder)
.andExpect(status().isOk());
}
}
}
I am new to unit testing REST API in Spring Boot.
I am expecting response status as CREATED but instead I am getting a PAGE NOT FOUND error.
Below is the code for:-
UserControllerUnitTests
#SpringBootTest
#ContextConfiguration(classes = { CommonConfig.class, SecurityConfig.class})
#RunWith(SpringRunner.class)
class UserControllerUnitTests {
private static ObjectMapper mapper;
private static final String URI = "/users";
MockMvc mvc;
#Autowired
WebApplicationContext webAppContext;
#Mock
UserService userService;
MvcResult mvcResult;
#BeforeAll
static void setUp() {
mapper = new ObjectMapper();
}
#BeforeEach
void initialize() throws Exception {
mvc = MockMvcBuilders.webAppContextSetup(webAppContext).build();
....
....
....
void shouldReturnStatusCreatedIfValidUserPassedForPostUser(long index) throws Exception {
int expectedStatus = HttpStatus.CREATED.value();
UserDAO returnUser;
UserDAO user = userList.get(index);
userList.remove(index);
String jsonContent = mapper.writeValueAsString(user);
user.setId(index);
user.setEncryptedPassword(null);
Mockito.when(userService.addUser(Mockito.any())).thenReturn(user);
mvcResult = mvc.perform(MockMvcRequestBuilders.post(URI)
.accept(MediaType.APPLICATION_JSON)
.contentType(MediaType.APPLICATION_JSON)
.content(jsonContent)).andReturn();
//Mockito.verify(userService, Mockito.times(1)).addUser(Mockito.any());
int actualStatus = mvcResult.getResponse().getStatus();
Assert.assertEquals("Response status should be CREATED", expectedStatus, actualStatus);
jsonContent = mvcResult.getResponse().getContentAsString();
returnUser = mapper.readValue(jsonContent, UserDAO.class);
Assert.assertEquals("EncryptedPassword should not be returned", null,
returnUser.getEncryptedPassword());
}
User Controller.class
#RestController
#RequestMapping("users/")
public class UserController {
UserService userService;
#Autowired
public UserController(UserService userService) {
this.userService = userService;
}
....
....
....
#PostMapping(path = "",
consumes = { MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON },
produces = { MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
public ResponseEntity<UserDAO> createUser(#Valid #RequestBody UserDAO user) {
String password = user.getEncryptedPassword();
user.setEncryptedPassword(null);
UserDAO retreivedUser;
if(user.getId() != 0)
return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
user.setEncryptedPassword(password);
retreivedUser = userService.addUser(user);
if(retreivedUser != null)
return new ResponseEntity<>(retreivedUser, HttpStatus.CREATED);
return new ResponseEntity<>(HttpStatus.CONFLICT);
}
}
The full code can be found at https://github.com/vineethmaller/springboot-userservice
I spotted a few errors:
Get rid of ContextConfiguration
#SpringBootTest
// #ContextConfiguration(classes = { CommonConfig.class, SecurityConfig.class})
#RunWith(SpringRunner.class)
class UserControllerUnitTests {
Specify correct mapping on the controller (no slash)
#RestController
#RequestMapping("users")
public class UserController {
You setup your UserService mock which is not used in the test. Did you mean #MockBean?
#MockBean
UserService userService;
I generated simple microservices application with Jhipster I wrote simple controller like hello world,
When I am trying to test through test method it is always giving Unauthorized error and the test fails.
Controller:
#RestController
#RequestMapping("/api")
public class TestController{
#GetMapping("/test/{Id}")
public String TestGetData(#PathVariable int Id) {
return "Here is your data!";
}
}
Testclass:
#SpringBootTest(classes = HerstellerController.class)
#AutoConfigureMockMvc
public class TestIT {
#Autowired
private MockMvc mockMvc;
private static final long ONE_MINUTE = 60000;
private String token;
private Key key;
private TokenProvider tokenProvider;
#BeforeEach
public void setup() {
tokenProvider = new TokenProvider( new JHipsterProperties());
key = Keys.hmacShaKeyFor(Decoders.BASE64
.decode("xxxx"));
ReflectionTestUtils.setField(tokenProvider, "key", key);
ReflectionTestUtils.setField(tokenProvider, "tokenValidityInMilliseconds", ONE_MINUTE);
}
#Test
public void TestData() throws Exception {
token=tokenProvider.createToken(createAuthentication(),false);
String id="1";
String expData = "Here is your data!";
String result = mockMvc.perform(get("/api/test/"+ id)
.header("Authorization","Bearer " + token))
.andExpect(status().isOk())
.andReturn()
.getResponse()
.getContentAsString();
System.out.println("\nResult:\n"+result);
}
private Authentication createAuthentication() {
Collection<GrantedAuthority> authorities = new ArrayList<>();
authorities.add(new SimpleGrantedAuthority(AuthoritiesConstants.ADMIN));
return new UsernamePasswordAuthenticationToken("admin", "admin", authorities);
}
Changed the securityconfig also like this
.antMatchers("/api/**").permitAll()
.antMatchers("/api/**").anonymous()
I added authentication to securityContext in setup of Testclass!, It works!
SecurityContext securityContext = SecurityContextHolder.createEmptyContext();
securityContext.setAuthentication(createAuthentication());
SecurityContextHolder.setContext(securityContext);
I get An Authentication object was not found in the SecurityContext error when I call a #Service after calling a #RestController through MockMvc in a test method annotated with #WithMockUser.
Calling in the opposite order works fine as does calling the service and controller individually. The #Service is clearing the SecurityContextHolder. The only workaround I can think of is to set the context manually. Am I missing something?
I need to call the service to mutate state and then test that the controller returns the correct state.
#Service
public class SimpleService {
#Secured("ROLE_SIMPLE_USER")
public void doThis(Long id) {
System.out.println("dothis : " + id);
}
#Secured("ROLE_SIMPLE_USER")
public void doThat(Long id) {
System.out.println("dothat : " + id);
}
}
#RestController
#RequestMapping("/api")
#Secured("ROLE_SIMPLE_USER")
public class SimpleController {
#Autowired
private SimpleService simpleService;
#PostMapping(value = "{id}/dothis")
public ResponseEntity dothis(#PathVariable("id") Long id) {
simpleService.doThis(id);
return ResponseEntity.status(HttpStatus.OK).build();
}
#PostMapping(value = "{id}/dothat")
public ResponseEntity dothat(#PathVariable("id") Long id) {
simpleService.doThat(id);
return ResponseEntity.status(HttpStatus.OK).build();
}
}
#RunWith(SpringJUnit4ClassRunner.class)
#SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
#AutoConfigureMockMvc
#ActiveProfiles({"devh2"})
public class SimpleControllerTest {
#Autowired
private SimpleService simpleService;
#Autowired
private WebApplicationContext context;
private MockMvc mockMvc;
#Before
public void setUpLiabilities() {
this.mockMvc = MockMvcBuilders
.webAppContextSetup(context)
.apply(springSecurity())
.build();
}
#Test
#WithMockUser(username="simple.user", password = "******", roles = {"SIMPLE_USER"})
public void callViaControllers() throws Exception {
mockMvc.perform(post("/api/1/dothis").with(csrf())).andExpect(status().isOk());
mockMvc.perform(post("/api/1/dothat").with(csrf())).andExpect(status().isOk());
}
#Test
#WithMockUser(username="simple.user", password = "******", roles = {"SIMPLE_USER"})
public void callViaService() throws Exception {
simpleService.doThis(1L);
simpleService.doThat(1L);
}
#Test
#WithMockUser(username="simple.user", password = "******", roles = {"SIMPLE_USER"})
public void callViaServiceThenControllers() throws Exception {
simpleService.doThis(1L);
mockMvc.perform(post("/api/1/dothat").with(csrf())).andExpect(status().isOk());
}
#Test
#WithMockUser(username="simple.user", password = "******", roles = {"SIMPLE_USER"})
public void callViaControllerThenService() throws Exception {
mockMvc.perform(post("/api/1/dothis").with(csrf())).andExpect(status().isOk());
// ***FAILS*** because SecurityContextPersistenceFilter clears the SecurityContext ???
simpleService.doThat(1L);
}
#Test
#WithMockUser(username="simple.user", password = "******", roles = {"SIMPLE_USER"})
public void callViaControllerThenServiceWithWorkaround() throws Exception {
mockMvc.perform(post("/api/1/dothis").with(csrf())).andExpect(status().isOk());
setSecurityContextAndThenCallDoThat(1L, "simple.user", "******", "ROLE_SIMPLE_USER");
}
// Workaround - set context manually
private void setSecurityContextAndThenCallDoThat(long id, String username, String password, String... roles) {
try {
final SecurityContextImpl holder = new SecurityContextImpl();
holder.setAuthentication(new TestingAuthenticationToken(username, password, roles));
SecurityContextHolder.setContext(holder);
this.simpleService.doThat(id);
} finally {
SecurityContextHolder.clearContext();
}
}
}
I have a small issue with mocking methods . Where mock should return an predefined object, it returns null. here is test set up:
#RunWith(SpringRunner.class)
#SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class UserControllerTest {
#Autowired
WebApplicationContext webContext;
#MockBean
UserTransferService userTransferService;
#MockBean
UserService userService;
MockMvc mockMvc;
private User user = DummyObjects.getDummyUser();
private User modifiedUser = DummyObjects.getModifiedUser();
private UserTO userTO = DummyObjects.getDummyUserTO();
private UserTO modifiedUserTO = DummyObjects.getModifiedUserTO();
#Before
public void setUp() throws Exception {
List<User> users = new ArrayList<>();
users.add(modifiedUser);
users.add(user);
given(this.userTransferService.getTO(user)).willReturn(userTO);
given(this.userTransferService.getObject(userTO)).willReturn(user);
given(this.userTransferService.getTO(modifiedUser)).willReturn(modifiedUserTO);
given(this.userTransferService.getObject(modifiedUserTO)).willReturn(modifiedUser);
given(this.userService.findAll()).willReturn(users);
given(this.userService.save(user)).willReturn(user);
given(this.userService.removeById(1)).willReturn(true);
given(this.userService.getById(1)).willReturn(user);
given(this.userService.getById(2)).willReturn(null);
given(this.userService.modify(modifiedUser)).willReturn(modifiedUser);
given(this.userService.findByLogin(user.getLogin())).willReturn(user);
given(this.userService.findByLogin("AAA")).willReturn(null);
mockMvc = MockMvcBuilders
.webAppContextSetup(webContext)
.apply(springSecurity())
.build();
}
test itself:
#Test
public void shouldAddUser() throws Exception {
mockMvc.perform(post("/api/user")
.content(TestingUtility.asJsonString(userTO))
.contentType(MediaType.APPLICATION_JSON)
.accept(MediaType.APPLICATION_JSON)
.with(csrf().asHeader()))
.andExpect(status().is(200))
.andExpect(content().json(TestingUtility.asJsonString(userTO)));
}
and Controller method:
#RequestMapping(method = RequestMethod.PUT, consumes = MediaType.APPLICATION_JSON_UTF8_VALUE)
public UserTO modifyUser(#RequestBody UserTO userTO, UsernamePasswordAuthenticationToken principal) throws IllegalAccessException{
User user = userTransferService.getObject(userTO);
if (principal.getName().equals(userTO.getLogin()) || permissionService.hasPermission(principal,Permission.SU)) {
return userTransferService.getTO(userService.modify(user));
} else {
throw new IllegalAccessException("You are not allowed to modify user");
}
}
User is null, but UserTO is filled. So mocked method UserTransferService.getObject(userTO) is not working properly.