Skip to content

Commit 8d47906

Browse files
Kehrlannrwinch
authored andcommitted
Render default UIs using lightweight templates
1 parent a953a3d commit 8d47906

File tree

9 files changed

+1258
-518
lines changed

9 files changed

+1258
-518
lines changed

config/src/test/java/org/springframework/security/config/annotation/web/configurers/DefaultLoginPageConfigurerTests.java

+240-214
Large diffs are not rendered by default.

config/src/test/java/org/springframework/security/config/http/FormLoginBeanDefinitionParserTests.java

+186-180
Original file line numberDiff line numberDiff line change
@@ -45,140 +45,142 @@ public class FormLoginBeanDefinitionParserTests {
4545

4646
private static final String CONFIG_LOCATION_PREFIX = "classpath:org/springframework/security/config/http/FormLoginBeanDefinitionParserTests";
4747

48-
//@formatter:off
49-
public static final String EXPECTED_HTML_HEAD = " <head>\n"
50-
+ " <meta charset=\"utf-8\">\n"
51-
+ " <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, shrink-to-fit=no\">\n"
52-
+ " <meta name=\"description\" content=\"\">\n"
53-
+ " <meta name=\"author\" content=\"\">\n"
54-
+ " <title>Please sign in</title>\n"
55-
+ " <style>\n"
56-
+ " /* General layout */\n"
57-
+ " body {\n"
58-
+ " font-family: system-ui, \"Segoe UI\", Roboto, \"Helvetica Neue\", Arial, sans-serif;\n"
59-
+ " background-color: #eee;\n"
60-
+ " padding: 40px 0;\n"
61-
+ " margin: 0;\n"
62-
+ " line-height: 1.5;\n"
63-
+ " }\n"
64-
+ " \n"
65-
+ " h2 {\n"
66-
+ " margin-top: 0;\n"
67-
+ " margin-bottom: 0.5rem;\n"
68-
+ " font-size: 2rem;\n"
69-
+ " font-weight: 500;\n"
70-
+ " line-height: 2rem;\n"
71-
+ " }\n"
72-
+ " \n"
73-
+ " .content {\n"
74-
+ " margin-right: auto;\n"
75-
+ " margin-left: auto;\n"
76-
+ " padding-right: 15px;\n"
77-
+ " padding-left: 15px;\n"
78-
+ " width: 100%;\n"
79-
+ " box-sizing: border-box;\n"
80-
+ " }\n"
81-
+ " \n"
82-
+ " @media (min-width: 800px) {\n"
83-
+ " .content {\n"
84-
+ " max-width: 760px;\n"
85-
+ " }\n"
86-
+ " }\n"
87-
+ " \n"
88-
+ " /* Components */\n"
89-
+ " a,\n"
90-
+ " a:visited {\n"
91-
+ " text-decoration: none;\n"
92-
+ " color: #06f;\n"
93-
+ " }\n"
94-
+ " \n"
95-
+ " a:hover {\n"
96-
+ " text-decoration: underline;\n"
97-
+ " color: #003c97;\n"
98-
+ " }\n"
99-
+ " \n"
100-
+ " input[type=\"text\"],\n"
101-
+ " input[type=\"password\"] {\n"
102-
+ " height: auto;\n"
103-
+ " width: 100%;\n"
104-
+ " font-size: 1rem;\n"
105-
+ " padding: 0.5rem;\n"
106-
+ " box-sizing: border-box;\n"
107-
+ " }\n"
108-
+ " \n"
109-
+ " button {\n"
110-
+ " padding: 0.5rem 1rem;\n"
111-
+ " font-size: 1.25rem;\n"
112-
+ " line-height: 1.5;\n"
113-
+ " border: none;\n"
114-
+ " border-radius: 0.1rem;\n"
115-
+ " width: 100%;\n"
116-
+ " }\n"
117-
+ " \n"
118-
+ " button.primary {\n"
119-
+ " color: #fff;\n"
120-
+ " background-color: #06f;\n"
121-
+ " }\n"
122-
+ " \n"
123-
+ " .alert {\n"
124-
+ " padding: 0.75rem 1rem;\n"
125-
+ " margin-bottom: 1rem;\n"
126-
+ " line-height: 1.5;\n"
127-
+ " border-radius: 0.1rem;\n"
128-
+ " width: 100%;\n"
129-
+ " box-sizing: border-box;\n"
130-
+ " border-width: 1px;\n"
131-
+ " border-style: solid;\n"
132-
+ " }\n"
133-
+ " \n"
134-
+ " .alert.alert-danger {\n"
135-
+ " color: #6b1922;\n"
136-
+ " background-color: #f7d5d7;\n"
137-
+ " border-color: #eab6bb;\n"
138-
+ " }\n"
139-
+ " \n"
140-
+ " .alert.alert-success {\n"
141-
+ " color: #145222;\n"
142-
+ " background-color: #d1f0d9;\n"
143-
+ " border-color: #c2ebcb;\n"
144-
+ " }\n"
145-
+ " \n"
146-
+ " .screenreader {\n"
147-
+ " position: absolute;\n"
148-
+ " clip: rect(0 0 0 0);\n"
149-
+ " height: 1px;\n"
150-
+ " width: 1px;\n"
151-
+ " padding: 0;\n"
152-
+ " border: 0;\n"
153-
+ " overflow: hidden;\n"
154-
+ " }\n"
155-
+ " \n"
156-
+ " table {\n"
157-
+ " width: 100%;\n"
158-
+ " max-width: 100%;\n"
159-
+ " margin-bottom: 2rem;\n"
160-
+ " }\n"
161-
+ " \n"
162-
+ " .table-striped tr:nth-of-type(2n + 1) {\n"
163-
+ " background-color: #e1e1e1;\n"
164-
+ " }\n"
165-
+ " \n"
166-
+ " td {\n"
167-
+ " padding: 0.75rem;\n"
168-
+ " vertical-align: top;\n"
169-
+ " }\n"
170-
+ " \n"
171-
+ " /* Login / logout layouts */\n"
172-
+ " .login-form,\n"
173-
+ " .logout-form {\n"
174-
+ " max-width: 340px;\n"
175-
+ " padding: 0 15px 15px 15px;\n"
176-
+ " margin: 0 auto 2rem auto;\n"
177-
+ " box-sizing: border-box;\n"
178-
+ " }\n"
179-
+ " </style>\n"
180-
+ " </head>\n";
181-
//@formatter:on
48+
public static final String EXPECTED_HTML_HEAD = """
49+
<!DOCTYPE html>
50+
<html lang="en">
51+
<head>
52+
<meta charset="utf-8">
53+
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
54+
<meta name="description" content="">
55+
<meta name="author" content="">
56+
<title>Please sign in</title>
57+
<style>
58+
/* General layout */
59+
body {
60+
font-family: system-ui, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
61+
background-color: #eee;
62+
padding: 40px 0;
63+
margin: 0;
64+
line-height: 1.5;
65+
}
66+
\s\s\s\s
67+
h2 {
68+
margin-top: 0;
69+
margin-bottom: 0.5rem;
70+
font-size: 2rem;
71+
font-weight: 500;
72+
line-height: 2rem;
73+
}
74+
\s\s\s\s
75+
.content {
76+
margin-right: auto;
77+
margin-left: auto;
78+
padding-right: 15px;
79+
padding-left: 15px;
80+
width: 100%;
81+
box-sizing: border-box;
82+
}
83+
\s\s\s\s
84+
@media (min-width: 800px) {
85+
.content {
86+
max-width: 760px;
87+
}
88+
}
89+
\s\s\s\s
90+
/* Components */
91+
a,
92+
a:visited {
93+
text-decoration: none;
94+
color: #06f;
95+
}
96+
\s\s\s\s
97+
a:hover {
98+
text-decoration: underline;
99+
color: #003c97;
100+
}
101+
\s\s\s\s
102+
input[type="text"],
103+
input[type="password"] {
104+
height: auto;
105+
width: 100%;
106+
font-size: 1rem;
107+
padding: 0.5rem;
108+
box-sizing: border-box;
109+
}
110+
\s\s\s\s
111+
button {
112+
padding: 0.5rem 1rem;
113+
font-size: 1.25rem;
114+
line-height: 1.5;
115+
border: none;
116+
border-radius: 0.1rem;
117+
width: 100%;
118+
}
119+
\s\s\s\s
120+
button.primary {
121+
color: #fff;
122+
background-color: #06f;
123+
}
124+
\s\s\s\s
125+
.alert {
126+
padding: 0.75rem 1rem;
127+
margin-bottom: 1rem;
128+
line-height: 1.5;
129+
border-radius: 0.1rem;
130+
width: 100%;
131+
box-sizing: border-box;
132+
border-width: 1px;
133+
border-style: solid;
134+
}
135+
\s\s\s\s
136+
.alert.alert-danger {
137+
color: #6b1922;
138+
background-color: #f7d5d7;
139+
border-color: #eab6bb;
140+
}
141+
\s\s\s\s
142+
.alert.alert-success {
143+
color: #145222;
144+
background-color: #d1f0d9;
145+
border-color: #c2ebcb;
146+
}
147+
\s\s\s\s
148+
.screenreader {
149+
position: absolute;
150+
clip: rect(0 0 0 0);
151+
height: 1px;
152+
width: 1px;
153+
padding: 0;
154+
border: 0;
155+
overflow: hidden;
156+
}
157+
\s\s\s\s
158+
table {
159+
width: 100%;
160+
max-width: 100%;
161+
margin-bottom: 2rem;
162+
}
163+
\s\s\s\s
164+
.table-striped tr:nth-of-type(2n + 1) {
165+
background-color: #e1e1e1;
166+
}
167+
\s\s\s\s
168+
td {
169+
padding: 0.75rem;
170+
vertical-align: top;
171+
}
172+
\s\s\s\s
173+
/* Login / logout layouts */
174+
.login-form,
175+
.logout-form {
176+
max-width: 340px;
177+
padding: 0 15px 15px 15px;
178+
margin: 0 auto 2rem auto;
179+
box-sizing: border-box;
180+
}
181+
</style>
182+
</head>
183+
""";
182184

183185
public final SpringTestContext spring = new SpringTestContext(this);
184186

@@ -188,27 +190,30 @@ public class FormLoginBeanDefinitionParserTests {
188190
@Test
189191
public void getLoginWhenAutoConfigThenShowsDefaultLoginPage() throws Exception {
190192
this.spring.configLocations(this.xml("Simple")).autowire();
191-
// @formatter:off
192-
String expectedContent = "<!DOCTYPE html>\n"
193-
+ "<html lang=\"en\">\n"
194-
+ EXPECTED_HTML_HEAD
195-
+ " <body>\n"
196-
+ " <div class=\"content\">\n"
197-
+ " <form class=\"login-form\" method=\"post\" action=\"/login\">\n"
198-
+ " <h2>Please sign in</h2>\n"
199-
+ " <p>\n"
200-
+ " <label for=\"username\" class=\"screenreader\">Username</label>\n"
201-
+ " <input type=\"text\" id=\"username\" name=\"username\" placeholder=\"Username\" required autofocus>\n"
202-
+ " </p>\n"
203-
+ " <p>\n"
204-
+ " <label for=\"password\" class=\"screenreader\">Password</label>\n"
205-
+ " <input type=\"password\" id=\"password\" name=\"password\" placeholder=\"Password\" required>\n"
206-
+ " </p>\n"
207-
+ " <button type=\"submit\" class=\"primary\">Sign in</button>\n"
208-
+ " </form>\n"
209-
+ "</div>\n"
210-
+ "</body></html>";
211-
// @formatter:on
193+
String expectedContent = EXPECTED_HTML_HEAD + """
194+
<body>
195+
<div class="content">
196+
<form class="login-form" method="post" action="/login">
197+
<h2>Please sign in</h2>
198+
\s
199+
<p>
200+
<label for="username" class="screenreader">Username</label>
201+
<input type="text" id="username" name="username" placeholder="Username" required autofocus>
202+
</p>
203+
<p>
204+
<label for="password" class="screenreader">Password</label>
205+
<input type="password" id="password" name="password" placeholder="Password" required>
206+
</p>
207+
208+
209+
<button type="submit" class="primary">Sign in</button>
210+
</form>
211+
212+
213+
214+
</div>
215+
</body>
216+
</html>""";
212217
this.mvc.perform(get("/login")).andExpect(content().string(expectedContent));
213218
}
214219

@@ -221,31 +226,32 @@ public void getLogoutWhenAutoConfigThenShowsDefaultLogoutPage() throws Exception
221226
@Test
222227
public void getLoginWhenConfiguredWithCustomAttributesThenLoginPageReflects() throws Exception {
223228
this.spring.configLocations(this.xml("WithCustomAttributes")).autowire();
224-
// @formatter:off
225-
String expectedContent = "<!DOCTYPE html>\n"
226-
+ "<html lang=\"en\">\n"
227-
+ EXPECTED_HTML_HEAD
228-
+ " <body>\n"
229-
+ " <div class=\"content\">\n"
230-
+ " <form class=\"login-form\" method=\"post\" action=\"/signin\">\n"
231-
+ " <h2>Please sign in</h2>\n"
232-
+ " <p>\n"
233-
+ " <label for=\"username\" class=\"screenreader\">Username</label>\n"
234-
+ " <input type=\"text\" id=\"username\" name=\"custom_user\" placeholder=\"Username\" required autofocus>\n"
235-
+ " </p>\n"
236-
+ " <p>\n"
237-
+ " <label for=\"password\" class=\"screenreader\">Password</label>\n"
238-
+ " <input type=\"password\" id=\"password\" name=\"custom_pass\" placeholder=\"Password\" required>\n"
239-
+ " </p>\n"
240-
+ " <button type=\"submit\" class=\"primary\">Sign in</button>\n"
241-
+ " </form>\n"
242-
+ "</div>\n"
243-
+ "</body></html>";
244-
this.mvc.perform(get("/login"))
245-
.andExpect(content().string(expectedContent));
246-
this.mvc.perform(get("/logout"))
247-
.andExpect(status().is3xxRedirection());
248-
// @formatter:on
229+
String expectedContent = EXPECTED_HTML_HEAD + """
230+
<body>
231+
<div class="content">
232+
<form class="login-form" method="post" action="/signin">
233+
<h2>Please sign in</h2>
234+
\s
235+
<p>
236+
<label for="username" class="screenreader">Username</label>
237+
<input type="text" id="username" name="custom_user" placeholder="Username" required autofocus>
238+
</p>
239+
<p>
240+
<label for="password" class="screenreader">Password</label>
241+
<input type="password" id="password" name="custom_pass" placeholder="Password" required>
242+
</p>
243+
244+
245+
<button type="submit" class="primary">Sign in</button>
246+
</form>
247+
248+
249+
250+
</div>
251+
</body>
252+
</html>""";
253+
this.mvc.perform(get("/login")).andExpect(content().string(expectedContent));
254+
this.mvc.perform(get("/logout")).andExpect(status().is3xxRedirection());
249255
}
250256

251257
@Test

0 commit comments

Comments
 (0)