Skip to content

Commit 8fad0a6

Browse files
committed
Update FormLogin+OTT to the Latest
1 parent c2d2cc8 commit 8fad0a6

File tree

12 files changed

+96
-138
lines changed

12 files changed

+96
-138
lines changed
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
= Form Login + One-Time-Token Login MFA Sample
2+
3+
This sample demonstrates Spring Security's support for multifactor authentication, specifically when using username/password and one-time-token as the two factors.
4+
5+
[[usage]]
6+
== Usage
7+
8+
To use the application, please run:
9+
10+
[source,bash]
11+
----
12+
./gradlew :bootRun
13+
----
14+
15+
You can then navigate to http://localhost:8080 where you will be presented with the default page, showing both the login and ott forms.
16+
17+
You can start with either; once authenticated, you'll be asked to give the other as well.
18+
19+
=== Username/Password Login
20+
21+
The username/password is `user/password`.
22+
23+
=== One-Time-Token Login
24+
25+
The username is `user`.
26+
27+
After clicking the submission button, you will be redirected to a page where you can enter the code given.
28+
You can find the code in the logs like so:
29+
30+
[source,bash]
31+
----
32+
********************************************************
33+
34+
Use this one-time token: 1319c31d-c5e0-4123-9b1f-3ffc34aba673
35+
36+
********************************************************
37+
----
38+
39+
== Configuring
40+
41+
There are three profiles in this sample; `default`, `custom-pages`, and `elevated-security`.
42+
43+
`default` is the arrangement described in <<usage>>.
44+
45+
`custom-pages` shows the same, but with a custom page for login and a custom page for one-time-token.
46+
47+
This can be launched with:
48+
49+
[source,bash]
50+
----
51+
./gradlew :bootRun --args='spring.profiles.active=custom-pages'
52+
----
53+
54+
`elevated-security` allows login with either, and will ask for one-time-token login for only the `/profile` page.
55+
56+
This can be launched with:
57+
58+
[source,bash]
59+
----
60+
./gradlew :bootRun --args='spring.profiles.active=elevated-security'
61+
----

servlet/spring-boot/java/authentication/mfa/formLogin+ott/README.md

Lines changed: 0 additions & 3 deletions
This file was deleted.

servlet/spring-boot/java/authentication/mfa/formLogin+ott/build.gradle

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ java {
1111
}
1212

1313
repositories {
14-
mavenLocal()
1514
mavenCentral()
1615
maven { url "https://repo.spring.io/milestone" }
1716
maven { url "https://repo.spring.io/snapshot" }
Lines changed: 15 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
package org.example.magiclink;
22

3-
import jakarta.servlet.http.HttpServletRequest;
4-
53
import org.springframework.context.annotation.Bean;
64
import org.springframework.context.annotation.Configuration;
75
import org.springframework.context.annotation.Profile;
6+
import org.springframework.security.authorization.AuthorizationManagerFactory;
7+
import org.springframework.security.authorization.DefaultAuthorizationManagerFactory;
88
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
9-
import org.springframework.security.core.Authentication;
109
import org.springframework.security.web.SecurityFilterChain;
1110
import org.springframework.stereotype.Controller;
1211
import org.springframework.web.bind.annotation.GetMapping;
12+
import org.springframework.web.bind.annotation.PathVariable;
1313

1414
@Profile("custom-pages")
1515
@Configuration(proxyBeanMethods = false)
@@ -18,33 +18,29 @@ public class CustomPagesSecurityConfig {
1818
@Controller
1919
@Profile("custom-pages")
2020
static class LoginController {
21-
@GetMapping("/login/form")
22-
public String login() {
23-
return "login";
24-
}
25-
26-
@GetMapping("/commence/ott")
27-
public String ott(HttpServletRequest request, Authentication authentication) {
28-
if (authentication != null) {
29-
request.setAttribute("username", authentication.getName());
30-
}
31-
return "ott";
21+
@GetMapping("/auth/{path}")
22+
public String auth(@PathVariable("path") String path) {
23+
return path;
3224
}
3325
}
3426

3527
@Bean
3628
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
3729
// @formatter:off
3830
http
39-
.authorizeHttpRequests((authorize) -> authorize.anyRequest().authenticated())
40-
.formLogin((form) -> form.loginPage("/login/form").permitAll())
41-
.oneTimeTokenLogin((ott) -> ott.loginPage("/commence/ott").permitAll());
31+
.authorizeHttpRequests((authorize) -> authorize
32+
.requestMatchers("/auth/**").permitAll()
33+
.anyRequest().authenticated()
34+
)
35+
.formLogin((form) -> form.loginPage("/auth/password"))
36+
.oneTimeTokenLogin((ott) -> ott.loginPage("/auth/ott"));
4237
// @formatter:on
4338
return http.build();
4439
}
4540

4641
@Bean
47-
FactorAuthorizationManagerFactory authz() {
48-
return new FactorAuthorizationManagerFactory("FACTOR_PASSWORD", "FACTOR_OTT");
42+
AuthorizationManagerFactory<Object> factors() {
43+
return DefaultAuthorizationManagerFactory.builder()
44+
.requireAdditionalAuthorities("FACTOR_PASSWORD", "FACTOR_OTT").build();
4945
}
5046
}

servlet/spring-boot/java/authentication/mfa/formLogin+ott/src/main/java/org/example/magiclink/DefaultSecurityConfig.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919
import org.springframework.context.annotation.Bean;
2020
import org.springframework.context.annotation.Configuration;
2121
import org.springframework.context.annotation.Profile;
22+
import org.springframework.security.authorization.AuthorizationManagerFactory;
23+
import org.springframework.security.authorization.DefaultAuthorizationManagerFactory;
2224
import org.springframework.security.config.Customizer;
2325
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
2426
import org.springframework.security.web.SecurityFilterChain;
@@ -39,8 +41,9 @@ public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Excepti
3941
}
4042

4143
@Bean
42-
FactorAuthorizationManagerFactory authz() {
43-
return new FactorAuthorizationManagerFactory("FACTOR_PASSWORD", "FACTOR_OTT");
44+
AuthorizationManagerFactory<Object> factors() {
45+
return DefaultAuthorizationManagerFactory.builder()
46+
.requireAdditionalAuthorities("FACTOR_PASSWORD", "FACTOR_OTT").build();
4447
}
4548

4649

servlet/spring-boot/java/authentication/mfa/formLogin+ott/src/main/java/org/example/magiclink/ElevatedSecurityPageSecurityConfig.java

Lines changed: 11 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import org.springframework.security.web.SecurityFilterChain;
1111
import org.springframework.stereotype.Controller;
1212
import org.springframework.web.bind.annotation.GetMapping;
13+
import org.springframework.web.bind.annotation.PathVariable;
1314

1415
@Profile("elevated-security")
1516
@Configuration(proxyBeanMethods = false)
@@ -18,34 +19,26 @@ public class ElevatedSecurityPageSecurityConfig {
1819
@Controller
1920
@Profile("elevated-security")
2021
static class LoginController {
21-
@GetMapping("/login/form")
22-
public String login() {
23-
return "login";
24-
}
25-
26-
@GetMapping("/commence/ott")
27-
public String ott(HttpServletRequest request, Authentication authentication) {
28-
if (authentication != null) {
29-
request.setAttribute("username", authentication.getName());
30-
}
31-
return "ott";
22+
@GetMapping("/auth/{path}")
23+
public String auth(@PathVariable("path") String path) {
24+
return path;
3225
}
3326
}
3427

3528
@Bean
3629
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
3730
// @formatter:off
3831
http
39-
.authorizeHttpRequests((authorize) -> authorize.anyRequest().authenticated())
40-
.formLogin((form) -> form.loginPage("/login/form").permitAll())
41-
.oneTimeTokenLogin((ott) -> ott.loginPage("/commence/ott").permitAll());
32+
.authorizeHttpRequests((authorize) -> authorize
33+
.requestMatchers("/auth/**").permitAll()
34+
.requestMatchers("/profile").hasAuthority("FACTOR_OTT")
35+
.anyRequest().authenticated()
36+
)
37+
.formLogin((form) -> form.loginPage("/auth/password"))
38+
.oneTimeTokenLogin((ott) -> ott.loginPage("/auth/ott"));
4239

4340
// @formatter:on
4441
return http.build();
4542
}
4643

47-
@Bean
48-
FactorAuthorizationManagerFactory authz() {
49-
return new FactorAuthorizationManagerFactory("FACTOR_PASSWORD", "FACTOR_OTT");
50-
}
5144
}

servlet/spring-boot/java/authentication/mfa/formLogin+ott/src/main/java/org/example/magiclink/FactorAuthorizationManagerFactory.java

Lines changed: 0 additions & 91 deletions
This file was deleted.

servlet/spring-boot/java/authentication/mfa/formLogin+ott/src/main/java/org/example/magiclink/MagicLinkApplication.java

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,6 @@ public static void main(String[] args) {
3838
@Controller
3939
static class AppController {
4040
@GetMapping("/profile")
41-
@PreAuthorize("@authz.hasAuthority('profile:read')") // FIXME add hasAuthorityWithin once
42-
// GrantedAuthority is timestamped
4341
String profile() {
4442
return "profile";
4543
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
logging.level.org.springframework.security: TRACE

servlet/spring-boot/java/authentication/mfa/formLogin+ott/src/main/resources/templates/index.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,5 +16,6 @@
1616
</div>
1717
<h1>Hello Spring Security</h1>
1818
<p>This is a secured page</p>
19+
<p>Visit the <a href="/profile">profile</a> page</p>
1920
</body>
2021
</html>

0 commit comments

Comments
 (0)