diff --git a/pom.xml b/pom.xml index df7a6cb36..4be087fcc 100644 --- a/pom.xml +++ b/pom.xml @@ -138,6 +138,10 @@ spring-boot-starter-test test + + org.springframework.boot + spring-boot-starter-security + org.springframework.security spring-security-test diff --git a/src/main/java/guru/sfg/brewery/config/SecurityConfig.java b/src/main/java/guru/sfg/brewery/config/SecurityConfig.java new file mode 100644 index 000000000..291ce67a1 --- /dev/null +++ b/src/main/java/guru/sfg/brewery/config/SecurityConfig.java @@ -0,0 +1,77 @@ +package guru.sfg.brewery.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.http.HttpMethod; +import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; +import org.springframework.security.core.userdetails.User; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.security.crypto.password.NoOpPasswordEncoder; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.security.provisioning.InMemoryUserDetailsManager; + +@Configuration +@EnableWebSecurity +public class SecurityConfig extends WebSecurityConfigurerAdapter { + + @Override + protected void configure(HttpSecurity http) throws Exception { + http.authorizeRequests(authorize -> { + authorize.antMatchers("/", "/webjars/**", "/login", "/resources/**").permitAll() + .antMatchers("/beers/find", "/beers*").permitAll() + .antMatchers(HttpMethod.GET, "/api/v1/beer/**", "/api/v1/beerUpc/**").permitAll(); + }) + .authorizeRequests() + .anyRequest() + .authenticated().and() + .formLogin().and() + .httpBasic(); + } + +// @Override +// @Bean +// protected UserDetailsService userDetailsService() { +// UserDetails admin = User.withDefaultPasswordEncoder() +// .username("spring") +// .password("password") +// .roles("ADMIN") +// .build(); +// +// UserDetails user = User.withDefaultPasswordEncoder() +// .username("user") +// .password("password") +// .roles("USER") +// .build(); +// +// UserDetails customer = User.withDefaultPasswordEncoder() +// .username("scott") +// .password("tiger") +// .roles("CUSTOMER") +// .build(); +// +// return new InMemoryUserDetailsManager(admin, user, customer); +// } + + @Override + protected void configure(AuthenticationManagerBuilder auth) throws Exception { + auth.inMemoryAuthentication() + .withUser("spring") + .password("password") + .roles("ADMIN") + .and() + .withUser("user") + .password("password") + .roles("USER"); + + auth.inMemoryAuthentication().withUser("scott").password("tiger").roles("CUSTOMER"); + } + + @Bean + PasswordEncoder passwordEncoder() { + return NoOpPasswordEncoder.getInstance(); + } +} diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 912080aaa..d22f7dcd4 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -23,4 +23,7 @@ spring.messages.basename=messages/messages logging.level.guru=debug # Spring Data hangs when not set under Spring Boot 2.3.0 -spring.data.jpa.repositories.bootstrap-mode=default \ No newline at end of file +spring.data.jpa.repositories.bootstrap-mode=default + +#spring.security.user.name=spring +#spring.security.user.password=password \ No newline at end of file diff --git a/src/test/java/guru/sfg/brewery/web/controllers/BaseIT.java b/src/test/java/guru/sfg/brewery/web/controllers/BaseIT.java new file mode 100644 index 000000000..f5000e7bc --- /dev/null +++ b/src/test/java/guru/sfg/brewery/web/controllers/BaseIT.java @@ -0,0 +1,48 @@ +package guru.sfg.brewery.web.controllers; + +import guru.sfg.brewery.repositories.BeerInventoryRepository; +import guru.sfg.brewery.repositories.BeerRepository; +import guru.sfg.brewery.repositories.CustomerRepository; +import guru.sfg.brewery.services.BeerService; +import guru.sfg.brewery.services.BreweryService; +import org.junit.jupiter.api.BeforeEach; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; +import org.springframework.web.context.WebApplicationContext; + +import static org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers.springSecurity; + +/** + * Created by jt on 6/13/20. + */ +public abstract class BaseIT { + @Autowired + WebApplicationContext wac; + + protected MockMvc mockMvc; + + @MockBean + BeerRepository beerRepository; + + @MockBean + BeerInventoryRepository beerInventoryRepository; + + @MockBean + BreweryService breweryService; + + @MockBean + CustomerRepository customerRepository; + + @MockBean + BeerService beerService; + + @BeforeEach + public void setup() { + mockMvc = MockMvcBuilders + .webAppContextSetup(wac) + .apply(springSecurity()) + .build(); + } +} diff --git a/src/test/java/guru/sfg/brewery/web/controllers/BeerControllerIT.java b/src/test/java/guru/sfg/brewery/web/controllers/BeerControllerIT.java new file mode 100644 index 000000000..6b6bf7edb --- /dev/null +++ b/src/test/java/guru/sfg/brewery/web/controllers/BeerControllerIT.java @@ -0,0 +1,44 @@ +package guru.sfg.brewery.web.controllers; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; + +import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.anonymous; +import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.httpBasic; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; + +/** + * Created by jt on 6/12/20. + */ +@WebMvcTest +public class BeerControllerIT extends BaseIT{ + + @Test + void initCreationForm() throws Exception { + mockMvc.perform(get("/beers/new").with(httpBasic("spring", "password"))) + .andExpect(status().isOk()) + .andExpect(view().name("beers/createBeer")) + .andExpect(model().attributeExists("beer")); + } + + @Test + void findBeers() throws Exception{ + mockMvc.perform(get("/beers/find")) + .andExpect(status().isOk()) + .andExpect(view().name("beers/findBeers")) + .andExpect(model().attributeExists("beer")); + } + + @Test + void findBeersWithAnonymous() throws Exception{ + mockMvc.perform(get("/beers/find").with(anonymous())) + .andExpect(status().isOk()) + .andExpect(view().name("beers/findBeers")) + .andExpect(model().attributeExists("beer")); + } + + + + +} \ No newline at end of file diff --git a/src/test/java/guru/sfg/brewery/web/controllers/IndexControllerIT.java b/src/test/java/guru/sfg/brewery/web/controllers/IndexControllerIT.java new file mode 100644 index 000000000..d7d0735d7 --- /dev/null +++ b/src/test/java/guru/sfg/brewery/web/controllers/IndexControllerIT.java @@ -0,0 +1,20 @@ +package guru.sfg.brewery.web.controllers; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; + +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +/** + * Created by jt on 6/13/20. + */ +@WebMvcTest +public class IndexControllerIT extends BaseIT { + + @Test + void testGetIndexSlash() throws Exception{ + mockMvc.perform(get("/" )) + .andExpect(status().isOk()); + } +} \ No newline at end of file diff --git a/src/test/java/guru/sfg/brewery/web/controllers/PasswordEncodingTests.java b/src/test/java/guru/sfg/brewery/web/controllers/PasswordEncodingTests.java new file mode 100644 index 000000000..928e21dbb --- /dev/null +++ b/src/test/java/guru/sfg/brewery/web/controllers/PasswordEncodingTests.java @@ -0,0 +1,30 @@ +package guru.sfg.brewery.web.controllers; + +import org.junit.jupiter.api.Test; +import org.springframework.security.crypto.password.NoOpPasswordEncoder; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.util.DigestUtils; + +/** + * Created by jt on 6/16/20. + */ +public class PasswordEncodingTests { + + static final String PASSWORD = "password"; + + @Test + void testNoOp() { + PasswordEncoder noOp = NoOpPasswordEncoder.getInstance(); + + System.out.println(noOp.encode(PASSWORD)); + } + + @Test + void hashingExample() { + System.out.println(DigestUtils.md5DigestAsHex(PASSWORD.getBytes())); + System.out.println(DigestUtils.md5DigestAsHex(PASSWORD.getBytes())); + + String salted = PASSWORD + "ThisIsMySALTVALUE"; + System.out.println(DigestUtils.md5DigestAsHex(salted.getBytes())); + } +} \ No newline at end of file diff --git a/src/test/java/guru/sfg/brewery/web/controllers/api/BeerRestControllerIT.java b/src/test/java/guru/sfg/brewery/web/controllers/api/BeerRestControllerIT.java new file mode 100644 index 000000000..580d98fcf --- /dev/null +++ b/src/test/java/guru/sfg/brewery/web/controllers/api/BeerRestControllerIT.java @@ -0,0 +1,34 @@ +package guru.sfg.brewery.web.controllers.api; + +import guru.sfg.brewery.web.controllers.BaseIT; +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; + +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +/** + * Created by jt on 6/13/20. + */ +@WebMvcTest +public class BeerRestControllerIT extends BaseIT { + + @Test + void findBeers() throws Exception{ + mockMvc.perform(get("/api/v1/beer/")) + .andExpect(status().isOk()); + + } + + @Test + void findBeerById() throws Exception{ + mockMvc.perform(get("/api/v1/beer/97df0c39-90c4-4ae0-b663-453e8e19c311")) + .andExpect(status().isOk()); + } + + @Test + void findBeerByUPC() throws Exception{ + mockMvc.perform(get("/api/v1/beerUpc/0631234200036")) + .andExpect(status().isOk()); + } +} \ No newline at end of file