Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit fd4f06a

Browse files
evgeniychebanjzheaux
authored andcommitted
Support Spring Data container types for AuthorizeReturnObject
Closes gh-15994 Signed-off-by: Evgeniy Cheban <mister.cheban@gmail.com>
1 parent 6d3b54d commit fd4f06a

File tree

2 files changed

+152
-12
lines changed

2 files changed

+152
-12
lines changed

‎config/src/main/java/org/springframework/security/config/annotation/method/configuration/AuthorizationProxyDataConfiguration.java‎

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2024 the original author or authors.
2+
* Copyright 2002-2025 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -16,13 +16,22 @@
1616

1717
package org.springframework.security.config.annotation.method.configuration;
1818

19+
import java.util.List;
20+
1921
import org.springframework.aop.framework.AopInfrastructureBean;
2022
import org.springframework.beans.factory.config.BeanDefinition;
2123
import org.springframework.context.annotation.Bean;
2224
import org.springframework.context.annotation.Configuration;
2325
import org.springframework.context.annotation.Role;
26+
import org.springframework.core.Ordered;
27+
import org.springframework.data.domain.PageImpl;
28+
import org.springframework.data.domain.SliceImpl;
29+
import org.springframework.data.geo.GeoPage;
30+
import org.springframework.data.geo.GeoResult;
31+
import org.springframework.data.geo.GeoResults;
2432
import org.springframework.security.aot.hint.SecurityHintsRegistrar;
2533
import org.springframework.security.authorization.AuthorizationProxyFactory;
34+
import org.springframework.security.authorization.method.AuthorizationAdvisorProxyFactory;
2635
import org.springframework.security.data.aot.hint.AuthorizeReturnObjectDataHintsRegistrar;
2736

2837
@Configuration(proxyBeanMethods = false)
@@ -34,4 +43,45 @@ static SecurityHintsRegistrar authorizeReturnObjectDataHintsRegistrar(Authorizat
3443
return new AuthorizeReturnObjectDataHintsRegistrar(proxyFactory);
3544
}
3645

46+
@Bean
47+
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
48+
DataTargetVisitor dataTargetVisitor() {
49+
return new DataTargetVisitor();
50+
}
51+
52+
private static final class DataTargetVisitor implements AuthorizationAdvisorProxyFactory.TargetVisitor, Ordered {
53+
54+
private static final int DEFAULT_ORDER = 200;
55+
56+
@Override
57+
public Object visit(AuthorizationAdvisorProxyFactory proxyFactory, Object target) {
58+
if (target instanceof GeoResults<?> geoResults) {
59+
return new GeoResults<>(proxyFactory.proxy(geoResults.getContent()), geoResults.getAverageDistance());
60+
}
61+
if (target instanceof GeoResult<?> geoResult) {
62+
return new GeoResult<>(proxyFactory.proxy(geoResult.getContent()), geoResult.getDistance());
63+
}
64+
if (target instanceof GeoPage<?> geoPage) {
65+
GeoResults<?> results = new GeoResults<>(proxyFactory.proxy(geoPage.getContent()),
66+
geoPage.getAverageDistance());
67+
return new GeoPage<>(results, geoPage.getPageable(), geoPage.getTotalElements());
68+
}
69+
if (target instanceof PageImpl<?> page) {
70+
List<?> content = proxyFactory.proxy(page.getContent());
71+
return new PageImpl<>(content, page.getPageable(), page.getTotalElements());
72+
}
73+
if (target instanceof SliceImpl<?> slice) {
74+
List<?> content = proxyFactory.proxy(slice.getContent());
75+
return new SliceImpl<>(content, slice.getPageable(), slice.hasNext());
76+
}
77+
return null;
78+
}
79+
80+
@Override
81+
public int getOrder() {
82+
return DEFAULT_ORDER;
83+
}
84+
85+
}
86+
3787
}

‎config/src/test/java/org/springframework/security/config/annotation/method/configuration/PrePostMethodSecurityConfigurationTests.java‎

Lines changed: 101 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,14 @@
6363
import org.springframework.context.event.EventListener;
6464
import org.springframework.core.annotation.AnnotationAwareOrderComparator;
6565
import org.springframework.core.annotation.AnnotationConfigurationException;
66-
import org.springframework.core.annotation.Order;
66+
import org.springframework.data.domain.Page;
67+
import org.springframework.data.domain.PageImpl;
68+
import org.springframework.data.domain.Slice;
69+
import org.springframework.data.domain.SliceImpl;
70+
import org.springframework.data.geo.Distance;
71+
import org.springframework.data.geo.GeoPage;
72+
import org.springframework.data.geo.GeoResult;
73+
import org.springframework.data.geo.GeoResults;
6774
import org.springframework.http.HttpStatus;
6875
import org.springframework.http.HttpStatusCode;
6976
import org.springframework.http.MediaType;
@@ -756,6 +763,28 @@ public void findByIdWhenUnauthorizedResultThenDenies() {
756763
assertThatExceptionOfType(AccessDeniedException.class).isThrownBy(flight::getAltitude);
757764
}
758765

766+
@Test
767+
@WithMockUser(authorities = "airplane:read")
768+
public void findGeoResultByIdWhenAuthorizedResultThenAuthorizes() {
769+
this.spring.register(AuthorizeResultConfig.class).autowire();
770+
FlightRepository flights = this.spring.getContext().getBean(FlightRepository.class);
771+
GeoResult<Flight> geoResultFlight = flights.findGeoResultFlightById("1");
772+
Flight flight = geoResultFlight.getContent();
773+
assertThatNoException().isThrownBy(flight::getAltitude);
774+
assertThatNoException().isThrownBy(flight::getSeats);
775+
}
776+
777+
@Test
778+
@WithMockUser(authorities = "seating:read")
779+
public void findGeoResultByIdWhenUnauthorizedResultThenDenies() {
780+
this.spring.register(AuthorizeResultConfig.class).autowire();
781+
FlightRepository flights = this.spring.getContext().getBean(FlightRepository.class);
782+
GeoResult<Flight> geoResultFlight = flights.findGeoResultFlightById("1");
783+
Flight flight = geoResultFlight.getContent();
784+
assertThatNoException().isThrownBy(flight::getSeats);
785+
assertThatExceptionOfType(AccessDeniedException.class).isThrownBy(flight::getAltitude);
786+
}
787+
759788
@Test
760789
@WithMockUser(authorities = "airplane:read")
761790
public void findByIdWhenAuthorizedResponseEntityThenAuthorizes() {
@@ -827,6 +856,46 @@ public void findAllWhenPostFilterThenFilters() {
827856
.doesNotContain("Kevin Mitnick"));
828857
}
829858

859+
@Test
860+
@WithMockUser(authorities = "airplane:read")
861+
public void findPageWhenPostFilterThenFilters() {
862+
this.spring.register(AuthorizeResultConfig.class).autowire();
863+
FlightRepository flights = this.spring.getContext().getBean(FlightRepository.class);
864+
flights.findPage()
865+
.forEach((flight) -> assertThat(flight.getPassengers()).extracting(Passenger::getName)
866+
.doesNotContain("Kevin Mitnick"));
867+
}
868+
869+
@Test
870+
@WithMockUser(authorities = "airplane:read")
871+
public void findSliceWhenPostFilterThenFilters() {
872+
this.spring.register(AuthorizeResultConfig.class).autowire();
873+
FlightRepository flights = this.spring.getContext().getBean(FlightRepository.class);
874+
flights.findSlice()
875+
.forEach((flight) -> assertThat(flight.getPassengers()).extracting(Passenger::getName)
876+
.doesNotContain("Kevin Mitnick"));
877+
}
878+
879+
@Test
880+
@WithMockUser(authorities = "airplane:read")
881+
public void findGeoPageWhenPostFilterThenFilters() {
882+
this.spring.register(AuthorizeResultConfig.class).autowire();
883+
FlightRepository flights = this.spring.getContext().getBean(FlightRepository.class);
884+
flights.findGeoPage()
885+
.forEach((flight) -> assertThat(flight.getContent().getPassengers()).extracting(Passenger::getName)
886+
.doesNotContain("Kevin Mitnick"));
887+
}
888+
889+
@Test
890+
@WithMockUser(authorities = "airplane:read")
891+
public void findGeoResultsWhenPostFilterThenFilters() {
892+
this.spring.register(AuthorizeResultConfig.class).autowire();
893+
FlightRepository flights = this.spring.getContext().getBean(FlightRepository.class);
894+
flights.findGeoResults()
895+
.forEach((flight) -> assertThat(flight.getContent().getPassengers()).extracting(Passenger::getName)
896+
.doesNotContain("Kevin Mitnick"));
897+
}
898+
830899
@Test
831900
@WithMockUser(authorities = "airplane:read")
832901
public void findAllWhenPreFilterThenFilters() {
@@ -1762,16 +1831,8 @@ static class AuthorizeResultConfig {
17621831

17631832
@Bean
17641833
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
1765-
@Order(1)
1766-
static TargetVisitor mock() {
1767-
return Mockito.mock(TargetVisitor.class);
1768-
}
1769-
1770-
@Bean
1771-
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
1772-
@Order(0)
1773-
static TargetVisitor skipValueTypes() {
1774-
return TargetVisitor.defaultsSkipValueTypes();
1834+
static TargetVisitor customTargetVisitor() {
1835+
return TargetVisitor.of(Mockito.mock(), TargetVisitor.defaultsSkipValueTypes());
17751836
}
17761837

17771838
@Bean
@@ -1802,10 +1863,39 @@ Iterator<Flight> findAll() {
18021863
return this.flights.values().iterator();
18031864
}
18041865

1866+
Page<Flight> findPage() {
1867+
return new PageImpl<>(new ArrayList<>(this.flights.values()));
1868+
}
1869+
1870+
Slice<Flight> findSlice() {
1871+
return new SliceImpl<>(new ArrayList<>(this.flights.values()));
1872+
}
1873+
1874+
GeoPage<Flight> findGeoPage() {
1875+
List<GeoResult<Flight>> results = new ArrayList<>();
1876+
for (Flight flight : this.flights.values()) {
1877+
results.add(new GeoResult<>(flight, new Distance(flight.altitude)));
1878+
}
1879+
return new GeoPage<>(new GeoResults<>(results));
1880+
}
1881+
1882+
GeoResults<Flight> findGeoResults() {
1883+
List<GeoResult<Flight>> results = new ArrayList<>();
1884+
for (Flight flight : this.flights.values()) {
1885+
results.add(new GeoResult<>(flight, new Distance(flight.altitude)));
1886+
}
1887+
return new GeoResults<>(results);
1888+
}
1889+
18051890
Flight findById(String id) {
18061891
return this.flights.get(id);
18071892
}
18081893

1894+
GeoResult<Flight> findGeoResultFlightById(String id) {
1895+
Flight flight = this.flights.get(id);
1896+
return new GeoResult<>(flight, new Distance(flight.altitude));
1897+
}
1898+
18091899
Flight save(Flight flight) {
18101900
this.flights.put(flight.getId(), flight);
18111901
return flight;

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /