From 3af619d56507068f39aaf059c6b0bbcc8925ed28 Mon Sep 17 00:00:00 2001 From: Steve Riesenberg Date: Wed, 1 Dec 2021 13:32:44 -0600 Subject: [PATCH] Add hasIpAddress to Reactive Kotlin DSL Closes gh-10571 --- .../config/web/server/AuthorizeExchangeDsl.kt | 10 ++++- .../web/server/AuthorizeExchangeDslTests.kt | 42 +++++++++++++++++-- 2 files changed, 48 insertions(+), 4 deletions(-) diff --git a/config/src/main/kotlin/org/springframework/security/config/web/server/AuthorizeExchangeDsl.kt b/config/src/main/kotlin/org/springframework/security/config/web/server/AuthorizeExchangeDsl.kt index 8df31aaca51..bfd029ec986 100644 --- a/config/src/main/kotlin/org/springframework/security/config/web/server/AuthorizeExchangeDsl.kt +++ b/config/src/main/kotlin/org/springframework/security/config/web/server/AuthorizeExchangeDsl.kt @@ -1,5 +1,5 @@ /* - * Copyright 2002-2020 the original author or authors. + * Copyright 2002-2021 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -22,6 +22,7 @@ import org.springframework.security.authorization.AuthorizationDecision import org.springframework.security.authorization.ReactiveAuthorizationManager import org.springframework.security.core.Authentication import org.springframework.security.web.server.authorization.AuthorizationContext +import org.springframework.security.web.server.authorization.IpAddressReactiveAuthorizationManager import org.springframework.security.web.server.util.matcher.ServerWebExchangeMatcher import org.springframework.security.web.server.util.matcher.ServerWebExchangeMatchers import org.springframework.security.web.util.matcher.RequestMatcher @@ -108,6 +109,13 @@ class AuthorizeExchangeDsl { fun hasAnyAuthority(vararg authorities: String): ReactiveAuthorizationManager = AuthorityReactiveAuthorizationManager.hasAnyAuthority(*authorities) + /** + * Require a specific IP or range of IP addresses. + * @since 5.7 + */ + fun hasIpAddress(ipAddress: String): ReactiveAuthorizationManager = + IpAddressReactiveAuthorizationManager.hasIpAddress(ipAddress) + /** * Require an authenticated user. */ diff --git a/config/src/test/kotlin/org/springframework/security/config/web/server/AuthorizeExchangeDslTests.kt b/config/src/test/kotlin/org/springframework/security/config/web/server/AuthorizeExchangeDslTests.kt index fd840ebd936..870b9a92834 100644 --- a/config/src/test/kotlin/org/springframework/security/config/web/server/AuthorizeExchangeDslTests.kt +++ b/config/src/test/kotlin/org/springframework/security/config/web/server/AuthorizeExchangeDslTests.kt @@ -22,16 +22,16 @@ import org.springframework.beans.factory.annotation.Autowired import org.springframework.context.ApplicationContext import org.springframework.context.annotation.Bean import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity -import org.springframework.security.core.userdetails.MapReactiveUserDetailsService -import org.springframework.security.core.userdetails.User import org.springframework.security.config.test.SpringTestContext import org.springframework.security.config.test.SpringTestContextExtension +import org.springframework.security.core.userdetails.MapReactiveUserDetailsService +import org.springframework.security.core.userdetails.User import org.springframework.security.web.server.SecurityWebFilterChain import org.springframework.test.web.reactive.server.WebTestClient import org.springframework.web.bind.annotation.RequestMapping import org.springframework.web.bind.annotation.RestController import org.springframework.web.reactive.config.EnableWebFlux -import java.util.* +import java.util.Base64 /** * Tests for [AuthorizeExchangeDsl] @@ -181,4 +181,40 @@ class AuthorizeExchangeDslTests { return MapReactiveUserDetailsService(user) } } + + @Test + fun `request when ip address does not match then responds with forbidden`() { + this.spring.register(HasIpAddressConfig::class.java).autowire() + + this.client + .get() + .uri("/") + .header("Authorization", "Basic " + Base64.getEncoder().encodeToString("user:password".toByteArray())) + .exchange() + .expectStatus().isForbidden + } + + @EnableWebFluxSecurity + @EnableWebFlux + open class HasIpAddressConfig { + @Bean + open fun springWebFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain { + return http { + authorizeExchange { + authorize(anyExchange, hasIpAddress("10.0.0.0/24")) + } + httpBasic { } + } + } + + @Bean + open fun userDetailsService(): MapReactiveUserDetailsService { + val user = User.withDefaultPasswordEncoder() + .username("user") + .password("password") + .roles("USER") + .build() + return MapReactiveUserDetailsService(user) + } + } }