diff --git a/docs/modules/ROOT/pages/reactive/authentication/onetimetoken.adoc b/docs/modules/ROOT/pages/reactive/authentication/onetimetoken.adoc index 9d5412e4b13..40e0b3cd706 100644 --- a/docs/modules/ROOT/pages/reactive/authentication/onetimetoken.adoc +++ b/docs/modules/ROOT/pages/reactive/authentication/onetimetoken.adoc @@ -53,138 +53,13 @@ Therefore, a custom javadoc:org.springframework.security.web.server.authenticati One of the most common delivery strategies is a Magic Link, via e-mail, SMS, etc. In the following example, we are going to create a magic link and sent it to the user's email. -.One-Time Token Login Configuration -[tabs] -====== -Java:: -+ -[source,java,role="primary"] ----- -@Configuration -@EnableWebFluxSecurity -public class SecurityConfig { - - @Bean - public SecurityWebFilterChain filterChain(ServerHttpSecurity http) { - http - // ... - .formLogin(Customizer.withDefaults()) - .oneTimeTokenLogin(Customizer.withDefaults()); - return http.build(); - } - -} - -import org.springframework.mail.SimpleMailMessage; -import org.springframework.mail.javamail.JavaMailSender; - -@Component <1> -public class MagicLinkOneTimeTokenGenerationSuccessHandler implements ServerOneTimeTokenGenerationSuccessHandler { - - private final MailSender mailSender; - - private final ServerOneTimeTokenGenerationSuccessHandler redirectHandler = new ServerRedirectOneTimeTokenGenerationSuccessHandler("/ott/sent"); - - // constructor omitted - - @Override - public Mono handle(ServerWebExchange exchange, OneTimeToken oneTimeToken) { - return Mono.just(exchange.getRequest()) - .map((request) -> - UriComponentsBuilder.fromUri(request.getURI()) - .replacePath(request.getPath().contextPath().value()) - .replaceQuery(null) - .fragment(null) - .path("/login/ott") - .queryParam("token", oneTimeToken.getTokenValue()) - .toUriString() <2> - ) - .flatMap((uri) -> this.mailSender.send(getUserEmail(oneTimeToken.getUsername()), <3> - "Use the following link to sign in into the application: " + magicLink)) <4> - .then(this.redirectHandler.handle(exchange, oneTimeToken)); <5> - } - - private String getUserEmail() { - // ... - } - -} - -@Controller -class PageController { - - @GetMapping("/ott/sent") - String ottSent() { - return "my-template"; - } - -} ----- - -Kotlin:: -+ -[source,kotlin,role="secondary"] ----- -@Configuration -@EnableWebFluxSecurity -class SecurityConfig { - - open fun springWebFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain { - return http { - authorizeExchange { - authorize(anyExchange, authenticated) - } - oneTimeTokenLogin { } - } - } - -} - -@Component (1) -class MagicLinkOneTimeTokenGenerationSuccessHandler(val mailSender: MailSender): ServerOneTimeTokenGenerationSuccessHandler { - - private val redirectStrategy: ServerRedirectStrategy = DefaultServerRedirectStrategy() - - override fun handle(exchange: ServerWebExchange, oneTimeToken: OneTimeToken): Mono { - val builder = UriComponentsBuilder.fromUri(exchange.request.uri) - .replacePath(null) - .replaceQuery(null) - .fragment(null) - .path("/login/ott") - .queryParam("token", oneTimeToken.getTokenValue()) (2) - val magicLink = builder.toUriString() - builder.replacePath(null) - .replaceQuery(null) - .path("/ott/sent") - val redirectLink = builder.toUriString() - return this.mailSender.send( - getUserEmail(oneTimeToken.getUsername()), (3) - "Use the following link to sign in into the application: $magicLink") (4) - .then(this.redirectStrategy.sendRedirect(exchange, URI.create(redirectLink))) (5) - } - - private String getUserEmail() { - // ... - } -} - -@Controller -class PageController { - - @GetMapping("/ott/sent") - fun ottSent(): String { - return "my-template" - } -} - ----- -====== - +include-code::./SecurityConfig[tag=config,indent=0] +include-code::./MagicLinkOneTimeTokenGenerationSuccessHandler[tag=snippet,indent=0] <1> Make the `MagicLinkOneTimeTokenGenerationSuccessHandler` a Spring bean <2> Create a login processing URL with the `token` as a query param <3> Retrieve the user's email based on the username <4> Use the `MailSender` API to send the email to the user with the magic link -<5> Use the `ServerRedirectStrategy` to perform a redirect to your desired URL +<5> Use the `ServerOneTimeTokenGenerationSuccessHandler` to perform a redirect to your desired URL The email content will look similar to: @@ -196,65 +71,10 @@ The default submit page will detect that the URL has the `token` query param and == Changing the One-Time Token Generate URL By default, the javadoc:org.springframework.security.web.server.authentication.ott.GenerateOneTimeTokenWebFilter[] listens to `POST /ott/generate` requests. -That URL can be changed by using the `generateTokenUrl(String)` DSL method: - -.Changing the Generate URL -[tabs] -====== -Java:: -+ -[source,java,role="primary"] ----- -@Configuration -@EnableWebFluxSecurity -public class SecurityConfig { - - @Bean - public SecurityWebFilterChain filterChain(ServerHttpSecurity http) { - http - // ... - .formLogin(Customizer.withDefaults()) - .oneTimeTokenLogin((ott) -> ott - .generateTokenUrl("/ott/my-generate-url") - ); - return http.build(); - } - -} - -@Component -public class MagicLinkOneTimeTokenGenerationSuccessHandler implements ServerOneTimeTokenGenerationSuccessHandler { - // ... -} ----- - -Kotlin:: -+ -[source,kotlin,role="secondary"] ----- -@Configuration -@EnableWebFluxSecurity -class SecurityConfig { - - open fun springWebFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain { - return http { - // ... - formLogin { } - oneTimeTokenLogin { - generateTokenUrl = "/ott/my-generate-url" - } - } - } - -} - -@Component -class MagicLinkOneTimeTokenGenerationSuccessHandler(val mailSender: MailSender): ServerOneTimeTokenGenerationSuccessHandler { - // ... -} - ----- -====== +That URL can be changed by using the `tokenGeneratingUrl(String)` DSL method: + +include-code::./SecurityConfig[tag=config,indent=0] +include-code::./MagicLinkOneTimeTokenGenerationSuccessHandler[tag=snippet,indent=0] [[changing-submit-page-url]] == Changing the Default Submit Page URL @@ -262,151 +82,17 @@ class MagicLinkOneTimeTokenGenerationSuccessHandler(val mailSender: MailSender): The default One-Time Token submit page is generated by the javadoc:org.springframework.security.web.server.ui.OneTimeTokenSubmitPageGeneratingWebFilter[] and listens to `GET /login/ott`. The URL can also be changed, like so: -.Configuring the Default Submit Page URL -[tabs] -====== -Java:: -+ -[source,java,role="primary"] ----- -@Configuration -@EnableWebFluxSecurity -public class SecurityConfig { - - @Bean - public SecurityWebFilterChain filterChain(ServerHttpSecurity http) { - http - // ... - .formLogin(Customizer.withDefaults()) - .oneTimeTokenLogin((ott) -> ott - .submitPageUrl("/ott/submit") - ); - return http.build(); - } - -} - -@Component -public class MagicLinkOneTimeTokenGenerationSuccessHandler implements ServerOneTimeTokenGenerationSuccessHandler { - // ... -} ----- - -Kotlin:: -+ -[source,kotlin,role="secondary"] ----- -@Configuration -@EnableWebFluxSecurity -class SecurityConfig { - - open fun springWebFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain { - return http { - // ... - formLogin { } - oneTimeTokenLogin { - submitPageUrl = "/ott/submit" - } - } - } - -} - -@Component -class MagicLinkOneTimeTokenGenerationSuccessHandler(val mailSender: MailSender): ServerOneTimeTokenGenerationSuccessHandler { - // ... -} - ----- -====== +include-code::./SecurityConfig[tag=config,indent=0] +include-code::./MagicLinkOneTimeTokenGenerationSuccessHandler[tag=snippet,indent=0] [[disabling-default-submit-page]] == Disabling the Default Submit Page If you want to use your own One-Time Token submit page, you can disable the default page and then provide your own endpoint. -.Disabling the Default Submit Page -[tabs] -====== -Java:: -+ -[source,java,role="primary"] ----- -@Configuration -@EnableWebFluxSecurity -public class SecurityConfig { - - @Bean - public SecurityWebFilterChain filterChain(ServerHttpSecurity http) { - http - .authorizeExchange((authorize) -> authorize - .pathMatchers("/my-ott-submit").permitAll() - .anyExchange().authenticated() - ) - .formLogin(Customizer.withDefaults()) - .oneTimeTokenLogin((ott) -> ott - .showDefaultSubmitPage(false) - ); - return http.build(); - } - -} - -@Controller -public class MyController { - - @GetMapping("/my-ott-submit") - public String ottSubmitPage() { - return "my-ott-submit"; - } - -} - -@Component -public class MagicLinkOneTimeTokenGenerationSuccessHandler implements ServerOneTimeTokenGenerationSuccessHandler { - // ... -} ----- - -Kotlin:: -+ -[source,kotlin,role="secondary"] ----- -@Configuration -@EnableWebFluxSecurity -class SecurityConfig { - - open fun springWebFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain { - return http { - authorizeExchange { - authorize(pathMatchers("/my-ott-submit"), permitAll) - authorize(anyExchange, authenticated) - } - .formLogin { } - oneTimeTokenLogin { - showDefaultSubmitPage = false - } - } - } - -} - -@Controller -class MyController { - - @GetMapping("/my-ott-submit") - fun ottSubmitPage(): String { - return "my-ott-submit" - } -} - -@Component -class MagicLinkOneTimeTokenGenerationSuccessHandler(val mailSender: MailSender): ServerOneTimeTokenGenerationSuccessHandler { - // ... -} - ----- -====== +include-code::./SecurityConfig[tag=config,indent=0] +include-code::./MagicLinkOneTimeTokenGenerationSuccessHandler[tag=snippet,indent=0] +include-code::./MyController[tag=snippet,indent=0] [[customize-generate-consume-token]] == Customize How to Generate and Consume One-Time Tokens @@ -424,157 +110,16 @@ Some of the most common reasons to customize the `ReactiveOneTimeTokenService` a There are two options to customize the `ReactiveOneTimeTokenService`. One option is to provide it as a bean, so it can be automatically be picked-up by the `oneTimeTokenLogin()` DSL: -.Passing the ReactiveOneTimeTokenService as a Bean -[tabs] -====== -Java:: -+ -[source,java,role="primary"] ----- -@Configuration -@EnableWebFluxSecurity -public class SecurityConfig { - - @Bean - public SecurityWebFilterChain filterChain(ServerHttpSecurity http) { - http - // ... - .formLogin(Customizer.withDefaults()) - .oneTimeTokenLogin(Customizer.withDefaults()); - return http.build(); - } - - @Bean - public ReactiveOneTimeTokenService oneTimeTokenService() { - return new MyCustomReactiveOneTimeTokenService(); - } - -} - -@Component -public class MagicLinkOneTimeTokenGenerationSuccessHandler implements ServerOneTimeTokenGenerationSuccessHandler { - // ... -} ----- - -Kotlin:: -+ -[source,kotlin,role="secondary"] ----- -@Configuration -@EnableWebFluxSecurity -class SecurityConfig { - - open fun springWebFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain { - return http { - //.. - .formLogin { } - oneTimeTokenLogin { } - } - } - - @Bean - open fun oneTimeTokenService():ReactiveOneTimeTokenService { - return MyCustomReactiveOneTimeTokenService(); - } - -} - -@Component -class MagicLinkOneTimeTokenGenerationSuccessHandler(val mailSender: MailSender): ServerOneTimeTokenGenerationSuccessHandler { - // ... -} - ----- -====== +include-code::./OneTimeTokenServiceBeanSecurityConfig[tag=config,indent=0] +include-code::./MagicLinkOneTimeTokenGenerationSuccessHandler[tag=snippet,indent=0] The second option is to pass the `ReactiveOneTimeTokenService` instance to the DSL, which is useful if there are multiple ``SecurityWebFilterChain``s and a different ``ReactiveOneTimeTokenService``s is needed for each of them. -.Passing the ReactiveOneTimeTokenService using the DSL -[tabs] -====== -Java:: -+ -[source,java,role="primary"] ----- -@Configuration -@EnableWebFluxSecurity -public class SecurityConfig { - - @Bean - public SecurityWebFilterChain filterChain(ServerHttpSecurity http) { - http - // ... - .formLogin(Customizer.withDefaults()) - .oneTimeTokenLogin((ott) -> ott - .oneTimeTokenService(new MyCustomReactiveOneTimeTokenService()) - ); - return http.build(); - } - -} - -@Component -public class MagicLinkOneTimeTokenGenerationSuccessHandler implements ServerOneTimeTokenGenerationSuccessHandler { - // ... -} ----- - -Kotlin:: -+ -[source,kotlin,role="secondary"] ----- -@Configuration -@EnableWebFluxSecurity -class SecurityConfig { - - open fun springWebFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain { - return http { - //.. - .formLogin { } - oneTimeTokenLogin { - oneTimeTokenService = MyCustomReactiveOneTimeTokenService() - } - } - } -} - -@Component -class MagicLinkOneTimeTokenGenerationSuccessHandler(val mailSender: MailSender): ServerOneTimeTokenGenerationSuccessHandler { - // ... -} - ----- -====== +include-code::./OneTimeTokenServiceDSLSecurityConfig[tag=config,indent=0] +include-code::./MagicLinkOneTimeTokenGenerationSuccessHandler[tag=snippet,indent=0] [[customize-generate-token-request]] == Customize GenerateOneTimeTokenRequest Instance There are a number of reasons that you may want to adjust an GenerateOneTimeTokenRequest. For example, you may want expiresIn to be set to 10 mins, which Spring Security sets to 5 mins by default. -You can customize elements of GenerateOneTimeTokenRequest by publishing an ServerGenerateOneTimeTokenRequestResolver as a @Bean, like so: -[tabs] -====== -Java:: -+ -[source,java,role="primary"] ----- -@Bean -ServerGenerateOneTimeTokenRequestResolver generateOneTimeTokenRequestResolver() { - DefaultServerGenerateOneTimeTokenRequestResolver resolver = new DefaultServerGenerateOneTimeTokenRequestResolver(); - resolver.setExpiresIn(Duration.ofSeconds(600)); - return resolver; -} ----- - -Kotlin:: -+ -[source,kotlin,role="secondary"] ----- -@Bean -fun generateOneTimeTokenRequestResolver() : ServerGenerateOneTimeTokenRequestResolver { - return DefaultServerGenerateOneTimeTokenRequestResolver().apply { - this.setExpiresIn(Duration.ofMinutes(10)) - } -} ----- -====== +include-code::./SecurityConfig[tag=config,indent=0] diff --git a/docs/modules/ROOT/pages/servlet/authentication/onetimetoken.adoc b/docs/modules/ROOT/pages/servlet/authentication/onetimetoken.adoc index 71875261464..3c392645649 100644 --- a/docs/modules/ROOT/pages/servlet/authentication/onetimetoken.adoc +++ b/docs/modules/ROOT/pages/servlet/authentication/onetimetoken.adoc @@ -53,133 +53,12 @@ Therefore, a custom javadoc:org.springframework.security.web.authentication.ott. One of the most common delivery strategies is a Magic Link, via e-mail, SMS, etc. In the following example, we are going to create a magic link and sent it to the user's email. -.One-Time Token Login Configuration -[tabs] -====== -Java:: -+ -[source,java,role="primary"] ----- -@Configuration -@EnableWebSecurity -public class SecurityConfig { - - @Bean - public SecurityFilterChain filterChain(HttpSecurity http) { - http - // ... - .formLogin(Customizer.withDefaults()) - .oneTimeTokenLogin(Customizer.withDefaults()); - return http.build(); - } - -} - -import org.springframework.mail.SimpleMailMessage; -import org.springframework.mail.javamail.JavaMailSender; - -@Component <1> -public class MagicLinkOneTimeTokenGenerationSuccessHandler implements OneTimeTokenGenerationSuccessHandler { - - private final MailSender mailSender; - - private final OneTimeTokenGenerationSuccessHandler redirectHandler = new RedirectOneTimeTokenGenerationSuccessHandler("/ott/sent"); - - // constructor omitted - - @Override - public void handle(HttpServletRequest request, HttpServletResponse response, OneTimeToken oneTimeToken) throws IOException, ServletException { - UriComponentsBuilder builder = UriComponentsBuilder.fromUriString(request.getRequestURL().toString()) - .replacePath(request.getContextPath()) - .replaceQuery(null) - .fragment(null) - .path("/login/ott") - .queryParam("token", oneTimeToken.getTokenValue()); <2> - String magicLink = builder.toUriString(); - String email = getUserEmail(oneTimeToken.getUsername()); <3> - this.mailSender.send(email, "Your Spring Security One Time Token", "Use the following link to sign in into the application: " + magicLink); <4> - this.redirectHandler.handle(request, response, oneTimeToken); <5> - } - - private String getUserEmail() { - // ... - } - -} - -@Controller -class PageController { - - @GetMapping("/ott/sent") - String ottSent() { - return "my-template"; - } - -} - ----- - -Kotlin:: -+ -[source,kotlin,role="secondary"] ----- -@Configuration -@EnableWebSecurity -class SecurityConfig { - - @Bean - open fun filterChain(http: HttpSecurity): SecurityFilterChain { - http{ - formLogin {} - oneTimeTokenLogin { } - } - return http.build() - } -} - -import org.springframework.mail.SimpleMailMessage; -import org.springframework.mail.javamail.JavaMailSender; - -@Component (1) -class MagicLinkOneTimeTokenGenerationSuccessHandler( - private val mailSender: MailSender, - private val redirectHandler: OneTimeTokenGenerationSuccessHandler = RedirectOneTimeTokenGenerationSuccessHandler("/ott/sent") -) : OneTimeTokenGenerationSuccessHandler { - - override fun handle(request: HttpServletRequest, response: HttpServletResponse, oneTimeToken: OneTimeToken) { - val builder = UriComponentsBuilder.fromUriString(request.getRequestURL().toString()) - .replacePath(request.contextPath) - .replaceQuery(null) - .fragment(null) - .path("/login/ott") - .queryParam("token", oneTimeToken.getTokenValue()) (2) - val magicLink = builder.toUriString() - val email = getUserEmail(oneTimeToken.getUsername()) (3) - this.mailSender.send(email, "Your Spring Security One Time Token", "Use the following link to sign in into the application: $magicLink")(4) - this.redirectHandler.handle(request, response, oneTimeToken) (5) - } - - private fun getUserEmail(): String { - // ... - } -} - -@Controller -class PageController { - - @GetMapping("/ott/sent") - fun ottSent(): String { - return "my-template" - } -} - ----- -====== - +include-code::./SecurityConfig[tag=config,indent=0] +include-code::./MagicLinkOneTimeTokenGenerationSuccessHandler[tag=snippet,indent=0] <1> Make the `MagicLinkOneTimeTokenGenerationSuccessHandler` a Spring bean <2> Create a login processing URL with the `token` as a query param <3> Retrieve the user's email based on the username -<4> Use the `JavaMailSender` API to send the email to the user with the magic link +<4> Use the `MailSender` API to send the email to the user with the magic link <5> Use the `RedirectOneTimeTokenGenerationSuccessHandler` to perform a redirect to your desired URL The email content will look similar to: @@ -192,70 +71,15 @@ The default submit page will detect that the URL has the `token` query param and == Changing the One-Time Token Generate URL By default, the javadoc:org.springframework.security.web.authentication.ott.GenerateOneTimeTokenFilter[] listens to `POST /ott/generate` requests. -That URL can be changed by using the `generateTokenUrl(String)` DSL method: - -.Changing the Generate URL -[tabs] -====== -Java:: -+ -[source,java,role="primary"] ----- -@Configuration -@EnableWebSecurity -public class SecurityConfig { - - @Bean - public SecurityFilterChain filterChain(HttpSecurity http) { - http - // ... - .formLogin(Customizer.withDefaults()) - .oneTimeTokenLogin((ott) -> ott - .tokenGeneratingUrl("/ott/my-generate-url") - ); - return http.build(); - } - -} - -@Component -public class MagicLinkOneTimeTokenGenerationSuccessHandler implements OneTimeTokenGenerationSuccessHandler { - // ... -} ----- - -Kotlin:: -+ -[source,kotlin,role="secondary"] ----- -@Configuration -@EnableWebSecurity -class SecurityConfig { - - @Bean - open fun filterChain(http: HttpSecurity): SecurityFilterChain { - http { - //... - formLogin { } - oneTimeTokenLogin { - tokenGeneratingUrl = "/ott/my-generate-url" - } - } - return http.build() - } -} - -@Component -class MagicLinkOneTimeTokenGenerationSuccessHandler : OneTimeTokenGenerationSuccessHandler { - // ... -} ----- -====== +That URL can be changed by using the `tokenGeneratingUrl(String)` DSL method: + +include-code::./SecurityConfig[tag=config,indent=0] +include-code::./MagicLinkOneTimeTokenGenerationSuccessHandler[tag=snippet,indent=0] [NOTE] ==== -The URI passed to `generateTokenUrl` is matched literally. -If you want it to live under your application servlet's base path, include that prefix explicitly — for example, `generateTokenUrl("/api/ott/generate")`. +The URI passed to `tokenGeneratingUrl` is matched literally. +If you want it to live under your application servlet's base path, include that prefix explicitly — for example, `tokenGeneratingUrl("/api/ott/generate")`. The same applies to `loginProcessingUrl` and `tokenGeneratingUrl` elsewhere on this page. ==== @@ -265,151 +89,17 @@ The same applies to `loginProcessingUrl` and `tokenGeneratingUrl` elsewhere on t The default One-Time Token submit page is generated by the javadoc:org.springframework.security.web.authentication.ui.DefaultOneTimeTokenSubmitPageGeneratingFilter[] and listens to `GET /login/ott`. The URL can also be changed, like so: -.Configuring the Default Submit Page URL -[tabs] -====== -Java:: -+ -[source,java,role="primary"] ----- -@Configuration -@EnableWebSecurity -public class SecurityConfig { - - @Bean - public SecurityFilterChain filterChain(HttpSecurity http) { - http - // ... - .formLogin(Customizer.withDefaults()) - .oneTimeTokenLogin((ott) -> ott - .defaultSubmitPageUrl("/ott/submit") - ); - return http.build(); - } - -} - -@Component -public class MagicLinkGenerationSuccessHandler implements OneTimeTokenGenerationSuccessHandler { - // ... -} ----- - -Kotlin:: -+ -[source,kotlin,role="secondary"] ----- -@Configuration -@EnableWebSecurity -class SecurityConfig { - - @Bean - open fun filterChain(http: HttpSecurity): SecurityFilterChain { - http { - //... - formLogin { } - oneTimeTokenLogin { - defaultSubmitPageUrl = "/ott/submit" - } - } - return http.build() - } -} - -@Component -class MagicLinkOneTimeTokenGenerationSuccessHandler : OneTimeTokenGenerationSuccessHandler { - // ... -} ----- -====== +include-code::./SecurityConfig[tag=config,indent=0] +include-code::./MagicLinkOneTimeTokenGenerationSuccessHandler[tag=snippet,indent=0] [[disabling-default-submit-page]] == Disabling the Default Submit Page If you want to use your own One-Time Token submit page, you can disable the default page and then provide your own endpoint. -.Disabling the Default Submit Page -[tabs] -====== -Java:: -+ -[source,java,role="primary"] ----- -@Configuration -@EnableWebSecurity -public class SecurityConfig { - - @Bean - public SecurityFilterChain filterChain(HttpSecurity http) { - http - .authorizeHttpRequests((authorize) -> authorize - .requestMatchers("/my-ott-submit").permitAll() - .anyRequest().authenticated() - ) - .formLogin(Customizer.withDefaults()) - .oneTimeTokenLogin((ott) -> ott - .showDefaultSubmitPage(false) - ); - return http.build(); - } - -} - -@Controller -public class MyController { - - @GetMapping("/my-ott-submit") - public String ottSubmitPage() { - return "my-ott-submit"; - } - -} - -@Component -public class OneTimeTokenGenerationSuccessHandler implements OneTimeTokenGenerationSuccessHandler { - // ... -} ----- - -Kotlin:: -+ -[source,kotlin,role="secondary"] ----- -@Configuration -@EnableWebSecurity -class SecurityConfig { - - @Bean - open fun filterChain(http: HttpSecurity): SecurityFilterChain { - http { - authorizeHttpRequests { - authorize("/my-ott-submit", authenticated) - authorize(anyRequest, authenticated) - } - formLogin { } - oneTimeTokenLogin { - showDefaultSubmitPage = false - } - } - return http.build() - } -} - -@Controller -class MyController { - - @GetMapping("/my-ott-submit") - fun ottSubmitPage(): String { - return "my-ott-submit" - } -} - -@Component -class MagicLinkOneTimeTokenGenerationSuccessHandler : OneTimeTokenGenerationSuccessHandler { - // ... -} ----- -====== +include-code::./SecurityConfig[tag=config,indent=0] +include-code::./MagicLinkOneTimeTokenGenerationSuccessHandler[tag=snippet,indent=0] +include-code::./MyController[tag=snippet,indent=0] [[customize-generate-consume-token]] == Customize How to Generate and Consume One-Time Tokens @@ -428,161 +118,18 @@ Some of the most common reasons to customize the `OneTimeTokenService` are, but There are two options to customize the `OneTimeTokenService`. One option is to provide it as a bean, so it can be automatically be picked-up by the `oneTimeTokenLogin()` DSL: -.Passing the OneTimeTokenService as a Bean -[tabs] -====== -Java:: -+ -[source,java,role="primary"] ----- -@Configuration -@EnableWebSecurity -public class SecurityConfig { - - @Bean - public SecurityFilterChain filterChain(HttpSecurity http) { - http - // ... - .formLogin(Customizer.withDefaults()) - .oneTimeTokenLogin(Customizer.withDefaults()); - return http.build(); - } - - @Bean - public OneTimeTokenService oneTimeTokenService() { - return new MyCustomOneTimeTokenService(); - } - -} - -@Component -public class MagicLinkOneTimeTokenGenerationSuccessHandler implements OneTimeTokenGenerationSuccessHandler { - // ... -} ----- - -Kotlin:: -+ -[source,kotlin,role="secondary"] ----- -@Configuration -@EnableWebSecurity -class SecurityConfig { - - @Bean - open fun filterChain(http: HttpSecurity): SecurityFilterChain { - http { - //... - formLogin { } - oneTimeTokenLogin { } - } - return http.build() - } - - @Bean - open fun oneTimeTokenService(): OneTimeTokenService { - return MyCustomOneTimeTokenService() - } -} - -@Component -class MagicLinkOneTimeTokenGenerationSuccessHandler : OneTimeTokenGenerationSuccessHandler { - // ... -} ----- -====== +include-code::./OneTimeTokenServiceBeanSecurityConfig[tag=config,indent=0] +include-code::./MagicLinkOneTimeTokenGenerationSuccessHandler[tag=snippet,indent=0] The second option is to pass the `OneTimeTokenService` instance to the DSL, which is useful if there are multiple `SecurityFilterChain` and a different `OneTimeTokenService` is needed for each of them. -.Passing the OneTimeTokenService using the DSL -[tabs] -====== -Java:: -+ -[source,java,role="primary"] ----- -@Configuration -@EnableWebSecurity -public class SecurityConfig { - - @Bean - public SecurityFilterChain filterChain(HttpSecurity http) { - http - // ... - .formLogin(Customizer.withDefaults()) - .oneTimeTokenLogin((ott) -> ott - .oneTimeTokenService(new MyCustomOneTimeTokenService()) - ); - return http.build(); - } - -} - -@Component -public class MagicLinkOneTimeTokenGenerationSuccessHandler implements OneTimeTokenGenerationSuccessHandler { - // ... -} ----- - -Kotlin:: -+ -[source,kotlin,role="secondary"] ----- -@Configuration -@EnableWebSecurity -class SecurityConfig { - - @Bean - open fun filterChain(http: HttpSecurity): SecurityFilterChain { - http { - //... - formLogin { } - oneTimeTokenLogin { - oneTimeTokenService = MyCustomOneTimeTokenService() - } - } - return http.build() - } - -} - -@Component -class MagicLinkOneTimeTokenGenerationSuccessHandler : OneTimeTokenGenerationSuccessHandler { - // ... -} ----- -====== +include-code::./OneTimeTokenServiceDSLSecurityConfig[tag=config,indent=0] +include-code::./MagicLinkOneTimeTokenGenerationSuccessHandler[tag=snippet,indent=0] [[customize-generate-token-request]] == Customize GenerateOneTimeTokenRequest Instance There are a number of reasons that you may want to adjust an GenerateOneTimeTokenRequest. For example, you may want expiresIn to be set to 10 mins, which Spring Security sets to 5 mins by default. -You can customize elements of GenerateOneTimeTokenRequest by publishing an GenerateOneTimeTokenRequestResolver as a @Bean, like so: -[tabs] -====== -Java:: -+ -[source,java,role="primary"] ----- -@Bean -GenerateOneTimeTokenRequestResolver generateOneTimeTokenRequestResolver() { - DefaultGenerateOneTimeTokenRequestResolver delegate = new DefaultGenerateOneTimeTokenRequestResolver(); - return (request) -> { - GenerateOneTimeTokenRequest generate = delegate.resolve(request); - return new GenerateOneTimeTokenRequest(generate.getUsername(), Duration.ofSeconds(600)); - }; -} ----- - -Kotlin:: -+ -[source,kotlin,role="secondary"] ----- -@Bean -fun generateRequestResolver() : GenerateOneTimeTokenRequestResolver { - return DefaultGenerateOneTimeTokenRequestResolver().apply { - this.setExpiresIn(Duration.ofMinutes(10)) - } -} ----- -====== +You can customize elements of GenerateOneTimeTokenRequest by publishing an GenerateOneTimeTokenRequestResolver as a `@Bean`, like so: + +include-code::./SecurityConfig[tag=config,indent=0] diff --git a/docs/spring-security-docs.gradle b/docs/spring-security-docs.gradle index 15612b8dda8..45717496a22 100644 --- a/docs/spring-security-docs.gradle +++ b/docs/spring-security-docs.gradle @@ -53,6 +53,7 @@ dependencies { testImplementation 'org.springframework:spring-test' testImplementation 'org.springframework:spring-webmvc' + testImplementation 'org.springframework:spring-context-support' testImplementation 'jakarta.servlet:jakarta.servlet-api' testImplementation 'io.mockk:mockk' testImplementation "org.junit.jupiter:junit-jupiter-api" diff --git a/docs/src/test/java/org/springframework/security/docs/reactive/authentication/changinggenerateurl/MagicLinkOneTimeTokenGenerationSuccessHandler.java b/docs/src/test/java/org/springframework/security/docs/reactive/authentication/changinggenerateurl/MagicLinkOneTimeTokenGenerationSuccessHandler.java new file mode 100644 index 00000000000..6d1aeeb1151 --- /dev/null +++ b/docs/src/test/java/org/springframework/security/docs/reactive/authentication/changinggenerateurl/MagicLinkOneTimeTokenGenerationSuccessHandler.java @@ -0,0 +1,35 @@ +/* + * Copyright 2004-present 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. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.security.docs.reactive.authentication.changinggenerateurl; + +import org.springframework.security.authentication.ott.OneTimeToken; +import org.springframework.security.web.server.authentication.ott.ServerOneTimeTokenGenerationSuccessHandler; +import org.springframework.stereotype.Component; +import org.springframework.web.server.ServerWebExchange; +import reactor.core.publisher.Mono; + +// tag::snippet[] +@Component +public class MagicLinkOneTimeTokenGenerationSuccessHandler implements ServerOneTimeTokenGenerationSuccessHandler { + + @Override + public Mono handle(ServerWebExchange exchange, OneTimeToken oneTimeToken) { + /**/ return Mono.empty(); + } + +} +// end::snippet[] \ No newline at end of file diff --git a/docs/src/test/java/org/springframework/security/docs/reactive/authentication/changinggenerateurl/SecurityConfig.java b/docs/src/test/java/org/springframework/security/docs/reactive/authentication/changinggenerateurl/SecurityConfig.java new file mode 100644 index 00000000000..81b1740548c --- /dev/null +++ b/docs/src/test/java/org/springframework/security/docs/reactive/authentication/changinggenerateurl/SecurityConfig.java @@ -0,0 +1,43 @@ +/* + * Copyright 2004-present 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. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.security.docs.reactive.authentication.changinggenerateurl; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.config.Customizer; +import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity; +import org.springframework.security.config.web.server.ServerHttpSecurity; +import org.springframework.security.web.server.SecurityWebFilterChain; + +// tag::config[] +@Configuration +@EnableWebFluxSecurity +public class SecurityConfig { + + @Bean + public SecurityWebFilterChain filterChain(ServerHttpSecurity http) { + http + // ... + .formLogin(Customizer.withDefaults()) + .oneTimeTokenLogin((ott) -> ott + .tokenGeneratingUrl("/ott/my-generate-url") + ); + return http.build(); + } + +} +// end::config[] \ No newline at end of file diff --git a/docs/src/test/java/org/springframework/security/docs/reactive/authentication/changingsubmitpageurl/MagicLinkOneTimeTokenGenerationSuccessHandler.java b/docs/src/test/java/org/springframework/security/docs/reactive/authentication/changingsubmitpageurl/MagicLinkOneTimeTokenGenerationSuccessHandler.java new file mode 100644 index 00000000000..9d8d3afb7c3 --- /dev/null +++ b/docs/src/test/java/org/springframework/security/docs/reactive/authentication/changingsubmitpageurl/MagicLinkOneTimeTokenGenerationSuccessHandler.java @@ -0,0 +1,35 @@ +/* + * Copyright 2004-present 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. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.security.docs.reactive.authentication.changingsubmitpageurl; + +import org.springframework.security.authentication.ott.OneTimeToken; +import org.springframework.security.web.server.authentication.ott.ServerOneTimeTokenGenerationSuccessHandler; +import org.springframework.stereotype.Component; +import org.springframework.web.server.ServerWebExchange; +import reactor.core.publisher.Mono; + +// tag::snippet[] +@Component +public class MagicLinkOneTimeTokenGenerationSuccessHandler implements ServerOneTimeTokenGenerationSuccessHandler { + + @Override + public Mono handle(ServerWebExchange exchange, OneTimeToken oneTimeToken) { + /**/ return Mono.empty(); + } + +} +// end::snippet[] \ No newline at end of file diff --git a/docs/src/test/java/org/springframework/security/docs/reactive/authentication/changingsubmitpageurl/SecurityConfig.java b/docs/src/test/java/org/springframework/security/docs/reactive/authentication/changingsubmitpageurl/SecurityConfig.java new file mode 100644 index 00000000000..0e5583e7e04 --- /dev/null +++ b/docs/src/test/java/org/springframework/security/docs/reactive/authentication/changingsubmitpageurl/SecurityConfig.java @@ -0,0 +1,43 @@ +/* + * Copyright 2004-present 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. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.security.docs.reactive.authentication.changingsubmitpageurl; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.config.Customizer; +import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity; +import org.springframework.security.config.web.server.ServerHttpSecurity; +import org.springframework.security.web.server.SecurityWebFilterChain; + +// tag::config[] +@Configuration +@EnableWebFluxSecurity +public class SecurityConfig { + + @Bean + public SecurityWebFilterChain filterChain(ServerHttpSecurity http) { + http + // ... + .formLogin(Customizer.withDefaults()) + .oneTimeTokenLogin((ott) -> ott + .defaultSubmitPageUrl("/ott/submit") + ); + return http.build(); + } + +} +// end::config[] \ No newline at end of file diff --git a/docs/src/test/java/org/springframework/security/docs/reactive/authentication/customizegenerateconsumetoken/MagicLinkOneTimeTokenGenerationSuccessHandler.java b/docs/src/test/java/org/springframework/security/docs/reactive/authentication/customizegenerateconsumetoken/MagicLinkOneTimeTokenGenerationSuccessHandler.java new file mode 100644 index 00000000000..5d57661c340 --- /dev/null +++ b/docs/src/test/java/org/springframework/security/docs/reactive/authentication/customizegenerateconsumetoken/MagicLinkOneTimeTokenGenerationSuccessHandler.java @@ -0,0 +1,35 @@ +/* + * Copyright 2004-present 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. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.security.docs.reactive.authentication.customizegenerateconsumetoken; + +import org.springframework.security.authentication.ott.OneTimeToken; +import org.springframework.security.web.server.authentication.ott.ServerOneTimeTokenGenerationSuccessHandler; +import org.springframework.stereotype.Component; +import org.springframework.web.server.ServerWebExchange; +import reactor.core.publisher.Mono; + +// tag::snippet[] +@Component +public class MagicLinkOneTimeTokenGenerationSuccessHandler implements ServerOneTimeTokenGenerationSuccessHandler { + + @Override + public Mono handle(ServerWebExchange exchange, OneTimeToken oneTimeToken) { + /**/ return Mono.empty(); + } + +} +// end::snippet[] \ No newline at end of file diff --git a/docs/src/test/java/org/springframework/security/docs/reactive/authentication/customizegenerateconsumetoken/MyCustomReactiveOneTimeTokenService.java b/docs/src/test/java/org/springframework/security/docs/reactive/authentication/customizegenerateconsumetoken/MyCustomReactiveOneTimeTokenService.java new file mode 100644 index 00000000000..bade97a060c --- /dev/null +++ b/docs/src/test/java/org/springframework/security/docs/reactive/authentication/customizegenerateconsumetoken/MyCustomReactiveOneTimeTokenService.java @@ -0,0 +1,38 @@ +/* + * Copyright 2004-present 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. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.security.docs.reactive.authentication.customizegenerateconsumetoken; + +import org.springframework.security.authentication.ott.GenerateOneTimeTokenRequest; +import org.springframework.security.authentication.ott.OneTimeToken; +import org.springframework.security.authentication.ott.OneTimeTokenAuthenticationToken; +import org.springframework.security.authentication.ott.reactive.ReactiveOneTimeTokenService; +import reactor.core.publisher.Mono; + +class MyCustomReactiveOneTimeTokenService implements ReactiveOneTimeTokenService { + + + @Override + public Mono generate(GenerateOneTimeTokenRequest request) { + return null; + } + + @Override + public Mono consume(OneTimeTokenAuthenticationToken authenticationToken) { + return null; + } + +} \ No newline at end of file diff --git a/docs/src/test/java/org/springframework/security/docs/reactive/authentication/customizegenerateconsumetoken/OneTimeTokenServiceBeanSecurityConfig.java b/docs/src/test/java/org/springframework/security/docs/reactive/authentication/customizegenerateconsumetoken/OneTimeTokenServiceBeanSecurityConfig.java new file mode 100644 index 00000000000..01f6de13ccc --- /dev/null +++ b/docs/src/test/java/org/springframework/security/docs/reactive/authentication/customizegenerateconsumetoken/OneTimeTokenServiceBeanSecurityConfig.java @@ -0,0 +1,48 @@ +/* + * Copyright 2004-present 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. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.security.docs.reactive.authentication.customizegenerateconsumetoken; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.authentication.ott.reactive.ReactiveOneTimeTokenService; +import org.springframework.security.config.Customizer; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.config.web.server.ServerHttpSecurity; +import org.springframework.security.kt.docs.reactive.authentication.customizegenerateconsumetoken.MyCustomReactiveOneTimeTokenService; +import org.springframework.security.web.server.SecurityWebFilterChain; + +// tag::config[] +@Configuration +@EnableWebSecurity +public class OneTimeTokenServiceBeanSecurityConfig { + + @Bean + public SecurityWebFilterChain filterChain(ServerHttpSecurity http) { + http + // ... + .formLogin(Customizer.withDefaults()) + .oneTimeTokenLogin(Customizer.withDefaults()); + return http.build(); + } + + @Bean + public ReactiveOneTimeTokenService oneTimeTokenService() { + return new MyCustomReactiveOneTimeTokenService(); + } + +} +// end::config[] \ No newline at end of file diff --git a/docs/src/test/java/org/springframework/security/docs/reactive/authentication/customizegenerateconsumetoken/OneTimeTokenServiceDSLSecurityConfig.java b/docs/src/test/java/org/springframework/security/docs/reactive/authentication/customizegenerateconsumetoken/OneTimeTokenServiceDSLSecurityConfig.java new file mode 100644 index 00000000000..2b61d39d38d --- /dev/null +++ b/docs/src/test/java/org/springframework/security/docs/reactive/authentication/customizegenerateconsumetoken/OneTimeTokenServiceDSLSecurityConfig.java @@ -0,0 +1,43 @@ +/* + * Copyright 2004-present 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. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.security.docs.reactive.authentication.customizegenerateconsumetoken; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.config.Customizer; +import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity; +import org.springframework.security.config.web.server.ServerHttpSecurity; +import org.springframework.security.web.server.SecurityWebFilterChain; + +// tag::config[] +@Configuration +@EnableWebFluxSecurity +public class OneTimeTokenServiceDSLSecurityConfig { + + @Bean + public SecurityWebFilterChain filterChain(ServerHttpSecurity http) { + http + // ... + .formLogin(Customizer.withDefaults()) + .oneTimeTokenLogin((ott) -> ott + .tokenService(new MyCustomReactiveOneTimeTokenService()) + ); + return http.build(); + } + +} +// end::config[] \ No newline at end of file diff --git a/docs/src/test/java/org/springframework/security/docs/reactive/authentication/customizegeneratetokenrequest/SecurityConfig.java b/docs/src/test/java/org/springframework/security/docs/reactive/authentication/customizegeneratetokenrequest/SecurityConfig.java new file mode 100644 index 00000000000..4b9386cc2f3 --- /dev/null +++ b/docs/src/test/java/org/springframework/security/docs/reactive/authentication/customizegeneratetokenrequest/SecurityConfig.java @@ -0,0 +1,35 @@ +/* + * Copyright 2004-present 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. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.security.docs.reactive.authentication.customizegeneratetokenrequest; + +import java.time.Duration; +import org.springframework.context.annotation.Bean; +import org.springframework.security.web.server.authentication.ott.DefaultServerGenerateOneTimeTokenRequestResolver; +import org.springframework.security.web.server.authentication.ott.ServerGenerateOneTimeTokenRequestResolver; + +public class SecurityConfig { + + // tag::config[] + @Bean + ServerGenerateOneTimeTokenRequestResolver generateOneTimeTokenRequestResolver() { + DefaultServerGenerateOneTimeTokenRequestResolver resolver = new DefaultServerGenerateOneTimeTokenRequestResolver(); + resolver.setExpiresIn(Duration.ofMinutes(10)); + return resolver; + } + // end::config[] + +} \ No newline at end of file diff --git a/docs/src/test/java/org/springframework/security/docs/reactive/authentication/disablingdefaultsubmitpage/MagicLinkOneTimeTokenGenerationSuccessHandler.java b/docs/src/test/java/org/springframework/security/docs/reactive/authentication/disablingdefaultsubmitpage/MagicLinkOneTimeTokenGenerationSuccessHandler.java new file mode 100644 index 00000000000..ab831a1d5a5 --- /dev/null +++ b/docs/src/test/java/org/springframework/security/docs/reactive/authentication/disablingdefaultsubmitpage/MagicLinkOneTimeTokenGenerationSuccessHandler.java @@ -0,0 +1,35 @@ +/* + * Copyright 2004-present 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. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.security.docs.reactive.authentication.disablingdefaultsubmitpage; + +import org.springframework.security.authentication.ott.OneTimeToken; +import org.springframework.security.web.server.authentication.ott.ServerOneTimeTokenGenerationSuccessHandler; +import org.springframework.stereotype.Component; +import org.springframework.web.server.ServerWebExchange; +import reactor.core.publisher.Mono; + +// tag::snippet[] +@Component +public class MagicLinkOneTimeTokenGenerationSuccessHandler implements ServerOneTimeTokenGenerationSuccessHandler { + + @Override + public Mono handle(ServerWebExchange exchange, OneTimeToken oneTimeToken) { + /**/ return Mono.empty(); + } + +} +// end::snippet[] \ No newline at end of file diff --git a/docs/src/test/java/org/springframework/security/docs/reactive/authentication/disablingdefaultsubmitpage/MyController.java b/docs/src/test/java/org/springframework/security/docs/reactive/authentication/disablingdefaultsubmitpage/MyController.java new file mode 100644 index 00000000000..18355597124 --- /dev/null +++ b/docs/src/test/java/org/springframework/security/docs/reactive/authentication/disablingdefaultsubmitpage/MyController.java @@ -0,0 +1,32 @@ +/* + * Copyright 2004-present 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. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.security.docs.reactive.authentication.disablingdefaultsubmitpage; + +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; + +// tag::snippet[] +@Controller +public class MyController { + + @GetMapping("/my-ott-submit") + public String ottSubmitPage() { + return "my-ott-submit"; + } + +} +// end::snippet[] \ No newline at end of file diff --git a/docs/src/test/java/org/springframework/security/docs/reactive/authentication/disablingdefaultsubmitpage/SecurityConfig.java b/docs/src/test/java/org/springframework/security/docs/reactive/authentication/disablingdefaultsubmitpage/SecurityConfig.java new file mode 100644 index 00000000000..c2240e40853 --- /dev/null +++ b/docs/src/test/java/org/springframework/security/docs/reactive/authentication/disablingdefaultsubmitpage/SecurityConfig.java @@ -0,0 +1,46 @@ +/* + * Copyright 2004-present 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. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.security.docs.reactive.authentication.disablingdefaultsubmitpage; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.config.Customizer; +import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity; +import org.springframework.security.config.web.server.ServerHttpSecurity; +import org.springframework.security.web.server.SecurityWebFilterChain; + +// tag::config[] +@Configuration +@EnableWebFluxSecurity +public class SecurityConfig { + + @Bean + public SecurityWebFilterChain filterChain(ServerHttpSecurity http) { + http + .authorizeExchange((authorize) -> authorize + .pathMatchers("/my-ott-submit").permitAll() + .anyExchange().authenticated() + ) + .formLogin(Customizer.withDefaults()) + .oneTimeTokenLogin((ott) -> ott + .showDefaultSubmitPage(false) + ); + return http.build(); + } + +} +// end::config[] \ No newline at end of file diff --git a/docs/src/test/java/org/springframework/security/docs/reactive/authentication/sendingtokentouser/MagicLinkOneTimeTokenGenerationSuccessHandler.java b/docs/src/test/java/org/springframework/security/docs/reactive/authentication/sendingtokentouser/MagicLinkOneTimeTokenGenerationSuccessHandler.java new file mode 100644 index 00000000000..998cb551cbf --- /dev/null +++ b/docs/src/test/java/org/springframework/security/docs/reactive/authentication/sendingtokentouser/MagicLinkOneTimeTokenGenerationSuccessHandler.java @@ -0,0 +1,84 @@ +/* + * Copyright 2004-present 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. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.security.docs.reactive.authentication.sendingtokentouser; + +import org.springframework.mail.MailSender; +import org.springframework.mail.SimpleMailMessage; +import org.springframework.security.authentication.ott.OneTimeToken; +import org.springframework.security.web.server.authentication.ott.ServerOneTimeTokenGenerationSuccessHandler; +import org.springframework.security.web.server.authentication.ott.ServerRedirectOneTimeTokenGenerationSuccessHandler; +import org.springframework.stereotype.Component; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.server.ServerWebExchange; +import org.springframework.web.util.UriComponentsBuilder; +import reactor.core.publisher.Mono; + +// tag::snippet[] +@Component // <1> +public class MagicLinkOneTimeTokenGenerationSuccessHandler implements ServerOneTimeTokenGenerationSuccessHandler { + + private final MailSender mailSender; + + private final ServerOneTimeTokenGenerationSuccessHandler redirectHandler = new ServerRedirectOneTimeTokenGenerationSuccessHandler("/ott/sent"); + + public MagicLinkOneTimeTokenGenerationSuccessHandler(MailSender mailSender) { + this.mailSender = mailSender; + } + + @Override + public Mono handle(ServerWebExchange exchange, OneTimeToken oneTimeToken) { + + return Mono.just(exchange.getRequest()) + .map((request) -> + UriComponentsBuilder.fromUri(request.getURI()) + .replacePath(request.getPath().contextPath().value()) + .replaceQuery(null) + .fragment(null) + .path("/login/ott") + .queryParam("token", oneTimeToken.getTokenValue()) + .toUriString() // <2> + ) + .flatMap((uri) -> { + + String email = getUserEmail(oneTimeToken.getUsername()); // <3> + SimpleMailMessage message = new SimpleMailMessage(); + message.setTo(email); + message.setSubject("Your Spring Security One Time Token"); + message.setText("Use the following link to sign in into the application: " + uri); + this.mailSender.send(message); // <4> + return Mono.empty(); + }) + .then(this.redirectHandler.handle(exchange, oneTimeToken)); // <5> + } + + private String getUserEmail(String username) { + /**/ return username; + } + +} + +@Controller +class PageController { + + @GetMapping("/ott/sent") + String ottSent() { + return "my-template"; + } + +} +// end::snippet[] \ No newline at end of file diff --git a/docs/src/test/java/org/springframework/security/docs/reactive/authentication/sendingtokentouser/SecurityConfig.java b/docs/src/test/java/org/springframework/security/docs/reactive/authentication/sendingtokentouser/SecurityConfig.java new file mode 100644 index 00000000000..3c14f5a4931 --- /dev/null +++ b/docs/src/test/java/org/springframework/security/docs/reactive/authentication/sendingtokentouser/SecurityConfig.java @@ -0,0 +1,41 @@ +/* + * Copyright 2004-present 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. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.security.docs.reactive.authentication.sendingtokentouser; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.config.Customizer; +import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity; +import org.springframework.security.config.web.server.ServerHttpSecurity; +import org.springframework.security.web.server.SecurityWebFilterChain; + +// tag::config[] +@Configuration +@EnableWebFluxSecurity +public class SecurityConfig { + + @Bean + public SecurityWebFilterChain filterChain(ServerHttpSecurity http) { + http + // ... + .formLogin(Customizer.withDefaults()) + .oneTimeTokenLogin(Customizer.withDefaults()); + return http.build(); + } + +} +// end::config[] \ No newline at end of file diff --git a/docs/src/test/java/org/springframework/security/docs/servlet/authentication/changinggenerateurl/MagicLinkOneTimeTokenGenerationSuccessHandler.java b/docs/src/test/java/org/springframework/security/docs/servlet/authentication/changinggenerateurl/MagicLinkOneTimeTokenGenerationSuccessHandler.java new file mode 100644 index 00000000000..17aec5c2092 --- /dev/null +++ b/docs/src/test/java/org/springframework/security/docs/servlet/authentication/changinggenerateurl/MagicLinkOneTimeTokenGenerationSuccessHandler.java @@ -0,0 +1,35 @@ +/* + * Copyright 2004-present 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. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.security.docs.servlet.authentication.changinggenerateurl; + +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import org.springframework.security.authentication.ott.OneTimeToken; +import org.springframework.security.web.authentication.ott.OneTimeTokenGenerationSuccessHandler; +import org.springframework.stereotype.Component; + +// tag::snippet[] +@Component +public class MagicLinkOneTimeTokenGenerationSuccessHandler implements OneTimeTokenGenerationSuccessHandler { + + @Override + public void handle(HttpServletRequest request, HttpServletResponse response, OneTimeToken oneTimeToken) { + // ... + } + +} +// end::snippet[] \ No newline at end of file diff --git a/docs/src/test/java/org/springframework/security/docs/servlet/authentication/changinggenerateurl/SecurityConfig.java b/docs/src/test/java/org/springframework/security/docs/servlet/authentication/changinggenerateurl/SecurityConfig.java new file mode 100644 index 00000000000..7ae9e92c70b --- /dev/null +++ b/docs/src/test/java/org/springframework/security/docs/servlet/authentication/changinggenerateurl/SecurityConfig.java @@ -0,0 +1,43 @@ +/* + * Copyright 2004-present 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. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.security.docs.servlet.authentication.changinggenerateurl; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.config.Customizer; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.web.SecurityFilterChain; + +// tag::config[] +@Configuration +@EnableWebSecurity +public class SecurityConfig { + + @Bean + public SecurityFilterChain filterChain(HttpSecurity http) { + http + // ... + .formLogin(Customizer.withDefaults()) + .oneTimeTokenLogin((ott) -> ott + .tokenGeneratingUrl("/ott/my-generate-url") + ); + return http.build(); + } + +} +// end::config[] \ No newline at end of file diff --git a/docs/src/test/java/org/springframework/security/docs/servlet/authentication/changingsubmitpageurl/MagicLinkOneTimeTokenGenerationSuccessHandler.java b/docs/src/test/java/org/springframework/security/docs/servlet/authentication/changingsubmitpageurl/MagicLinkOneTimeTokenGenerationSuccessHandler.java new file mode 100644 index 00000000000..84458254818 --- /dev/null +++ b/docs/src/test/java/org/springframework/security/docs/servlet/authentication/changingsubmitpageurl/MagicLinkOneTimeTokenGenerationSuccessHandler.java @@ -0,0 +1,35 @@ +/* + * Copyright 2004-present 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. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.security.docs.servlet.authentication.changingsubmitpageurl; + +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import org.springframework.security.authentication.ott.OneTimeToken; +import org.springframework.security.web.authentication.ott.OneTimeTokenGenerationSuccessHandler; +import org.springframework.stereotype.Component; + +// tag::snippet[] +@Component +public class MagicLinkOneTimeTokenGenerationSuccessHandler implements OneTimeTokenGenerationSuccessHandler { + + @Override + public void handle(HttpServletRequest request, HttpServletResponse response, OneTimeToken oneTimeToken) { + // ... + } + +} +// end::snippet[] \ No newline at end of file diff --git a/docs/src/test/java/org/springframework/security/docs/servlet/authentication/changingsubmitpageurl/SecurityConfig.java b/docs/src/test/java/org/springframework/security/docs/servlet/authentication/changingsubmitpageurl/SecurityConfig.java new file mode 100644 index 00000000000..7c26fb34fe5 --- /dev/null +++ b/docs/src/test/java/org/springframework/security/docs/servlet/authentication/changingsubmitpageurl/SecurityConfig.java @@ -0,0 +1,43 @@ +/* + * Copyright 2004-present 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. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.security.docs.servlet.authentication.changingsubmitpageurl; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.config.Customizer; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.web.SecurityFilterChain; + +// tag::config[] +@Configuration +@EnableWebSecurity +public class SecurityConfig { + + @Bean + public SecurityFilterChain filterChain(HttpSecurity http) { + http + // ... + .formLogin(Customizer.withDefaults()) + .oneTimeTokenLogin((ott) -> ott + .defaultSubmitPageUrl("/ott/submit") + ); + return http.build(); + } + +} +// end::config[] \ No newline at end of file diff --git a/docs/src/test/java/org/springframework/security/docs/servlet/authentication/customizegenerateconsumetoken/MagicLinkOneTimeTokenGenerationSuccessHandler.java b/docs/src/test/java/org/springframework/security/docs/servlet/authentication/customizegenerateconsumetoken/MagicLinkOneTimeTokenGenerationSuccessHandler.java new file mode 100644 index 00000000000..0304b819852 --- /dev/null +++ b/docs/src/test/java/org/springframework/security/docs/servlet/authentication/customizegenerateconsumetoken/MagicLinkOneTimeTokenGenerationSuccessHandler.java @@ -0,0 +1,35 @@ +/* + * Copyright 2004-present 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. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.security.docs.servlet.authentication.customizegenerateconsumetoken; + +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import org.springframework.security.authentication.ott.OneTimeToken; +import org.springframework.security.web.authentication.ott.OneTimeTokenGenerationSuccessHandler; +import org.springframework.stereotype.Component; + +// tag::snippet[] +@Component +public class MagicLinkOneTimeTokenGenerationSuccessHandler implements OneTimeTokenGenerationSuccessHandler { + + @Override + public void handle(HttpServletRequest request, HttpServletResponse response, OneTimeToken oneTimeToken) { + // ... + } + +} +// end::snippet[] \ No newline at end of file diff --git a/docs/src/test/java/org/springframework/security/docs/servlet/authentication/customizegenerateconsumetoken/MyCustomOneTimeTokenService.java b/docs/src/test/java/org/springframework/security/docs/servlet/authentication/customizegenerateconsumetoken/MyCustomOneTimeTokenService.java new file mode 100644 index 00000000000..921d6f79303 --- /dev/null +++ b/docs/src/test/java/org/springframework/security/docs/servlet/authentication/customizegenerateconsumetoken/MyCustomOneTimeTokenService.java @@ -0,0 +1,37 @@ +/* + * Copyright 2004-present 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. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.security.docs.servlet.authentication.customizegenerateconsumetoken; + +import org.jspecify.annotations.Nullable; +import org.springframework.security.authentication.ott.GenerateOneTimeTokenRequest; +import org.springframework.security.authentication.ott.OneTimeToken; +import org.springframework.security.authentication.ott.OneTimeTokenAuthenticationToken; +import org.springframework.security.authentication.ott.OneTimeTokenService; + +class MyCustomOneTimeTokenService implements OneTimeTokenService { + + @Override + public OneTimeToken generate(GenerateOneTimeTokenRequest request) { + return null; + } + + @Override + public @Nullable OneTimeToken consume(OneTimeTokenAuthenticationToken authenticationToken) { + return null; + } + +} \ No newline at end of file diff --git a/docs/src/test/java/org/springframework/security/docs/servlet/authentication/customizegenerateconsumetoken/OneTimeTokenServiceBeanSecurityConfig.java b/docs/src/test/java/org/springframework/security/docs/servlet/authentication/customizegenerateconsumetoken/OneTimeTokenServiceBeanSecurityConfig.java new file mode 100644 index 00000000000..0b8e8cc4ec9 --- /dev/null +++ b/docs/src/test/java/org/springframework/security/docs/servlet/authentication/customizegenerateconsumetoken/OneTimeTokenServiceBeanSecurityConfig.java @@ -0,0 +1,47 @@ +/* + * Copyright 2004-present 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. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.security.docs.servlet.authentication.customizegenerateconsumetoken; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.authentication.ott.OneTimeTokenService; +import org.springframework.security.config.Customizer; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.web.SecurityFilterChain; + +// tag::config[] +@Configuration +@EnableWebSecurity +public class OneTimeTokenServiceBeanSecurityConfig { + + @Bean + public SecurityFilterChain filterChain(HttpSecurity http) { + http + // ... + .formLogin(Customizer.withDefaults()) + .oneTimeTokenLogin(Customizer.withDefaults()); + return http.build(); + } + + @Bean + public OneTimeTokenService oneTimeTokenService() { + return new MyCustomOneTimeTokenService(); + } + +} +// end::config[] \ No newline at end of file diff --git a/docs/src/test/java/org/springframework/security/docs/servlet/authentication/customizegenerateconsumetoken/OneTimeTokenServiceDSLSecurityConfig.java b/docs/src/test/java/org/springframework/security/docs/servlet/authentication/customizegenerateconsumetoken/OneTimeTokenServiceDSLSecurityConfig.java new file mode 100644 index 00000000000..a262bb7627f --- /dev/null +++ b/docs/src/test/java/org/springframework/security/docs/servlet/authentication/customizegenerateconsumetoken/OneTimeTokenServiceDSLSecurityConfig.java @@ -0,0 +1,43 @@ +/* + * Copyright 2004-present 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. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.security.docs.servlet.authentication.customizegenerateconsumetoken; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.config.Customizer; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.web.SecurityFilterChain; + +// tag::config[] +@Configuration +@EnableWebSecurity +public class OneTimeTokenServiceDSLSecurityConfig { + + @Bean + public SecurityFilterChain filterChain(HttpSecurity http) { + http + // ... + .formLogin(Customizer.withDefaults()) + .oneTimeTokenLogin((ott) -> ott + .tokenService(new MyCustomOneTimeTokenService()) + ); + return http.build(); + } + +} +// end::config[] \ No newline at end of file diff --git a/docs/src/test/java/org/springframework/security/docs/servlet/authentication/customizegeneratetokenrequest/SecurityConfig.java b/docs/src/test/java/org/springframework/security/docs/servlet/authentication/customizegeneratetokenrequest/SecurityConfig.java new file mode 100644 index 00000000000..2b872402d22 --- /dev/null +++ b/docs/src/test/java/org/springframework/security/docs/servlet/authentication/customizegeneratetokenrequest/SecurityConfig.java @@ -0,0 +1,39 @@ +/* + * Copyright 2004-present 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. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.security.docs.servlet.authentication.customizegeneratetokenrequest; + +import org.springframework.context.annotation.Bean; +import org.springframework.security.authentication.ott.GenerateOneTimeTokenRequest; +import org.springframework.security.web.authentication.ott.DefaultGenerateOneTimeTokenRequestResolver; +import org.springframework.security.web.authentication.ott.GenerateOneTimeTokenRequestResolver; + +import java.time.Duration; + +public class SecurityConfig { + + // tag::config[] + @Bean + GenerateOneTimeTokenRequestResolver generateOneTimeTokenRequestResolver() { + DefaultGenerateOneTimeTokenRequestResolver delegate = new DefaultGenerateOneTimeTokenRequestResolver(); + return (request) -> { + GenerateOneTimeTokenRequest generate = delegate.resolve(request); + return new GenerateOneTimeTokenRequest(generate.getUsername(), Duration.ofMinutes(10)); + }; + } + // end::config[] + +} \ No newline at end of file diff --git a/docs/src/test/java/org/springframework/security/docs/servlet/authentication/disablingdefaultsubmitpage/MagicLinkOneTimeTokenGenerationSuccessHandler.java b/docs/src/test/java/org/springframework/security/docs/servlet/authentication/disablingdefaultsubmitpage/MagicLinkOneTimeTokenGenerationSuccessHandler.java new file mode 100644 index 00000000000..f8f9c558578 --- /dev/null +++ b/docs/src/test/java/org/springframework/security/docs/servlet/authentication/disablingdefaultsubmitpage/MagicLinkOneTimeTokenGenerationSuccessHandler.java @@ -0,0 +1,35 @@ +/* + * Copyright 2004-present 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. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.security.docs.servlet.authentication.disablingdefaultsubmitpage; + +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import org.springframework.security.authentication.ott.OneTimeToken; +import org.springframework.security.web.authentication.ott.OneTimeTokenGenerationSuccessHandler; +import org.springframework.stereotype.Component; + +// tag::snippet[] +@Component +public class MagicLinkOneTimeTokenGenerationSuccessHandler implements OneTimeTokenGenerationSuccessHandler { + + @Override + public void handle(HttpServletRequest request, HttpServletResponse response, OneTimeToken oneTimeToken) { + // ... + } + +} +// end::snippet[] \ No newline at end of file diff --git a/docs/src/test/java/org/springframework/security/docs/servlet/authentication/disablingdefaultsubmitpage/MyController.java b/docs/src/test/java/org/springframework/security/docs/servlet/authentication/disablingdefaultsubmitpage/MyController.java new file mode 100644 index 00000000000..8a7a1c410b7 --- /dev/null +++ b/docs/src/test/java/org/springframework/security/docs/servlet/authentication/disablingdefaultsubmitpage/MyController.java @@ -0,0 +1,32 @@ +/* + * Copyright 2004-present 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. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.security.docs.servlet.authentication.disablingdefaultsubmitpage; + +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; + +// tag::snippet[] +@Controller +public class MyController { + + @GetMapping("/my-ott-submit") + public String ottSubmitPage() { + return "my-ott-submit"; + } + +} +// end::snippet[] \ No newline at end of file diff --git a/docs/src/test/java/org/springframework/security/docs/servlet/authentication/disablingdefaultsubmitpage/SecurityConfig.java b/docs/src/test/java/org/springframework/security/docs/servlet/authentication/disablingdefaultsubmitpage/SecurityConfig.java new file mode 100644 index 00000000000..29a43cb46f3 --- /dev/null +++ b/docs/src/test/java/org/springframework/security/docs/servlet/authentication/disablingdefaultsubmitpage/SecurityConfig.java @@ -0,0 +1,46 @@ +/* + * Copyright 2004-present 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. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.security.docs.servlet.authentication.disablingdefaultsubmitpage; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.config.Customizer; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.web.SecurityFilterChain; + +// tag::config[] +@Configuration +@EnableWebSecurity +public class SecurityConfig { + + @Bean + public SecurityFilterChain filterChain(HttpSecurity http) { + http + .authorizeHttpRequests((authorize) -> authorize + .requestMatchers("/my-ott-submit").permitAll() + .anyRequest().authenticated() + ) + .formLogin(Customizer.withDefaults()) + .oneTimeTokenLogin((ott) -> ott + .showDefaultSubmitPage(false) + ); + return http.build(); + } + +} +// end::config[] \ No newline at end of file diff --git a/docs/src/test/java/org/springframework/security/docs/servlet/authentication/sendingtokentouser/MagicLinkOneTimeTokenGenerationSuccessHandler.java b/docs/src/test/java/org/springframework/security/docs/servlet/authentication/sendingtokentouser/MagicLinkOneTimeTokenGenerationSuccessHandler.java new file mode 100644 index 00000000000..ed2c7ce49cc --- /dev/null +++ b/docs/src/test/java/org/springframework/security/docs/servlet/authentication/sendingtokentouser/MagicLinkOneTimeTokenGenerationSuccessHandler.java @@ -0,0 +1,80 @@ +/* + * Copyright 2004-present 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. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.security.docs.servlet.authentication.sendingtokentouser; + +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import org.springframework.mail.MailSender; +import org.springframework.mail.SimpleMailMessage; +import org.springframework.security.authentication.ott.OneTimeToken; +import org.springframework.security.web.authentication.ott.OneTimeTokenGenerationSuccessHandler; +import org.springframework.security.web.authentication.ott.RedirectOneTimeTokenGenerationSuccessHandler; +import org.springframework.security.web.util.UrlUtils; +import org.springframework.stereotype.Component; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.util.UriComponentsBuilder; + +import java.io.IOException; + +// tag::snippet[] +@Component // <1> +public class MagicLinkOneTimeTokenGenerationSuccessHandler implements OneTimeTokenGenerationSuccessHandler { + + private final MailSender mailSender; + + private final OneTimeTokenGenerationSuccessHandler redirectHandler = new RedirectOneTimeTokenGenerationSuccessHandler("/ott/sent"); + + public MagicLinkOneTimeTokenGenerationSuccessHandler(MailSender mailSender) { + this.mailSender = mailSender; + } + + @Override + public void handle(HttpServletRequest request, HttpServletResponse response, OneTimeToken oneTimeToken) throws IOException, ServletException { + UriComponentsBuilder builder = UriComponentsBuilder.fromUriString(UrlUtils.buildFullRequestUrl(request)) + .replacePath(request.getContextPath()) + .replaceQuery(null) + .fragment(null) + .path("/login/ott") + .queryParam("token", oneTimeToken.getTokenValue()); // <2> + String magicLink = builder.toUriString(); + String email = getUserEmail(oneTimeToken.getUsername()); // <3> + SimpleMailMessage message = new SimpleMailMessage(); + message.setTo(email); + message.setSubject("Your Spring Security One Time Token"); + message.setText("Use the following link to sign in into the application: " + magicLink); + this.mailSender.send(message); // <4> + this.redirectHandler.handle(request, response, oneTimeToken); // <5> + } + + private String getUserEmail(String username) { + /**/ return username; + } + +} + +@Controller +class PageController { + + @GetMapping("/ott/sent") + String ottSent() { + return "my-template"; + } + +} +// end::snippet[] \ No newline at end of file diff --git a/docs/src/test/java/org/springframework/security/docs/servlet/authentication/sendingtokentouser/SecurityConfig.java b/docs/src/test/java/org/springframework/security/docs/servlet/authentication/sendingtokentouser/SecurityConfig.java new file mode 100644 index 00000000000..dd1ff54d5d9 --- /dev/null +++ b/docs/src/test/java/org/springframework/security/docs/servlet/authentication/sendingtokentouser/SecurityConfig.java @@ -0,0 +1,41 @@ +/* + * Copyright 2004-present 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. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.security.docs.servlet.authentication.sendingtokentouser; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.config.Customizer; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.web.SecurityFilterChain; + +// tag::config[] +@Configuration +@EnableWebSecurity +public class SecurityConfig { + + @Bean + public SecurityFilterChain filterChain(HttpSecurity http) { + http + // ... + .formLogin(Customizer.withDefaults()) + .oneTimeTokenLogin(Customizer.withDefaults()); + return http.build(); + } + +} +// end::config[] \ No newline at end of file diff --git a/docs/src/test/kotlin/org/springframework/security/kt/docs/reactive/authentication/changinggenerateurl/MagicLinkOneTimeTokenGenerationSuccessHandler.kt b/docs/src/test/kotlin/org/springframework/security/kt/docs/reactive/authentication/changinggenerateurl/MagicLinkOneTimeTokenGenerationSuccessHandler.kt new file mode 100644 index 00000000000..73e69cca5ff --- /dev/null +++ b/docs/src/test/kotlin/org/springframework/security/kt/docs/reactive/authentication/changinggenerateurl/MagicLinkOneTimeTokenGenerationSuccessHandler.kt @@ -0,0 +1,34 @@ +/* + * Copyright 2004-present 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. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.security.kt.docs.reactive.authentication.changinggenerateurl + +import org.springframework.security.authentication.ott.OneTimeToken +import org.springframework.security.web.server.authentication.ott.ServerOneTimeTokenGenerationSuccessHandler +import org.springframework.stereotype.Component +import org.springframework.web.server.ServerWebExchange +import reactor.core.publisher.Mono + +// tag::snippet[] +@Component +class MagicLinkOneTimeTokenGenerationSuccessHandler : ServerOneTimeTokenGenerationSuccessHandler { + + override fun handle(exchange: ServerWebExchange, oneTimeToken: OneTimeToken): Mono { + /**/ return Mono.empty() + } + +} +// end::snippet[] \ No newline at end of file diff --git a/docs/src/test/kotlin/org/springframework/security/kt/docs/reactive/authentication/changinggenerateurl/SecurityConfig.kt b/docs/src/test/kotlin/org/springframework/security/kt/docs/reactive/authentication/changinggenerateurl/SecurityConfig.kt new file mode 100644 index 00000000000..cc2b045abcf --- /dev/null +++ b/docs/src/test/kotlin/org/springframework/security/kt/docs/reactive/authentication/changinggenerateurl/SecurityConfig.kt @@ -0,0 +1,41 @@ +/* + * Copyright 2004-present 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. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.security.kt.docs.reactive.authentication.changinggenerateurl + +import org.springframework.context.annotation.Configuration +import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity +import org.springframework.security.config.web.server.ServerHttpSecurity +import org.springframework.security.config.web.server.invoke +import org.springframework.security.web.server.SecurityWebFilterChain + +// tag::config[] +@Configuration +@EnableWebFluxSecurity +open class SecurityConfig { + + open fun springWebFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain { + return http { + // ... + formLogin { } + oneTimeTokenLogin { + tokenGeneratingUrl = "/ott/my-generate-url" + } + } + } + +} +// end::config[] \ No newline at end of file diff --git a/docs/src/test/kotlin/org/springframework/security/kt/docs/reactive/authentication/changingsubmitpageurl/MagicLinkOneTimeTokenGenerationSuccessHandler.kt b/docs/src/test/kotlin/org/springframework/security/kt/docs/reactive/authentication/changingsubmitpageurl/MagicLinkOneTimeTokenGenerationSuccessHandler.kt new file mode 100644 index 00000000000..7918816cdd2 --- /dev/null +++ b/docs/src/test/kotlin/org/springframework/security/kt/docs/reactive/authentication/changingsubmitpageurl/MagicLinkOneTimeTokenGenerationSuccessHandler.kt @@ -0,0 +1,34 @@ +/* + * Copyright 2004-present 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. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.security.kt.docs.reactive.authentication.changingsubmitpageurl + +import org.springframework.security.authentication.ott.OneTimeToken +import org.springframework.security.web.server.authentication.ott.ServerOneTimeTokenGenerationSuccessHandler +import org.springframework.stereotype.Component +import org.springframework.web.server.ServerWebExchange +import reactor.core.publisher.Mono + +// tag::snippet[] +@Component +class MagicLinkOneTimeTokenGenerationSuccessHandler : ServerOneTimeTokenGenerationSuccessHandler { + + override fun handle(exchange: ServerWebExchange, oneTimeToken: OneTimeToken): Mono { + /**/ return Mono.empty() + } + +} +// end::snippet[] \ No newline at end of file diff --git a/docs/src/test/kotlin/org/springframework/security/kt/docs/reactive/authentication/changingsubmitpageurl/SecurityConfig.kt b/docs/src/test/kotlin/org/springframework/security/kt/docs/reactive/authentication/changingsubmitpageurl/SecurityConfig.kt new file mode 100644 index 00000000000..ab0f5122c18 --- /dev/null +++ b/docs/src/test/kotlin/org/springframework/security/kt/docs/reactive/authentication/changingsubmitpageurl/SecurityConfig.kt @@ -0,0 +1,41 @@ +/* + * Copyright 2004-present 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. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.security.kt.docs.reactive.authentication.changingsubmitpageurl + +import org.springframework.context.annotation.Configuration +import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity +import org.springframework.security.config.web.server.ServerHttpSecurity +import org.springframework.security.config.web.server.invoke +import org.springframework.security.web.server.SecurityWebFilterChain + +// tag::config[] +@Configuration +@EnableWebFluxSecurity +open class SecurityConfig { + + open fun springWebFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain { + return http { + // ... + formLogin { } + oneTimeTokenLogin { + defaultSubmitPageUrl = "/ott/submit" + } + } + } + +} +// end::config[] \ No newline at end of file diff --git a/docs/src/test/kotlin/org/springframework/security/kt/docs/reactive/authentication/customizegenerateconsumetoken/MagicLinkOneTimeTokenGenerationSuccessHandler.kt b/docs/src/test/kotlin/org/springframework/security/kt/docs/reactive/authentication/customizegenerateconsumetoken/MagicLinkOneTimeTokenGenerationSuccessHandler.kt new file mode 100644 index 00000000000..6680ec2d971 --- /dev/null +++ b/docs/src/test/kotlin/org/springframework/security/kt/docs/reactive/authentication/customizegenerateconsumetoken/MagicLinkOneTimeTokenGenerationSuccessHandler.kt @@ -0,0 +1,34 @@ +/* + * Copyright 2004-present 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. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.security.kt.docs.reactive.authentication.customizegenerateconsumetoken + +import org.springframework.security.authentication.ott.OneTimeToken +import org.springframework.security.web.server.authentication.ott.ServerOneTimeTokenGenerationSuccessHandler +import org.springframework.stereotype.Component +import org.springframework.web.server.ServerWebExchange +import reactor.core.publisher.Mono + +// tag::snippet[] +@Component +class MagicLinkOneTimeTokenGenerationSuccessHandler : ServerOneTimeTokenGenerationSuccessHandler { + + override fun handle(exchange: ServerWebExchange, oneTimeToken: OneTimeToken): Mono { + /**/ return Mono.empty() + } + +} +// end::snippet[] \ No newline at end of file diff --git a/docs/src/test/kotlin/org/springframework/security/kt/docs/reactive/authentication/customizegenerateconsumetoken/MyCustomReactiveOneTimeTokenService.kt b/docs/src/test/kotlin/org/springframework/security/kt/docs/reactive/authentication/customizegenerateconsumetoken/MyCustomReactiveOneTimeTokenService.kt new file mode 100644 index 00000000000..34db37194bc --- /dev/null +++ b/docs/src/test/kotlin/org/springframework/security/kt/docs/reactive/authentication/customizegenerateconsumetoken/MyCustomReactiveOneTimeTokenService.kt @@ -0,0 +1,36 @@ +/* + * Copyright 2004-present 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. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.security.kt.docs.reactive.authentication.customizegenerateconsumetoken + +import org.springframework.security.authentication.ott.GenerateOneTimeTokenRequest +import org.springframework.security.authentication.ott.OneTimeToken +import org.springframework.security.authentication.ott.OneTimeTokenAuthenticationToken +import org.springframework.security.authentication.ott.reactive.ReactiveOneTimeTokenService +import reactor.core.publisher.Mono + +class MyCustomReactiveOneTimeTokenService: ReactiveOneTimeTokenService { + + override fun generate(request: GenerateOneTimeTokenRequest): Mono { + TODO("Not yet implemented") + } + + override fun consume(authenticationToken: OneTimeTokenAuthenticationToken): Mono { + TODO("Not yet implemented") + } + + +} \ No newline at end of file diff --git a/docs/src/test/kotlin/org/springframework/security/kt/docs/reactive/authentication/customizegenerateconsumetoken/OneTimeTokenServiceBeanSecurityConfig.kt b/docs/src/test/kotlin/org/springframework/security/kt/docs/reactive/authentication/customizegenerateconsumetoken/OneTimeTokenServiceBeanSecurityConfig.kt new file mode 100644 index 00000000000..010a5bc8d72 --- /dev/null +++ b/docs/src/test/kotlin/org/springframework/security/kt/docs/reactive/authentication/customizegenerateconsumetoken/OneTimeTokenServiceBeanSecurityConfig.kt @@ -0,0 +1,46 @@ +/* + * Copyright 2004-present 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. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.security.kt.docs.reactive.authentication.customizegenerateconsumetoken + +import org.springframework.context.annotation.Bean +import org.springframework.context.annotation.Configuration +import org.springframework.security.authentication.ott.reactive.ReactiveOneTimeTokenService +import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity +import org.springframework.security.config.web.server.ServerHttpSecurity +import org.springframework.security.config.web.server.invoke +import org.springframework.security.web.server.SecurityWebFilterChain + +// tag::config[] +@Configuration +@EnableWebFluxSecurity +open class OneTimeTokenServiceBeanSecurityConfig { + + open fun springWebFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain { + return http { + //.. + formLogin { } + oneTimeTokenLogin { } + } + } + + @Bean + open fun oneTimeTokenService(): ReactiveOneTimeTokenService { + return MyCustomReactiveOneTimeTokenService() + } + +} +// end::config[] \ No newline at end of file diff --git a/docs/src/test/kotlin/org/springframework/security/kt/docs/reactive/authentication/customizegenerateconsumetoken/OneTimeTokenServiceDSLSecurityConfig.kt b/docs/src/test/kotlin/org/springframework/security/kt/docs/reactive/authentication/customizegenerateconsumetoken/OneTimeTokenServiceDSLSecurityConfig.kt new file mode 100644 index 00000000000..8413672b4fb --- /dev/null +++ b/docs/src/test/kotlin/org/springframework/security/kt/docs/reactive/authentication/customizegenerateconsumetoken/OneTimeTokenServiceDSLSecurityConfig.kt @@ -0,0 +1,41 @@ +/* + * Copyright 2004-present 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. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.security.kt.docs.reactive.authentication.customizegenerateconsumetoken + +import org.springframework.context.annotation.Configuration +import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity +import org.springframework.security.config.web.server.ServerHttpSecurity +import org.springframework.security.config.web.server.invoke +import org.springframework.security.web.server.SecurityWebFilterChain + +// tag::config[] +@Configuration +@EnableWebFluxSecurity +open class OneTimeTokenServiceDSLSecurityConfig { + + open fun springWebFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain { + return http { + //.. + formLogin { } + oneTimeTokenLogin { + tokenService = MyCustomReactiveOneTimeTokenService() + } + } + } + +} +// end::config[] \ No newline at end of file diff --git a/docs/src/test/kotlin/org/springframework/security/kt/docs/reactive/authentication/customizegeneratetokenrequest/SecurityConfig.kt b/docs/src/test/kotlin/org/springframework/security/kt/docs/reactive/authentication/customizegeneratetokenrequest/SecurityConfig.kt new file mode 100644 index 00000000000..0d26096f825 --- /dev/null +++ b/docs/src/test/kotlin/org/springframework/security/kt/docs/reactive/authentication/customizegeneratetokenrequest/SecurityConfig.kt @@ -0,0 +1,35 @@ +/* + * Copyright 2004-present 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. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.security.kt.docs.reactive.authentication.customizegeneratetokenrequest + +import org.springframework.context.annotation.Bean +import org.springframework.security.web.server.authentication.ott.DefaultServerGenerateOneTimeTokenRequestResolver +import org.springframework.security.web.server.authentication.ott.ServerGenerateOneTimeTokenRequestResolver +import java.time.Duration + +open class SecurityConfig { + + // tag::config[] + @Bean + fun generateOneTimeTokenRequestResolver() : ServerGenerateOneTimeTokenRequestResolver { + return DefaultServerGenerateOneTimeTokenRequestResolver().apply { + this.setExpiresIn(Duration.ofMinutes(10)) + } + } + // end::config[] + +} \ No newline at end of file diff --git a/docs/src/test/kotlin/org/springframework/security/kt/docs/reactive/authentication/disablingdefaultsubmitpage/MagicLinkOneTimeTokenGenerationSuccessHandler.kt b/docs/src/test/kotlin/org/springframework/security/kt/docs/reactive/authentication/disablingdefaultsubmitpage/MagicLinkOneTimeTokenGenerationSuccessHandler.kt new file mode 100644 index 00000000000..8233dba12e0 --- /dev/null +++ b/docs/src/test/kotlin/org/springframework/security/kt/docs/reactive/authentication/disablingdefaultsubmitpage/MagicLinkOneTimeTokenGenerationSuccessHandler.kt @@ -0,0 +1,35 @@ +/* + * Copyright 2004-present 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. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.security.kt.docs.reactive.authentication.disablingdefaultsubmitpage + +import org.springframework.security.authentication.ott.OneTimeToken +import org.springframework.security.web.server.authentication.ott.ServerOneTimeTokenGenerationSuccessHandler +import org.springframework.stereotype.Component +import org.springframework.web.server.ServerWebExchange +import reactor.core.publisher.Mono + +// tag::snippet[] +@Component +class MagicLinkOneTimeTokenGenerationSuccessHandler : ServerOneTimeTokenGenerationSuccessHandler { + + override fun handle(exchange: ServerWebExchange, oneTimeToken: OneTimeToken): Mono { + /**/ return Mono.empty() + } + +} + +// end::snippet[] \ No newline at end of file diff --git a/docs/src/test/kotlin/org/springframework/security/kt/docs/reactive/authentication/disablingdefaultsubmitpage/MyController.kt b/docs/src/test/kotlin/org/springframework/security/kt/docs/reactive/authentication/disablingdefaultsubmitpage/MyController.kt new file mode 100644 index 00000000000..a5b02498a3b --- /dev/null +++ b/docs/src/test/kotlin/org/springframework/security/kt/docs/reactive/authentication/disablingdefaultsubmitpage/MyController.kt @@ -0,0 +1,32 @@ +/* + * Copyright 2004-present 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. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.security.kt.docs.reactive.authentication.disablingdefaultsubmitpage + +import org.springframework.stereotype.Controller +import org.springframework.web.bind.annotation.GetMapping + +// tag::snippet[] +@Controller +class MyController { + + @GetMapping("/my-ott-submit") + fun ottSubmitPage(): String { + return "my-ott-submit" + } + +} +// end::snippet[] \ No newline at end of file diff --git a/docs/src/test/kotlin/org/springframework/security/kt/docs/reactive/authentication/disablingdefaultsubmitpage/SecurityConfig.kt b/docs/src/test/kotlin/org/springframework/security/kt/docs/reactive/authentication/disablingdefaultsubmitpage/SecurityConfig.kt new file mode 100644 index 00000000000..9ca02360f36 --- /dev/null +++ b/docs/src/test/kotlin/org/springframework/security/kt/docs/reactive/authentication/disablingdefaultsubmitpage/SecurityConfig.kt @@ -0,0 +1,45 @@ +/* + * Copyright 2004-present 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. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.security.kt.docs.reactive.authentication.disablingdefaultsubmitpage + +import org.springframework.context.annotation.Configuration +import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity +import org.springframework.security.config.web.server.ServerHttpSecurity +import org.springframework.security.config.web.server.invoke +import org.springframework.security.web.server.SecurityWebFilterChain +import org.springframework.security.web.server.util.matcher.ServerWebExchangeMatchers.pathMatchers + +// tag::config[] +@Configuration +@EnableWebFluxSecurity +open class SecurityConfig { + + open fun springWebFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain { + return http { + authorizeExchange { + authorize(pathMatchers("/my-ott-submit"), permitAll) + authorize(anyExchange, authenticated) + } + formLogin { } + oneTimeTokenLogin { + showDefaultSubmitPage = false + } + } + } + +} +// end::config[] \ No newline at end of file diff --git a/docs/src/test/kotlin/org/springframework/security/kt/docs/reactive/authentication/sendingtokentouser/MagicLinkOneTimeTokenGenerationSuccessHandler.kt b/docs/src/test/kotlin/org/springframework/security/kt/docs/reactive/authentication/sendingtokentouser/MagicLinkOneTimeTokenGenerationSuccessHandler.kt new file mode 100644 index 00000000000..499ed250f68 --- /dev/null +++ b/docs/src/test/kotlin/org/springframework/security/kt/docs/reactive/authentication/sendingtokentouser/MagicLinkOneTimeTokenGenerationSuccessHandler.kt @@ -0,0 +1,78 @@ +/* + * Copyright 2004-present 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. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.security.kt.docs.reactive.authentication.sendingtokentouser + +import org.springframework.mail.MailSender +import org.springframework.mail.SimpleMailMessage +import org.springframework.security.authentication.ott.OneTimeToken +import org.springframework.security.web.server.authentication.ott.ServerOneTimeTokenGenerationSuccessHandler +import org.springframework.security.web.server.authentication.ott.ServerRedirectOneTimeTokenGenerationSuccessHandler +import org.springframework.stereotype.Component +import org.springframework.stereotype.Controller +import org.springframework.web.bind.annotation.GetMapping +import org.springframework.web.server.ServerWebExchange +import org.springframework.web.util.UriComponentsBuilder +import reactor.core.publisher.Mono +import java.util.function.Function + + +// tag::snippet[] +@Component // <1> +class MagicLinkOneTimeTokenGenerationSuccessHandler(val mailSender: MailSender) : ServerOneTimeTokenGenerationSuccessHandler { + + private val redirectHandler: ServerOneTimeTokenGenerationSuccessHandler = ServerRedirectOneTimeTokenGenerationSuccessHandler("/ott/sent") + + override fun handle(exchange: ServerWebExchange, oneTimeToken: OneTimeToken): Mono { + + return Mono.just(exchange.request) + .map(Function { request -> + UriComponentsBuilder.fromUri(request.uri) + .replacePath(request.path.contextPath().value()) + .replaceQuery(null) + .fragment(null) + .path("/login/ott") + .queryParam("token", oneTimeToken.getTokenValue()) + .toUriString() // <2> + }) + .flatMap(Function { uri -> + val email = getUserEmail(oneTimeToken.getUsername()) // <3> + val message = SimpleMailMessage() + message.setTo(email) + message.subject = "Your Spring Security One Time Token" + message.text = "Use the following link to sign in into the application: $uri" + this.mailSender.send(message) // <4> + Mono.empty() + }) + .then(this.redirectHandler.handle(exchange, oneTimeToken)) // <5> + } + + private fun getUserEmail(username: String): String { + /**/ return username + } + +} + +@Controller +class PageController { + + @GetMapping("/ott/sent") + fun ottSent(): String { + return "my-template" + } + +} +// end::snippet[] \ No newline at end of file diff --git a/docs/src/test/kotlin/org/springframework/security/kt/docs/reactive/authentication/sendingtokentouser/SecurityConfig.kt b/docs/src/test/kotlin/org/springframework/security/kt/docs/reactive/authentication/sendingtokentouser/SecurityConfig.kt new file mode 100644 index 00000000000..0645c133f08 --- /dev/null +++ b/docs/src/test/kotlin/org/springframework/security/kt/docs/reactive/authentication/sendingtokentouser/SecurityConfig.kt @@ -0,0 +1,40 @@ +/* + * Copyright 2004-present 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. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.security.kt.docs.reactive.authentication.sendingtokentouser + +import org.springframework.context.annotation.Configuration +import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity +import org.springframework.security.config.web.server.ServerHttpSecurity +import org.springframework.security.config.web.server.invoke +import org.springframework.security.web.server.SecurityWebFilterChain + +// tag::config[] +@Configuration +@EnableWebFluxSecurity +open class SecurityConfig { + + open fun springWebFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain { + return http { + authorizeExchange { + authorize(anyExchange, authenticated) + } + oneTimeTokenLogin { } + } + } + +} +// end::config[] \ No newline at end of file diff --git a/docs/src/test/kotlin/org/springframework/security/kt/docs/servlet/authentication/changinggenerateurl/MagicLinkOneTimeTokenGenerationSuccessHandler.kt b/docs/src/test/kotlin/org/springframework/security/kt/docs/servlet/authentication/changinggenerateurl/MagicLinkOneTimeTokenGenerationSuccessHandler.kt new file mode 100644 index 00000000000..52ca626a7cd --- /dev/null +++ b/docs/src/test/kotlin/org/springframework/security/kt/docs/servlet/authentication/changinggenerateurl/MagicLinkOneTimeTokenGenerationSuccessHandler.kt @@ -0,0 +1,34 @@ +/* + * Copyright 2004-present 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. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.security.kt.docs.servlet.authentication.changinggenerateurl + +import jakarta.servlet.http.HttpServletRequest +import jakarta.servlet.http.HttpServletResponse +import org.springframework.security.authentication.ott.OneTimeToken +import org.springframework.security.web.authentication.ott.OneTimeTokenGenerationSuccessHandler +import org.springframework.stereotype.Component + +// tag::snippet[] +@Component +class MagicLinkOneTimeTokenGenerationSuccessHandler : OneTimeTokenGenerationSuccessHandler { + + override fun handle(request: HttpServletRequest, response: HttpServletResponse, oneTimeToken: OneTimeToken) { + // ... + } + +} +// end::snippet[] \ No newline at end of file diff --git a/docs/src/test/kotlin/org/springframework/security/kt/docs/servlet/authentication/changinggenerateurl/SecurityConfig.kt b/docs/src/test/kotlin/org/springframework/security/kt/docs/servlet/authentication/changinggenerateurl/SecurityConfig.kt new file mode 100644 index 00000000000..c78c812b123 --- /dev/null +++ b/docs/src/test/kotlin/org/springframework/security/kt/docs/servlet/authentication/changinggenerateurl/SecurityConfig.kt @@ -0,0 +1,43 @@ +/* + * Copyright 2004-present 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. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.security.kt.docs.servlet.authentication.changinggenerateurl + +import org.springframework.context.annotation.Bean +import org.springframework.context.annotation.Configuration +import org.springframework.security.config.annotation.web.builders.HttpSecurity +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity +import org.springframework.security.config.annotation.web.invoke +import org.springframework.security.web.SecurityFilterChain + +// tag::config[] +@Configuration +@EnableWebSecurity +open class SecurityConfig { + + @Bean + open fun filterChain(http: HttpSecurity): SecurityFilterChain { + http { + //... + formLogin { } + oneTimeTokenLogin { + tokenGeneratingUrl = "/ott/my-generate-url" + } + } + return http.build() + } +} +// end::config[] \ No newline at end of file diff --git a/docs/src/test/kotlin/org/springframework/security/kt/docs/servlet/authentication/changingsubmitpageurl/MagicLinkOneTimeTokenGenerationSuccessHandler.kt b/docs/src/test/kotlin/org/springframework/security/kt/docs/servlet/authentication/changingsubmitpageurl/MagicLinkOneTimeTokenGenerationSuccessHandler.kt new file mode 100644 index 00000000000..256b14ebaf3 --- /dev/null +++ b/docs/src/test/kotlin/org/springframework/security/kt/docs/servlet/authentication/changingsubmitpageurl/MagicLinkOneTimeTokenGenerationSuccessHandler.kt @@ -0,0 +1,34 @@ +/* + * Copyright 2004-present 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. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.security.kt.docs.servlet.authentication.changingsubmitpageurl + +import jakarta.servlet.http.HttpServletRequest +import jakarta.servlet.http.HttpServletResponse +import org.springframework.security.authentication.ott.OneTimeToken +import org.springframework.security.web.authentication.ott.OneTimeTokenGenerationSuccessHandler +import org.springframework.stereotype.Component + +// tag::snippet[] +@Component +class MagicLinkOneTimeTokenGenerationSuccessHandler : OneTimeTokenGenerationSuccessHandler { + + override fun handle(request: HttpServletRequest, response: HttpServletResponse, oneTimeToken: OneTimeToken) { + // ... + } + +} +// end::snippet[] \ No newline at end of file diff --git a/docs/src/test/kotlin/org/springframework/security/kt/docs/servlet/authentication/changingsubmitpageurl/SecurityConfig.kt b/docs/src/test/kotlin/org/springframework/security/kt/docs/servlet/authentication/changingsubmitpageurl/SecurityConfig.kt new file mode 100644 index 00000000000..05d388e9c46 --- /dev/null +++ b/docs/src/test/kotlin/org/springframework/security/kt/docs/servlet/authentication/changingsubmitpageurl/SecurityConfig.kt @@ -0,0 +1,43 @@ +/* + * Copyright 2004-present 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. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.security.kt.docs.servlet.authentication.changingsubmitpageurl + +import org.springframework.context.annotation.Bean +import org.springframework.context.annotation.Configuration +import org.springframework.security.config.annotation.web.builders.HttpSecurity +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity +import org.springframework.security.config.annotation.web.invoke +import org.springframework.security.web.SecurityFilterChain + +// tag::config[] +@Configuration +@EnableWebSecurity +open class SecurityConfig { + + @Bean + open fun filterChain(http: HttpSecurity): SecurityFilterChain { + http { + //... + formLogin { } + oneTimeTokenLogin { + defaultSubmitPageUrl = "/ott/submit" + } + } + return http.build() + } +} +// end::config[] \ No newline at end of file diff --git a/docs/src/test/kotlin/org/springframework/security/kt/docs/servlet/authentication/customizegenerateconsumetoken/MagicLinkOneTimeTokenGenerationSuccessHandler.kt b/docs/src/test/kotlin/org/springframework/security/kt/docs/servlet/authentication/customizegenerateconsumetoken/MagicLinkOneTimeTokenGenerationSuccessHandler.kt new file mode 100644 index 00000000000..d05c31200a9 --- /dev/null +++ b/docs/src/test/kotlin/org/springframework/security/kt/docs/servlet/authentication/customizegenerateconsumetoken/MagicLinkOneTimeTokenGenerationSuccessHandler.kt @@ -0,0 +1,34 @@ +/* + * Copyright 2004-present 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. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.security.kt.docs.servlet.authentication.customizegenerateconsumetoken + +import jakarta.servlet.http.HttpServletRequest +import jakarta.servlet.http.HttpServletResponse +import org.springframework.security.authentication.ott.OneTimeToken +import org.springframework.security.web.authentication.ott.OneTimeTokenGenerationSuccessHandler +import org.springframework.stereotype.Component + +// tag::snippet[] +@Component +class MagicLinkOneTimeTokenGenerationSuccessHandler : OneTimeTokenGenerationSuccessHandler { + + override fun handle(request: HttpServletRequest, response: HttpServletResponse, oneTimeToken: OneTimeToken) { + // ... + } + +} +// end::snippet[] \ No newline at end of file diff --git a/docs/src/test/kotlin/org/springframework/security/kt/docs/servlet/authentication/customizegenerateconsumetoken/MyCustomOneTimeTokenService.kt b/docs/src/test/kotlin/org/springframework/security/kt/docs/servlet/authentication/customizegenerateconsumetoken/MyCustomOneTimeTokenService.kt new file mode 100644 index 00000000000..8324afa79b7 --- /dev/null +++ b/docs/src/test/kotlin/org/springframework/security/kt/docs/servlet/authentication/customizegenerateconsumetoken/MyCustomOneTimeTokenService.kt @@ -0,0 +1,34 @@ +/* + * Copyright 2004-present 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. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.security.kt.docs.servlet.authentication.customizegenerateconsumetoken + +import org.springframework.security.authentication.ott.GenerateOneTimeTokenRequest +import org.springframework.security.authentication.ott.OneTimeToken +import org.springframework.security.authentication.ott.OneTimeTokenAuthenticationToken +import org.springframework.security.authentication.ott.OneTimeTokenService + +class MyCustomOneTimeTokenService: OneTimeTokenService { + + override fun generate(request: GenerateOneTimeTokenRequest): OneTimeToken { + TODO("Not yet implemented") + } + + override fun consume(authenticationToken: OneTimeTokenAuthenticationToken): OneTimeToken? { + TODO("Not yet implemented") + } + +} \ No newline at end of file diff --git a/docs/src/test/kotlin/org/springframework/security/kt/docs/servlet/authentication/customizegenerateconsumetoken/OneTimeTokenServiceBeanSecurityConfig.kt b/docs/src/test/kotlin/org/springframework/security/kt/docs/servlet/authentication/customizegenerateconsumetoken/OneTimeTokenServiceBeanSecurityConfig.kt new file mode 100644 index 00000000000..acd74c7dd3a --- /dev/null +++ b/docs/src/test/kotlin/org/springframework/security/kt/docs/servlet/authentication/customizegenerateconsumetoken/OneTimeTokenServiceBeanSecurityConfig.kt @@ -0,0 +1,48 @@ +/* + * Copyright 2004-present 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. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.security.kt.docs.servlet.authentication.customizegenerateconsumetoken + +import org.springframework.context.annotation.Bean +import org.springframework.context.annotation.Configuration +import org.springframework.security.authentication.ott.OneTimeTokenService +import org.springframework.security.config.annotation.web.builders.HttpSecurity +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity +import org.springframework.security.config.annotation.web.invoke +import org.springframework.security.web.SecurityFilterChain + +// tag::config[] +@Configuration +@EnableWebSecurity +open class OneTimeTokenServiceBeanSecurityConfig { + + @Bean + open fun filterChain(http: HttpSecurity): SecurityFilterChain { + http { + //... + formLogin { } + oneTimeTokenLogin { } + } + return http.build() + } + + @Bean + open fun oneTimeTokenService(): OneTimeTokenService { + return MyCustomOneTimeTokenService() + } + +} +// end::config[] \ No newline at end of file diff --git a/docs/src/test/kotlin/org/springframework/security/kt/docs/servlet/authentication/customizegenerateconsumetoken/OneTimeTokenServiceDSLSecurityConfig.kt b/docs/src/test/kotlin/org/springframework/security/kt/docs/servlet/authentication/customizegenerateconsumetoken/OneTimeTokenServiceDSLSecurityConfig.kt new file mode 100644 index 00000000000..7a1411558fa --- /dev/null +++ b/docs/src/test/kotlin/org/springframework/security/kt/docs/servlet/authentication/customizegenerateconsumetoken/OneTimeTokenServiceDSLSecurityConfig.kt @@ -0,0 +1,44 @@ +/* + * Copyright 2004-present 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. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.security.kt.docs.servlet.authentication.customizegenerateconsumetoken + +import org.springframework.context.annotation.Bean +import org.springframework.context.annotation.Configuration +import org.springframework.security.config.annotation.web.builders.HttpSecurity +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity +import org.springframework.security.config.annotation.web.invoke +import org.springframework.security.web.SecurityFilterChain + +// tag::config[] +@Configuration +@EnableWebSecurity +open class OneTimeTokenServiceDSLSecurityConfig { + + @Bean + open fun filterChain(http: HttpSecurity): SecurityFilterChain { + http { + //... + formLogin { } + oneTimeTokenLogin { + tokenService = MyCustomOneTimeTokenService() + } + } + return http.build() + } + +} +// end::config[] \ No newline at end of file diff --git a/docs/src/test/kotlin/org/springframework/security/kt/docs/servlet/authentication/customizegeneratetokenrequest/SecurityConfig.kt b/docs/src/test/kotlin/org/springframework/security/kt/docs/servlet/authentication/customizegeneratetokenrequest/SecurityConfig.kt new file mode 100644 index 00000000000..0488afc7061 --- /dev/null +++ b/docs/src/test/kotlin/org/springframework/security/kt/docs/servlet/authentication/customizegeneratetokenrequest/SecurityConfig.kt @@ -0,0 +1,35 @@ +/* + * Copyright 2004-present 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. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.security.kt.docs.servlet.authentication.customizegeneratetokenrequest + +import org.springframework.context.annotation.Bean +import org.springframework.security.web.authentication.ott.DefaultGenerateOneTimeTokenRequestResolver +import org.springframework.security.web.authentication.ott.GenerateOneTimeTokenRequestResolver +import java.time.Duration + +open class SecurityConfig { + + // tag::config[] + @Bean + open fun generateRequestResolver() : GenerateOneTimeTokenRequestResolver { + return DefaultGenerateOneTimeTokenRequestResolver().apply { + this.setExpiresIn(Duration.ofMinutes(10)) + } + } + // end::config[] + +} \ No newline at end of file diff --git a/docs/src/test/kotlin/org/springframework/security/kt/docs/servlet/authentication/disablingdefaultsubmitpage/MagicLinkOneTimeTokenGenerationSuccessHandler.kt b/docs/src/test/kotlin/org/springframework/security/kt/docs/servlet/authentication/disablingdefaultsubmitpage/MagicLinkOneTimeTokenGenerationSuccessHandler.kt new file mode 100644 index 00000000000..2bad70e27e9 --- /dev/null +++ b/docs/src/test/kotlin/org/springframework/security/kt/docs/servlet/authentication/disablingdefaultsubmitpage/MagicLinkOneTimeTokenGenerationSuccessHandler.kt @@ -0,0 +1,34 @@ +/* + * Copyright 2004-present 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. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.security.kt.docs.servlet.authentication.disablingdefaultsubmitpage + +import jakarta.servlet.http.HttpServletRequest +import jakarta.servlet.http.HttpServletResponse +import org.springframework.security.authentication.ott.OneTimeToken +import org.springframework.security.web.authentication.ott.OneTimeTokenGenerationSuccessHandler +import org.springframework.stereotype.Component + +// tag::snippet[] +@Component +class MagicLinkOneTimeTokenGenerationSuccessHandler : OneTimeTokenGenerationSuccessHandler { + + override fun handle(request: HttpServletRequest, response: HttpServletResponse, oneTimeToken: OneTimeToken) { + // ... + } + +} +// end::snippet[] \ No newline at end of file diff --git a/docs/src/test/kotlin/org/springframework/security/kt/docs/servlet/authentication/disablingdefaultsubmitpage/MyController.kt b/docs/src/test/kotlin/org/springframework/security/kt/docs/servlet/authentication/disablingdefaultsubmitpage/MyController.kt new file mode 100644 index 00000000000..2f23e1f988f --- /dev/null +++ b/docs/src/test/kotlin/org/springframework/security/kt/docs/servlet/authentication/disablingdefaultsubmitpage/MyController.kt @@ -0,0 +1,32 @@ +/* + * Copyright 2004-present 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. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.security.kt.docs.servlet.authentication.disablingdefaultsubmitpage + +import org.springframework.stereotype.Controller +import org.springframework.web.bind.annotation.GetMapping + +// tag::snippet[] +@Controller +class MyController { + + @GetMapping("/my-ott-submit") + fun ottSubmitPage(): String { + return "my-ott-submit" + } + +} +// end::snippet[] \ No newline at end of file diff --git a/docs/src/test/kotlin/org/springframework/security/kt/docs/servlet/authentication/disablingdefaultsubmitpage/SecurityConfig.kt b/docs/src/test/kotlin/org/springframework/security/kt/docs/servlet/authentication/disablingdefaultsubmitpage/SecurityConfig.kt new file mode 100644 index 00000000000..8b94d78d261 --- /dev/null +++ b/docs/src/test/kotlin/org/springframework/security/kt/docs/servlet/authentication/disablingdefaultsubmitpage/SecurityConfig.kt @@ -0,0 +1,47 @@ +/* + * Copyright 2004-present 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. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.security.kt.docs.servlet.authentication.disablingdefaultsubmitpage + +import org.springframework.context.annotation.Bean +import org.springframework.context.annotation.Configuration +import org.springframework.security.config.annotation.web.builders.HttpSecurity +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity +import org.springframework.security.config.annotation.web.invoke +import org.springframework.security.web.SecurityFilterChain + +// tag::config[] +@Configuration +@EnableWebSecurity +open class SecurityConfig { + + @Bean + open fun filterChain(http: HttpSecurity): SecurityFilterChain { + http { + authorizeHttpRequests { + authorize("/my-ott-submit", authenticated) + authorize(anyRequest, authenticated) + } + formLogin { } + oneTimeTokenLogin { + showDefaultSubmitPage = false + } + } + return http.build() + } + +} +// end::config[] \ No newline at end of file diff --git a/docs/src/test/kotlin/org/springframework/security/kt/docs/servlet/authentication/sendingtokentouser/MagicLinkOneTimeTokenGenerationSuccessHandler.kt b/docs/src/test/kotlin/org/springframework/security/kt/docs/servlet/authentication/sendingtokentouser/MagicLinkOneTimeTokenGenerationSuccessHandler.kt new file mode 100644 index 00000000000..c68c29d0879 --- /dev/null +++ b/docs/src/test/kotlin/org/springframework/security/kt/docs/servlet/authentication/sendingtokentouser/MagicLinkOneTimeTokenGenerationSuccessHandler.kt @@ -0,0 +1,69 @@ +/* + * Copyright 2004-present 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. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.security.kt.docs.servlet.authentication.sendingtokentouser + +import jakarta.servlet.http.HttpServletRequest +import jakarta.servlet.http.HttpServletResponse +import org.springframework.mail.MailSender +import org.springframework.mail.SimpleMailMessage +import org.springframework.security.authentication.ott.OneTimeToken +import org.springframework.security.web.authentication.ott.OneTimeTokenGenerationSuccessHandler +import org.springframework.security.web.authentication.ott.RedirectOneTimeTokenGenerationSuccessHandler +import org.springframework.security.web.util.UrlUtils +import org.springframework.stereotype.Component +import org.springframework.stereotype.Controller +import org.springframework.web.bind.annotation.GetMapping +import org.springframework.web.util.UriComponentsBuilder + +// tag::snippet[] +@Component // <1> +class MagicLinkOneTimeTokenGenerationSuccessHandler(val mailSender: MailSender) : OneTimeTokenGenerationSuccessHandler { + + private val redirectHandler: OneTimeTokenGenerationSuccessHandler = RedirectOneTimeTokenGenerationSuccessHandler("/ott/sent") + + override fun handle(request: HttpServletRequest, response: HttpServletResponse, oneTimeToken: OneTimeToken) { + val builder = UriComponentsBuilder.fromUriString(UrlUtils.buildFullRequestUrl(request)) + .replacePath(request.contextPath) + .replaceQuery(null) + .fragment(null) + .path("/login/ott") + .queryParam("token", oneTimeToken.getTokenValue()) // <2> + val magicLink = builder.toUriString() + val email = getUserEmail(oneTimeToken.getUsername()) // <3> + val message = SimpleMailMessage() + message.setTo(email) + message.subject = "Your Spring Security One Time Token" + message.text = "Use the following link to sign in into the application: $magicLink" + this.mailSender.send(message) // <4> + this.redirectHandler.handle(request, response, oneTimeToken) // <5> + } + + private fun getUserEmail(username: String): String { + /**/ return username + } +} + +@Controller +class PageController { + + @GetMapping("/ott/sent") + fun ottSent(): String { + return "my-template" + } + +} +// end::snippet[] \ No newline at end of file diff --git a/docs/src/test/kotlin/org/springframework/security/kt/docs/servlet/authentication/sendingtokentouser/SecurityConfig.kt b/docs/src/test/kotlin/org/springframework/security/kt/docs/servlet/authentication/sendingtokentouser/SecurityConfig.kt new file mode 100644 index 00000000000..f02af5ec432 --- /dev/null +++ b/docs/src/test/kotlin/org/springframework/security/kt/docs/servlet/authentication/sendingtokentouser/SecurityConfig.kt @@ -0,0 +1,40 @@ +/* + * Copyright 2004-present 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. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.security.kt.docs.servlet.authentication.sendingtokentouser + +import org.springframework.context.annotation.Bean +import org.springframework.context.annotation.Configuration +import org.springframework.security.config.annotation.web.builders.HttpSecurity +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity +import org.springframework.security.config.annotation.web.invoke +import org.springframework.security.web.SecurityFilterChain + +// tag::config[] +@Configuration +@EnableWebSecurity +open class SecurityConfig { + + @Bean + open fun filterChain(http: HttpSecurity): SecurityFilterChain { + http { + formLogin { } + oneTimeTokenLogin { } + } + return http.build() + } +} +// end::config[] \ No newline at end of file