Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -1689,6 +1689,7 @@ public AuthorizeExchangeSpec authenticated() {
* @param ipAddress the address or range of addresses from which the request
* must come.
* @return the {@link AuthorizeExchangeSpec} to configure
* @since 5.7
*/
public AuthorizeExchangeSpec hasIpAddress(String ipAddress) {
return access(IpAddressReactiveAuthorizationManager.hasIpAddress(ipAddress));
Expand Down
Original file line number Diff line number Diff line change
@@ -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.
Expand All @@ -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
Expand Down Expand Up @@ -108,6 +109,13 @@ class AuthorizeExchangeDsl {
fun hasAnyAuthority(vararg authorities: String): ReactiveAuthorizationManager<AuthorizationContext> =
AuthorityReactiveAuthorizationManager.hasAnyAuthority<AuthorizationContext>(*authorities)

/**
* Require a specific IP or range of IP addresses.
* @since 5.7
*/
fun hasIpAddress(ipAddress: String): ReactiveAuthorizationManager<AuthorizationContext> =
IpAddressReactiveAuthorizationManager.hasIpAddress(ipAddress)

/**
* Require an authenticated user.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand Down Expand Up @@ -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)
}
}
}