Skip to content

Commit fd05c5a

Browse files
kse-musicjzheaux
authored andcommitted
Remove Advised Methods from Authorization Proxy Objects
Closes gh-15561
1 parent ecf6cac commit fd05c5a

File tree

3 files changed

+16
-31
lines changed

3 files changed

+16
-31
lines changed

core/src/main/java/org/springframework/security/authorization/method/AuthorizationAdvisorProxyFactory.java

+2
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,7 @@ public Object proxy(Object target) {
171171
for (Advisor advisor : this.advisors) {
172172
factory.addAdvisors(advisor);
173173
}
174+
factory.setOpaque(true);
174175
factory.setProxyTargetClass(!Modifier.isFinal(target.getClass().getModifiers()));
175176
return factory.getProxy();
176177
}
@@ -357,6 +358,7 @@ public Object visit(AuthorizationAdvisorProxyFactory proxyFactory, Object object
357358
ProxyFactory factory = new ProxyFactory();
358359
factory.setTargetClass(targetClass);
359360
factory.setInterfaces(ClassUtils.getAllInterfacesForClass(targetClass));
361+
factory.setOpaque(true);
360362
factory.setProxyTargetClass(!Modifier.isFinal(targetClass.getModifiers()));
361363
for (Advisor advisor : proxyFactory) {
362364
factory.addAdvisors(advisor);

core/src/test/java/org/springframework/security/authorization/AuthorizationAdvisorProxyFactoryTests.java

+14
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@
3434
import java.util.function.Supplier;
3535
import java.util.stream.Stream;
3636

37+
import com.fasterxml.jackson.core.JsonProcessingException;
38+
import com.fasterxml.jackson.databind.ObjectMapper;
3739
import org.jetbrains.annotations.NotNull;
3840
import org.junit.jupiter.api.Test;
3941

@@ -336,6 +338,18 @@ public void setTargetVisitorIgnoreValueTypesThenIgnores() {
336338
assertThat(factory.proxy(35)).isEqualTo(35);
337339
}
338340

341+
@Test
342+
public void serializeWhenAuthorizationProxyObjectThenOnlyIncludesProxiedProperties()
343+
throws JsonProcessingException {
344+
SecurityContextHolder.getContext().setAuthentication(this.admin);
345+
AuthorizationAdvisorProxyFactory factory = AuthorizationAdvisorProxyFactory.withDefaults();
346+
User user = proxy(factory, this.alan);
347+
ObjectMapper mapper = new ObjectMapper();
348+
String serialized = mapper.writeValueAsString(user);
349+
Map<String, Object> properties = mapper.readValue(serialized, Map.class);
350+
assertThat(properties).hasSize(3).containsKeys("id", "firstName", "lastName");
351+
}
352+
339353
private Authentication authenticated(String user, String... authorities) {
340354
return TestAuthentication.authenticated(TestAuthentication.withUsername(user).authorities(authorities).build());
341355
}

docs/modules/ROOT/pages/servlet/authorization/method-security.adoc

-31
Original file line numberDiff line numberDiff line change
@@ -2227,37 +2227,6 @@ class UserController {
22272227
----
22282228
======
22292229

2230-
If you are using Jackson, though, this may result in a serialization error like the following:
2231-
2232-
[source,bash]
2233-
====
2234-
com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Direct self-reference leading to cycle
2235-
====
2236-
2237-
This is due to how Jackson works with CGLIB proxies.
2238-
To address this, add the following annotation to the top of the `User` class:
2239-
2240-
[tabs]
2241-
======
2242-
Java::
2243-
+
2244-
[source,java,role="primary"]
2245-
----
2246-
@JsonSerialize(as = User.class)
2247-
public class User {
2248-
2249-
}
2250-
----
2251-
2252-
Kotlin::
2253-
+
2254-
[source,kotlin,role="secondary"]
2255-
----
2256-
@JsonSerialize(`as` = User::class)
2257-
class User
2258-
----
2259-
======
2260-
22612230
Finally, you will need to publish a <<custom_advice, custom interceptor>> to catch the `AccessDeniedException` thrown for each field, which you can do like so:
22622231

22632232
[tabs]

0 commit comments

Comments
 (0)