I was trying to find it in docs or anywhere on the web but I did not find.
What I am asking about?
I am building website for multiple users. Frontend is not important, back backend API is being build in Loopback.
Every user will be assigned to some, let's name it GROUP.
Group content will be then exposed on subdomain but it is not important now.
Users will be kind of admins of their group.
I will have plenty of different models, but I will always have to protect user from accessing elements which not belongs to his group.
How should I do it? I think it will be some middleware but I do not know how to do it properly.
Of course, every user and every element have field "group_id".
I am also trying to find a good solution... I did find this npm package that looks worth a try: https://www.npmjs.com/package/loopback-component-access-groups
Here is a short description of what the package is used for:
"This loopback component enables you to add multi-tenant style access controls to a loopback application. It enables you to restrict access to model data based on a user's roles within a specific context."
I'm struggeling with the same problem, and I did not yet find a satisfatory response.
My workaround is explained in this question. I've got my user ID and with this, I retrieve the data I need to restrict the access. Then I alter the query in accordance with fetched data.
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.
I've got a Symfony application that has multiple subsites.
Each site has it's own set of users, but all users are stored in the same table. All users are linked to 1 subsite, never 2 or more.
Allowing a user to use a single account on multiple sites is not an option given the use-case of this website.
I've got a RequestSubscriber which figures out what site is currently being requested (based on hostname) and pushes some extra information into the Request object attributes.
When a user attempts to login Symfony should only attempt to load users from the current subsite, not all users.
I've got a Doctrine Repository class that implements the loadUserByUsername method, but this only receives the requested username.
What would be the best way to adjust my UserProvider so only users from the current site are attempted to be loaded?
Can I configure the security in such a way additional information is passed?
One possible solution I've already got is to inject the RequestStack into the Repository class, and use that to add additional parameters to my query.
I would need to write a decorator for the Doctrine EntityManager to make sure it is injected when the Repository is requested, but that is not really a problem.
I don't really like this solution, so I'm looking for better alternatives (if any).
We have a little discussion in my team how to handle http restriction in our app.
In our app a user can create products. So we have routes like /products and /product/1/show to list and show products of a user. A user can not see products of another user. The app uses a REST endpoint to fetch the data. The API call looks like this /api/product/1/ to fetch a single product.
We have more routes/API endpoint for other kinds of entities.
The question is how to protect a route/API request against other users?
We have two solutions:
use the firewall and voters. The voter gets the current url /product/1/show and checks if given product is owned by the current logged in user.
use a voter without the firewall: http://symfony.com/doc/current/cookbook/security/voters_data_permission.html
use the role system: http://jmsyst.com/bundles/JMSSecurityExtraBundle/master/annotations
I prefer solution 1. because all information we need (who is the owner of the product) still exist. We only need to fetch the entity and do a check.
In solution 2. we have to spread the voter logic over several controllers.
Are there recommendations or experiences on this problem?
If i have to choose between those three it would be 1. But i suggest a different route. I assume that the digit 1 in /product/1/show stands for the user number? If that is the case i suggest that you make new routes without the numbers e.g. /my-products/show . The controller must then use the id of the currently logged in user.
In my XPages application, web users can perform a self-registration. In the registration process, a user document for the web user is created in the address book and the user is added to a group that has Editor access for the database. After executing show nlcache reset on the Domino server, the user can login to and access the application.
In ~98% of all registrations this works perfectly fine. However, sometimes new users cannot enter the application after the login because, according to the Domino server, they "are not authorized to access" the database. The login must have worked because the user id is correct. The exact same user id can also be found in the Members field of the group that has Editor access to the database. To additionally verify the user's access level, I executed NotesDatabase.queryAccess() with the user's id. It returned 0, which is the ACL default and means "No Access". Yet, there are dozens of users in the same ACL group which have absolutely no problem with accessing the database.
At the moment, we "circumvent" this problem by manually removing the user's document from the address book as well as remove him/her from the Members of the ACL group. Afterwards we ask the user the re-do the self-registration with the exact same information as before. Up to now, this second registration has always worked and the user can access the application. Yet, this is not a real solution, which is why I have to ask if anyone knows what could be the problem?
Don't create entries in the address book directly. Use the adminp process for registration. To minimize perceived delay send a validation/confirmation message the user has to click.
Comment of 12/02/2015 seems to be the correct Answer:
Check if the self-registrated user has TWO consecutives spaces in his name, (could be because trailling space too)
In group domino do a FullTrim. So we have
John<space><space>Smith
that is not in group XXX because in the members it's:
John<space>Smith.
This may have something to do with the frequency at which the views index are refreshed in the names.nsf
Since the access control is done groups in the ACL, the server will "know" which user belongs to which group only after the views index have been updated.
In a normal setting, this can take a couple of minutes.
You can test this hypothesis by forcing an index refresh, either with CTRL-MAJ-F9 from your Notes client (warning, can take very long depending on network and number of entries in the names.nsf) or with the command
load updall -v names.nsf
... or by having the users wait a little while and try again 5min later.
Ok, first a question. If you let the user wait a couple of minutes will the access then work? I.e. is it a refresh/caching problem - or an inconsistency in the way you add the user to the group?
I assume that the format of the user name is correct as it works in most cases (i.e. fully hierarchical name)... Is there anything "special" about the names that do not work?
I do a similar thing (and has done several times) - although with some differences :-)
I typically use Directory Assistance to include my database with a "($Users)" view. When I update anything in this view I do a view.refresh() on the view (using Java). I typically do not use groups in these type of applications (either not applicable - or I use OU's or roles for specific users). I am not sure how the group membership is calculated - but I guess you could try to locate the relevant view (though none of them seemed obvious when I looked) - and do a refresh on it.
/John
I'm working on a hobbyist project in order to become more familiar with CouchDB. This is my first time working with CouchDB. For this project, my goal is to investigate whether or not it's possible to build a web application with nothing but HTML, CSS, JavaScript, CouchDB, and nginx (i.e., I'm not hosting any of my code in Couch, just data).
It could be that this is highly impractical, but I'd first like to explore all the options in this stack.
At the moment, my biggest questions are about security. Let's say that I have a few databases in CouchDB, each corresponding to a hosted site. For this example, we'll focus on a single database-- i.e., a single site. Some of the content from this site should be available to everyone, even anonymous users; and other stuff should only be available to users with a certain role. What are my options, and how secure are each of them?
I've come up with a few ideas so far, and this is the one I was planning to work on over the weekend:
Add users and roles to /{site_db}/_security.
According to the Couch documentation, doing so will require any request for data in {site_db} to be from an authenticated user.
Add a user called anon, which will only have one role, which is anon.
When the user first visits the site, my JS model will check the status of the current session (GET /_session).
If no session exists, the JS model will authenticate using the anon account.
Define views in my design document.
Any views that should only be available to non-anonymous users should check the roles on the userCtx object.
Validation of any newly-created documents should check userCtx to see if the user's role is on the whitelist.
This seems like it should work, although I can't help thinking it's overly complex, and that there must be a better way. Also, I'm not sure how to prevent the anon user from updating his own user document to add more roles.
If you don't like CouchDB security model, you can implement yours easily in your reverse proxy instead.
Here is an example with Apache but it seems to be very similar in nginx.