Add Value-Type Ignore Support
This PR makes using @AuthorizeReturnObject practical on a more diverse set of classes and interfaces, including Spring Data interfaces.
A typical Spring Data interface begins like this:
public interface UserRepository extends CrudRepository<User, UUID> {
}
and because CrudRepository has methods that return primitive types like int count(), an application cannot use @AuthorizeReturnObject at the class level.
This is a reasonable default since the semantics around Spring Security method security annotations are that placing it at the class level is functionally equivalent to placing it on the method level. Since it would be an error to use @AuthorizeReturnObject on a method that returns an int, we want to error by default.
With this PR, an application can relax that behavior by doing:
@Bean
AuthorizationProxyTargetVisitor ignoreValueTypes() {
return AuthorizationProxyTargetVisitors.defaultVisitorIgnoreValueTypes();
}
It incidentally introduces AuthorizationProxyTargetVisitor to simplify any kind of proxy customization of the target object.
Note that this same functionality can be achieved by adding setIgnoreValueTypes(boolean) to the proxy factory, and I'm open to that.
The reason I like this approach is that it gives folks more power to customize how a given type is handled. The alternative is to not use @EnableMethodSecurity so that they can publish their own AuthorizationProxyFactory or possibly add a bean factory post-processor to inject their own authorization proxy factory implementation.
Some simple examples other than ignoring a type are to use different ProxyFactory settings or to programmatically visit an object:
AuthorizationProxyTargetVisitor visitor = (authorizationProxyFactory, target) -> {
if (target class has some custom annotation) {
ProxyFactory proxyFactory = ...
proxyFactory.setAopProxyFactory(new MyAopProxyFactory())
// ...
return proxyFactory.getProxy();
}
if (target class is some kind of custom container class) {
target.setX(authorizationProxyFactory.visit(target.getX());
target.setY(authorizationProxyFactory.visit(target.getY());
return target;
}
return null;
}
// ...
@Bean
AuthorizationProxyTargetVisitor proxyTargetVisitor() {
return AuthorizationProxyTargetVisitors.of(visitor, defaultVisitorIgnoreValueTypes());
}
Issue gh-14597