Skip to content

Navigation Menu

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

[Security] Add ability for voters to explain their vote #59771

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

Merged
merged 1 commit into from
Feb 17, 2025

Conversation

nicolas-grekas
Copy link
Member

@nicolas-grekas nicolas-grekas commented Feb 13, 2025

Q A
Branch? 7.3
Bug fix? no
New feature? no
Deprecations? no
Issues Fix #27995, #26343, #35592, #43147
License MIT

This PR takes over #58107, which itself took over from #46493, etc.

It takes the only approach I could think of that would preserve BC.

The visible tip of what this achieves is:

image

image

Internally, this provides a new access audit log infrastructure that relies on new AccessDecision and Vote objects.

Note that I didn't add (nor fix) tests for now. I'll borrow (and credit) from #58107 / #46493 as much as possible.

Copy link
Member

@alexandre-daubois alexandre-daubois left a comment

Choose a reason for hiding this comment

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

Just a thought at first read: Vote and AccessDecision really look like value objects.

Should we make:

  • AccessDecision::isGranted readonly and set with a constructor? The decision may not change when the object is created, and if so, a new instance may be created instead because that's another decision actually ;
  • The same thing for Vote::$result and Vote::$voter? Here again, if one of these property has to change after instantiation, then it may be more correct to create a new instance because this is not the "same" vote anymore.

@nicolas-grekas
Copy link
Member Author

@alexandre-daubois making the properties readonly would break the FC layer: setting the results multiple times is how an updated implementation can still give proper feedback when given a non-updated one (voters/access decision managers/strategies.)

@nicolas-grekas nicolas-grekas force-pushed the sec-vote-reasons branch 3 times, most recently from fae982d to 20e7b35 Compare February 14, 2025 13:26
try {
return $this->userSecurityChecker->isGrantedForUser($user, $attribute, $subject, $accessDecision);
} catch (AuthenticationCredentialsNotFoundException) {
return false;
Copy link
Member Author

Choose a reason for hiding this comment

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

added for parity with isGranted() above

@nicolas-grekas nicolas-grekas force-pushed the sec-vote-reasons branch 2 times, most recently from 69264d6 to 2f4b88e Compare February 14, 2025 15:24
@nicolas-grekas
Copy link
Member Author

This PR should be ready for review.
I fixed tests, so that it's green, but I'll add more.

Status: needs review

public function __construct(
private TokenStorageInterface $tokenStorage,
private AccessDecisionManagerInterface $accessDecisionManager,
) {
}

final public function isGranted(mixed $attribute, mixed $subject = null): bool
final public function isGranted(mixed $attribute, mixed $subject = null, ?AccessDecision $accessDecision = null): bool
Copy link
Member Author

@nicolas-grekas nicolas-grekas Feb 14, 2025

Choose a reason for hiding this comment

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

Note that we could decide to not expose AccessDecision objects when using (User)AuthorizationCheckerInterface.
Any opinions on this?

Having the AccessDecision available to isGranted[ForUser]() methods would allow userland to get the audit log more easily. It's also used right now in AbstractController::denyUnlessGranted(), to compute a better error message. Using the AccessDecisionManager instead of the (User)AuthorizationChecker would be the alternative.

Copy link
Member

Choose a reason for hiding this comment

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

Having it in (User)AuthorizationCheckerInterface looks useful enough

@94noni
Copy link
Contributor

94noni commented Feb 16, 2025

What a ride for those PRs :)
Bravo to all devs includes in the process 👏

@fabpot
Copy link
Member

fabpot commented Feb 17, 2025

Thank you @nicolas-grekas.

@kevinpapst
Copy link

The method Vote:addReason() was added, but the code calls $vote->reasons[] all the time. Would be great if we could replace the actual Vote instance with a custom implementation that does not store the reasons. This code can be called hundreds of times and there is no benefit in production to actually store these information.

@nicolas-grekas
Copy link
Member Author

We'd need benchmarks to consider any perf/mem issue here. To me, this should be negligible.
Also: this can be used in prod to compute nice user error messages if one wants to (some will).

@j-schumann
Copy link

Also: this can be used in prod to compute nice user error messages if one wants to (some will).

This is our primary/only reason why we wanted this feature.

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

Successfully merging this pull request may close these issues.

[Security][DX] Be able to know why exactly SecurityVoter returns false
Morty Proxy This is a proxified and sanitized view of the page, visit original site.