Skip to content

Finished Section 21: Spring Security Basic Auth #28

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: 109-lock-demo-optimistic
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
Expand Down Expand Up @@ -68,6 +72,10 @@
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
</dependency>
</dependencies>

<build>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package guru.springframework.spring6restmvc.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.web.SecurityFilterChain;

/**
* Created by jt, Spring Framework Guru.
*/
@Configuration
public class SpringSecConfig {

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {

http.authorizeHttpRequests()
.anyRequest().authenticated()
.and().httpBasic(Customizer.withDefaults())
.csrf().ignoringRequestMatchers("/api/**");
return http.build();
}

}
5 changes: 5 additions & 0 deletions src/main/resources/application.properties
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@
logging.level.guru.springframework=debug
spring.flyway.enabled=false

spring.security.user.name=user1
spring.security.user.password=password

#logging.level.org.springframework.security=trace

#spring.jpa.properties.jakarta.persistence.schema-generation.scripts.action=drop-and-create
#spring.jpa.properties.jakarta.persistence.schema-generation.scripts.create-source=metadata
#spring.jpa.properties.jakarta.persistence.schema-generation.scripts.drop-target=drop-and-create.sql
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import org.springframework.http.HttpStatusCode;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.test.annotation.Rollback;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
Expand All @@ -30,6 +31,8 @@
import static org.assertj.core.api.Assertions.assertThat;
import static org.hamcrest.core.Is.is;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.httpBasic;
import static org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers.springSecurity;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
Expand All @@ -55,7 +58,10 @@ class BeerControllerIT {

@BeforeEach
void setUp() {
mockMvc = MockMvcBuilders.webAppContextSetup(wac).build();

mockMvc = MockMvcBuilders.webAppContextSetup(wac)
.apply(springSecurity())
.build();
}

@Disabled // just for demo purposes
Expand All @@ -68,6 +74,7 @@ void testUpdateBeerBadVersion() throws Exception {
beerDTO.setBeerName("Updated Name");

MvcResult result = mockMvc.perform(put(BeerController.BEER_PATH_ID, beer.getId())
.with(httpBasic(BeerControllerTest.USERNAME, BeerControllerTest.PASSWORD))
.contentType(MediaType.APPLICATION_JSON)
.accept(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(beerDTO)))
Expand All @@ -79,6 +86,7 @@ void testUpdateBeerBadVersion() throws Exception {
beerDTO.setBeerName("Updated Name 2");

MvcResult result2 = mockMvc.perform(put(BeerController.BEER_PATH_ID, beer.getId())
.with(httpBasic(BeerControllerTest.USERNAME, BeerControllerTest.PASSWORD))
.contentType(MediaType.APPLICATION_JSON)
.accept(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(beerDTO)))
Expand All @@ -91,6 +99,7 @@ void testUpdateBeerBadVersion() throws Exception {
@Test
void tesListBeersByStyleAndNameShowInventoryTruePage2() throws Exception {
mockMvc.perform(get(BeerController.BEER_PATH)
.with(httpBasic(BeerControllerTest.USERNAME, BeerControllerTest.PASSWORD))
.queryParam("beerName", "IPA")
.queryParam("beerStyle", BeerStyle.IPA.name())
.queryParam("showInventory", "true")
Expand All @@ -104,6 +113,7 @@ void tesListBeersByStyleAndNameShowInventoryTruePage2() throws Exception {
@Test
void tesListBeersByStyleAndNameShowInventoryTrue() throws Exception {
mockMvc.perform(get(BeerController.BEER_PATH)
.with(httpBasic(BeerControllerTest.USERNAME, BeerControllerTest.PASSWORD))
.queryParam("beerName", "IPA")
.queryParam("beerStyle", BeerStyle.IPA.name())
.queryParam("showInventory", "true")
Expand All @@ -116,6 +126,7 @@ void tesListBeersByStyleAndNameShowInventoryTrue() throws Exception {
@Test
void tesListBeersByStyleAndNameShowInventoryFalse() throws Exception {
mockMvc.perform(get(BeerController.BEER_PATH)
.with(httpBasic(BeerControllerTest.USERNAME, BeerControllerTest.PASSWORD))
.queryParam("beerName", "IPA")
.queryParam("beerStyle", BeerStyle.IPA.name())
.queryParam("showInventory", "false")
Expand All @@ -128,16 +139,28 @@ void tesListBeersByStyleAndNameShowInventoryFalse() throws Exception {
@Test
void tesListBeersByStyleAndName() throws Exception {
mockMvc.perform(get(BeerController.BEER_PATH)
.with(httpBasic(BeerControllerTest.USERNAME, BeerControllerTest.PASSWORD))
.queryParam("beerName", "IPA")
.queryParam("beerStyle", BeerStyle.IPA.name())
.queryParam("pageSize", "800"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.content.size()", is(310)));
}

@Test
void testNoAuth() throws Exception {

//Test No Auth
mockMvc.perform(get(BeerController.BEER_PATH)
.queryParam("beerStyle", BeerStyle.IPA.name())
.queryParam("pageSize", "800"))
.andExpect(status().isUnauthorized());
}

@Test
void tesListBeersByStyle() throws Exception {
mockMvc.perform(get(BeerController.BEER_PATH)
.with(httpBasic(BeerControllerTest.USERNAME, BeerControllerTest.PASSWORD))
.queryParam("beerStyle", BeerStyle.IPA.name())
.queryParam("pageSize", "800"))
.andExpect(status().isOk())
Expand All @@ -147,6 +170,7 @@ void tesListBeersByStyle() throws Exception {
@Test
void tesListBeersByName() throws Exception {
mockMvc.perform(get(BeerController.BEER_PATH)
.with(httpBasic(BeerControllerTest.USERNAME, BeerControllerTest.PASSWORD))
.queryParam("beerName", "IPA")
.queryParam("pageSize", "800"))
.andExpect(status().isOk())
Expand All @@ -161,6 +185,7 @@ void testPatchBeerBadName() throws Exception {
beerMap.put("beerName", "New Name 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890");

mockMvc.perform(patch(BeerController.BEER_PATH_ID, beer.getId())
.with(httpBasic(BeerControllerTest.USERNAME, BeerControllerTest.PASSWORD))
.contentType(MediaType.APPLICATION_JSON)
.accept(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(beerMap)))
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package guru.springframework.spring6restmvc.controller;

import com.fasterxml.jackson.databind.ObjectMapper;
import guru.springframework.spring6restmvc.config.SpringSecConfig;
import guru.springframework.spring6restmvc.model.BeerDTO;
import guru.springframework.spring6restmvc.services.BeerService;
import guru.springframework.spring6restmvc.services.BeerServiceImpl;
Expand All @@ -11,6 +12,7 @@
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.context.annotation.Import;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
Expand All @@ -25,10 +27,12 @@
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.verify;
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.httpBasic;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;

@WebMvcTest(BeerController.class)
@Import(SpringSecConfig.class)
class BeerControllerTest {

@Autowired
Expand All @@ -48,6 +52,9 @@ class BeerControllerTest {
@Captor
ArgumentCaptor<BeerDTO> beerArgumentCaptor;

public static final String USERNAME = "user1";
public static final String PASSWORD = "password";

@BeforeEach
void setUp() {
beerServiceImpl = new BeerServiceImpl();
Expand All @@ -61,6 +68,7 @@ void testPatchBeer() throws Exception {
beerMap.put("beerName", "New Name");

mockMvc.perform(patch(BeerController.BEER_PATH_ID, beer.getId())
.with(httpBasic(USERNAME, PASSWORD))
.contentType(MediaType.APPLICATION_JSON)
.accept(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(beerMap)))
Expand All @@ -79,6 +87,7 @@ void testDeleteBeer() throws Exception {
given(beerService.deleteById(any())).willReturn(true);

mockMvc.perform(delete(BeerController.BEER_PATH_ID, beer.getId())
.with(httpBasic(USERNAME, PASSWORD))
.accept(MediaType.APPLICATION_JSON))
.andExpect(status().isNoContent());

Expand All @@ -94,6 +103,7 @@ void testUpdateBeer() throws Exception {
given(beerService.updateBeerById(any(), any())).willReturn(Optional.of(beer));

mockMvc.perform(put(BeerController.BEER_PATH_ID, beer.getId())
.with(httpBasic(USERNAME, PASSWORD))
.accept(MediaType.APPLICATION_JSON)
.contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(beer)))
Expand All @@ -109,6 +119,7 @@ void testUpdateBeerBlankName() throws Exception {
given(beerService.updateBeerById(any(), any())).willReturn(Optional.of(beer));

mockMvc.perform(put(BeerController.BEER_PATH_ID, beer.getId())
.with(httpBasic(USERNAME, PASSWORD))
.accept(MediaType.APPLICATION_JSON)
.contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(beer)))
Expand All @@ -126,6 +137,7 @@ void testCreateNewBeer() throws Exception {
given(beerService.saveNewBeer(any(BeerDTO.class))).willReturn(beerServiceImpl.listBeers(null, null, false, 1, 25).getContent().get(1));

mockMvc.perform(post(BeerController.BEER_PATH)
.with(httpBasic(USERNAME, PASSWORD))
.accept(MediaType.APPLICATION_JSON)
.contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(beer)))
Expand All @@ -141,6 +153,7 @@ void testCreateBeerNullBeerName() throws Exception {
given(beerService.saveNewBeer(any(BeerDTO.class))).willReturn(beerServiceImpl.listBeers(null, null, false, 1, 25).getContent().get(1));

MvcResult mvcResult = mockMvc.perform(post(BeerController.BEER_PATH)
.with(httpBasic(USERNAME, PASSWORD))
.accept(MediaType.APPLICATION_JSON)
.contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(beerDTO)))
Expand All @@ -157,6 +170,7 @@ void testListBeers() throws Exception {
.willReturn(beerServiceImpl.listBeers(null, null, false, null, null));

mockMvc.perform(get(BeerController.BEER_PATH)
.with(httpBasic(USERNAME, PASSWORD))
.accept(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON))
Expand All @@ -168,7 +182,8 @@ void getBeerByIdNotFound() throws Exception {

given(beerService.getBeerById(any(UUID.class))).willReturn(Optional.empty());

mockMvc.perform(get(BeerController.BEER_PATH_ID, UUID.randomUUID()))
mockMvc.perform(get(BeerController.BEER_PATH_ID, UUID.randomUUID())
.with(httpBasic(USERNAME, PASSWORD)))
.andExpect(status().isNotFound());
}

Expand All @@ -179,6 +194,7 @@ void getBeerById() throws Exception {
given(beerService.getBeerById(testBeer.getId())).willReturn(Optional.of(testBeer));

mockMvc.perform(get(BeerController.BEER_PATH_ID, testBeer.getId())
.with(httpBasic(USERNAME, PASSWORD))
.accept(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON))
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package guru.springframework.spring6restmvc.controller;

import com.fasterxml.jackson.databind.ObjectMapper;
import guru.springframework.spring6restmvc.config.SpringSecConfig;
import guru.springframework.spring6restmvc.model.CustomerDTO;
import guru.springframework.spring6restmvc.services.CustomerService;
import guru.springframework.spring6restmvc.services.CustomerServiceImpl;
Expand All @@ -11,6 +12,7 @@
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.context.annotation.Import;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.MockMvc;

Expand All @@ -24,10 +26,12 @@
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.verify;
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.httpBasic;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;

@WebMvcTest(CustomerController.class)
@Import(SpringSecConfig.class)
class CustomerControllerTest {

@MockBean
Expand Down Expand Up @@ -59,7 +63,8 @@ void testPatchCustomer() throws Exception {
Map<String, Object> customerMap = new HashMap<>();
customerMap.put("name", "New Name");

mockMvc.perform(patch( CustomerController.CUSTOMER_PATH_ID, customer.getId())
mockMvc.perform(patch(CustomerController.CUSTOMER_PATH_ID, customer.getId())
.with(httpBasic(BeerControllerTest.USERNAME, BeerControllerTest.PASSWORD))
.contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(customerMap)))
.andExpect(status().isNoContent());
Expand All @@ -79,6 +84,7 @@ void testDeleteCustomer() throws Exception {
given(customerService.deleteCustomerById(any())).willReturn(true);

mockMvc.perform(delete(CustomerController.CUSTOMER_PATH_ID, customer.getId())
.with(httpBasic(BeerControllerTest.USERNAME, BeerControllerTest.PASSWORD))
.contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isNoContent());

Expand All @@ -95,6 +101,7 @@ void testUpdateCustomer() throws Exception {
.build()));

mockMvc.perform(put(CustomerController.CUSTOMER_PATH_ID, customer.getId())
.with(httpBasic(BeerControllerTest.USERNAME, BeerControllerTest.PASSWORD))
.content(objectMapper.writeValueAsString(customer))
.contentType(MediaType.APPLICATION_JSON)
.accept(MediaType.APPLICATION_JSON))
Expand All @@ -114,7 +121,9 @@ void testCreateCustomer() throws Exception {
given(customerService.saveNewCustomer(any(CustomerDTO.class)))
.willReturn(customerServiceImpl.getAllCustomers().get(1));

mockMvc.perform(post(CustomerController.CUSTOMER_PATH).contentType(MediaType.APPLICATION_JSON)
mockMvc.perform(post(CustomerController.CUSTOMER_PATH)
.with(httpBasic(BeerControllerTest.USERNAME, BeerControllerTest.PASSWORD))
.contentType(MediaType.APPLICATION_JSON)
.accept(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(customer)))
.andExpect(status().isCreated())
Expand All @@ -126,6 +135,7 @@ void listAllCustomers() throws Exception {
given(customerService.getAllCustomers()).willReturn(customerServiceImpl.getAllCustomers());

mockMvc.perform(get(CustomerController.CUSTOMER_PATH)
.with(httpBasic(BeerControllerTest.USERNAME, BeerControllerTest.PASSWORD))
.accept(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON))
Expand All @@ -137,7 +147,8 @@ void getCustomerByIdNotFound() throws Exception {

given(customerService.getCustomerById(any(UUID.class))).willReturn(Optional.empty());

mockMvc.perform(get(CustomerController.CUSTOMER_PATH_ID, UUID.randomUUID()))
mockMvc.perform(get(CustomerController.CUSTOMER_PATH_ID, UUID.randomUUID())
.with(httpBasic(BeerControllerTest.USERNAME, BeerControllerTest.PASSWORD)))
.andExpect(status().isNotFound());
}

Expand All @@ -148,6 +159,7 @@ void getCustomerById() throws Exception {
given(customerService.getCustomerById(customer.getId())).willReturn(Optional.of(customer));

mockMvc.perform(get(CustomerController.CUSTOMER_PATH_ID, customer.getId())
.with(httpBasic(BeerControllerTest.USERNAME, BeerControllerTest.PASSWORD))
.accept(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON))
Expand Down