Skip to content

Commit daa745c

Browse files
committed
Render default UIs using lightweight templates
1 parent 36a408f commit daa745c

File tree

10 files changed

+1232
-544
lines changed

10 files changed

+1232
-544
lines changed

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

Lines changed: 216 additions & 197 deletions
Large diffs are not rendered by default.

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

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

183183
public final SpringTestContext spring = new SpringTestContext(this);
184184

@@ -192,22 +192,28 @@ public void getLoginWhenAutoConfigThenShowsDefaultLoginPage() throws Exception {
192192
String expectedContent = "<!DOCTYPE html>\n"
193193
+ "<html lang=\"en\">\n"
194194
+ 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>";
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+
+ " \n"
200+
+ " <p>\n"
201+
+ " <label for=\"username\" class=\"screenreader\">Username</label>\n"
202+
+ " <input type=\"text\" id=\"username\" name=\"username\" placeholder=\"Username\" required autofocus>\n"
203+
+ " </p>\n"
204+
+ " <p>\n"
205+
+ " <label for=\"password\" class=\"screenreader\">Password</label>\n"
206+
+ " <input type=\"password\" id=\"password\" name=\"password\" placeholder=\"Password\" required>\n"
207+
+ " </p>\n"
208+
+ "\n"
209+
+ "\n"
210+
+ " <button type=\"submit\" class=\"primary\">Sign in</button>\n"
211+
+ " </form>\n"
212+
+ "\n"
213+
+ "\n"
214+
+ " </div>\n"
215+
+ " </body>\n"
216+
+ "</html>";
211217
// @formatter:on
212218
this.mvc.perform(get("/login")).andExpect(content().string(expectedContent));
213219
}
@@ -225,27 +231,31 @@ public void getLoginWhenConfiguredWithCustomAttributesThenLoginPageReflects() th
225231
String expectedContent = "<!DOCTYPE html>\n"
226232
+ "<html lang=\"en\">\n"
227233
+ 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());
234+
+ " <body>\n"
235+
+ " <div class=\"content\">\n"
236+
+ " <form class=\"login-form\" method=\"post\" action=\"/signin\">\n"
237+
+ " <h2>Please sign in</h2>\n"
238+
+ " \n"
239+
+ " <p>\n"
240+
+ " <label for=\"username\" class=\"screenreader\">Username</label>\n"
241+
+ " <input type=\"text\" id=\"username\" name=\"custom_user\" placeholder=\"Username\" required autofocus>\n"
242+
+ " </p>\n"
243+
+ " <p>\n"
244+
+ " <label for=\"password\" class=\"screenreader\">Password</label>\n"
245+
+ " <input type=\"password\" id=\"password\" name=\"custom_pass\" placeholder=\"Password\" required>\n"
246+
+ " </p>\n"
247+
+ "\n"
248+
+ "\n"
249+
+ " <button type=\"submit\" class=\"primary\">Sign in</button>\n"
250+
+ " </form>\n"
251+
+ "\n"
252+
+ "\n"
253+
+ " </div>\n"
254+
+ " </body>\n"
255+
+ "</html>";
248256
// @formatter:on
257+
this.mvc.perform(get("/login")).andExpect(content().string(expectedContent));
258+
this.mvc.perform(get("/logout")).andExpect(status().is3xxRedirection());
249259
}
250260

251261
@Test

0 commit comments

Comments
 (0)