diff --git a/spring-security/getting-started/SecureApplication/pom.xml b/spring-security/getting-started/SecureApplication/pom.xml
index 83528b2..9e10fb7 100644
--- a/spring-security/getting-started/SecureApplication/pom.xml
+++ b/spring-security/getting-started/SecureApplication/pom.xml
@@ -71,6 +71,14 @@
problem-spring-web
0.27.0
+
+
+ org.hamcrest
+ hamcrest-library
+ 2.2
+ test
+
+
diff --git a/spring-security/getting-started/SecureApplication/src/main/java/com/reflectoring/security/config/SecurityConfiguration.java b/spring-security/getting-started/SecureApplication/src/main/java/com/reflectoring/security/config/SecurityConfiguration.java
index 0a0211d..f782dce 100644
--- a/spring-security/getting-started/SecureApplication/src/main/java/com/reflectoring/security/config/SecurityConfiguration.java
+++ b/spring-security/getting-started/SecureApplication/src/main/java/com/reflectoring/security/config/SecurityConfiguration.java
@@ -9,6 +9,7 @@ import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
+import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
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.WebSecurityCustomizer;
diff --git a/spring-security/getting-started/SecureApplication/src/main/resources/application.yml b/spring-security/getting-started/SecureApplication/src/main/resources/application.yml
index 083f3b1..4331107 100644
--- a/spring-security/getting-started/SecureApplication/src/main/resources/application.yml
+++ b/spring-security/getting-started/SecureApplication/src/main/resources/application.yml
@@ -1,7 +1,7 @@
server:
port: 8083
-#spring:
+spring:
#security:
#user:
#name: admin
diff --git a/spring-security/getting-started/SecureApplication/src/test/java/com/reflectoring/security/web/BookControllerTest.java b/spring-security/getting-started/SecureApplication/src/test/java/com/reflectoring/security/web/BookControllerTest.java
new file mode 100644
index 0000000..24838e2
--- /dev/null
+++ b/spring-security/getting-started/SecureApplication/src/test/java/com/reflectoring/security/web/BookControllerTest.java
@@ -0,0 +1,119 @@
+package com.reflectoring.security.web;
+
+import com.reflectoring.security.config.BasicAuthProperties;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.security.test.context.support.WithMockUser;
+import org.springframework.security.test.context.support.WithUserDetails;
+import org.springframework.test.context.ActiveProfiles;
+import org.springframework.test.context.jdbc.Sql;
+import org.springframework.test.context.jdbc.SqlGroup;
+import org.springframework.test.web.servlet.MockMvc;
+
+import static org.hamcrest.Matchers.hasSize;
+import static org.springframework.test.context.jdbc.Sql.ExecutionPhase.BEFORE_TEST_METHOD;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
+import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
+import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.httpBasic;
+
+@SpringBootTest
+@AutoConfigureMockMvc
+@SqlGroup({
+ @Sql(value = "classpath:init/first.sql", executionPhase = BEFORE_TEST_METHOD),
+ @Sql(value = "classpath:init/second.sql", executionPhase = BEFORE_TEST_METHOD)
+})
+public class BookControllerTest {
+
+ @Autowired
+ private MockMvc mockMvc;
+
+ @Test
+ @WithMockUser(username = "bookadmin", roles = {"USER"})
+ void successIfSecurityApplies() throws Exception {
+ mockMvc.perform(get("/library/books")
+ .param("genre", "Fiction")
+ .param("user", "bookadmin")
+ .header("X-Application-Name", "Library"))
+ .andDo(print())
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$", hasSize(3)))
+ ;
+ }
+
+ @Test
+ @WithMockUser(username = "bookadmin", roles = {"ADMIN"})
+ void failsForWrongAuthorization() throws Exception {
+ mockMvc.perform(get("/library/books")
+ .param("genre", "Fiction")
+ .param("user", "bookadmin")
+ .header("X-Application-Name", "Library"))
+ .andDo(print())
+ .andExpect(status().isForbidden())
+ ;
+ }
+
+ @Test
+ void failsIfSecurityApplies() throws Exception {
+ mockMvc.perform(get("/library/books")
+ .param("genre", "Fiction")
+ .param("user", "bookadmin")
+ .header("X-Application-Name", "Library"))
+ .andDo(print())
+ .andExpect(status().isUnauthorized())
+ ;
+ }
+
+ @Test
+ @WithUserDetails(value="bookadmin", userDetailsServiceBeanName="userDetailsService")
+ void testBookWithConfiguredUserDetails() throws Exception {
+ mockMvc.perform(get("/library/books")
+ .param("genre", "Fantasy")
+ .param("user", "bookadmin")
+ .header("X-Application-Name", "Library"))
+ .andDo(print())
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$", hasSize(1)))
+ ;
+ }
+
+ @Test
+ @WithUserDetails(value="bookadmin", userDetailsServiceBeanName="userDetailsService")
+ void failsIfMandatoryHeaderIsMissing() throws Exception {
+ mockMvc.perform(get("/library/books")
+ .param("genre", "Fantasy")
+ .param("user", "bookadmin"))
+ //.header("X-Application-Name", "Library"))
+ .andDo(print())
+ .andExpect(status().isForbidden())
+ ;
+ }
+
+ @Test
+ @WithUserDetails(value="bookadmin", userDetailsServiceBeanName="userDetailsService")
+ void failsIfPreAuthorizeConditionFails() throws Exception {
+ mockMvc.perform(get("/library/books")
+ .param("genre", "Fantasy")
+ .param("user", "bookuser")
+ .header("X-Application-Name", "Library"))
+ .andDo(print())
+ .andExpect(status().isForbidden())
+ ;
+ }
+
+ @Test
+ //@WithUserDetails(value="bookadmin", userDetailsServiceBeanName="userDetailsService")
+ void testBookWithWrongCredentialsUserDetails() throws Exception {
+ mockMvc.perform(get("/library/books")
+ .param("genre", "Fantasy")
+ .param("user", "bookadmin")
+ .header("X-Application-Name", "Library")
+ .with(httpBasic("bookadmin", "password")))
+ .andDo(print())
+ .andExpect(status().isUnauthorized());
+ }
+}
diff --git a/spring-security/getting-started/SecureApplication/src/test/resources/application-test.yml b/spring-security/getting-started/SecureApplication/src/test/resources/application-test.yml
new file mode 100644
index 0000000..399a688
--- /dev/null
+++ b/spring-security/getting-started/SecureApplication/src/test/resources/application-test.yml
@@ -0,0 +1,21 @@
+spring:
+ datasource:
+ driver-class-name: org.hsqldb.jdbc.JDBCDriver
+ url: jdbc:hsqldb:mem:testdb;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE
+ username: sa
+ password:
+ jpa:
+ hibernate:
+ ddl-auto: create-drop
+ defer-datasource-initialization: true
+ show-sql: true
+ properties:
+ hibernate:
+ dialect: H2Dialect
+ format_sql: true
+
+logging:
+ level:
+ org:
+ hibernate:
+ sql: info
\ No newline at end of file
diff --git a/spring-security/getting-started/SecureApplication/src/test/resources/init/first.sql b/spring-security/getting-started/SecureApplication/src/test/resources/init/first.sql
new file mode 100644
index 0000000..f82b525
--- /dev/null
+++ b/spring-security/getting-started/SecureApplication/src/test/resources/init/first.sql
@@ -0,0 +1,3 @@
+TRUNCATE TABLE AUTHOR_BOOK RESTART IDENTITY;
+TRUNCATE TABLE BOOK RESTART IDENTITY;
+TRUNCATE TABLE AUTHOR RESTART IDENTITY;
\ No newline at end of file
diff --git a/spring-security/getting-started/SecureApplication/src/test/resources/init/second.sql b/spring-security/getting-started/SecureApplication/src/test/resources/init/second.sql
new file mode 100644
index 0000000..c1b6632
--- /dev/null
+++ b/spring-security/getting-started/SecureApplication/src/test/resources/init/second.sql
@@ -0,0 +1,5 @@
+INSERT INTO BOOK (id, name, publisher, publication_year, genre) VALUES (1, 'The Kite Runner', 'Riverhead books', '2003', 'Fiction');
+INSERT INTO BOOK (id, name, publisher, publication_year, genre) VALUES (2, 'Exiles', 'Pan Macmillan', '2022', 'Fiction');
+INSERT INTO BOOK (id, name, publisher, publication_year, genre) VALUES (3, 'A Game of Thrones', 'Bantam Spectra', '1996', 'Fiction');
+INSERT INTO BOOK (id, name, publisher, publication_year, genre) VALUES (4, 'American Gods', 'Headline', '2001', 'Fantasy');
+INSERT INTO BOOK (id, name, publisher, publication_year, genre) VALUES (5, 'The Passenger', 'Knopf', '2022', 'Mystery');
\ No newline at end of file