Skip to content
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

Add SingleResultAuthorizationManager #16612

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

Conversation

franticticktick
Copy link
Contributor

Closes gh-16590

@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged label Feb 17, 2025
@franticticktick
Copy link
Contributor Author

Hey @plll0123, we invite you to join the review so that your interest in contributions does not disappear :)

Copy link
Contributor

@jzheaux jzheaux left a comment

Choose a reason for hiding this comment

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

Thanks again, @franticticktick! I've left my feedback inline. Note that most if it is based on the premise that I think it class should hold an AuthorizationResult member variable, set in the constructor. This will give this class many more uses.

* @param <C>
* @return permit-all {@link AuthorizationManager} instance
*/
public static <C> AuthorizationManager<C> PERMIT_ALL() {
Copy link
Contributor

Choose a reason for hiding this comment

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

Spring Security conventionally uses camelCase for methods, even ones that return a constant; please change this to permitAll().

* @param <C>
* @return deny-all {@link AuthorizationManager} instance
*/
public static <C> AuthorizationManager<C> DENY_ALL() {
Copy link
Contributor

Choose a reason for hiding this comment

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

Spring Security conventionally uses camelCase for methods, even ones that return a constant; please change this to denyAll().

* @param <C>
* @return deny-all {@link AuthorizationManager} instance
*/
public static <C> AuthorizationManager<C> DENY_ALL() {
Copy link
Contributor

Choose a reason for hiding this comment

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

I think this should return the concrete type. Just like constructors emit the concrete type. Can you please change both method to return SingleResultAuthorizationManager?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

No, we can't do this, java uses LambdaMetafactory for lambda creation. This factory creates CallSite object, which returns intenface implementation. Therefore these methods must return an interface.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sorry, you can ignore this comment :)

return (a, o) -> DENY;
}

private SingleResultAuthorizationManager() {
Copy link
Contributor

Choose a reason for hiding this comment

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

While having this for permitAll and denyAll is great, we can expand it by taking an AuthorizationResult in the constructor and having it be public.

* @return deny-all {@link AuthorizationManager} instance
*/
public static <C> AuthorizationManager<C> DENY_ALL() {
return (a, o) -> DENY;
Copy link
Contributor

Choose a reason for hiding this comment

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

Instead of a lambda, consider returning a static final instance of SingleResultAuthorizationManager.


@Override
public AuthorizationDecision check(Supplier<Authentication> authentication, C object) {
throw new UnsupportedOperationException("Not supported");
Copy link
Contributor

Choose a reason for hiding this comment

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

Let's still implement this. If the private member result isn't of type AuthenticationDecision, we can throw and exception.

}

@Override
public AuthorizationDecision check(Supplier<Authentication> authentication, C object) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Let's please implement authorize, returning whatever single result was set in the constructor.

* @author Max Batischev
* @since 6.5
*/
public final class SingleResultAuthorizationManager<C> implements AuthorizationManager<C> {
Copy link
Contributor

Choose a reason for hiding this comment

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

Please add tests for the class.

@jzheaux jzheaux changed the title Add Support SingleResultAuthorizationManager Add SingleResultAuthorizationManager Feb 24, 2025
@franticticktick
Copy link
Contributor Author

Hi @jzheaux, thanks for your feedback. There are several points that need to be discussed. We can add a static method, for example denyAll, and return a static final instance:

public static <C> SingleResultAuthorizationManager<C> denyAll() {
   return DENY_MANAGER;
}

This is only possible if the SingleResultAuthorizationManager instance has a raw type:

private static final SingleResultAuthorizationManager DENY_MANAGER = new SingleResultAuthorizationManager<>(new AuthorizationDecision(false));

Generics are not available in a static context, which forces us to use a raw type. I'm not sure if this is the best pattern in this case, @jzheaux what do you think about it?

@jzheaux
Copy link
Contributor

jzheaux commented Feb 28, 2025

@franticticktick good questions. First, I think it's okay to construct a SingleResultAuthorizationManager each time denyAll() is called. This is conventionally the most type-safe and I'm fine going that route.

However, since the implementation knows that it won't use the type, then it can safely use <?>:

private static final SingleResultAuthorizationManager<?> DENY = new SingleResultAuthorizationManager<>(new AuthorizationDecision(false));

That does require a cast in the static method, but again in practice this isn't a concern since this implementation never uses the type at runtime:

public static <T> SingleResultAuthorizationManager<T> denyAll() {
    return (SingleResultAuthorizationManager<T>) DENY;
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
status: waiting-for-triage An issue we've not yet triaged
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Add PermitAll and DenyAll AuthorizationManager instances
3 participants