mirror of
https://github.com/spring-projects/spring-boot.git
synced 2024-07-05 00:56:58 +08:00
Remove use of Thymeleaf from smoke tests
Closes gh-28788
This commit is contained in:
parent
03e283a2e6
commit
12244a8edd
@ -76,9 +76,7 @@ dependencies {
|
||||
testImplementation("org.springframework:spring-websocket")
|
||||
testImplementation("org.springframework.hateoas:spring-hateoas")
|
||||
testImplementation("org.springframework.security:spring-security-test")
|
||||
testImplementation("org.thymeleaf:thymeleaf")
|
||||
testImplementation("org.thymeleaf:thymeleaf-spring5")
|
||||
testImplementation("nz.net.ultraq.thymeleaf:thymeleaf-layout-dialect")
|
||||
testImplementation("org.freemarker:freemarker")
|
||||
|
||||
testRuntimeOnly("org.aspectj:aspectjweaver")
|
||||
testRuntimeOnly("org.yaml:snakeyaml")
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2019 the original author or authors.
|
||||
* Copyright 2012-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -64,7 +64,6 @@ class RemoteUrlPropertyExtractorTests {
|
||||
void validUrl() {
|
||||
ApplicationContext context = doTest("http://localhost:8080");
|
||||
assertThat(context.getEnvironment().getProperty("remoteUrl")).isEqualTo("http://localhost:8080");
|
||||
assertThat(context.getEnvironment().getProperty("spring.thymeleaf.cache")).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2020 the original author or authors.
|
||||
* Copyright 2012-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -29,12 +29,11 @@ import org.apache.jasper.EmbeddedServletOptions;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver;
|
||||
|
||||
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.thymeleaf.ThymeleafAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.freemarker.FreeMarkerAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.web.WebProperties;
|
||||
import org.springframework.boot.autoconfigure.web.WebProperties.Resources;
|
||||
import org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration;
|
||||
@ -55,6 +54,7 @@ import org.springframework.context.event.ContextRefreshedEvent;
|
||||
import org.springframework.data.redis.connection.RedisConnectionFactory;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
import org.springframework.web.servlet.view.AbstractTemplateViewResolver;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
@ -83,18 +83,11 @@ class LocalDevToolsAutoConfigurationTests {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void thymeleafCacheIsFalse() throws Exception {
|
||||
this.context = getContext(() -> initializeAndRun(Config.class));
|
||||
SpringResourceTemplateResolver resolver = this.context.getBean(SpringResourceTemplateResolver.class);
|
||||
assertThat(resolver.isCacheable()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
void defaultPropertyCanBeOverriddenFromCommandLine() throws Exception {
|
||||
this.context = getContext(() -> initializeAndRun(Config.class, "--spring.thymeleaf.cache=true"));
|
||||
SpringResourceTemplateResolver resolver = this.context.getBean(SpringResourceTemplateResolver.class);
|
||||
assertThat(resolver.isCacheable()).isTrue();
|
||||
this.context = getContext(() -> initializeAndRun(Config.class, "--spring.freemarker.cache=true"));
|
||||
AbstractTemplateViewResolver resolver = this.context.getBean(AbstractTemplateViewResolver.class);
|
||||
assertThat(resolver.isCache()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -103,8 +96,8 @@ class LocalDevToolsAutoConfigurationTests {
|
||||
System.setProperty("user.home", new File("src/test/resources/user-home").getAbsolutePath());
|
||||
try {
|
||||
this.context = getContext(() -> initializeAndRun(Config.class));
|
||||
SpringResourceTemplateResolver resolver = this.context.getBean(SpringResourceTemplateResolver.class);
|
||||
assertThat(resolver.isCacheable()).isTrue();
|
||||
AbstractTemplateViewResolver resolver = this.context.getBean(AbstractTemplateViewResolver.class);
|
||||
assertThat(resolver.isCache()).isTrue();
|
||||
}
|
||||
finally {
|
||||
System.setProperty("user.home", userHome);
|
||||
@ -267,7 +260,6 @@ class LocalDevToolsAutoConfigurationTests {
|
||||
|
||||
private Map<String, Object> getDefaultProperties(Map<String, Object> specifiedProperties) {
|
||||
Map<String, Object> properties = new HashMap<>();
|
||||
properties.put("spring.thymeleaf.check-template-location", false);
|
||||
properties.put("spring.devtools.livereload.port", 0);
|
||||
properties.put("server.port", 0);
|
||||
properties.putAll(specifiedProperties);
|
||||
@ -276,14 +268,14 @@ class LocalDevToolsAutoConfigurationTests {
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@Import({ ServletWebServerFactoryAutoConfiguration.class, LocalDevToolsAutoConfiguration.class,
|
||||
ThymeleafAutoConfiguration.class })
|
||||
FreeMarkerAutoConfiguration.class })
|
||||
static class Config {
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ImportAutoConfiguration({ ServletWebServerFactoryAutoConfiguration.class, LocalDevToolsAutoConfiguration.class,
|
||||
ThymeleafAutoConfiguration.class })
|
||||
FreeMarkerAutoConfiguration.class })
|
||||
static class ConfigWithMockLiveReload {
|
||||
|
||||
@Bean
|
||||
|
@ -1 +1 @@
|
||||
spring.thymeleaf.cache=true
|
||||
spring.freemarker.cache=true
|
||||
|
@ -13,7 +13,6 @@ configurations {
|
||||
dependencies {
|
||||
developmentOnly project(":spring-boot-project:spring-boot-devtools")
|
||||
|
||||
implementation(project(":spring-boot-project:spring-boot-starters:spring-boot-starter-thymeleaf"))
|
||||
implementation(project(":spring-boot-project:spring-boot-starters:spring-boot-starter-web"))
|
||||
|
||||
testImplementation(project(":spring-boot-project:spring-boot-starters:spring-boot-starter-test"))
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2019 the original author or authors.
|
||||
* Copyright 2012-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -16,15 +16,9 @@
|
||||
|
||||
package smoketest.devtools;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import javax.servlet.http.HttpSession;
|
||||
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.ModelMap;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
|
||||
@Controller
|
||||
public class MyController {
|
||||
@ -34,15 +28,4 @@ public class MyController {
|
||||
Thread.sleep(5000);
|
||||
}
|
||||
|
||||
@GetMapping("/")
|
||||
public ModelAndView get(HttpSession session) {
|
||||
Object sessionVar = session.getAttribute("var");
|
||||
if (sessionVar == null) {
|
||||
sessionVar = new Date();
|
||||
session.setAttribute("var", sessionVar);
|
||||
}
|
||||
ModelMap model = new ModelMap("message", Message.MESSAGE).addAttribute("sessionVar", sessionVar);
|
||||
return new ModelAndView("hello", model);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,23 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html xmlns:th="https://www.thymeleaf.org">
|
||||
<head>
|
||||
<title>Hello</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1 th:text="${message}">Header</h1>
|
||||
<div class="content">
|
||||
<h2 th:text="${sessionVar}">Session Var</h2>
|
||||
Lorem ipsum dolor sit amet,
|
||||
consectetur adipiscing elit. Cras ut fringilla augue, quis dictum
|
||||
turpis. Sed tincidunt mi vel euismod viverra. Nulla facilisi.
|
||||
Suspendisse mauris dolor, egestas ac leo at, porttitor ullamcorper
|
||||
leo. Suspendisse consequat, justo ut rutrum interdum, nibh massa
|
||||
semper dui, id sagittis tellus lectus at nibh. Etiam at scelerisque
|
||||
nisi. Quisque vel eros tempor, fermentum sapien sed, gravida neque.
|
||||
Fusce interdum sed dolor a semper. Morbi porta mauris a velit laoreet
|
||||
viverra. Praesent et tellus vehicula, sagittis mi quis, faucibus urna.
|
||||
Ut diam tortor, vehicula eget aliquam eget, elementum a odio. Fusce at
|
||||
nisl sapien. Suspendisse potenti.
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
@ -8,7 +8,6 @@ description = "Spring Boot web method security smoke test"
|
||||
dependencies {
|
||||
implementation(project(":spring-boot-project:spring-boot-starters:spring-boot-starter-actuator"))
|
||||
implementation(project(":spring-boot-project:spring-boot-starters:spring-boot-starter-security"))
|
||||
implementation(project(":spring-boot-project:spring-boot-starters:spring-boot-starter-thymeleaf"))
|
||||
implementation(project(":spring-boot-project:spring-boot-starters:spring-boot-starter-web"))
|
||||
|
||||
testImplementation(project(":spring-boot-project:spring-boot-starters:spring-boot-starter-test"))
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2020 the original author or authors.
|
||||
* Copyright 2012-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -16,9 +16,6 @@
|
||||
|
||||
package smoketest.security.method;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.boot.actuate.autoconfigure.security.servlet.EndpointRequest;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.boot.builder.SpringApplicationBuilder;
|
||||
@ -32,7 +29,6 @@ import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.core.userdetails.User;
|
||||
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
|
||||
import org.springframework.security.web.SecurityFilterChain;
|
||||
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
|
||||
@ -71,17 +67,11 @@ public class SampleMethodSecurityApplication implements WebMvcConfigurer {
|
||||
protected static class ApplicationSecurity {
|
||||
|
||||
@Bean
|
||||
SecurityFilterChain appSecurity(HttpSecurity http) throws Exception {
|
||||
http.authorizeRequests((requests) -> {
|
||||
requests.antMatchers("/login").permitAll();
|
||||
requests.anyRequest().fullyAuthenticated();
|
||||
});
|
||||
http.formLogin((form) -> {
|
||||
form.loginPage("/login");
|
||||
form.failureUrl("/login?error");
|
||||
});
|
||||
http.logout((logout) -> logout.logoutRequestMatcher(new AntPathRequestMatcher("/logout")));
|
||||
http.exceptionHandling((exceptions) -> exceptions.accessDeniedPage("/access?error"));
|
||||
SecurityFilterChain configure(HttpSecurity http) throws Exception {
|
||||
http.csrf().disable();
|
||||
http.authorizeRequests((requests) -> requests.anyRequest().fullyAuthenticated());
|
||||
http.formLogin((form) -> form.loginPage("/login").permitAll());
|
||||
http.exceptionHandling((exceptions) -> exceptions.accessDeniedPage("/access"));
|
||||
return http.build();
|
||||
}
|
||||
|
||||
@ -93,6 +83,7 @@ public class SampleMethodSecurityApplication implements WebMvcConfigurer {
|
||||
|
||||
@Bean
|
||||
SecurityFilterChain actuatorSecurity(HttpSecurity http) throws Exception {
|
||||
http.csrf().disable();
|
||||
http.requestMatcher(EndpointRequest.toAnyEndpoint());
|
||||
http.authorizeRequests((requests) -> requests.anyRequest().authenticated());
|
||||
http.httpBasic();
|
||||
@ -106,10 +97,7 @@ public class SampleMethodSecurityApplication implements WebMvcConfigurer {
|
||||
|
||||
@GetMapping("/")
|
||||
@Secured("ROLE_ADMIN")
|
||||
public String home(Map<String, Object> model) {
|
||||
model.put("message", "Hello World");
|
||||
model.put("title", "Hello Home");
|
||||
model.put("date", new Date());
|
||||
public String home() {
|
||||
return "home";
|
||||
}
|
||||
|
||||
|
@ -1,3 +1,4 @@
|
||||
spring.thymeleaf.cache: false
|
||||
logging.level.org.springframework.security: INFO
|
||||
logging.level.org.springframework.security=INFO
|
||||
management.endpoints.web.exposure.include=*
|
||||
spring.mvc.view.prefix=/templates/
|
||||
spring.mvc.view.suffix=.html
|
||||
|
File diff suppressed because one or more lines are too long
@ -1,27 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html xmlns:th="https://www.thymeleaf.org">
|
||||
<head>
|
||||
<title>Error</title>
|
||||
<link rel="stylesheet" th:href="@{/css/bootstrap.min.css}"
|
||||
href="../../css/bootstrap.min.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<div class="navbar">
|
||||
<div class="navbar-inner">
|
||||
<a class="brand" href="https://www.thymeleaf.org"> Thymeleaf -
|
||||
Plain </a>
|
||||
<ul class="nav">
|
||||
<li><a th:href="@{/}" href="home.html"> Home </a></li>
|
||||
<li><a th:href="@{/logout}" href="logout"> Logout </a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<h1 th:text="${title}">Title</h1>
|
||||
<p class="alert alert-error">Access denied:
|
||||
you do not have permission for that resource</p>
|
||||
<div th:text="${message}">Fake content</div>
|
||||
<div>Please contact the operator with the above information.</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
@ -1,32 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html xmlns:th="https://www.thymeleaf.org">
|
||||
<head>
|
||||
<title>Error</title>
|
||||
<link rel="stylesheet" th:href="@{/css/bootstrap.min.css}"
|
||||
href="../../css/bootstrap.min.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<div class="navbar">
|
||||
<div class="navbar-inner">
|
||||
<a class="brand" href="https://www.thymeleaf.org"> Thymeleaf -
|
||||
Plain </a>
|
||||
<ul class="nav">
|
||||
<li><a th:href="@{/}" href="home.html"> Home </a></li>
|
||||
<li><a th:href="@{/logout}" href="logout"> Logout </a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<h1 th:text="${title}">Title</h1>
|
||||
<div id="created" th:text="${#dates.format(timestamp)}">July 11,
|
||||
2012 2:17:16 PM CDT</div>
|
||||
<div>
|
||||
There was an unexpected error (type=<span th:text="${error}">Bad</span>, status=<span th:text="${status}">500</span>).
|
||||
</div>
|
||||
<div th:text="${message}">Fake content</div>
|
||||
<div>
|
||||
Please contact the operator with the above information.
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
@ -1,26 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html xmlns:th="https://www.thymeleaf.org">
|
||||
<head>
|
||||
<title th:text="${title}">Title</title>
|
||||
<link rel="stylesheet" th:href="@{/css/bootstrap.min.css}"
|
||||
href="../../css/bootstrap.min.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<div class="navbar">
|
||||
<div class="navbar-inner">
|
||||
<a class="brand" href="https://www.thymeleaf.org"> Thymeleaf -
|
||||
Plain </a>
|
||||
<ul class="nav">
|
||||
<li><a th:href="@{/}" href="home.html"> Home </a></li>
|
||||
<li><a th:href="@{/logout}" href="logout"> Logout </a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<h1 th:text="${title}">Title</h1>
|
||||
<div th:text="${message}">Fake content</div>
|
||||
<div id="created" th:text="${#dates.format(date)}">July 11,
|
||||
2012 2:17:16 PM CDT</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
@ -1,34 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html xmlns:th="https://www.thymeleaf.org">
|
||||
<head>
|
||||
<title>Login</title>
|
||||
<link rel="stylesheet" th:href="@{/css/bootstrap.min.css}"
|
||||
href="../../css/bootstrap.min.css" />
|
||||
</head>
|
||||
<body onload="document.f.username.focus();">
|
||||
<div class="container">
|
||||
<div class="navbar">
|
||||
<div class="navbar-inner">
|
||||
<a class="brand" href="https://www.thymeleaf.org"> Thymeleaf -
|
||||
Plain </a>
|
||||
<ul class="nav">
|
||||
<li><a th:href="@{/}" href="home.html"> Home </a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class="content">
|
||||
<p th:if="${param.logout}" class="alert">You have been logged out</p>
|
||||
<p th:if="${param.error}" class="alert alert-error">There was an error, please try again</p>
|
||||
<h2>Login with Username and Password</h2>
|
||||
<form name="form" th:action="@{/login}" action="/login" method="POST">
|
||||
<fieldset>
|
||||
<input type="text" name="username" value="" placeholder="Username" />
|
||||
<input type="password" name="password" placeholder="Password" />
|
||||
</fieldset>
|
||||
<input type="submit" id="login" value="Login"
|
||||
class="btn btn-primary" />
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
@ -0,0 +1,11 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Error</title>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<p>Access denied: you do not have permission for that resource</p>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
@ -0,0 +1,11 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Home</title>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<p>Home</p>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
@ -0,0 +1,20 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Login</title>
|
||||
</head>
|
||||
<body">
|
||||
<div class="container">
|
||||
<div class="content">
|
||||
<h2>Login with Username and Password</h2>
|
||||
<form name="form" action="/login" method="POST">
|
||||
<fieldset>
|
||||
<input type="text" name="username" value="" placeholder="Username" />
|
||||
<input type="password" name="password" placeholder="Password" />
|
||||
</fieldset>
|
||||
<input type="submit" id="login" value="Login" class="btn btn-primary" />
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2019 the original author or authors.
|
||||
* Copyright 2012-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -16,9 +16,7 @@
|
||||
|
||||
package smoketest.security.method;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.Collections;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
@ -43,6 +41,7 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
* Basic integration tests for demo application.
|
||||
*
|
||||
* @author Dave Syer
|
||||
* @author Scott Frederick
|
||||
*/
|
||||
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
|
||||
class SampleMethodSecurityApplicationTests {
|
||||
@ -56,35 +55,32 @@ class SampleMethodSecurityApplicationTests {
|
||||
@Test
|
||||
void testHome() {
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.setAccept(Arrays.asList(MediaType.TEXT_HTML));
|
||||
headers.setAccept(Collections.singletonList(MediaType.TEXT_HTML));
|
||||
ResponseEntity<String> entity = this.restTemplate.exchange("/", HttpMethod.GET, new HttpEntity<Void>(headers),
|
||||
String.class);
|
||||
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);
|
||||
assertThat(entity.getBody()).contains("<title>Login");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testLogin() {
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.setAccept(Arrays.asList(MediaType.TEXT_HTML));
|
||||
headers.setAccept(Collections.singletonList(MediaType.TEXT_HTML));
|
||||
MultiValueMap<String, String> form = new LinkedMultiValueMap<>();
|
||||
form.set("username", "admin");
|
||||
form.set("password", "admin");
|
||||
getCsrf(form, headers);
|
||||
ResponseEntity<String> entity = this.restTemplate.exchange("/login", HttpMethod.POST,
|
||||
new HttpEntity<>(form, headers), String.class);
|
||||
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.FOUND);
|
||||
assertThat(entity.getHeaders().getLocation().toString()).isEqualTo("http://localhost:" + this.port + "/");
|
||||
assertThat(entity.getHeaders().getLocation().toString()).endsWith(this.port + "/");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testDenied() {
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.setAccept(Arrays.asList(MediaType.TEXT_HTML));
|
||||
headers.setAccept(Collections.singletonList(MediaType.TEXT_HTML));
|
||||
MultiValueMap<String, String> form = new LinkedMultiValueMap<>();
|
||||
form.set("username", "user");
|
||||
form.set("password", "user");
|
||||
getCsrf(form, headers);
|
||||
ResponseEntity<String> entity = this.restTemplate.exchange("/login", HttpMethod.POST,
|
||||
new HttpEntity<>(form, headers), String.class);
|
||||
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.FOUND);
|
||||
@ -99,7 +95,7 @@ class SampleMethodSecurityApplicationTests {
|
||||
@Test
|
||||
void testManagementProtected() {
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.setAccept(Arrays.asList(MediaType.APPLICATION_JSON));
|
||||
headers.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON));
|
||||
ResponseEntity<String> entity = this.restTemplate.exchange("/actuator/beans", HttpMethod.GET,
|
||||
new HttpEntity<Void>(headers), String.class);
|
||||
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.UNAUTHORIZED);
|
||||
@ -118,14 +114,4 @@ class SampleMethodSecurityApplicationTests {
|
||||
}
|
||||
}
|
||||
|
||||
private void getCsrf(MultiValueMap<String, String> form, HttpHeaders headers) {
|
||||
ResponseEntity<String> page = this.restTemplate.getForEntity("/login", String.class);
|
||||
String cookie = page.getHeaders().getFirst("Set-Cookie");
|
||||
headers.set("Cookie", cookie);
|
||||
String body = page.getBody();
|
||||
Matcher matcher = Pattern.compile("(?s).*name=\"_csrf\".*?value=\"([^\"]+).*").matcher(body);
|
||||
matcher.find();
|
||||
form.set("_csrf", matcher.group(1));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -7,7 +7,6 @@ description = "Spring Boot web secure custom smoke test"
|
||||
|
||||
dependencies {
|
||||
implementation(project(":spring-boot-project:spring-boot-starters:spring-boot-starter-security"))
|
||||
implementation(project(":spring-boot-project:spring-boot-starters:spring-boot-starter-thymeleaf"))
|
||||
implementation(project(":spring-boot-project:spring-boot-starters:spring-boot-starter-web"))
|
||||
|
||||
testImplementation(project(":spring-boot-project:spring-boot-starters:spring-boot-starter-test"))
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2020 the original author or authors.
|
||||
* Copyright 2012-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -16,41 +16,21 @@
|
||||
|
||||
package smoketest.web.secure.custom;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.boot.builder.SpringApplicationBuilder;
|
||||
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.configurers.LogoutConfigurer;
|
||||
import org.springframework.security.web.SecurityFilterChain;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||
|
||||
@SpringBootApplication
|
||||
@Controller
|
||||
public class SampleWebSecureCustomApplication implements WebMvcConfigurer {
|
||||
|
||||
@GetMapping("/")
|
||||
public String home(Map<String, Object> model) {
|
||||
model.put("message", "Hello World");
|
||||
model.put("title", "Hello Home");
|
||||
model.put("date", new Date());
|
||||
return "home";
|
||||
}
|
||||
|
||||
@RequestMapping("/foo")
|
||||
public String foo() {
|
||||
throw new RuntimeException("Expected exception in controller");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addViewControllers(ViewControllerRegistry registry) {
|
||||
registry.addViewController("/").setViewName("home");
|
||||
registry.addViewController("/login").setViewName("login");
|
||||
}
|
||||
|
||||
@ -63,15 +43,9 @@ public class SampleWebSecureCustomApplication implements WebMvcConfigurer {
|
||||
|
||||
@Bean
|
||||
SecurityFilterChain configure(HttpSecurity http) throws Exception {
|
||||
http.authorizeRequests((requests) -> {
|
||||
requests.antMatchers("/css/**").permitAll();
|
||||
requests.anyRequest().fullyAuthenticated();
|
||||
});
|
||||
http.formLogin((form) -> {
|
||||
form.loginPage("/login");
|
||||
form.failureUrl("/login?error").permitAll();
|
||||
});
|
||||
http.logout(LogoutConfigurer::permitAll);
|
||||
http.csrf().disable();
|
||||
http.authorizeRequests((requests) -> requests.anyRequest().fullyAuthenticated());
|
||||
http.formLogin((form) -> form.loginPage("/login").permitAll());
|
||||
return http.build();
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
spring.thymeleaf.cache: false
|
||||
logging.level.org.springframework.security: INFO
|
||||
logging.level.org.springframework.security=INFO
|
||||
spring.security.user.name=user
|
||||
spring.security.user.password=password
|
||||
spring.mvc.view.prefix=/templates/
|
||||
spring.mvc.view.suffix=.html
|
File diff suppressed because one or more lines are too long
@ -1,32 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html xmlns:th="https://www.thymeleaf.org">
|
||||
<head>
|
||||
<title>Error</title>
|
||||
<link rel="stylesheet" th:href="@{/css/bootstrap.min.css}"
|
||||
href="../../css/bootstrap.min.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<div class="navbar">
|
||||
<div class="navbar-inner">
|
||||
<a class="brand" href="https://www.thymeleaf.org"> Thymeleaf -
|
||||
Plain </a>
|
||||
<ul class="nav">
|
||||
<li><a th:href="@{/}" href="home.html"> Home </a></li>
|
||||
<li><a th:href="@{/logout}" href="logout"> Logout </a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<h1 th:text="${title}">Title</h1>
|
||||
<div id="created" th:text="${#dates.format(timestamp)}">July 11,
|
||||
2012 2:17:16 PM CDT</div>
|
||||
<div>
|
||||
There was an unexpected error (type=<span th:text="${error}">Bad</span>, status=<span th:text="${status}">500</span>).
|
||||
</div>
|
||||
<div th:text="${message}">Fake content</div>
|
||||
<div>
|
||||
Please contact the operator with the above information.
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
@ -1,28 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html xmlns:th="https://www.thymeleaf.org">
|
||||
<head>
|
||||
<title th:text="${title}">Title</title>
|
||||
<link rel="stylesheet" th:href="@{/css/bootstrap.min.css}"
|
||||
href="../../css/bootstrap.min.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<div class="navbar">
|
||||
<div class="navbar-inner">
|
||||
<a class="brand" href="https://www.thymeleaf.org"> Thymeleaf -
|
||||
Plain </a>
|
||||
<ul class="nav">
|
||||
<li><a th:href="@{/}" href="home.html"> Home </a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<h1 th:text="${title}">Title</h1>
|
||||
<div th:text="${message}">Fake content</div>
|
||||
<div id="created" th:text="${#dates.format(date)}">July 11,
|
||||
2012 2:17:16 PM CDT</div>
|
||||
<form th:action="@{/logout}" method="post">
|
||||
<input type="submit" value="Sign Out"/>
|
||||
</form>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
@ -1,34 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html xmlns:th="https://www.thymeleaf.org">
|
||||
<head>
|
||||
<title>Login</title>
|
||||
<link rel="stylesheet" th:href="@{/css/bootstrap.min.css}"
|
||||
href="../../css/bootstrap.min.css" />
|
||||
</head>
|
||||
<body onload="document.f.username.focus();">
|
||||
<div class="container">
|
||||
<div class="navbar">
|
||||
<div class="navbar-inner">
|
||||
<a class="brand" href="https://www.thymeleaf.org"> Thymeleaf -
|
||||
Plain </a>
|
||||
<ul class="nav">
|
||||
<li><a th:href="@{/}" href="home.html"> Home </a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class="content">
|
||||
<p th:if="${param.logout}" class="alert">You have been logged out</p>
|
||||
<p th:if="${param.error}" class="alert alert-error">There was an error, please try again</p>
|
||||
<h2>Login with Username and Password</h2>
|
||||
<form name="form" th:action="@{/login}" action="/login" method="POST">
|
||||
<fieldset>
|
||||
<input type="text" name="username" value="" placeholder="Username" />
|
||||
<input type="password" name="password" placeholder="Password" />
|
||||
</fieldset>
|
||||
<input type="submit" id="login" value="Login"
|
||||
class="btn btn-primary" />
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
@ -0,0 +1,11 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Home</title>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<p>Home</p>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
@ -0,0 +1,20 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Login</title>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<div class="content">
|
||||
<h2>Login with Username and Password</h2>
|
||||
<form name="form" action="/login" method="POST">
|
||||
<fieldset>
|
||||
<input type="text" name="username" value="" placeholder="Username" />
|
||||
<input type="password" name="password" placeholder="Password" />
|
||||
</fieldset>
|
||||
<input type="submit" id="login" value="Login" class="btn btn-primary" />
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2019 the original author or authors.
|
||||
* Copyright 2012-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -16,9 +16,7 @@
|
||||
|
||||
package smoketest.web.secure.custom;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.Collections;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
@ -42,6 +40,7 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
* Basic integration tests for demo application.
|
||||
*
|
||||
* @author Dave Syer
|
||||
* @author Scott Frederick
|
||||
*/
|
||||
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
|
||||
class SampleWebSecureCustomApplicationTests {
|
||||
@ -55,7 +54,7 @@ class SampleWebSecureCustomApplicationTests {
|
||||
@Test
|
||||
void testHome() {
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.setAccept(Arrays.asList(MediaType.TEXT_HTML));
|
||||
headers.setAccept(Collections.singletonList(MediaType.TEXT_HTML));
|
||||
ResponseEntity<String> entity = this.restTemplate.exchange("/", HttpMethod.GET, new HttpEntity<Void>(headers),
|
||||
String.class);
|
||||
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.FOUND);
|
||||
@ -65,17 +64,17 @@ class SampleWebSecureCustomApplicationTests {
|
||||
@Test
|
||||
void testLoginPage() {
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.setAccept(Arrays.asList(MediaType.TEXT_HTML));
|
||||
headers.setAccept(Collections.singletonList(MediaType.TEXT_HTML));
|
||||
ResponseEntity<String> entity = this.restTemplate.exchange("/login", HttpMethod.GET,
|
||||
new HttpEntity<Void>(headers), String.class);
|
||||
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);
|
||||
assertThat(entity.getBody()).contains("_csrf");
|
||||
assertThat(entity.getBody()).contains("<title>Login</title>");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testLogin() {
|
||||
HttpHeaders headers = getHeaders();
|
||||
headers.setAccept(Arrays.asList(MediaType.TEXT_HTML));
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.setAccept(Collections.singletonList(MediaType.TEXT_HTML));
|
||||
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
|
||||
MultiValueMap<String, String> form = new LinkedMultiValueMap<>();
|
||||
form.set("username", "user");
|
||||
@ -84,27 +83,6 @@ class SampleWebSecureCustomApplicationTests {
|
||||
new HttpEntity<>(form, headers), String.class);
|
||||
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.FOUND);
|
||||
assertThat(entity.getHeaders().getLocation().toString()).endsWith(this.port + "/");
|
||||
assertThat(entity.getHeaders().get("Set-Cookie")).isNotNull();
|
||||
}
|
||||
|
||||
private HttpHeaders getHeaders() {
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
ResponseEntity<String> page = this.restTemplate.getForEntity("/login", String.class);
|
||||
assertThat(page.getStatusCode()).isEqualTo(HttpStatus.OK);
|
||||
String cookie = page.getHeaders().getFirst("Set-Cookie");
|
||||
headers.set("Cookie", cookie);
|
||||
Pattern pattern = Pattern.compile("(?s).*name=\"_csrf\".*?value=\"([^\"]+).*");
|
||||
Matcher matcher = pattern.matcher(page.getBody());
|
||||
assertThat(matcher.matches()).as(page.getBody()).isTrue();
|
||||
headers.set("X-CSRF-TOKEN", matcher.group(1));
|
||||
return headers;
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCss() {
|
||||
ResponseEntity<String> entity = this.restTemplate.getForEntity("/css/bootstrap.min.css", String.class);
|
||||
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);
|
||||
assertThat(entity.getBody()).contains("body");
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -8,7 +8,6 @@ description = "Spring Boot web secure JDBC smoke test"
|
||||
dependencies {
|
||||
implementation(project(":spring-boot-project:spring-boot-starters:spring-boot-starter-jdbc"))
|
||||
implementation(project(":spring-boot-project:spring-boot-starters:spring-boot-starter-security"))
|
||||
implementation(project(":spring-boot-project:spring-boot-starters:spring-boot-starter-thymeleaf"))
|
||||
implementation(project(":spring-boot-project:spring-boot-starters:spring-boot-starter-web"))
|
||||
|
||||
runtimeOnly("com.h2database:h2")
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2020 the original author or authors.
|
||||
* Copyright 2012-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -16,9 +16,6 @@
|
||||
|
||||
package smoketest.web.secure.jdbc;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
@ -26,34 +23,17 @@ import org.springframework.boot.builder.SpringApplicationBuilder;
|
||||
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.configurers.LogoutConfigurer;
|
||||
import org.springframework.security.provisioning.JdbcUserDetailsManager;
|
||||
import org.springframework.security.web.SecurityFilterChain;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||
|
||||
@SpringBootApplication
|
||||
@Controller
|
||||
public class SampleWebSecureJdbcApplication implements WebMvcConfigurer {
|
||||
|
||||
@GetMapping("/")
|
||||
public String home(Map<String, Object> model) {
|
||||
model.put("message", "Hello World");
|
||||
model.put("title", "Hello Home");
|
||||
model.put("date", new Date());
|
||||
return "home";
|
||||
}
|
||||
|
||||
@RequestMapping("/foo")
|
||||
public String foo() {
|
||||
throw new RuntimeException("Expected exception in controller");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addViewControllers(ViewControllerRegistry registry) {
|
||||
registry.addViewController("/").setViewName("home");
|
||||
registry.addViewController("/login").setViewName("login");
|
||||
}
|
||||
|
||||
@ -66,15 +46,9 @@ public class SampleWebSecureJdbcApplication implements WebMvcConfigurer {
|
||||
|
||||
@Bean
|
||||
SecurityFilterChain configure(HttpSecurity http) throws Exception {
|
||||
http.authorizeRequests((requests) -> {
|
||||
requests.antMatchers("/css/**").permitAll();
|
||||
requests.anyRequest().fullyAuthenticated();
|
||||
});
|
||||
http.formLogin((form) -> {
|
||||
form.loginPage("/login");
|
||||
form.failureUrl("/login?error").permitAll();
|
||||
});
|
||||
http.logout(LogoutConfigurer::permitAll);
|
||||
http.csrf().disable();
|
||||
http.authorizeRequests((requests) -> requests.anyRequest().fullyAuthenticated());
|
||||
http.formLogin((form) -> form.loginPage("/login").permitAll());
|
||||
return http.build();
|
||||
}
|
||||
|
||||
|
@ -1,3 +1,3 @@
|
||||
debug: true
|
||||
spring.thymeleaf.cache: false
|
||||
logging.level.org.springframework.security: INFO
|
||||
logging.level.org.springframework.security=INFO
|
||||
spring.mvc.view.prefix=/templates/
|
||||
spring.mvc.view.suffix=.html
|
File diff suppressed because one or more lines are too long
@ -1,32 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html xmlns:th="https://www.thymeleaf.org">
|
||||
<head>
|
||||
<title>Error</title>
|
||||
<link rel="stylesheet" th:href="@{/css/bootstrap.min.css}"
|
||||
href="../../css/bootstrap.min.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<div class="navbar">
|
||||
<div class="navbar-inner">
|
||||
<a class="brand" href="https://www.thymeleaf.org"> Thymeleaf -
|
||||
Plain </a>
|
||||
<ul class="nav">
|
||||
<li><a th:href="@{/}" href="home.html"> Home </a></li>
|
||||
<li><a th:href="@{/logout}" href="logout"> Logout </a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<h1 th:text="${title}">Title</h1>
|
||||
<div id="created" th:text="${#dates.format(timestamp)}">July 11,
|
||||
2012 2:17:16 PM CDT</div>
|
||||
<div>
|
||||
There was an unexpected error (type=<span th:text="${error}">Bad</span>, status=<span th:text="${status}">500</span>).
|
||||
</div>
|
||||
<div th:text="${message}">Fake content</div>
|
||||
<div>
|
||||
Please contact the operator with the above information.
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
@ -1,28 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html xmlns:th="https://www.thymeleaf.org">
|
||||
<head>
|
||||
<title th:text="${title}">Title</title>
|
||||
<link rel="stylesheet" th:href="@{/css/bootstrap.min.css}"
|
||||
href="../../css/bootstrap.min.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<div class="navbar">
|
||||
<div class="navbar-inner">
|
||||
<a class="brand" href="https://www.thymeleaf.org"> Thymeleaf -
|
||||
Plain </a>
|
||||
<ul class="nav">
|
||||
<li><a th:href="@{/}" href="home.html"> Home </a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<h1 th:text="${title}">Title</h1>
|
||||
<div th:text="${message}">Fake content</div>
|
||||
<div id="created" th:text="${#dates.format(date)}">July 11,
|
||||
2012 2:17:16 PM CDT</div>
|
||||
<form th:action="@{/logout}" method="post">
|
||||
<input type="submit" value="Sign Out"/>
|
||||
</form>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
@ -1,34 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html xmlns:th="https://www.thymeleaf.org">
|
||||
<head>
|
||||
<title>Login</title>
|
||||
<link rel="stylesheet" th:href="@{/css/bootstrap.min.css}"
|
||||
href="../../css/bootstrap.min.css" />
|
||||
</head>
|
||||
<body onload="document.f.username.focus();">
|
||||
<div class="container">
|
||||
<div class="navbar">
|
||||
<div class="navbar-inner">
|
||||
<a class="brand" href="https://www.thymeleaf.org"> Thymeleaf -
|
||||
Plain </a>
|
||||
<ul class="nav">
|
||||
<li><a th:href="@{/}" href="home.html"> Home </a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class="content">
|
||||
<p th:if="${param.logout}" class="alert">You have been logged out</p>
|
||||
<p th:if="${param.error}" class="alert alert-error">There was an error, please try again</p>
|
||||
<h2>Login with Username and Password</h2>
|
||||
<form name="form" th:action="@{/login}" action="/login" method="POST">
|
||||
<fieldset>
|
||||
<input type="text" name="username" value="" placeholder="Username" />
|
||||
<input type="password" name="password" placeholder="Password" />
|
||||
</fieldset>
|
||||
<input type="submit" id="login" value="Login"
|
||||
class="btn btn-primary" />
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
@ -0,0 +1,11 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Home</title>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<p>Home</p>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
@ -0,0 +1,20 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Login</title>
|
||||
</head>
|
||||
<body">
|
||||
<div class="container">
|
||||
<div class="content">
|
||||
<h2>Login with Username and Password</h2>
|
||||
<form name="form" action="/login" method="POST">
|
||||
<fieldset>
|
||||
<input type="text" name="username" value="" placeholder="Username" />
|
||||
<input type="password" name="password" placeholder="Password" />
|
||||
</fieldset>
|
||||
<input type="submit" id="login" value="Login" class="btn btn-primary" />
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2019 the original author or authors.
|
||||
* Copyright 2012-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -16,9 +16,7 @@
|
||||
|
||||
package smoketest.web.secure.jdbc;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.Collections;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
@ -42,6 +40,7 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
* Basic integration tests for demo application.
|
||||
*
|
||||
* @author Dave Syer
|
||||
* @author Scott Frederick
|
||||
*/
|
||||
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
|
||||
class SampleWebSecureJdbcApplicationTests {
|
||||
@ -55,7 +54,7 @@ class SampleWebSecureJdbcApplicationTests {
|
||||
@Test
|
||||
void testHome() {
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.setAccept(Arrays.asList(MediaType.TEXT_HTML));
|
||||
headers.setAccept(Collections.singletonList(MediaType.TEXT_HTML));
|
||||
ResponseEntity<String> entity = this.restTemplate.exchange("/", HttpMethod.GET, new HttpEntity<Void>(headers),
|
||||
String.class);
|
||||
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.FOUND);
|
||||
@ -65,17 +64,17 @@ class SampleWebSecureJdbcApplicationTests {
|
||||
@Test
|
||||
void testLoginPage() {
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.setAccept(Arrays.asList(MediaType.TEXT_HTML));
|
||||
headers.setAccept(Collections.singletonList(MediaType.TEXT_HTML));
|
||||
ResponseEntity<String> entity = this.restTemplate.exchange("/login", HttpMethod.GET,
|
||||
new HttpEntity<Void>(headers), String.class);
|
||||
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);
|
||||
assertThat(entity.getBody()).contains("_csrf");
|
||||
assertThat(entity.getBody()).contains("<title>Login</title>");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testLogin() {
|
||||
HttpHeaders headers = getHeaders();
|
||||
headers.setAccept(Arrays.asList(MediaType.TEXT_HTML));
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.setAccept(Collections.singletonList(MediaType.TEXT_HTML));
|
||||
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
|
||||
MultiValueMap<String, String> form = new LinkedMultiValueMap<>();
|
||||
form.set("username", "user");
|
||||
@ -84,27 +83,6 @@ class SampleWebSecureJdbcApplicationTests {
|
||||
new HttpEntity<>(form, headers), String.class);
|
||||
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.FOUND);
|
||||
assertThat(entity.getHeaders().getLocation().toString()).endsWith(this.port + "/");
|
||||
assertThat(entity.getHeaders().get("Set-Cookie")).isNotNull();
|
||||
}
|
||||
|
||||
private HttpHeaders getHeaders() {
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
ResponseEntity<String> page = this.restTemplate.getForEntity("/login", String.class);
|
||||
assertThat(page.getStatusCode()).isEqualTo(HttpStatus.OK);
|
||||
String cookie = page.getHeaders().getFirst("Set-Cookie");
|
||||
headers.set("Cookie", cookie);
|
||||
Pattern pattern = Pattern.compile("(?s).*name=\"_csrf\".*?value=\"([^\"]+).*");
|
||||
Matcher matcher = pattern.matcher(page.getBody());
|
||||
assertThat(matcher.matches()).as(page.getBody()).isTrue();
|
||||
headers.set("X-CSRF-TOKEN", matcher.group(1));
|
||||
return headers;
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCss() {
|
||||
ResponseEntity<String> entity = this.restTemplate.getForEntity("/css/bootstrap.min.css", String.class);
|
||||
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);
|
||||
assertThat(entity.getBody()).contains("body");
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -6,9 +6,7 @@ plugins {
|
||||
description = "Spring Boot web secure smoke test"
|
||||
|
||||
dependencies {
|
||||
implementation(project(":spring-boot-project:spring-boot-starters:spring-boot-starter-actuator"))
|
||||
implementation(project(":spring-boot-project:spring-boot-starters:spring-boot-starter-security"))
|
||||
implementation(project(":spring-boot-project:spring-boot-starters:spring-boot-starter-thymeleaf"))
|
||||
implementation(project(":spring-boot-project:spring-boot-starters:spring-boot-starter-web"))
|
||||
|
||||
testImplementation(project(":spring-boot-project:spring-boot-starters:spring-boot-starter-test"))
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2020 the original author or authors.
|
||||
* Copyright 2012-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -16,42 +16,21 @@
|
||||
|
||||
package smoketest.web.secure;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.boot.autoconfigure.security.servlet.PathRequest;
|
||||
import org.springframework.boot.builder.SpringApplicationBuilder;
|
||||
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.configurers.LogoutConfigurer;
|
||||
import org.springframework.security.web.SecurityFilterChain;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||
|
||||
@SpringBootApplication
|
||||
@Controller
|
||||
public class SampleWebSecureApplication implements WebMvcConfigurer {
|
||||
|
||||
@GetMapping("/")
|
||||
public String home(Map<String, Object> model) {
|
||||
model.put("message", "Hello World");
|
||||
model.put("title", "Hello Home");
|
||||
model.put("date", new Date());
|
||||
return "home";
|
||||
}
|
||||
|
||||
@RequestMapping("/foo")
|
||||
public String foo() {
|
||||
throw new RuntimeException("Expected exception in controller");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addViewControllers(ViewControllerRegistry registry) {
|
||||
registry.addViewController("/").setViewName("home");
|
||||
registry.addViewController("/login").setViewName("login");
|
||||
}
|
||||
|
||||
@ -64,15 +43,9 @@ public class SampleWebSecureApplication implements WebMvcConfigurer {
|
||||
|
||||
@Bean
|
||||
SecurityFilterChain configure(HttpSecurity http) throws Exception {
|
||||
http.authorizeRequests((requests) -> {
|
||||
requests.requestMatchers(PathRequest.toStaticResources().atCommonLocations()).permitAll();
|
||||
requests.anyRequest().fullyAuthenticated();
|
||||
});
|
||||
http.formLogin((form) -> {
|
||||
form.loginPage("/login");
|
||||
form.failureUrl("/login?error").permitAll();
|
||||
});
|
||||
http.logout(LogoutConfigurer::permitAll);
|
||||
http.csrf().disable();
|
||||
http.authorizeRequests((requests) -> requests.anyRequest().fullyAuthenticated());
|
||||
http.formLogin((form) -> form.loginPage("/login").permitAll());
|
||||
return http.build();
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
spring.thymeleaf.cache: false
|
||||
# demo only:
|
||||
logging.level.org.springframework.security: INFO
|
||||
logging.level.org.springframework.boot.actuate.audit.listener.AuditListener: DEBUG
|
||||
logging.level.org.springframework.security=INFO
|
||||
logging.level.org.springframework.boot.actuate.audit.listener.AuditListener=DEBUG
|
||||
spring.security.user.name=user
|
||||
spring.security.user.password=password
|
||||
spring.mvc.view.prefix=/templates/
|
||||
spring.mvc.view.suffix=.html
|
@ -1,10 +0,0 @@
|
||||
create table users (
|
||||
username varchar(256),
|
||||
password varchar(256),
|
||||
enabled boolean
|
||||
);
|
||||
|
||||
create table authorities (
|
||||
username varchar(256),
|
||||
authority varchar(256)
|
||||
);
|
File diff suppressed because one or more lines are too long
@ -1,32 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html xmlns:th="https://www.thymeleaf.org">
|
||||
<head>
|
||||
<title>Error</title>
|
||||
<link rel="stylesheet" th:href="@{/css/bootstrap.min.css}"
|
||||
href="../../css/bootstrap.min.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<div class="navbar">
|
||||
<div class="navbar-inner">
|
||||
<a class="brand" href="https://www.thymeleaf.org"> Thymeleaf -
|
||||
Plain </a>
|
||||
<ul class="nav">
|
||||
<li><a th:href="@{/}" href="home.html"> Home </a></li>
|
||||
<li><a th:href="@{/logout}" href="logout"> Logout </a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<h1 th:text="${title}">Title</h1>
|
||||
<div id="created" th:text="${#dates.format(timestamp)}">July 11,
|
||||
2012 2:17:16 PM CDT</div>
|
||||
<div>
|
||||
There was an unexpected error (type=<span th:text="${error}">Bad</span>, status=<span th:text="${status}">500</span>).
|
||||
</div>
|
||||
<div th:text="${message}">Fake content</div>
|
||||
<div>
|
||||
Please contact the operator with the above information.
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
@ -1,28 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html xmlns:th="https://www.thymeleaf.org">
|
||||
<head>
|
||||
<title th:text="${title}">Title</title>
|
||||
<link rel="stylesheet" th:href="@{/css/bootstrap.min.css}"
|
||||
href="../../css/bootstrap.min.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<div class="navbar">
|
||||
<div class="navbar-inner">
|
||||
<a class="brand" href="https://www.thymeleaf.org"> Thymeleaf -
|
||||
Plain </a>
|
||||
<ul class="nav">
|
||||
<li><a th:href="@{/}" href="home.html"> Home </a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<h1 th:text="${title}">Title</h1>
|
||||
<div th:text="${message}">Fake content</div>
|
||||
<div id="created" th:text="${#dates.format(date)}">July 11,
|
||||
2012 2:17:16 PM CDT</div>
|
||||
<form th:action="@{/logout}" method="post">
|
||||
<input type="submit" value="Sign Out"/>
|
||||
</form>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
@ -1,34 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html xmlns:th="https://www.thymeleaf.org">
|
||||
<head>
|
||||
<title>Login</title>
|
||||
<link rel="stylesheet" th:href="@{/css/bootstrap.min.css}"
|
||||
href="../../css/bootstrap.min.css" />
|
||||
</head>
|
||||
<body onload="document.f.username.focus();">
|
||||
<div class="container">
|
||||
<div class="navbar">
|
||||
<div class="navbar-inner">
|
||||
<a class="brand" href="https://www.thymeleaf.org"> Thymeleaf -
|
||||
Plain </a>
|
||||
<ul class="nav">
|
||||
<li><a th:href="@{/}" href="home.html"> Home </a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class="content">
|
||||
<p th:if="${param.logout}" class="alert">You have been logged out</p>
|
||||
<p th:if="${param.error}" class="alert alert-error">There was an error, please try again</p>
|
||||
<h2>Login with Username and Password</h2>
|
||||
<form name="form" th:action="@{/login}" action="/login" method="POST">
|
||||
<fieldset>
|
||||
<input type="text" name="username" value="" placeholder="Username" />
|
||||
<input type="password" name="password" placeholder="Password" />
|
||||
</fieldset>
|
||||
<input type="submit" id="login" value="Login"
|
||||
class="btn btn-primary" />
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
@ -0,0 +1,11 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Home</title>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<p>Home</p>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
@ -0,0 +1,20 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Login</title>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<div class="content">
|
||||
<h2>Login with Username and Password</h2>
|
||||
<form name="form" action="/login" method="POST">
|
||||
<fieldset>
|
||||
<input type="text" name="username" value="" placeholder="Username" />
|
||||
<input type="password" name="password" placeholder="Password" />
|
||||
</fieldset>
|
||||
<input type="submit" id="login" value="Login" class="btn btn-primary" />
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2019 the original author or authors.
|
||||
* Copyright 2012-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -16,9 +16,7 @@
|
||||
|
||||
package smoketest.web.secure;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.Collections;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
@ -42,9 +40,10 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
* Basic integration tests for demo application.
|
||||
*
|
||||
* @author Dave Syer
|
||||
* @author Scott Frederick
|
||||
*/
|
||||
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
|
||||
class SampleSecureApplicationTests {
|
||||
class SampleWebSecureApplicationTests {
|
||||
|
||||
@Autowired
|
||||
private TestRestTemplate restTemplate;
|
||||
@ -55,9 +54,9 @@ class SampleSecureApplicationTests {
|
||||
@Test
|
||||
void testHome() {
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.setAccept(Arrays.asList(MediaType.TEXT_HTML));
|
||||
ResponseEntity<String> entity = this.restTemplate.exchange("/", HttpMethod.GET, new HttpEntity<Void>(headers),
|
||||
String.class);
|
||||
headers.setAccept(Collections.singletonList(MediaType.TEXT_HTML));
|
||||
ResponseEntity<String> entity = this.restTemplate.exchange("/home", HttpMethod.GET,
|
||||
new HttpEntity<Void>(headers), String.class);
|
||||
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.FOUND);
|
||||
assertThat(entity.getHeaders().getLocation().toString()).endsWith(this.port + "/login");
|
||||
}
|
||||
@ -65,17 +64,17 @@ class SampleSecureApplicationTests {
|
||||
@Test
|
||||
void testLoginPage() {
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.setAccept(Arrays.asList(MediaType.TEXT_HTML));
|
||||
headers.setAccept(Collections.singletonList(MediaType.TEXT_HTML));
|
||||
ResponseEntity<String> entity = this.restTemplate.exchange("/login", HttpMethod.GET,
|
||||
new HttpEntity<Void>(headers), String.class);
|
||||
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);
|
||||
assertThat(entity.getBody()).contains("_csrf");
|
||||
assertThat(entity.getBody()).contains("<title>Login</title>");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testLogin() {
|
||||
HttpHeaders headers = getHeaders();
|
||||
headers.setAccept(Arrays.asList(MediaType.TEXT_HTML));
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.setAccept(Collections.singletonList(MediaType.TEXT_HTML));
|
||||
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
|
||||
MultiValueMap<String, String> form = new LinkedMultiValueMap<>();
|
||||
form.set("username", "user");
|
||||
@ -84,27 +83,6 @@ class SampleSecureApplicationTests {
|
||||
new HttpEntity<>(form, headers), String.class);
|
||||
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.FOUND);
|
||||
assertThat(entity.getHeaders().getLocation().toString()).endsWith(this.port + "/");
|
||||
assertThat(entity.getHeaders().get("Set-Cookie")).isNotNull();
|
||||
}
|
||||
|
||||
private HttpHeaders getHeaders() {
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
ResponseEntity<String> page = this.restTemplate.getForEntity("/login", String.class);
|
||||
assertThat(page.getStatusCode()).isEqualTo(HttpStatus.OK);
|
||||
String cookie = page.getHeaders().getFirst("Set-Cookie");
|
||||
headers.set("Cookie", cookie);
|
||||
Pattern pattern = Pattern.compile("(?s).*name=\"_csrf\".*?value=\"([^\"]+).*");
|
||||
Matcher matcher = pattern.matcher(page.getBody());
|
||||
assertThat(matcher.matches()).as(page.getBody()).isTrue();
|
||||
headers.set("X-CSRF-TOKEN", matcher.group(1));
|
||||
return headers;
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCss() {
|
||||
ResponseEntity<String> entity = this.restTemplate.getForEntity("/css/bootstrap.min.css", String.class);
|
||||
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);
|
||||
assertThat(entity.getBody()).contains("body");
|
||||
}
|
||||
|
||||
}
|
@ -3,7 +3,7 @@ plugins {
|
||||
id "org.springframework.boot.conventions"
|
||||
}
|
||||
|
||||
description = "Spring Boot web UI smoke test"
|
||||
description = "Spring Boot web Thymeleaf smoke test"
|
||||
|
||||
dependencies {
|
||||
implementation(project(":spring-boot-project:spring-boot-starters:spring-boot-starter-thymeleaf"))
|
4
spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-web-ui/src/main/java/smoketest/web/ui/InMemoryMessageRepository.java → spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-web-thymeleaf/src/main/java/smoketest/web/thymeleaf/InMemoryMessageRepository.java
Executable file → Normal file
4
spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-web-ui/src/main/java/smoketest/web/ui/InMemoryMessageRepository.java → spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-web-thymeleaf/src/main/java/smoketest/web/thymeleaf/InMemoryMessageRepository.java
Executable file → Normal file
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2019 the original author or authors.
|
||||
* Copyright 2012-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package smoketest.web.ui;
|
||||
package smoketest.web.thymeleaf;
|
||||
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2019 the original author or authors.
|
||||
* Copyright 2012-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package smoketest.web.ui;
|
||||
package smoketest.web.thymeleaf;
|
||||
|
||||
import java.util.Calendar;
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2019 the original author or authors.
|
||||
* Copyright 2012-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package smoketest.web.ui;
|
||||
package smoketest.web.thymeleaf;
|
||||
|
||||
public interface MessageRepository {
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2019 the original author or authors.
|
||||
* Copyright 2012-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package smoketest.web.ui;
|
||||
package smoketest.web.thymeleaf;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
8
spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-web-ui/src/main/java/smoketest/web/ui/mvc/MessageController.java → spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-web-thymeleaf/src/main/java/smoketest/web/thymeleaf/mvc/MessageController.java
Executable file → Normal file
8
spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-web-ui/src/main/java/smoketest/web/ui/mvc/MessageController.java → spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-web-thymeleaf/src/main/java/smoketest/web/thymeleaf/mvc/MessageController.java
Executable file → Normal file
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2019 the original author or authors.
|
||||
* Copyright 2012-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -14,12 +14,12 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package smoketest.web.ui.mvc;
|
||||
package smoketest.web.thymeleaf.mvc;
|
||||
|
||||
import javax.validation.Valid;
|
||||
|
||||
import smoketest.web.ui.Message;
|
||||
import smoketest.web.ui.MessageRepository;
|
||||
import smoketest.web.thymeleaf.Message;
|
||||
import smoketest.web.thymeleaf.MessageRepository;
|
||||
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.validation.BindingResult;
|
Before Width: | Height: | Size: 2.8 KiB After Width: | Height: | Size: 2.8 KiB |
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2019 the original author or authors.
|
||||
* Copyright 2012-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package smoketest.web.ui;
|
||||
package smoketest.web.thymeleaf;
|
||||
|
||||
import java.util.regex.Pattern;
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2019 the original author or authors.
|
||||
* Copyright 2012-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package smoketest.web.ui;
|
||||
package smoketest.web.thymeleaf;
|
||||
|
||||
import java.net.URI;
|
||||
|
||||
@ -63,12 +63,4 @@ class SampleWebUiApplicationTests {
|
||||
assertThat(location.toString()).contains("localhost:" + this.port);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCss() {
|
||||
ResponseEntity<String> entity = this.restTemplate
|
||||
.getForEntity("http://localhost:" + this.port + "/css/bootstrap.min.css", String.class);
|
||||
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);
|
||||
assertThat(entity.getBody()).contains("body");
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user