Skip to content

Commit 04bfedb

Browse files
committed
Improve serialize of proxy objects generated by AuthorizeReturnObject
Issue gh-15561
1 parent 84fc5a7 commit 04bfedb

File tree

3 files changed

+40
-31
lines changed

3 files changed

+40
-31
lines changed

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

Lines changed: 2 additions & 0 deletions
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

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,9 @@
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;
39+
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
3740
import org.jetbrains.annotations.NotNull;
3841
import org.junit.jupiter.api.Test;
3942

@@ -336,6 +339,25 @@ public void setTargetVisitorIgnoreValueTypesThenIgnores() {
336339
assertThat(factory.proxy(35)).isEqualTo(35);
337340
}
338341

342+
@Test
343+
public void serializeAuthorizationProxyObjectWhenProvideJsonSerialize() throws JsonProcessingException {
344+
SecurityContextHolder.getContext().setAuthentication(this.admin);
345+
AuthorizationAdvisorProxyFactory factory = AuthorizationAdvisorProxyFactory.withDefaults();
346+
JsonSerializeUser user = new JsonSerializeUser("used JsonSerialize annotation");
347+
348+
ObjectMapper mapper = new ObjectMapper();
349+
assertThat(mapper.writeValueAsString(proxy(factory, user))).doesNotContain("description");
350+
}
351+
352+
@Test
353+
public void serializeAuthorizationProxyObject() throws JsonProcessingException {
354+
SecurityContextHolder.getContext().setAuthentication(this.admin);
355+
AuthorizationAdvisorProxyFactory factory = AuthorizationAdvisorProxyFactory.withDefaults();
356+
User user = proxy(factory, this.alan);
357+
ObjectMapper mapper = new ObjectMapper();
358+
assertThat(mapper.writeValueAsString(user)).isInstanceOf(String.class);
359+
}
360+
339361
private Authentication authenticated(String user, String... authorities) {
340362
return TestAuthentication.authenticated(TestAuthentication.withUsername(user).authorities(authorities).build());
341363
}
@@ -363,6 +385,22 @@ interface Identifiable {
363385

364386
}
365387

388+
@JsonSerialize(as = User.class)
389+
public static class JsonSerializeUser extends User {
390+
391+
private final String description;
392+
393+
JsonSerializeUser(String description) {
394+
super("alan", "alan", "turing");
395+
this.description = description;
396+
}
397+
398+
public String getDescription() {
399+
return this.description;
400+
}
401+
402+
}
403+
366404
public static class User implements Identifiable, Comparable<User> {
367405

368406
private final String id;

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

Lines changed: 0 additions & 31 deletions
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)