Skip to content

Add AuthorizationManagerFactory #17673

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

sjohnr
Copy link
Contributor

@sjohnr sjohnr commented Aug 8, 2025

This PR is a work in progress. cc: @rwinch

@sjohnr sjohnr force-pushed the gh-17585-authorization-manager-factory branch 3 times, most recently from 5f55ad2 to 4ef91a4 Compare August 12, 2025 05:06
Signed-off-by: Steve Riesenberg <[email protected]>
@sjohnr sjohnr force-pushed the gh-17585-authorization-manager-factory branch from 4ef91a4 to 1de115e Compare August 13, 2025 15:49
Copy link
Member

@rwinch rwinch left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the updates @sjohnr! I've provided feedback inline.

@@ -47,7 +49,9 @@ public abstract class AbstractSecurityExpressionHandler<T>

private @Nullable BeanResolver beanResolver;

private @Nullable RoleHierarchy roleHierarchy;
private final DefaultAuthorizationManagerFactory<T> defaultAuthorizationManagerFactory = new DefaultAuthorizationManagerFactory<>();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove the defaultAuthorizationManagerFactory in favor of a method named getDefaultAuthorizationManagerFactory() that:

  • is deprecated for removal in 8.0 in favor of getAuthorizationManagerFactory(). Any methods that need to access it to perform setters should be deprecated in favor of setting an already initialized (properties already set) AuthorizationManagerFactory directly vs accessing the properties on the current member.
  • Throws an IllegalStateException if authorizationManagerFactory is not an instance of DefaultAuthorizationManagerFactory, but otherwise performs a cast. This ensures that the AuthorizationManagerFactory being used aligns with what is being configured or gotten.


private @Nullable Set<String> roles;
private @Nullable DefaultAuthorizationManagerFactory<T> defaultAuthorizationManagerFactory;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same feedback as the comment on AbstractSecurityExpressionHandler.defaultAuthorizationManagerFactory.


private final Supplier<Authentication> authentication;
private static final AuthorizationManagerFactory<?> DEFAULT_AUTHORIZATION_MANAGER_FACTORY = new DefaultAuthorizationManagerFactory<>();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

DEFAULT_AUTHORIZATION_MANAGER_FACTORY should also be removed in favor of just using authorizationManagerFactory. as described below.

* @since 3.0
*/
public abstract class SecurityExpressionRoot implements SecurityExpressionOperations {
public abstract class SecurityExpressionRoot<T> implements SecurityExpressionOperations {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
public abstract class SecurityExpressionRoot<T> implements SecurityExpressionOperations {
public abstract class SecurityExpressionRoot<T extends @Nullable Object> implements SecurityExpressionOperations {

I think this is necessary for the generic to allow for a Nullable generic (e.g. MyExpressionRoot <@Nullable SomeType>)

* @author Steve Riesenberg
* @since 7.0
*/
public final class DefaultAuthorizationManagerFactory<T> implements AuthorizationManagerFactory<T> {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
public final class DefaultAuthorizationManagerFactory<T> implements AuthorizationManagerFactory<T> {
public final class DefaultAuthorizationManagerFactory<T extends @Nullable Object> implements AuthorizationManagerFactory<T> {

@@ -45,7 +45,7 @@ public MessageSecurityExpressionRoot(Authentication authentication, Message<?> m
* @since 5.8
*/
public MessageSecurityExpressionRoot(Supplier<Authentication> authentication, Message<?> message) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
public MessageSecurityExpressionRoot(Supplier<Authentication> authentication, Message<?> message) {
public MessageSecurityExpressionRoot(Supplier<Authentication> authentication, Message<T> message) {

@@ -29,7 +29,7 @@
* @author Evgeniy Cheban
* @since 4.0
*/
public class MessageSecurityExpressionRoot extends SecurityExpressionRoot {
public class MessageSecurityExpressionRoot extends SecurityExpressionRoot<Message<?>> {

public final Message<?> message;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
public final Message<?> message;
public final Message<T> message;

Comment on lines +59 to +62
// Since MessageSecurityExpressionRoot is of a different type, use the default
// factory instead of the one configured with this class.
root.setTrustResolver(getDefaultAuthorizationManagerFactory().getTrustResolver());
root.setRoleHierarchy(getDefaultAuthorizationManagerFactory().getRoleHierarchy());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// Since MessageSecurityExpressionRoot is of a different type, use the default
// factory instead of the one configured with this class.
root.setTrustResolver(getDefaultAuthorizationManagerFactory().getTrustResolver());
root.setRoleHierarchy(getDefaultAuthorizationManagerFactory().getRoleHierarchy());
root.setAuthorizationManagerFactory(getAuthorizationManagerFactory());

If a custom authorizationManagerFactory is used, this does not use it. I've fixed the generic types so that they align

Comment on lines +40 to 47
// Since WebSecurityExpressionRoot is of a different type, use the default factory
// instead of the one configured with this class.
root.setTrustResolver(getDefaultAuthorizationManagerFactory().getTrustResolver());
root.setRoleHierarchy(getDefaultAuthorizationManagerFactory().getRoleHierarchy());
root.setDefaultRolePrefix(getDefaultAuthorizationManagerFactory().getRolePrefix());
return root;
}

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// Since WebSecurityExpressionRoot is of a different type, use the default factory
// instead of the one configured with this class.
root.setTrustResolver(getDefaultAuthorizationManagerFactory().getTrustResolver());
root.setRoleHierarchy(getDefaultAuthorizationManagerFactory().getRoleHierarchy());
root.setDefaultRolePrefix(getDefaultAuthorizationManagerFactory().getRolePrefix());
return root;
}
root.setAuthorizationManagerFactory(getAuthorizationManagerFactory());
return root;
}
@Deprecated(forRemoval = true, since = "7.0")
protected SecurityExpressionOperations createSecurityExpressionRoot(Authentication authentication,
FilterInvocation fi) {
RequestAuthorizationContext authorizationContext = new RequestAuthorizationContext(
fi.getRequest());
return createSecurityExpressionRoot(authentication, authorizationContext);
}

Comment on lines +40 to +44
// Since WebSecurityExpressionRoot is of a different type, use the default factory
// instead of the one configured with this class.
root.setTrustResolver(getDefaultAuthorizationManagerFactory().getTrustResolver());
root.setRoleHierarchy(getDefaultAuthorizationManagerFactory().getRoleHierarchy());
root.setDefaultRolePrefix(getDefaultAuthorizationManagerFactory().getRolePrefix());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a similar problem to the comment for DefaultMessageSecurityExpressionHandler.

To solve it, we should create a package scoped FilterInvocationContextRoot that has a public final HttpServletRequest request member and extends SecurityExpressionRoot<FilterInvocation>. This method would then use FilterInvocationContextRoot instead of WebSecurityExpressionRoot.

Then, we should create a ticket to consider deprecating the authorization logic that depends on FilterInvocation (e.g. the SecurityExressionHandler and FilterInvocationContextRoot)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants