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

Ignore user start nodes option in pickers #2441

Merged
merged 41 commits into from
Mar 23, 2019

Conversation

dnwhte
Copy link
Contributor

@dnwhte dnwhte commented Feb 9, 2018

This addresses the feature request at http://issues.umbraco.org/issue/U4-10147.

2018-02-09_13-24-12

List of pickers supported:
2018-02-09_13-25-48

Content Picker List View currently has an issue. Umbraco's user permissions do not work on the content picker list view ATM. http://issues.umbraco.org/issue/U4-10876

Update:
Issue preventing content picker list view from working is https://issues.umbraco.org/issue/U4-11488.

Dan White and others added 28 commits January 26, 2018 17:07
Results in a very basic working POC for the content picker
Has to refactor how the prevalue was added to the RTE config
so the grid could have a separate config.
This way we don't have to unknowingly add the canceler to the media request
@emmaburstow
Copy link
Contributor

Hi @danwhite85

Thanks for this PR! I've already started testing and am really pleased with what it does. I'll have a play this evening and let you know if there's anything I need from you at all. It's a really useful change.

Emma, Community Pull Request team

Copy link
Contributor

@emmaburstow emmaburstow left a comment

Choose a reason for hiding this comment

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

I've tested this with each of the pickers you have put in the chart - it all works nicely! I've had a good look through the code too and I'm happy with it for my part.

I really like this feature. Excellent work!

Emma

@nul800sebastiaan
Copy link
Member

Verbiage changed and I've redone all the testing, I think it all works as expected now. Which means...

PARTY! 🎉 🍰 🍻 🍾

Merged and ready to go in 7.15. 👍 🏅

Now I will have to do a v8 merge, that's going to be fun. 😉

Thanks so much @dnwhte for your patience and for the great job!

@dnwhte
Copy link
Contributor Author

dnwhte commented Mar 25, 2019

Woohoo! This is awesome. Thanks a lot for your time and work, @nul800sebastiaan!

@nul800sebastiaan
Copy link
Member

This has now also been merged up to v8 🥵🥵😅

@emmaburstow
Copy link
Contributor

Yay! Really chuffed about this one 👍

Copy link
Contributor

@Shazwazza Shazwazza left a comment

Choose a reason for hiding this comment

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

I have added notes to the code. I'm not quite comfortable with some of these changes since it exposes the ability for users to request data they don't have access to outside of pickers or regardless of if pickers are configured for this behaviour. Perhaps it's not such a big deal that people get access to some of this data, but we don't know what type of data people have in their sites so i think it's naive to assume that it's ok to expose this as easily as passing in a query string?
thoughts?

@@ -77,7 +79,12 @@ public override void OnActionExecuted(HttpActionExecutedContext actionExecutedCo

protected virtual void FilterItems(IUser user, IList items)
{
FilterBasedOnStartNode(items, user);
bool.TryParse(HttpContext.Current.Request.QueryString.Get(TreeQueryStringParameters.IgnoreUserStartNodes), out var ignoreUserStartNodes);
Copy link
Contributor

Choose a reason for hiding this comment

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

HttpContext.Current should not be used here, you can get query string values from the action's HttpActionExecutedContext

Copy link
Contributor

Choose a reason for hiding this comment

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

Adding this logic here means that any action or controller that uses this filter will have the filter bypassed simply if a user adds this query string, this will have unintended side affects since you don't know where this filter might be used. I think we need to reconsider how this is put together.

@@ -264,11 +264,12 @@ protected int[] UserStartNodes
string orderBy = "SortOrder",
Direction orderDirection = Direction.Ascending,
bool orderBySystemField = true,
string filter = "")
string filter = "",
bool ignoreUserStartNodes = false)
Copy link
Contributor

Choose a reason for hiding this comment

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

All of the changes to these controllers that now have a ignoreUserStartNodes parameter means that anyone logged into the back office can just make a request to these controllers and set this to true which will give them the data that they might not have access to.

So now, even if a site doesn't have any data type with this feature enabled now exposes the possibility for users to request data they don't have access to, or shouldn't have access to.

@@ -190,7 +190,7 @@ private int GetTopNodeId(IUmbracoEntity entity)

protected abstract UmbracoObjectTypes UmbracoObjectType { get; }

protected IEnumerable<IUmbracoEntity> GetChildEntities(string id)
protected IEnumerable<IUmbracoEntity> GetChildEntities(string id, FormDataCollection queryStrings)
Copy link
Contributor

Choose a reason for hiding this comment

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

Changing protected members is an API breaking change, there might be a few of these in this PR that we might need to consider and/or add the breaking change tag for.

Copy link
Member

Choose a reason for hiding this comment

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

Ah shoot, I fixed all the public methods but didn't notice the protected ones. Will have a look.

@dnwhte
Copy link
Contributor Author

dnwhte commented Jun 13, 2019

@Shazwazza just for reference. In Jan 2018 we vaguely discussed some of these things (querystrings, and providing on context to FilterAllowedOutgoingMediaAttribute) (https://issues.umbraco.org/issue/U4-10147#comment=67-43737).

I agree with your concerns. Given your response in 2018, I'm not sure how to go about it without a querystring. It may not be much better, but what if instead of passing "ignoreUserStartNodes" as a querystring we pass the picker id and check the picker's settings in the handler?

Thanks for the feedback.

@Shazwazza
Copy link
Contributor

Hi @dnwhte,

There's a bunch of code in this PR so I'm unsure how exactly it all is glue'd together but the main things that we cannot do is : bypass security on ContentController or MediaController. I'm unsure why these controllers are being requested for pickers, perhaps it's an issue with Umbraco in general, for example i can see in the code that mediaResource is being called for the mediaPicker controller by why? I mean surely we can get the children from the entityResource (this would also improve performance). Similarly contentResource is being called by linkPicker controller, but again why? This should also be using entityResource. ... if neither of these is 'possible' then we should re-think how we can make this possible.

Pickers should in theory only use EntityController. In this case the risk of exposing data that the user doesn't have access to is more minimal since an Entity doesn't contain much information ... well that's actually not entirely true in v7. In v7 and 8.0.x, The EntityController for media will return all media properties too which we cannot do. In 8.1 this will be fixed.

In my opinion, to implement this while maintaining reasonable security we would need to:

Trees

Don't use a query string like ignoreUserStartNodes and instead for pickers that are using the tree's, yes, please pass in the data type ID, then check if the tree is currently in dialog mode, then check if a data type id has been passed in, then lookup that data type, check if it is a type that has config like ignoreUserStartNodes, then check if that is allowed and proceed as necessary

Entity data

Unfortunately this isn't going to be the most straightforward thing to do due to how the EntityController and EntityService work pre 8.1 since it returns more data than we should be allowed to return if bypassing security. So a decision will need to be made - do we postpone this feature for 8.1+ or do we proceed with the below requirements?

First we need to ensure that security cannot be bypassed at all on MediaController/ContentController. Then we need to make sure that mediaResource and contentResource are not used for anything with that changes required for this feature - such as linkPicker and mediaPicker and instead determine if entityResource can be used instead and if not then document why so we can figure out how to make that work.

If we are going to proceed with this feature in a 7.x version, then various things will need to be done:

  • We will need to back port the EntityService changes done in 8.1 so that simple media can be looked up with it's media path (v8 EntityService changes #3498, V8/bugfix/3498 entity service updates #5658)
  • We will need to add another method to the EntityController like GetMediaChildren which will use the new EntityService method ensuring that the bare minimum media data is returned and in turn update the entityResource and mediaPicker to use this endpoint. This endpoint will work like the trees (see above) where you can request children on behalf of a picker by optionally passing in the picker Id and doing the checks like in trees

Result

The end result of this is that an authenticated user could still request data that they don't have access to given that they know a valid Data Type picker Id that has this option configured by making requests either to the content/media tree or to the entityResource.getById or the new entityResource.getMediaChildren (if we proceed with a 7.x version, else if we only target 8.1 then entityResource.getChildren will work). However the data returned will be a minimal subset of data for these entities which don't expose any property values. This also means that unless a Data Type is configured to bypass security there is no way that a user can simply request security to be bypassed.

@dnwhte
Copy link
Contributor Author

dnwhte commented Jun 17, 2019

Hi @Shazwazza -

I'm currently working on a v7 project for which this feature is required, so I'm willing to help however I can.

From what I can tell, the mediaPicker and linkPicker use the content/media resources in order to get extra properties that are not available with the entityResource. Media picker needs images and link picker needs the url and the properties array to pass to the tinymce service.

I'm not too familiar with the v8 codebase, but giving it a quick scan I'm assuming the general approach to do this would be to use entityResource and then supplement the data with mediaHelper and contentEditingHelper. Is this correct?

It looks like the media picker could go without the media resource by using mediaHelper.resolveFileFromEntity as seen here.

In order to not use the contentResource in linkPicker more data would probably need to be added to metaData in the entityResource response or additional helpers in contentEditingHelper. The linkPicker in v8 still uses the contentResource.

How would you like to proceed? I could start refactoring the ignoreUserStartNodes querystring to use the data type id instead.

Thanks again for your time.

nul800sebastiaan added a commit that referenced this pull request Jun 18, 2019
This reverts commit cc9a7ff.

# Conflicts:
#	src/Umbraco.Web/Editors/ContentController.cs
#	src/Umbraco.Web/Editors/EntityController.cs
#	src/Umbraco.Web/Search/UmbracoTreeSearcher.cs
bergmania added a commit that referenced this pull request Jun 20, 2019
@nul800sebastiaan nul800sebastiaan changed the title U4 10147 - Bypass User Security option in pickers Ignore user start nodes option in pickers Jul 3, 2019
@nul800sebastiaan
Copy link
Member

Tagged as breaking since in in change 966b07b IUmbracoEntity GetByKey(Guid key, bool loadBaseType = true); has been changed to IUmbracoEntity GetByKey(Guid key);.

@PeteDuncanson
Copy link
Contributor

@nul800sebastiaan I'm a little confused by the last few comments on this one. Have @Shazwazza concerns about security be addressed/implemented or are they shipped as it in the latest v7.15 and v8.1 releases? What state is this now in?

@Shazwazza
Copy link
Contributor

@PeteDuncanson yes the concerns were addressed and much had to be refactored. Many pickers had to be adjusted to use entityResource (which is what they should have been using anyways) and you cannot request data that you don't have access to unless you have a data type configured to allow that scenario, the data returned is minimal (i.e. entityResource results)

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.

6 participants