Merge branch 'master' into task/JAVA-26765

This commit is contained in:
Harry9656
2023-11-30 00:58:57 +01:00
committed by GitHub
245 changed files with 3138 additions and 383 deletions
+14 -8
View File
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.baeldung.app</groupId>
<artifactId>spring-boot-groovy</artifactId>
@@ -10,9 +10,10 @@
<description>Spring Boot Todo Application with Groovy</description>
<parent>
<groupId>com.baeldung.spring-boot-modules</groupId>
<artifactId>spring-boot-modules</artifactId>
<version>1.0.0-SNAPSHOT</version>
<groupId>com.baeldung</groupId>
<artifactId>parent-boot-3</artifactId>
<version>0.0.1-SNAPSHOT</version>
<relativePath>../../parent-boot-3</relativePath>
</parent>
<dependencies>
@@ -25,7 +26,7 @@
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.codehaus.groovy</groupId>
<groupId>org.apache.groovy</groupId>
<artifactId>groovy</artifactId>
<version>${groovy.version}</version>
</dependency>
@@ -39,6 +40,11 @@
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>io.rest-assured</groupId>
<artifactId>rest-assured</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
@@ -71,8 +77,8 @@
<properties>
<start-class>com.baeldung.springwithgroovy.SpringBootGroovyApplication</start-class>
<groovy.version>3.0.13</groovy.version>
<gmavenplus-plugin.version>1.9.0</gmavenplus-plugin.version>
<groovy.version>4.0.11</groovy.version>
<gmavenplus-plugin.version>3.0.2</gmavenplus-plugin.version>
</properties>
</project>
@@ -1,11 +1,11 @@
package com.baeldung.springwithgroovy.entity
import javax.persistence.Column
import javax.persistence.Entity
import javax.persistence.GeneratedValue
import javax.persistence.GenerationType
import javax.persistence.Id
import javax.persistence.Table
import jakarta.persistence.Column
import jakarta.persistence.Entity
import jakarta.persistence.GeneratedValue
import jakarta.persistence.GenerationType
import jakarta.persistence.Id
import jakarta.persistence.Table
@Entity
@Table(name = 'todo')
@@ -1,9 +1,10 @@
package com.baeldung.caffeine;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
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.web.SecurityFilterChain;
/**
* Because the POM imports Spring Security, we need a simple security
@@ -11,14 +12,14 @@ import org.springframework.security.config.annotation.web.configuration.WebSecur
*/
@Configuration
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
public class SecurityConfiguration {
@Override
protected void configure(HttpSecurity http) throws Exception {
@Bean
public SecurityFilterChain securityFilter(HttpSecurity http) throws Exception {
http.csrf().disable();
http.authorizeRequests()
return http.authorizeRequests()
.antMatchers("/**")
.permitAll();
.permitAll().and().build();
}
}
@@ -49,6 +49,10 @@
<artifactId>commons-configuration</artifactId>
<version>${commons-configuration.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
</dependencies>
<build>
@@ -61,6 +65,14 @@
<layout>JAR</layout>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>9</source>
<target>9</target>
</configuration>
</plugin>
</plugins>
</build>
@@ -0,0 +1,11 @@
package com.baeldung.modifyrequest;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication(scanBasePackages = "com.baeldung.modifyrequest")
public class ModifyRequestApp {
public static void main(String[] args) {
SpringApplication.run(ModifyRequestApp.class, args);
}
}
@@ -0,0 +1,78 @@
package com.baeldung.modifyrequest.aop;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Profile;
import org.springframework.core.MethodParameter;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpInputMessage;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.RequestBodyAdvice;
import java.io.*;
import java.lang.reflect.Type;
import java.nio.charset.StandardCharsets;
@RestControllerAdvice
@Profile("aspectExample")
public class EscapeHtmlAspect implements RequestBodyAdvice {
private static final Logger logger = LoggerFactory.getLogger(EscapeHtmlAspect.class);
@Override
public boolean supports(MethodParameter methodParameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) {
//Apply this to all Controllers
return true;
}
@Override
public HttpInputMessage beforeBodyRead(HttpInputMessage inputMessage, MethodParameter parameter, Type targetType,
Class<? extends HttpMessageConverter<?>> converterType) throws IOException {
logger.info("beforeBodyRead called");
InputStream inputStream = inputMessage.getBody();
return new HttpInputMessage() {
@Override
public InputStream getBody() throws IOException {
return new ByteArrayInputStream(escapeHtml(inputStream).getBytes(StandardCharsets.UTF_8));
}
@Override
public HttpHeaders getHeaders() {
return inputMessage.getHeaders();
}
};
}
@Override
public Object afterBodyRead(Object body, HttpInputMessage inputMessage, MethodParameter parameter, Type targetType,
Class<? extends HttpMessageConverter<?>> converterType) {
// Return the modified object after reading the body
return body;
}
@Override
public Object handleEmptyBody(Object body, HttpInputMessage inputMessage, MethodParameter parameter, Type targetType,
Class<? extends HttpMessageConverter<?>> converterType) {
//return the original body
return body;
}
private String escapeHtml(InputStream inputStream) throws IOException {
StringBuilder stringBuilder = new StringBuilder();
BufferedReader bufferedReader = null;
try (inputStream) {
bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
char[] charBuffer = new char[128];
int bytesRead = -1;
while ((bytesRead = bufferedReader.read(charBuffer)) > 0) {
stringBuilder.append(charBuffer, 0, bytesRead);
}
}
String input = stringBuilder.toString();
// Escape HTML characters
return input.replaceAll("&", "&amp;")
.replaceAll("<", "&lt;")
.replaceAll(">", "&gt;");
}
}
@@ -0,0 +1,26 @@
package com.baeldung.modifyrequest.config;
import com.baeldung.modifyrequest.interceptor.EscapeHtmlRequestInterceptor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
@Profile("interceptorExample")
public class WebMvcConfiguration implements WebMvcConfigurer {
private static final Logger logger = LoggerFactory.getLogger(WebMvcConfiguration.class);
@Override
public void addInterceptors(InterceptorRegistry registry) {
logger.info("addInterceptors() called");
registry.addInterceptor(new EscapeHtmlRequestInterceptor())
.addPathPatterns("/save");
WebMvcConfigurer.super.addInterceptors(registry);
}
}
@@ -0,0 +1,23 @@
package com.baeldung.modifyrequest.controller;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/")
public class UserController {
Logger logger = LoggerFactory.getLogger(UserController.class);
@PostMapping(value = "save")
public ResponseEntity<String> saveUser(@RequestBody String user) {
logger.info("save user info into database");
ResponseEntity<String> responseEntity = new ResponseEntity<>(user, HttpStatus.CREATED);
return responseEntity;
}
}
@@ -0,0 +1,27 @@
package com.baeldung.modifyrequest.filter;
import com.baeldung.modifyrequest.requestwrapper.EscapeHtmlRequestWrapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Profile;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
@Component
@Order(1)
@Profile("filterExample")
public class EscapeHtmlFilter implements Filter {
Logger logger = LoggerFactory.getLogger(EscapeHtmlFilter.class);
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
throws IOException, ServletException {
logger.info("Modify the request");
filterChain.doFilter(new EscapeHtmlRequestWrapper((HttpServletRequest) servletRequest), servletResponse);
}
}
@@ -0,0 +1,19 @@
package com.baeldung.modifyrequest.interceptor;
import com.baeldung.modifyrequest.requestwrapper.EscapeHtmlRequestWrapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class EscapeHtmlRequestInterceptor implements HandlerInterceptor {
private static final Logger logger = LoggerFactory.getLogger(EscapeHtmlRequestInterceptor.class);
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
EscapeHtmlRequestWrapper escapeHtmlRequestWrapper = new EscapeHtmlRequestWrapper(request);
return true;
}
}
@@ -0,0 +1,67 @@
package com.baeldung.modifyrequest.requestwrapper;
import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.*;
public class EscapeHtmlRequestWrapper extends HttpServletRequestWrapper {
private String body = null;
public EscapeHtmlRequestWrapper(HttpServletRequest request) throws IOException {
super(request);
this.body = this.escapeHtml(request);
}
private String escapeHtml(HttpServletRequest request) throws IOException {
StringBuilder stringBuilder = new StringBuilder();
BufferedReader bufferedReader = null;
try (InputStream inputStream = request.getInputStream()) {
bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
char[] charBuffer = new char[128];
int bytesRead = -1;
while ((bytesRead = bufferedReader.read(charBuffer)) > 0) {
stringBuilder.append(charBuffer, 0, bytesRead);
}
}
String input = stringBuilder.toString();
// Escape HTML characters
return input.replaceAll("&", "&amp;")
.replaceAll("<", "&lt;")
.replaceAll(">", "&gt;")
.replaceAll("'", "&#39;");
}
@Override
public ServletInputStream getInputStream() {
final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(body.getBytes());
ServletInputStream servletInputStream = new ServletInputStream() {
@Override
public int read() {
return byteArrayInputStream.read();
}
@Override
public boolean isFinished() {
return false;
}
@Override
public boolean isReady() {
return false;
}
@Override
public void setReadListener(ReadListener listener) {
}
};
return servletInputStream;
}
@Override
public BufferedReader getReader() throws IOException {
return new BufferedReader(new InputStreamReader(this.getInputStream()));
}
}
@@ -0,0 +1,31 @@
@startuml
'https://plantuml.com/sequence-diagram
skinparam sequenceMessageAlign direction
skinparam handwritten true
skinparam sequence {
ParticipantBackgroundColor beige
ParticipantPadding 50
}
autonumber
Browser -[#63b175]> Filter: HTTP Request
activate Browser
activate Filter
Filter -[#63b175]> Filter: doFilter()
Filter -[#63b175]> DispatcherServlet: HTTP Request
activate DispatcherServlet
DispatcherServlet -[#63b175]> Controller: HTTP Request
activate Controller
Controller --[#63b175]> DispatcherServlet: HTTP Response
deactivate Controller
DispatcherServlet --[#63b175]> Filter: HTTP Response
deactivate DispatcherServlet
Filter --[#63b175]> Browser: HTTP Response
deactivate Filter
deactivate Browser
@enduml
@@ -0,0 +1,33 @@
@startuml
'https://plantuml.com/sequence-diagram
skinparam sequenceMessageAlign direction
skinparam handwritten true
skinparam sequence {
ParticipantBackgroundColor beige
ParticipantPadding 50
}
autonumber
Browser -[#63b175]> Filter: Http Request
activate Browser
activate Filter
Filter -[#63b175]> DispatcherServlet: Http Request
activate DispatcherServlet
DispatcherServlet -[#63b175]> Interceptor: Http Request
activate Interceptor
Interceptor -[#63b175]> Interceptor: preHandle()
Interceptor -[#63b175]> Controller: Http Request
activate Controller
Controller --[#63b175]> Interceptor: Http Response
deactivate Controller
Interceptor --[#63b175]> DispatcherServlet: Http Response
deactivate Interceptor
DispatcherServlet --[#63b175]> Filter: Http Response
deactivate DispatcherServlet
Filter --[#63b175]> Browser: Http Response
deactivate Filter
deactivate Browser
@enduml
@@ -0,0 +1,54 @@
package com.baeldung.modifyrequest;
import com.baeldung.modifyrequest.controller.UserController;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.http.MediaType;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.result.MockMvcResultMatchers;
import java.net.URI;
import java.util.Map;
@ExtendWith(SpringExtension.class)
@AutoConfigureMockMvc
@WebMvcTest(UserController.class)
@ActiveProfiles("aspectExample")
public class EscapeHtmlAspectIntegrationTest {
Logger logger = LoggerFactory.getLogger(EscapeHtmlAspectIntegrationTest.class);
@Autowired
private MockMvc mockMvc;
@Test
void givenAspect_whenEscapeHtmlAspect_thenEscapeHtml() throws Exception {
Map<String, String> requestBody = Map.of(
"name", "James Cameron",
"email", "<script>alert()</script>james@gmail.com"
);
Map<String, String> expectedResponseBody = Map.of(
"name", "James Cameron",
"email", "&lt;script&gt;alert()&lt;/script&gt;james@gmail.com"
);
ObjectMapper objectMapper = new ObjectMapper();
mockMvc.perform(MockMvcRequestBuilders.post(URI.create("/save"))
.contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(requestBody)))
.andExpect(MockMvcResultMatchers.status()
.isCreated())
.andExpect(MockMvcResultMatchers.content()
.json(objectMapper.writeValueAsString(expectedResponseBody)));
}
}
@@ -0,0 +1,51 @@
package com.baeldung.modifyrequest;
import com.baeldung.modifyrequest.controller.UserController;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.http.MediaType;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.result.MockMvcResultMatchers;
import java.net.URI;
import java.util.Map;
@ExtendWith(SpringExtension.class)
@AutoConfigureMockMvc
@WebMvcTest(UserController.class)
@ActiveProfiles("filterExample")
public class EscapeHtmlFilterIntegrationTest {
Logger logger = LoggerFactory.getLogger(EscapeHtmlFilterIntegrationTest.class);
@Autowired
private MockMvc mockMvc;
@Test
void givenFilter_whenEscapeHtmlFilter_thenEscapeHtml() throws Exception {
Map<String, String> requestBody = Map.of(
"name", "James Cameron",
"email", "<script>alert()</script>james@gmail.com"
);
Map<String, String> expectedResponseBody = Map.of(
"name", "James Cameron",
"email", "&lt;script&gt;alert()&lt;/script&gt;james@gmail.com"
);
ObjectMapper objectMapper = new ObjectMapper();
mockMvc.perform(MockMvcRequestBuilders.post(URI.create("/save"))
.contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(requestBody))).andExpect(MockMvcResultMatchers.status()
.isCreated()).andExpect(MockMvcResultMatchers.content()
.json(objectMapper.writeValueAsString(expectedResponseBody)));
}
}
@@ -0,0 +1,46 @@
package com.baeldung.modifyrequest;
import com.baeldung.modifyrequest.controller.UserController;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.http.MediaType;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.result.MockMvcResultMatchers;
import java.net.URI;
import java.util.Map;
@ExtendWith(SpringExtension.class)
@AutoConfigureMockMvc
@WebMvcTest(UserController.class)
@ActiveProfiles("interceptorExample")
public class EscapeHtmlInterceptorIntegrationTest {
Logger logger = LoggerFactory.getLogger(EscapeHtmlInterceptorIntegrationTest.class);
@Autowired
private MockMvc mockMvc;
@Test
void givenInterceptor_whenEscapeHtmlInterceptor_thenEscapeHtml() throws Exception {
Map<String, String> requestBody = Map.of(
"name", "James Cameron",
"email", "<script>alert()</script>james@gmail.com"
);
ObjectMapper objectMapper = new ObjectMapper();
mockMvc.perform(MockMvcRequestBuilders.post(URI.create("/save"))
.contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(requestBody))).andExpect(MockMvcResultMatchers.status()
.is4xxClientError());
}
}
@@ -1,14 +1,16 @@
package com.baeldung.spring.boot.management.logging;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.web.SecurityFilterChain;
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf()
.ignoringAntMatchers("/actuator/**");
public class SecurityConfig {
@Bean
public SecurityFilterChain securityFilter(HttpSecurity http) throws Exception {
return http.csrf()
.ignoringAntMatchers("/actuator/**").and()
.build();
}
}