I am currently working on my first headless system.
The API is written in PHP.
It basically consists of three parts:
endpoints
functions
output
Each request to an endpoint is passed to a function which passes the database response to the output.
In order to keep the number of functions manageable, I have made them relatively general.
For example, the lists of customers and employees are created by the same function and the corresponding table is passed via a parameter in the URL.
Now I want to create a rights management system in which the users have different roles and access is thus restricted.
I have thought of three possibilities for this:
Everything only in the frontend
Not a good idea, as it is easily hackable.
Integrate the entire restriction into the output function.
That's safe, but all records are queried first and then the ones that are not allowed are sorted.
Make the database queries "even" more dynamic.
So each query to the database only asks for the rows that the respective role is allowed to see or change.
This is very time-consuming and the idea of creating general functions is actually obsolete, because they then become very complex.
Is the last, the usual way?
Are there other concepts?
Related
I have a Web-App that control selling and buying of merchandise as well as stock and prices...
it is built with AngularJs, PHP and MySQL(PDO).
My Model has many General perpose query functions such as:
getShops()
getShopInfo(shopId)
GetItems(shopId)
GetSuppliers()
and many more...
now, i develop a Dashboard Page, to show statistics and Top-Level vision on things, containing f.e:
Number of active items
Number of Sold items + total sum
Current Debt to suppliers
and many more aggregations on the data.
My question is what option of the two:
Should i use many basic queries in my model, and aggregate the data Client-Side...
will this be bit more maintainable?
OR
Should i create a Specific Query to get exactly what data this dashboard needs.
probably performance will be better.
You should without a doubt create a specific query to get exactly what data your dashboard needs. In fact, you should create a view for it so that the actual select statement is plain simple. It has several advantages:
Aggregation is what databases are good at: indexes are used (if you design it well), and results are cached for all clients to benefit from, resulting in a performance that can hardly be beaten;
The SQL language is quite suitable for formulating aggregations, certainly when you compare it to client-side JavaScript;
It will help you in debugging. Without running the web app, you can run the select directly on your database to verify the result, and so better isolate any problems;
If you create a database view, you can even decide to one day change the internal definition of the view without having to touch your Web App code;
The volume of data transfered between server and client is kept minimal: only the needed data is transferred. This can be important for users connecting over mobile networks.
I am currently working with a medium-sized team developing a custom content management system for a large client. The CMS is written using PHP and follows the MVC pattern (custom). It is a modular system, for which plugins can be added to the system by us or other developers at a later stage.
The system will contain user-based permissions, and a series of generic roles that have predefined permissions. It is required that a super-admin user can also modify permissions on a user basis (for example John Doe might be defined as a regular user, but has the possibility of modifying content).
Opinion is currently divided about the best way for us to store and handle these permissions. Half of the dev team are suggesting to add a new DB table that will store key/value pairs and user IDs for each user, with boolean values stored in each record. The table structure would be something like this:
user_ID: the ID of the user
perm_name: the name of the permission
perm_value: a boolean value dictating whether the user can carry out this action
The proposal is that if the value associated with a particular permission is set to 0, or does not exist in the table, the user does not have the required permission.
The other half of the dev team is favouring storing the permissions in a single field as a JSON-encoded string within the users table. So for example, we would store the following JSON for John Doe):
{
'modifyProducts': 1,
'addProducts': 1,
'addPages': 0
}
We would then be able to use json_decode() within the User class to extract the permissions, for example:
$this->permissions = json_decode($dbval);
I am personally leaning towards the latter option for two main reasons:
It is scalable
It does not require us to modify the database if we need a new permissions.
In short, what is the best approach for such an application?
I think the best solution in this case would be to use NoSQL database, such as MongoDB - this way you can still keep the scalability and take advantage of the JSON structure.
On the other hand, depending on your user table you could take possible advantage of column type indexing and optimize your requests for querying and reading, if of course you're working with normalized database.
I personally would store JSON within a relational DB only when I want to directly display the info and not use it for any querying. Just like you've said yourself - there's always the possibility of ending up with huge and growing JSON string and this would most probably cause troubles at some point.
Assuming I have a valid session and an authenticated user, what are some ways to go about implementing user authorization in an application with a PHP/MySQL backend, and a heavy JavaScript front-end?
Most of the implementation examples I can find seem too focused on user authentication and the authorization just sort of happens. For instance, an if statement checking if the type of user an admin. This seems way too implemented to me.
In an implementation like mine, there is no way of knowing what "page" the user was on when they initiated the request. So, a method of only serving certain content for certain users, determined by PHP, is too broad for what I need to do.
Ideally each entity has a sort of access control list based either on the user explicitly or what group or type the user is/in.
I went to a local bookstore and spent an afternoon looking through all they had on PHP, MySQL and JavaScript. Surprisingly, most of the books had virtually nothing on user authorization. That scares the hell out of me! This has to be solved by anyone building a large web application that uses AJAX, I just can't seem to find something to get me started.
I would appreciate any and all feedback, experiences, tips, etc. (Any books on this subject?)
PHP security seems stuck in the dark ages of single password gives a token for a single user for a class of particular pages. You seem to be wanting to get a lot more fine-grained in your app, maybe even allowing access to specific pieces of resources depending on that login token. Your thought of access control lists is absolutely correct, and yes, you've discovered the dark secret: no one really published how to design or write an ACL mechanism. That said, it has been done.
First, are you familiar with unix file permissions? The're the -rwxr-xr-x things you see in an ls -l on the command line. Unix has chosen a very simplified approach to ACLs. Each person logged in has a User ID (UID) and one or more Group IDs (GID) (whoami, groups). The Unix file permissions allow three operations, Read, Write, and Execute which can be on or off. With 2^^9 states, these permissions easily fit in an integer, and Unix can then attach that
integer to the file directly in the file system. When a user attempts to access a file, permissions are compared from strict to permissive, matching the most permissive privileges allowed. So, users get the first set of permissions, groups get the second, and anyone gets the third. Thus, an executable is usually 755: only the owner can change it, but anyone can read and use it.
Second, LDAP is the Lightweight Directory Access Protocol, a system designed to give multiple network users access to resources. OpenLDAP is a common Linux implementation, and Microsoft's Active Directory on Windows Server speaks LDAP (with a lot of extensions). LDAP has a much more robust system of ACLs. A general configuration is access to [resources] by [who] [type of access granted] [control] or access to dn="uid=matt,ou=Users,dc=example,dc=com" by * none to limit all access to to Matt's user information. For a much more complete discussion, I would highly recommend Mastering LDAP, specifically chapter 4 on security. (This is where I get a bit out of my direct knowledge.) I am under the impression that LDAP stores this information in a separate database table, but I don't know that and can't find documentation one way or another. I am keeping an eye out for a possible schema for that.
Short stop to summarize: ACLs take a concept of a user token with possible groups above the user level, a collection of objects to secure in some way, and several consistent possible operations on those pieces- 3 dimensions of information. Unix stores two of those dimensions with the thing to be secured directly. OpenLDAP stores those three dimensions separately, in some way we don't quite know, but that I suspect is a linked tree structure.
Given that, let's take a look at how we could design an ACL system for a RESTful web application. For assumptions, we will break your application into discrete addressable units- each thing that needs to be secured will be accessible via a URI (http://example.com/users, http://example.com/page_pieces/ticker). Our users will be a simple UID/GIDs token- a user can be part of a several groups. Finally, our available operations will be based on the HTTP requests- GET, POST, PUT, DELETE, etc. We now need a system that efficiently handles a 3-dimensional array of data. Our schema should be pretty obvious: (uri, userid, groupid, operations). We deliberately denormalize the operations column into a string list of GET,POST,... so we only need one table. There is no primary key, since we will never really be looking up by ID.
Queries will be done in two steps: SELECT * FROM acl WHERE uri=#uri, userid=#userid which will return 0 or 1 rows. If it returns 1 row, we're done and can grep permisssion to see if the operation is in the list (use * to indicate all perms). If we got 0 rows, run a second query SELECT * FROM acl WHERE uri=#uri, userid='*', groupid in (#groupid) which will again return 0 or some rows. If it returns some, loop through and look at perms. If it returns 0, do one last query SELECT * FROM acl WHERE uri=#uri, userid='*', groupid='*' which will finally return 0 or 1 row. If it returns 1, look at perms. If it returns 0, take the default action.
We can set permissions in several ways:
INSERT INTO acl VALUES (#uri, #userid, '', 'GET,POST') allows a single user GET or POST access
INSERT INTO acl VALUES (#uri, '*', 'admin,contributors', 'GET,PUT,POST,DELETE')
INSERT INTO acl VALUES (#uri, '*', '*', '') denies all access.
A couple things to note:
All URIs must be expressed exactly; this solution has no way to set
default permissions at a higher level and have them trickle down
(left as exercise to the Questioner).
Uniqueness of uri/uid/gid pairs should happen at some point. The app can handle it, or in MySQL you can do ALTER TABLE acl ADD UNIQUE INDEX (uri, userid, groupid) (look up documentation for similar constraints in other DBMSes).
It seems that you are looking for something called Access Control List aka ACL (which is dead according to Zed Shaw, great video).
It's pretty hard to give a you a solution without knowing what kind of backend you have, but you might check out how other are doing that.
For something specific to the lithium framework (PHP), see: Lithium Access Control
This is what I understand:
You need to build an access control list for your users? do you?
[correct me if I'm wrong]
I suggest you to create a DB table in which you can store the User ID (or username) and what kind of access it has on your Web Application. Then you can check the table to know if the requested URL/resource is accessible to that user. That's all.
I've been working on a web application for a company that assists them with quoting, managing inventory, and running jobs. We believe the app will be useful to other companies in the industry, but there's no way I want to roll out separate instances of the app, so we're making it multi-user (or multi-company might be a better term, as each company has multiple users).
It's built in Codeigniter (wish I had've done it in Rails, too late now though), and I've tried to follow the skinny-controller fat-model approach. I just want to make sure I do the authorisation side of things properly. When a user logs in I'd store the companyID along with the userID in the session. I'm thinking that every table that the user interfaces with should have an additional companyID field (tables accessed indirectly via relationships probably wouldn't need to store the companyID too, tell me if I'm wrong though). Retrieving data seems pretty straight forward, just have an additional where clause in AR to add the company ID to the select, eg $this->db->where('companyID', $companyID). I'm ok with this.
However, what I'd like to know is how to ensure users can only modify data within their own company (in case they send say, a delete request to a random quoteID, using firebug or a similar tool). One way I thought of is to add the same where clause above to every update and delete method in the models as well. This would technically work, but I just wanted to know whether it's the correct way to go about doing it, or if anyone had any other ideas.
Another option would be to check to see if the user's company owned the record prior to modification, but that seems like a double-up on database requests, and I don't really know if there's any benefit to doing it this way.
I'm surprised I couldn't find an answer to this question, I must be searching for the wrong terms :p. But I would appreciate any answers on this topic.
Thanks in advance,
Christian
I'd say you're going about this the correct way. Keeping all of the items in the same tables will allow you to run global statistics as well as localized statistics - so I think this is the better way to go.
I would also say that it would be best to add the where clause you mention to each query (whether it's a get, update, delete. However, I'm not sure you'd want to manually go in and do that for all of your queries. I would suggest you overwrite those methods in your models to add the relevant where clauses. That way, when you call $this->model->get(), you will automatically get the where->($companyID, $userID) clause added to the query.
From the looks of things it looks like this might be a more API type system (as otherwise this is simply a normal user authentication system).
Simple Authentication
Anyway, the best bet I can see for an API is to have two tables, companies and users
in the companies table have an companyID, and password. in the users table link each user to a company.
Then when a user makes a request have them send through the companyID and password with every request.
oauth
The next option, slightly harder to implement, and means that the other end must also setup Oauth authentication is oauth.
But, in my opinion is much nicer overall to use and is a bit more secure.
One way to do it would be with table prefixes. However, if you have a lot of tables already, duplicating them will obviously grow the size of the db rapidly. If you don't have many tables, this should scale. You can set the prefix based on user credentials. See the prefixes section of this page: http://codeigniter.com/user_guide/database/queries.html for more on working with them.
Another option is to not roll out separate instances of the application, but use separate databases. Here is a post on CI forum discussing multiple db's: http://codeigniter.com/forums/viewthread/145901/ Here again you can select the proper db based on user credentials.
The only other option I see is the one you proposed where you add an identifier to the data designating ownership. This should work, but seems kinda scary.
Can anyone recommend a source of information or working example showing how to deal with access permissions when dealing simultaneously with admin system users and website users?
Our code at the moment is kind of like a big version of an online shop, with several members of staff administrating the orders using the admin system, and any number of customers using the website. The admin system is built around an access control list (like LiveUser) but there is a fairly big 'band-aid' holding that together with one 'dummy' user holding the role of all website users (all customers).
Ideally the application code will use phrases like can_place_order() to determine if the user can perform a task. A customer can place an order as long as the stock levels are at least as much as the order quantity and they have made a payment to the value of the order. An admin user can place an order as long as they have the 'customer_services' role.
Ideally, we'd like to extend the system so that we can have certain registered customers place an order without having sufficient stock or paying, simply having an invoice and backorder generated instead. That would be at least two customer 'roles' in addition to the many staff 'roles'...
How can I use the same permissions system with two separate lists of users?
Or, how can I combine the apparent two sets of users into one list?
We're using php & MySQL for the application, but any other language patterns are welcome.
I've tried a lot of different schemes for permissions and I've only ever found one way to make them work that satisfies the programmer AND the clients in nearly all cases. And this is to make them partially data driven.
My most-recent attempt works like this:
Each user has attached to it a permissions object. In my case created automatically when a user is requested. (In my case, permissions can be different for different sections. So a user might be allowed to do X for Y but not for Z.)
Each page, code block, or view that needs to be permissive is wrapped with an if statement that checks the permission object. If that permission needs to worry about the section too, the current relevant section ids are passed in as an array, returning a new array of bools to match.
The interface then does not expose this complicated mess to the users directly, instead a superadmin interface lets new user types be created. These types carry sets of permissions that will be enabled for that 'type' of user. There can be overlap in the permissions of different types, so both the Admin and the Editor might be able to "Edit Copy" or whatever.
The normal admin interface lets individual users be set as different user types for different sections. So one user may be an Admin for section 2, and an Editor for sections 2, 3, 4, and 5. They can also be set globally which overloads an unused section (0).
This has many benefits and one drawback. First, the drawback. Because these keys are baked directly into the code, only a superadmin (aka a developer) should have access to that part of the interface. Indeed, an interface may not be needed at all, as the list of permissions should only change with the code. The real problem here is that you won't know anything is wrong with a title until your run the code, as the syntax will be just fine. Now, if this was coded in something like C#, this would be a very serious issue. But just about everything in PHP is not type safe, so it is really just par for the course. These values could also be loaded from a config file, or even baked into the GUI that you build user types from, although that seems wrong.
What you gain from this is the ability to setup new permission types on the fly. You gain the ability to rename those permissions with relative ease. (As the system just uses the number, the title is only used to capture the number so can be changed easily in just a few places.) And the code is very simple to use. It would look something like this:
if($current_user->permissions->can("View Sales Records"))
{
//Code to view sales records
}
Or slightly more complicated
$sections = array(1,2,3,4); //Probably really a list of all sections in the system
$section_permissions = $current_user->permissions->these($sections)->can("Edit Section");
foreach($sections as $s)
{
if($section_permissions[$s])
{
// Code for maybe displaying a list of sections to edit or something
}
}
The method chaining is pretty simple too. ->these() sets an internal array to those values and then returns a reference to the object itself. ->can() then acts on that list if it exists, and then unsets it. In my own version I also have ->any() which always returns a complete list of sections, so I can check ->any()->can().
Finally, the permission object also contains a list of what types a user is. Which makes it really easy to show a list of users and what permissions they have active. In my case we just use ->types() to access that list an an array of ids => names.
Non-present permission titles are simply ignored. They are also matched in lowercase and with spaces and special characters removed to help decrease problems with typing errors. I've considered even doing a levenshtein distance check and picking the closest match. But in the end it is probably better not to rely on something like that. (maybe log the error, but gracefully select the nearest match.)
Outside of the code and in the interface, the users only need to relate to each other in a So-in-so is an Admin, Editor, Publisher, Writer, and CEO, so on so on. It would also be trivial to create different sets of user types for different organizations.
All parts of this can be heavily cached, setting up a basic user for people who aren't logged in at all is very easy, and I've yet to run into a permission-based issue that isn't obvious to solve using this structure.
I only wish I could share the actual code with you. I just don't own it myself and therefore can't post it.