Fix personal setting for apps which are not whitelisted#36258
Fix personal setting for apps which are not whitelisted#36258
Conversation
fe9ab19 to
6aab82f
Compare
485f4aa to
62b28ca
Compare
lib/private/App/AppManager.php
Outdated
| /** | ||
| * Check if the user is guest user, if so get the apps which it is allowed for. | ||
| */ | ||
| if (\array_key_exists('guests', $userAppAttributes)) { |
There was a problem hiding this comment.
if (isset($userAppAttributes['guests']['whitelistedApps']) && !\in_array($appName, $userAppAttributes['guests']['whitelistedApps'], true))
this seems a bit better, thought we might need to change it a bit.
Note that we might need to check if the whitelistedApps is an array.
In addition, clarify what is the expected behaviour:
- when the "guest" and / or "whitelistedApps" don't exists.
- when the "whitelistedApps" is null / empty / string
- when the "whitelistedApps" is an empty array
- any other additional case.
There was a problem hiding this comment.
- If
guestsandwhitelistedAppsdon't exist, then do the normal checks which already existed before this change. - If the
whitelistedAppsis empty / null / string, then continue with the checks which already existed before this change. - Expectation is whitelistedApps should be an array we would check if the
appNameis there in any of the elements in the array. Expectation here is when the code will access$userAttributes['guests']['whitelistedApps']we should get a list of strings. - When
whitelistedAppsis an empty array then proceed ahead with further checks which were already present before this change.
| * @param string $appName | ||
| * @param array $data | ||
| */ | ||
| public function setAttributes($app, $data) { |
There was a problem hiding this comment.
Clarify and document clear how this method will behave. Note that it's expected that multiple apps will be listening this event and will use this method to add their own attributes. This means that apps can easily overwrite information of other apps.
- What params do we need? Do we need the app name? What for?
- What "data" do we need? I expected something like
setAttributes(string $attrName, mixed $attrValue), where the attrValue could be an string or an array (or maybe anything) - How are we going to deal with multiple apps? I think we could have a "first in wins" policy: if the attribute doesn't exists, write it and return false; it it already exists, ignore it and return false. This needs to be documented anyway.
There was a problem hiding this comment.
How are we going to deal with multiple apps? I think we could have a "first in wins" policy: if the attribute doesn't exists, write it and return false; it it already exists, ignore it and return false
There is another possibile flaw I see here, which is say for example if we use the policy to only add new attributes which don't exist and leave if the attribute already exist. Then it could also happen for example the user updated the app attribute and we might miss that, because we don't update. We only add the new attributes and skip if the attribute already exists. imho, shouldn't we consider to add/update it anyway? Or did I misread your feedback, please let me know your opinion.
There was a problem hiding this comment.
The app can detect that case by checking the returned value and take a decision.
Overwriting might be more problematic because that case is more difficult to detect. Debugging might be also more difficult because we don't know which app overwrote the attribute. You'll see a different value than the one you could expect.
Note that there is no specific order in which the apps will be notified, so we have to consider it's a random order. This means that checking the returned value should be considered as mandatory. As said, documenting this is very important.
There was a problem hiding this comment.
Yes you are right, the app can do the check and take the decision. So before updating make sure whether the app should update or not. Sure I will document these in my next pr update.
62b28ca to
5efe9da
Compare
| } | ||
|
|
||
| /** | ||
| * get the attributes of user for apps |
There was a problem hiding this comment.
Document this method extensively, specially because the method uses an event and could take a while to get a response. The method isn't cheap to keep calling it over and over.
In addition, consider to include a cache here to speed up the next calls.
There was a problem hiding this comment.
I have added documenation for this method. Let me know if this looks ok
There was a problem hiding this comment.
I think most of the documentation, if not all, should be copied / moved to the interface. I expect people to check the interface first.
| * @param string $appName | ||
| * @return mixed | ||
| */ | ||
| public function getAttribute($appName) { |
There was a problem hiding this comment.
As far as I know, this isn't needed. Keep things as easy as possible. Adding more methods will increase the confusion.
We only need one method for the listeners to add new user attributes, and another one for the User class to get those new attributes, nothing more.
|
One additional thing: the event is "owned" or "controlled" by the The Noone cares which app added the "blogSite" key. |
8006e75 to
8a3ddc9
Compare
| } | ||
|
|
||
| /** | ||
| * get the attributes of user for apps |
There was a problem hiding this comment.
I think most of the documentation, if not all, should be copied / moved to the interface. I expect people to check the interface first.
9905cbb to
25b5a55
Compare
lib/private/App/AppManager.php
Outdated
| $userAppAttributes = $user->getExtendedAttributes(); | ||
| /** | ||
| * Guests will only have access to some whitelisted apps | ||
| * - If the list is missing (no "whitelistedAppsForGuests" key found), the guest will have access to all the apps as any normal user. The same will happen if the "whitelistedAppsForGuests" isn't an array. |
There was a problem hiding this comment.
adjust text here: if the "whitelistedAppsForGuests" isn't found, the user isn't considered a guest, so he'll have access to all enabled apps.
|
I think we'll need to protect some methods to be called from the apps. It could be risky to let the apps modify things, and calling again the "getExtendedAttributes" could trigger an infinite loop. The idea I have for this is to change all these "problematic" methods to check for a flag and throw an exception if the flag is set. This flag will be private, set as active before sending the event, and disable the flag after the sending the event. |
fb08245 to
c677130
Compare
|
Well passing user object can be dangerous in one way, the apps can change user attributes through the user object. So lets say if the user id is passed, which is also dangerous because the app can access the same user object via userManager. I did an experiment using @micbar @PVince81 @VicDeo Let me know your thoughts regarding the same as this input will help us to move ahead with the pr. |
fbf23af to
2dd0252
Compare
Codecov Report
@@ Coverage Diff @@
## master #36258 +/- ##
============================================
+ Coverage 65.00% 65.02% +0.02%
- Complexity 19772 19798 +26
============================================
Files 1271 1273 +2
Lines 74696 74745 +49
Branches 1309 1309
============================================
+ Hits 48554 48602 +48
- Misses 25756 25757 +1
Partials 386 386
Flags with carried forward coverage won't be shown. Click here to find out more.
Continue to review full report at Codecov.
|
dab996e to
e586d8b
Compare
e586d8b to
c119b28
Compare
lib/private/User/User.php
Outdated
| * user. | ||
| */ | ||
| $this->allowUserAccountUpdate = false; | ||
| $this->eventDispatcher->dispatch(UserExtendedAttributesEvent::USER_EXTENDED_ATTRIBUTES, $userExtendedAttributesEvent); |
There was a problem hiding this comment.
we need to handle exceptions triggered from inside the listeners, specially because the flag could remain active.
There was a problem hiding this comment.
I have updated the code to handle the exception thrown. Also I have updated the AppManager where getExtendedAttributes is called. I have added try/catch block. The catch block is kept empty. So that the code flow will happen as if its a regular user and not a guest user.
|
BTW, we'll need tests for the changes made in the |
769e1a1 to
04a3289
Compare
I have updated the tests for the exceptions thrown for the |
|
Some additional notes:
|
04a3289 to
1c6bdc8
Compare
|
Looks like it isn't possible to force the event to reach all the listeners. We'd need a custom eventDispatcher (which is out of scope at the moment). |
Get extended attributes for user from the apps. A new method which emits events to get the attributes for user, which is listened by apps to provide the attributes for the specific user. Use case for example: When apps are not whitelisted for guest user they should not be visible in the personal settings. Signed-off-by: Sujith H <sharidasan@owncloud.com>
1c6bdc8 to
517931f
Compare
| * using empty because userExtendedAttributes could either be null or empty array | ||
| * or an array of attributes | ||
| */ | ||
| if ($clearCache || !isset($this->userExtendedAttributes) || [] === $this->userExtendedAttributes) { |
There was a problem hiding this comment.
We don't need to retrigger the event if the userExtendedAttributes is an empty array.
You triggered the event, no one listened and you get an empty array. This is a valid result. There is no need to trigger the event again to get another empty array.
|
Hopefully last change. Please make sure the comments are updated and match the code behaviour. |
|
I don't feel comfortable with this approach, it seems it doesn't fully suit. Looking at the guests app we are setting an attribute "whitelistedAppsForGuests" which sounds like a generic setting, not something specific to a user. So having this in a user specific attribute feels wrong. Thinking further: if the user attribute is something that defines what is accessible for a user, then maybe it fits more into a "roles" concept or "permissions" concept, and in this case the attribute would need to be called "whitelistedApps", as it applies only for this one user. Maybe we should rather introduce the concept of "app access" into core in a more API-like way instead of just attributes. We already have the concept of "enabled apps for users" but here it's a softer one as the app needs to be loaded and its elements need to be discarded. In a broader view, an app should have a way to find out whether the current user is supposed to see its controls or not, so having an API for "app access" or "app permissions" might be more suitable. @DeepDiver1975 @micbar any thoughts on this ? does this fit somehow into the discussions related to roles concept ? |
|
The problem we've noticed at the last moment is that the all the apps are required to be loaded before calling the I think the idea is worth to keep because it has other uses such as properly expose the login name of the user, expose LDAP attributes for LDAP users, or other information for shibboleth or openIdConnect.
The original idea was to use 2 keys: the "isGuest" in order to identify guests users, and the "whitelistedApps" to include the list. "whitelistedAppsForGuests" was a simple way to merge both keys since the intention was to use that key for both identify a guest user and get the list of apps. In any case, I'm starting to think this approach won't work for guests. Guests are added in the DB backend and they aren't inside a "guests" backend part of the guests app. When the guests app is disabled, guests users will still be available, but we won't be able to identify them as a guest with this approach because the app will be disabled. |
|
didn't we have an event (hook) for the moment after which all apps have finished loading ? |
Searched the code base in core, and found this https://github.com/owncloud/core/blob/master/lib/private/legacy/app.php#L162 Other than this I couldn't find further references. |
|
@phil-davis @sharidas is there any progress? |
This PR got "left behind" a long time ago. I have no idea if anyone will (or should) take it over. |
|
@jvillafanez maybe you could take a look on to bring this forward... |
|
Looks good to me. Maybe @DeepDiver1975 can have a second look for the approach. |
Rebased in #40257 - we can review and comment there, and if needed and good it can easily be merged from there. |
|
PR #40257 is passing now. I had to just fixup some code-style and unit test things. So someone can comment there if this is wanted, and if the code is OK. |
|
This code has been merged in PR #40257 |
When apps are not whitelisted for guest user
they should not be visible in the personal settings.
Signed-off-by: Sujith H sharidasan@owncloud.com
Description
When apps are not enabled for guest users, they should not be listed in personal settings. In this change a new method is introduced in the user class
getExtendedAttributes(). The purpose of this method is to grab the attributes related to the user for the apps. So when this method is invoked an event is emitted which is listened by the apps, and populate the event array with the attributes in the form of key => value. So when logged in as guest user the guest app would populate the event array withisGuestandwhiteListedApps. Which could be used by core or any other apps. This feature is used SettingsManagersloadPanelto filter out the apps which are not whitelisted.Related Issue
Motivation and Context
Do not show the apps which are not whitelisted for the guest user.
How Has This Been Tested?
Screenshots (if appropriate):
Types of changes
Checklist: