Skip to content

Support AysncSecurityPolicy in SecurityPolicies.allOf. #12158

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

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

Conversation

mateusazis
Copy link
Contributor

Addresses part of #11547.

new AsyncSecurityPolicy() {
@Override
public ListenableFuture<Status> checkAuthorizationAsync(int uid) {
return immediateFuture(policy.checkAuthorization(uid));
Copy link
Member

@jdcormie jdcormie Jun 17, 2025

Choose a reason for hiding this comment

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

This doesn't seem to be a valid implementation of the checkAuthorizationAsync() API contract because it blocks the calling thread.

Copy link
Member

Choose a reason for hiding this comment

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

If ALL of your input securityPolicies are AsyncSecurityPolicy, I think you can implement an async allOf(). But if even one of your inputs is not an AsyncSecurityPolicy, someone needs to provide an Executor to make this possible.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

My goal was to not force the clients to pick another API if they have any AsyncSecurityPolicy, specially because the current method is still compatible (though inefficient) with AsyncSecurityPolicy, so I felt like having two methods could be confusing.

This doesn't seem to be a valid implementation of the checkAuthorizationAsync() API contract because it blocks the calling thread.

My intention was to treat all policies as AsyncSecurityPolicy by obtaining a List<ListenableFuture<Status>> and transforming them without blocking. If one of the policies is synchronous, we just produce an immediate future.

This could be harmful, yes, if that policy were slow, but I see that as API misuse: the integrator should have provided an AsyncSecurityPolicy instead and we wouldn't monopolize a thread waiting on it.

Please let me know what you think.

Copy link
Member

Choose a reason for hiding this comment

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

IDK what more to say except that implementations of checkAuthorizationAsync() aren't allowed to block. If they were, there wouldn't be much reason for AsyncSecurityPolicy to even exist: Plain old SecurityPolicy.checkAuthorization() has always had the property that it may or may not block. And we've always been able to turn checkAuthorization() into a ListenableFuture using Futures.submit(securityPolicy::checkAuthorization, blockingExecutor). What makes checkAuthorizationAsync() interesting is that it promises not to block so I can call it from any thread.

Hiding a blocking call to checkAuthorization() behind checkAuthorizationAsync() actively defeats one of your two most important callers here:

ListenableFuture<Status> authFuture =
(securityPolicy instanceof AsyncSecurityPolicy)
? ((AsyncSecurityPolicy) securityPolicy).checkAuthorizationAsync(remoteUid)
: Futures.submit(
() -> securityPolicy.checkAuthorization(remoteUid), offloadExecutor);

This could be harmful, yes, if that policy were slow, but I see that as API misuse: the integrator should have provided an AsyncSecurityPolicy instead and we wouldn't monopolize a thread waiting on it.

OK but your javadoc doesn't say any of that. Even if it did, we want APIs that are difficult to misuse and, ideally, impossible to misuse, by way of checks at compile time.

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