I have 2 parts to my question. If I have a Document library with 10K documents, and all documents set to inherit permissions from the library which itself has explicit ACL comprising 500 users (i.e. the library does not inherit security from the site), then:
Is the ACL replicated in SharePoint's database per document that is set to inherit security.
If I add another user on the list, would SharePoint in its underlying implementation need to add that user further to 10K document ACLs.
If the answer to 1) is NO, then the answers to 2) would perhaps be NO itself, still wanted to be sure and thus listed them out separately.
The reason this is important for us is:
We would have lots of users on a DL and lots of documents in the DL inheriting security. If the same is replicated per document, it means increased storage space would be needed.
The security would be updated frequently on the DL via SP api calls. If it needs replication per document, we would need to factor-in the time needed for the same while making api calls.
As per my own research, the ACL is not replicated for objects inheriting security in SharePoint.
ACL afaik is stored in Perms + RoleAssignment tables in SharePoint's content database. Perms contains an entry only for objects not inheriting security from parent (identified by ScopeId column) and RoleAssignment contains roles for ScopeIds in Perms table.
So effectively if an object is inheriting security, it won't have ACL entries defined in the database. I wrote a blog post with further insights into my research in the same context here:
https://imbibe.in/blog/2018/01/08/permission-storage-sharepoints-database/
Related
I'm currently reading a lot about access control possibilites/mechanisms that can be used to protect resources in an application or web application. There's ACL, RBAC, ABAC and many other concepts out there.
Assuming I have developed a simple webservice that returns knowledgebase articles on a route like '/api/article'. The 'controller' connects to the database and fetches all articles and returns them as XML or JSON.
Now I would like to have control over which article in the database is accessible for which user or group. So for instance if user 'peter' accesses the route '/api/article' with his credentials, the webservice shall return only articles that are visible for 'peter'.
I would want to use ACL to control what each user/group can read/write/delete. But what I don't quite understand:
Where does one enforce the access control? Do I just fetch all records in the controller if a user accesses the route '/api/articles' and check each single record against an access control list (that doesn't sound very good performance wise)? Or is there a way that the 'SELECT' statement to the database only return the records that can actually be seen by that specific user?
I really tried hard to find more information on that topic, and there is a lot about different access control mechanisms, but not about where and how the actual enforcement happens...and it even get's more complex if it comes to other actions like modification, deletion and so on...
This is really a matter of implementation and everyone does it its own way. It also depends on the nature of the data, particularly on the size of your authorization (do your have 5 roles and users are attached to them or does each user have a specific set of articles he can access, different for each user - for instance)
If you do not want to make the processing on the controller, you could store the authorization information in your database, in a table which links a user to a set of KB articles, or a role (which would then be reflected in the article). In that case your SELECT query would just pass the authenticated user ID. This requires that the maintenance of the relationship is done of the database, which may not be obvious.
Alternatively you can store the ACL on the controller and build a query from there - for specific articles or groups of articles.
Getting all the articles and checking them on the controller is not a good idea (as you mention), DBs have been designed also to avoid such issues.
How can I let only managers to acces a certain view, what do i need to write in the PostOpen of the view(lotusscript),
TY very much guys
AFAIK there is a "Security Tab" in the view design editor where you can specify who (person,roles) can use the view. No script necessary. The view will be hidden for persons that is not allow to access the view.
As you are not describing in your question, why you want to hide the view, here are a view general comments:
Hiding a view from a group of people does not limit access to certain documents to this group of people. Unless the documents are otherwise protected, users can create private views and folders that display the documents shown in the restricted view. If you do not want to grant them access to the documents, please use reader fields.
"Managers" in the ACL have the right to change the database ACL, ... In regards to read access to documents, there is no difference to "Reader"s, as long as you are not using Reader fields in documents.
If you meant "Managers" as a role, please follow Peter's and Knuth's advice but keep in mind once more that limiting access to a view does not limit access to the documents via another view.
For more details on access rights, ... please take a look at Access levels in the ACL, Roles in the ACL, Creating read access lists to limit view and folder access and The Domino security model.
I am using nodejs, and have been researching acl/authorization for the past week. I have found only a couple, but none seem to have all the features I require. The closest has been https://github.com/OptimalBits/node_acl, but I don't think it supports protecting resources by id (for example, if I wanted to allow user 12345 and only user 12345 to access user/12345/edit). Hence, I think I will have to make a custom acl solution for myself.
My question regarding this is, what are some pros and cons to storing roles (user, admin, moderator, etc.) under each user object, as opposed to creating another collection/table that maps each user with their authorization rules? node_acl uses a separate collection, whereas most of the other ones depend on the roles array in user objects.
By the way, I am using Mongodb at the moment. However I have not researched the pros and cons yet of using relational vs. nonrelational databases for authentication yet, so if let me know if your answer depends on that.
As I was typing this up, I thought of one thing. If I store roles in a separate collection, it is more portable. I would be able to swap out the acl system much more easily. (I think?)
The question here seems like it could be abstracted from "where should I store my roles" to "how should I store related information in Mongo (or NoSQL in general)". It's a relation vs non-relational modeling issue.
Non-Relational
Using Node + Mongo, storing the roles on the user will make it really easy to determine if a user has access to the feature, given that you can just look in the 'roles' property. The trade off is that you have lots of duplicate information ('user_read' could be a role on every user account) and if you end up changing that property, you'll need to update it inside every user object.
You could store the roles in their own collection and then store the id for that entry in the Roles collection on your User model, but then you'll still need to fetch the actual record from the collection to display any of it's information (though arguably this could be a rare occurrence)
Relational
Storing these in a relational DB would be a more "traditional" approach in that you can establish the relationships between the tables (via FKs / join tables or what not). This can be a good solution, but then you no longer have the benefits of using a NoSQL database.
Summary
If the rest of your app is stored in Mongo and has to stay there (for performance or whatever constraint) then you are probably better off doing it all in Mongo. Most of the advice I've come across says don't mix & match data stores, e.g. use one or the other, but not both. That being said, I've done projects with both and it can get messy but sometimes the pros outweigh the cons.
I like #DavidWelch answer, but I'd like to tackle the question from another perspective because the library mentioned gives the option to use a different data store entirely.
Storing roles in a separate data store:
(Pro) Can make the system more performant if you are using a faster data store. (More advantageous in distributed environments?)
(Con) You will have to ensure consistency between the two data stores.
General notes:
You can add roles/permissions such as 'blog\123' in acl. You can also give a user permissions based on verbs such as put, delete, get, etc..
I think it is easier to create a pluggable solution that does not depend on your storage implementation. Perhaps that is why acl does not store roles in the same collections you have.
If you choose to keep the roles in your own collection, consider adding them to a token (JWT). That way, you will not have to check your collection for every request that needs authorization.
I hope that helped.
I am trying to understand how the read side of CQRS can work with a large document management application (videos/pdf files/ etc) that we are writing.
We want to show a list of all documents which the user has edit permission on (i.e. show all the documents the user can edit).There could be 10,000s of documents that a particular user could edit.
In general I have read that the a single "table" (flat structure) should suffice for most screens and with permissions you could have a table per role.
How would I design my read model to allow me to quickly get the documents that I can edit for a specific user?
Currently I can see a table holding holding my documents, another holding the users and another table that links the "editing" role between the user and the documents. So I am doing joins to get the data for this screen.
Also, there could be roles for deleting, viewing etc.
Is this the correct way in this case?
JD
You can provide a flat table that has a user id along with the respective denormalized document information.
SELECT * FROM documents_editable_by_user WHERE UserId = #UserId
SELECT * FROM documents_deletable_by_user WHERE UserId = #UserId
SELECT * FROM documents_visible_for_user WHERE UserId = #UserId
But you could even dynamically create a table/list per user in your read model store. This becomes quite easy once you switch from a SQL-based read store to NoSQL (if you haven't already.)
Especially when there are tens of thousands of documents visible for or editable by a user, flattened tables can give a real performance boost compared to joins.
When I had a read model that took the form of a filtering-search-form (pun not intended), I used rhino-security as the foundation of an authorization service.
I configured the system so that the authorization service's tables got pushed through SQL Server's pub-sub system and SQL Server Agent, to the clients that were partially displaying the denormalized data - I then let Rhino.Security join the authorization model together into the read model, on a per-user basis.
Because I essentially never wrote to the read model's authorization tables from the read model, we got a nice encapsulation on the authorization service's database and logic, because authorization was only changed through that service, and it was globally unique and specific (consistent) to that service. This meant that our custom GUIs for handling advanced (hierarchial entities, user groups, users, permissions, per-entity-permissions) authorization requirements could still do CRUD against this authorization model and that would be pushed in soft real time to any read model.
I have some user-specific data that I need to store in SharePoint and make accessible to the user through custom webparts. Let's say a list of favorite URLs. What would be the most straightforward way to store this information?
Some builtin propertybag for SPUser or similar that I'm not aware of.
SPList, associated through User column.
Custom database table, associated through SPUser ID.
Otherwise?
Sounds like a RTFM to me, but I'm probably asking google the wrong questions.
[Update]
We eventually stored this information in a simple list, in a fixed location, with a Person field to filter on. Perhaps the simplest solution indeed, but technically I think the marked answer below is nicer.
If you want to make them reusable across the site collection for each user you can add Fields to the User Information List. You can add a feature receiver to your web parts solution that can create this column or check to see if this column exists in the User information list to be sure that the Column exists.
The User Information list is a Standard SharePoint list that SharePoint uses to store user information.
To access the User Information List you can go to the Root web of the Site Collection and use the SiteUserInfoList property
E.G.
SPList userInformationlist = SPContext.Current.Site.RootWeb.SiteUserInfoList;
//Or
SPWeb web = SPContext.Current.Site.RootWeb;
SPList userInformationlist = web.SiteUserInfoList;
To access a users List Item you can use the Users Id to get the ListItem back from the User Information List
E.G.
SPListItem currentUserItem = userInformationlist.GetItemById(web.CurrentUser.ID);
If you are using MOSS you can store this information in the User Profiles and make it available across Site Collections this does not need My Sites to be enabled. You would need to use the User Profile classes to access this.
I would go for the properties on the user profiles. You do not want to store the information on the root web as it is not information regarding the root web.
Your example with the favorite urls, each user has a "quick links" collection on their profile. An ideal place for storing urls for each user. :)
Build a webpart that reads/writes a custom database and you'll have the flexibility to use the webpart across SiteCollections, WebApps, or even seperate Farms.
This was implemented where I work and it has been a big success. We needed a way to provide our end users a large selection of important, commonly used links. End users have the ability to display the links that are useful for their particular job function and have a webpart that can be put anywhere to reference those links that are important to them. You also have the ability for an “admin” to go to the custom database and update any URL’s that might change without the end user ever being impacted or ending up with a broken link.
This is a very good question.
Although I have no perfect answer, here are some things you can consider:
Store data in a browser cookie if this is feasible.
Store in the Site collection's rootweb in the Properties, keyed by the user's login ID. You may want to elevate when reading / writing the properties just in case the user has access to a subweb, but not the rootweb.