Skip to content

[Security] $attributes can be anything, but RoleVoter assumes strings #19725

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
Oct 6, 2016
Merged

[Security] $attributes can be anything, but RoleVoter assumes strings #19725

merged 1 commit into from
Oct 6, 2016

Conversation

maennchen
Copy link

@maennchen maennchen commented Aug 24, 2016

Q A
Branch? 2.7
Bug fix? yes
New feature? no
BC breaks? yes
Deprecations? no
Tests pass? yes
Fixed tickets #18042
License MIT
Doc PR reference to the documentation PR, if any

@linaori
Copy link
Contributor

linaori commented Aug 24, 2016

Considering this has most likely never worked, I think attributes should be hinted as string instead.

@maennchen
Copy link
Author

maennchen commented Aug 24, 2016

@iltar I don't think that this is a good idea.

I have a use case where i want to check if some operations (attributes) can be applied on an object (subject).

For sure those operations could be flattened into a string, but one would have to parse them in the voter again which is total nonsense.

Type Hinting for string would be a BC break since one can supply objects as attributes already, but only if the objects implements a __toString() method.

@linaori
Copy link
Contributor

linaori commented Aug 24, 2016

I guess implementing __toString() is already a debatable feature on its own. For the other cases, you have examples of how this would be used? I can't imagine because it's not how it's documented.

@Gladhon
Copy link

Gladhon commented Aug 25, 2016

@iltar i think its basically a good idea to allow objects there, cause in that case you can easy check if your voter is responsible or not. Like ExpressionVoter: https://github.com/symfony/symfony/blob/master/src/Symfony/Component/Security/Core/Authorization/Voter/ExpressionVoter.php#L60

Of course you also can do that with strings, and prefix strings, and hope that there are no conflicts ... but who want this?

@maennchen
Copy link
Author

@iltar I only implemented the __toString to maintain backwards compatibility. In my opinion I'd rather remove that.

But there are already examples in Symfony itself using non string values. (See @Gladhon's comment) The ExpressionVoter only works because the Expression implements __toString.

@hhamon
Copy link
Contributor

hhamon commented Aug 26, 2016

I think we should not rely on the __toString() method because you usually want to use it to return a "display" value. For instance, returning Administrators label for an associated ROLE_ADMIN role. The security system requires that any objects to be used as a role must implement the RoleInterface. So the RoleVoter should probably be upgraded to check it the $attribute is an instance of RoleInterface instance, so that you can convert it to a string with its getRole() method.

@hhamon
Copy link
Contributor

hhamon commented Aug 26, 2016

Otherwise you must implement your custom voter that support your custom type of attribute.

@hhamon
Copy link
Contributor

hhamon commented Aug 26, 2016

Btw, the border between bug and new feature is really close in this case. I think it's better to consider it a new feature and submit the PR against the master branch.

@maennchen
Copy link
Author

@hhamon I'd like your proposed solution. I implemented the __toString() thing to avoid BC breaks.

@maennchen
Copy link
Author

I think that it's definitely a bug since the interface clearly says that mixed is accepted. (Which is currently only if you implement __toString.
Could we implement this as a bug and introduce a new feature for master which cleans the behaviour up?

@sstok
Copy link
Contributor

sstok commented Aug 26, 2016

supportsAttribute for RoleVoter should only allow a string or Role(Interface) (Role is actually the only one that is officially supported, because of the string promise).

But when the attributes of a not supported type, the de decision should be abstained?
When passing an unsupported attribute it would have failed with an php error, no?

@maennchen
Copy link
Author

@sstok Two times yes.

@maennchen
Copy link
Author

Also supportsAttribute does not exist anymore in >= 3.0 I think.

@hhamon
Copy link
Contributor

hhamon commented Aug 26, 2016

Yes supportAttributes as a "public" method was removed from the VoterInterface in Symfony 3.0 because this method was never called by the Security component in Symfony 2. But its piece of logic still resides in the RoleVoter class.

@maennchen
Copy link
Author

Should I change to check if the attribute is instance of RoleInterface instead of __toString? This will be a small BC break.

@ro0NL
Copy link
Contributor

ro0NL commented Sep 20, 2016

@maennchen why exactly do you want to remove __toString support? Imo we should first check for RoleInterface then string/string-object.

That would still be a BC break, but personally i consider it a bugfix.

if (is_object($attribute) && !method_exists($attribute, '__toString')) {
return false;
}

return 0 === strpos($attribute, $this->prefix);
Copy link
Contributor

Choose a reason for hiding this comment

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

Could be simply (string) $attribtute as well. No need for the above statements... it should crash for invalid values by design.

Copy link
Author

Choose a reason for hiding this comment

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

An attribute is mixed by design. It shouldn't crash for non string values. It should abstain. Why should it be a convention that every object passed as an attribute can be converted to a string.

I implemented a Voter, that was designed to vote for Operations on a subject when I encountered the error. Why should those operations which are not by any means strings have a toString method? That makes no sense for something that is by design mixed.

(By the way: strpos will automatically do a string casting. No string cast needed for that.)

Copy link
Author

Choose a reason for hiding this comment

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

I'd change the code to check if $attribute instanceof RoleInterface, if yes do a getRole() on it. If it is no string or RoleInterface, I'd continue / ABSTAIN.

Copy link
Contributor

Choose a reason for hiding this comment

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

It shouldn't crash for non string values. It should abstain

Sorry, you're right. However i think for 2.7 supportAttribute should also consider RoleInterface due mixed attribute support.

@maennchen
Copy link
Author

I refactored it with specific checks for RoleInterface.

I personally don't really care if there is support for objects having a __toString() method. In my opinion it's cleaner just to handle strings & RoleInterface, but with __toString() support there is no BC break.

@@ -57,6 +58,10 @@ public function vote(TokenInterface $token, $object, array $attributes)
$roles = $this->extractRoles($token);

foreach ($attributes as $attribute) {
if ($attribute instanceof RoleInterface) {
$attribute = $attribute->getRole();
Copy link
Member

Choose a reason for hiding this comment

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

We should not call supportAttribute if the return value of getRole() is null as it means that there is no good representation of the role as a string.

Copy link
Member

Choose a reason for hiding this comment

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

nevermind, that's already covered in supportsAttribute() via the is_string() check.

@fabpot
Copy link
Member

fabpot commented Oct 6, 2016

Thank you @maennchen.

@fabpot fabpot merged commit ad3ac95 into symfony:2.7 Oct 6, 2016
fabpot added a commit that referenced this pull request Oct 6, 2016
…mes strings (Jonatan Männchen)

This PR was merged into the 2.7 branch.

Discussion
----------

[Security] $attributes can be anything, but RoleVoter assumes strings

| Q             | A
| ------------- | ---
| Branch?       | 2.7
| Bug fix?      | yes
| New feature?  | no
| BC breaks?    | yes
| Deprecations? | no
| Tests pass?   | yes
| Fixed tickets | #18042
| License       | MIT
| Doc PR        | reference to the documentation PR, if any

Commits
-------

ad3ac95 bug #18042 [Security] $attributes can be anything, but RoleVoter assumes strings
@maennchen maennchen deleted the hotfix/18042_support_mixed_types branch October 6, 2016 07:59
@fabpot fabpot mentioned this pull request Oct 27, 2016
This was referenced Oct 27, 2016
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.

8 participants