Skip to content

Commit

Permalink
Remove Advised Methods from Authorization Proxy Objects
Browse files Browse the repository at this point in the history
Closes gh-15561
  • Loading branch information
kse-music authored and jzheaux committed Aug 30, 2024
1 parent ecf6cac commit fd05c5a
Show file tree
Hide file tree
Showing 3 changed files with 16 additions and 31 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,7 @@ public Object proxy(Object target) {
for (Advisor advisor : this.advisors) {
factory.addAdvisors(advisor);
}
factory.setOpaque(true);
factory.setProxyTargetClass(!Modifier.isFinal(target.getClass().getModifiers()));
return factory.getProxy();
}
Expand Down Expand Up @@ -357,6 +358,7 @@ public Object visit(AuthorizationAdvisorProxyFactory proxyFactory, Object object
ProxyFactory factory = new ProxyFactory();
factory.setTargetClass(targetClass);
factory.setInterfaces(ClassUtils.getAllInterfacesForClass(targetClass));
factory.setOpaque(true);
factory.setProxyTargetClass(!Modifier.isFinal(targetClass.getModifiers()));
for (Advisor advisor : proxyFactory) {
factory.addAdvisors(advisor);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@
import java.util.function.Supplier;
import java.util.stream.Stream;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.jetbrains.annotations.NotNull;
import org.junit.jupiter.api.Test;

Expand Down Expand Up @@ -336,6 +338,18 @@ public void setTargetVisitorIgnoreValueTypesThenIgnores() {
assertThat(factory.proxy(35)).isEqualTo(35);
}

@Test
public void serializeWhenAuthorizationProxyObjectThenOnlyIncludesProxiedProperties()
throws JsonProcessingException {
SecurityContextHolder.getContext().setAuthentication(this.admin);
AuthorizationAdvisorProxyFactory factory = AuthorizationAdvisorProxyFactory.withDefaults();
User user = proxy(factory, this.alan);
ObjectMapper mapper = new ObjectMapper();
String serialized = mapper.writeValueAsString(user);
Map<String, Object> properties = mapper.readValue(serialized, Map.class);
assertThat(properties).hasSize(3).containsKeys("id", "firstName", "lastName");
}

private Authentication authenticated(String user, String... authorities) {
return TestAuthentication.authenticated(TestAuthentication.withUsername(user).authorities(authorities).build());
}
Expand Down
31 changes: 0 additions & 31 deletions docs/modules/ROOT/pages/servlet/authorization/method-security.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -2227,37 +2227,6 @@ class UserController {
----
======

If you are using Jackson, though, this may result in a serialization error like the following:

[source,bash]
====
com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Direct self-reference leading to cycle
====

This is due to how Jackson works with CGLIB proxies.
To address this, add the following annotation to the top of the `User` class:

[tabs]
======
Java::
+
[source,java,role="primary"]
----
@JsonSerialize(as = User.class)
public class User {
}
----
Kotlin::
+
[source,kotlin,role="secondary"]
----
@JsonSerialize(`as` = User::class)
class User
----
======

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:

[tabs]
Expand Down

0 comments on commit fd05c5a

Please sign in to comment.