I have a clientside rendered frontend with a REST API. The frontend should render some elements based on the user authorization. Example permissions could be
delete users
being able to delete supervisors too
create users
add users to workflows
...
A huge amount of permissions is managed by an administrator. My question is:
How would you get to know what permissions you have for this rendered page and what to render?
The only idea that comes to my mind would be to create an API endpoint /user/:id/permissions and ask for every permission the user has. An example response object could be
[
{
"permissionId": 0,
"description": "Has access to page"
},
{
"permissionId": 1,
"description": "Can create users"
},
{
"permissionId": 2,
"description": "Can delete users"
}
// ...
]
Then I could start rendering my HTML based on these permissions (Pseudo code / I normally use VueJs)
<button render-if="permissions.contains(1)">This shows up if the user can create users</button>
<button render-if="permissions.contains(2)">This shows up if the user can delete other users</button>
I think the frontend code might get a bit messy. The API endpoint should be fine but maybe there is a better solution. Does a best practise solution already exist?
Your approach (having a separate permissions endpoint) is a good way to handle this.
Another alternative is to use a hypermedia format like HAL or Siren. Whenever you access any resource, that resource will include a list of links with information about what the user might want to do next. If a link doesn't appear in a response, the implication is that the user can't perform that action (due to permission issues or otherwise).
Related
I´m currently developing an application based on user authentication where each user can register a student-campus as a teacher and currently, I'm on a feature where I have two routes:
Route 1: It has a Datagrid where I'm listing all of the student campuses that I've already created and each row has an edit button that navigates to "Route 2" and the purpose of that is to edit the already created student campus.
Route 2: It has a form with all the necessary fields to create a student-campus.
As you can see I need to pass the student-campus ID to fetch data in the ngOnInit to fill the fields and be able to edit the above-mentioned, so I have several options in consideration:
Option 1: Pass ID in the URL.
this.router.navigate(['planteles/registrar', idPlantel]);
https://myapplication/planteles/registrar/1
Option 2: Pass ID in the URL with queryParams.
this.router.navigate(['planteles/registrar'], { queryParams: { ID: idPlantel } });
https://myapplication/planteles/registrar?ID=1
Option 3: Pass ID in the state object of navigation extras.
this.router.navigate(['planteles/registrar'], { state: { id: idPlantel } });
Option 4: Shared service and BehaviorSubject to subscribe to data.
I owe you the code
I'm able to use any of these but I have a problem with each one of them.
I can't use Option 1 and Option 2 because the ID cannot be changed by the teacher because that gives him the possibility to fetch the student-campus data of another teacher and edit it, so it isn't safe.
The problem with option 3 and option 4 is when I refresh the page the state is lost.
Currently, I have a workaround with option 3 which is to redirect the user to the previous page if the state is undefined but I don't like that solution. I'd like to persist data if the user reloads the page without using LocalStorage.
Thanks in advance, all help or contribution is well appreciated.
Option 1 is the correct option here (and the way you will find most sites in the real world are implemented... including this one we're on now). The problem is your approach to web security, and what you need to fix is your backend. You're approaching web security as though front end security is real, it's not. Web security exists on your backend. Users should not be able to fetch or view or manipulate data that does not belong to them, and this must be enforced by your backend.
A high level example of how this might work: some secure authentication token should be granted when the user logs in, then this authentication token should be attached to each request. The API then uses this token to check which user is making the request and ensures they have the proper permissions. If they do not (as in the case of the user editing their URL param to some ID they do not have permissions for) or if there is no token, the API should return a 401 or 403 response and the front end should handle it appropriately (ie sending them back to list, or showing an error page, whatever you decide)... how to issue this token, make it secure, and make use of it is an entirely separate topic beyond the scope of this answer.
In any of the options, I could open my dev tools, and view any API requests being made, and change the ID's and use that to view or manipulate other people's data without any effort at all. So options 3 / 4 are barely more "safe" than 1 or 2. As none of these are safe without properly implemented backend security.
Front end "security" exists only as user experience. Me and you are both using the same URL to view this page, but we see different options and buttons, like you can edit or delete your post and accept answers, while I can't, but I can edit or delete my answer etc. This isn't for true security purposes, SO's servers enforce who can and can't take what actions. It's just showing me and you the UI that reflects our different permissions, ie, its all just UX.
There's another way too, which is defined in Angular docs itself.
NavigationExtras
Example:
let navigationExtras: NavigationExtras = {
queryParams: {
"firstname": "Nic",
"lastname": "Raboy"
}
};
this.router.navigate(["page2"], navigationExtras);
I am currently working on a javascript project that fetches various data from a customer's Facebook page, so that it can be displayed on the customer's website.
One requirement of this project is that it can also fetch an display all offers that are currently active on the customer's Facebook page.
I already dug through the Open Graph API documentation and Facebook is listing two different endpoints to access offers from a Facebook page.
I tried /{PAGEID}/nativeoffers but this just gives me a empty response.
I also tried /{PAGEID}/offers_v3 but I just get the following error response:
{
"error": {
"message": "(#3) User must be on whitelist",
"type": "OAuthException",
"code": 3,
"fbtrace_id": "BV8zwWvE7Gv"
}
}
Because of that, I have two questions:
If I just want to fetch the standard offers of a Facebook page, which API endpoint do I have to use? /nativeoffers or /offers_v3 ?
How to get whitelisted to use /offers_v3? In the Open Graph API docs the description is as follows:
Entity to describe an offer. One needs to be whitelisted to use this API. Please contact the support group and ask them to reach out to the team that is responsible for this API to request to be whitelisted.
What support group is meant here?
Any help is greatly appreciated!
I'm trying to delete a comment using a Graph API call.
https://graph.facebook.com/[comment-id]?access_token=[access-token]&method=delete
However, in terms of access-token, I'm not sure which one to use? I have used my App's "User Access Token", "Page Access Token" and "App Token". It doesn't work for any of these.
[PS, my app has all permissions, and I have even submitted it for review]
I just wanted to know if it was even possible to delete a comment which was not posted by the application? (Because I see that Delete is only allowed for page access tokens).
So, please do let me know if it is possible to delete a comment from a user's posts. And if so, which access_token to provide.
The docs list all the neccessary Access Tokens and permissions:
https://developers.facebook.com/docs/graph-api/reference/v2.10/comment#deleting
I tried it with a user profile, it does not seem to be possible to post comments or delete them - no matter if was created by the App or manually:
Publishing comments through the API is only available for page access
tokens
For Pages, you need to use a Page Tokens with the neccessary permissions according to the docs.
It looks to me that you're doing an HTTP GET call and just putting &method=delete at the end. That's not how it works
You should do an HTTP DELETE call. So instead of doing something like $.get(...), you should do $.ajax with type: 'DELETE'
Also, make sure your token has publish_actions permission
I put company in between quotations because my question relates to our Rugby team page but in Facebook it acts like a company page.
I am currently rebuilding my teams website (BBRFC Celtic) and I am going to add a user login system which will have coaches and admin staff with different levels of authority.
Sometimes due to weather conditions, events, or other things a training time may be changed or a match canceled or other various events. When these happen we normally send emails through a mailing list or sms or post on Facebook by hand.
What I want to have is a little bot of some kind that runs behind the scenes of the server and when coaches or admins change something it allows them to make an automated post to Facebook.
Something like after changing a trainings time it asking Would you like this to be posted to the facebook page and groups?.
I have been unsuccessful in finding out how I would go about writing the code for this. Our webpage will use php but maybe this can be done with javascript?
Do I need to get a key to post something as if I were the page?
How about to the different groups we have?
Any pointers would be helpful since I am totally stuck not really programmatically but more conceptually, I do not know if this is even possible.
I will explain the steps you need to accomplish your goal for a website. Note that the documentation also explains the case of a mobile application and others. I used the facebook API before, however, not to manage groups/pages, hence, this post will only point you in the right direction. I will explain how to post a message as being the admin of the page, not sure if you meant facebook pages or groups.
First, the user need to log in with facebook. This can be done using Javascript and the facebook API. Their documentation provides a very detailed explanation with code examples etc. Note that i will explain for the case of Javascript, however, this could be done in php, ...
Once the user is logged in, you can retrieve all kind of information about the user, his pages, etc. I would suggest to retrieve the pages the user is managing, then check if your "company" is part of this list (note that you will need the manage_pages permission). If this is the case, the user can post a message in name of the page.
/* Retrieve pages the user is managing */
FB.api(
"/me/accounts",
function (response) {
if (response && !response.error) {
/* handle the result */
}
}
);
Now response is an object containing multiple fields (see the official documentation).
Now, if the user is an administrator of your page, you can post a message as a Page.
/* Post a message as a Page, use your page id */
FB.api(
"/{page-id}/feed",
"POST",
{
"message": "The match has been delayed to ..."
},
function (response) {
if (response && !response.error) {
/* handle the result */
}
}
);
If successful, the ID of the post will be returned as part of a JSON response (see doc)
I'm working on a materials exchange site for instructors and students. The material is confidential in the sense that it's ours and we don't want other instructors to steal it. On the other hand, it has no personal or sensitive information so security is not a huge concern. If you steal my grammar exercise, I'm not going to sue you. I'm using Ion Auth in a Codeigniter framework and am satisfied with that. I use YUI 2.8 to display editable datatables and editable trees. Building on the Codeigniter MVC framework I have a controller to handle Ajax requests. When I post a request via the YUI Connection class I pass a serialised object called data as the only parameter, which comes from a JSON object assembled on the client side by passing a config object to YAHOO.si.factory.Method like this:
addTreeNode: new YAHOO.si.factory.Method({
className: "instructors_model",
methodName: "add_exercise_tree_node",
key: "id",
mode: "child",
fields: ['n0', 'n1','n2', 'n3'],
params: [{
key: "nodeData",
name: "nodeData",
type: "text",
direction: "IN",
value: "34"
},{
key: "name",
name: "name",
type: "text",
direction: "IN",
value: "Grammar"
}],
success: "You have successfully added a node to the tree."
}),
The controller parses the JSON string assembled by YAHOO.si.factory.Method and figures out that it has to call add_exercise_tree_node in the instructors_model and pass 2 parameters. The add_exercise_tree_node method does the dirty work on the database and, hopefully, returns a success message. If so, the success message is displayed on the client side and the tree is updated to include the new node.
My question is, am I giving away too much information about the server in this plain-text querystring? It's a post so it doesn't appear in the URL, but of course it's completely visible in something like the Firebug console.
The question behind that question of course is what do you security experts out there advise about parcelling out responsibility for Ajax in an MVC framework? I want the manageability of having just one controller responsible for handling Ajax requests, so I've ended up with a slightly complicated (and insecure?) overloading on the client-side. What patterns do you advise for this?
My claim in the comments was that you're defeating the purpose of RESTful architecture in the MVC paradigm, primarily with focus on "all AJAX calls go to one controller". So let's tear this down into something usable, and then rebuild our understanding of why/how.
REST just means REpresentational State Transfer but that's not what we mean when we say REST or RESTful. We mean that we intend each URL to represent a type of resource, and we use verbs to indicate what we're doing with each request. So "GET", "POST", "PUT", etc all have a purpose, and we use that purpose to dictate how we interact with the individual resources.
So let's put that into perspective, let's do something with that; consider an HR application (this is one of those easy ones that people adopt). We have People and Departments. Departments have an ID, a Name, and a Manager (who is a Person). People have an ID, a Name, a Manager (may be -1 in our system to indicate no manager, or an ID of a person) and a Phone Number.
When we HTTP GET http://server.domain/app/Person we get a directory of all people, that gives us their name and ID.
[ {Name: "Cole Brand", ID: 1}, {Name: "user341180", ID: 2} ]
When we HTTP GET http://server.domain/app/Person/1 we get
{ Name: "Cole Brand", ID: 1, Manager: -1, "Phone Number": "222-555-1234" }
When we HTTP GET http://server.domain/app/Person/2 we get
{ Name: "user341180", ID: 2, Manager: 1, "Phone Number": "222-555-6789" }
And just for the sake of completeness, a list of departments:
HTTP GET http://server.domain/app/Department/
{ Name: "HR", Manager: 1 }
Now obviously, my example is a little dry, because for instance, the employees certainly work in a department, but I haven't associated them to it by their profile. Surely the database would track that, but we don't have it here. This is a simple example.
So you can see from this that there is no HTML being returned. We will come back to that.
For the next part, notice that I've kept using HTTP GET. What if we used HTTP POST? That would mean that whatever we passed, would overwrite that data. So let me give a brief example:
HTTP POST http://server.domain/app/Person/2
send this data in the post body { Manager: -1, "Phone Number": "222-555-0089" }
get nothing in response (we could return the object, but my API doesn't for whatever reason, call it a specification deficiency)
When we HTTP GET http://server.domain/app/Person/2 we now get
{ Name: "user341180", ID: 2, Manager: -1, "Phone Number": "222-555-0089" }
See how we used HTTP POST to update the record? That's how we use our RESTful methods, we use the verb to indicate the action.
So what else could we use to communicate with the server? What if we wanted to have the RESTful methods return both a webpage and the data, but for GET? We could use an HTTP HEADER (maybe an X-Header?) to specify that we're making a data call, so by default we make a request to HTTP GET http://server.domain/app/Person/1 and we get a webpage. If you would like an example of that (a rest response providing a webpage) check the page we're on now. https://stackoverflow.com/questions/11061912/ <-- is actually served by MVC restful principles (but I don't think they supply the JSON by this method, because that's not how their system is setup).
So I'm probably scrambling you all up, I just wanted to review REST, and how we use it today for MVC purposes. Let's look at part of that again, the part where we do http://server.domain/app/Person
In MVC terms, that would mean that we've got a Person controller in our app. Any requests made against the Person controller would be routed based on their verb type first, then any additional parameters next. For instance, submitting this answer makes a post to https://stackoverflow.com/questions/11061912/answer/submit. So the Controller knows that it expects to receive "Post ID" (so it knows the parent that the answer belongs to), "answer" telling it that I'm adding an answer, and "submit" so it knows what I'm doing. If I were editing it would be an edit-submit instead of answer/submit.
Ok, so I feel like I'm making things confusing, and I don't know if you read my answer on MVC in node and general: How are models tied to views? but let me clarify: The Controller is a routing device to take input, send it to the appropriate model, and then render some view (HTML, JSON, XML, plain text, etc). Note that rendering a view is not required (remember my crappy API that didn't return anything on a HTTP POST?).
So now we get to the point of what I was trying to get at in my response earlier, which I'm still not being clear enough on. When you move methods from the "appropriate resource" (in the case of this post /question/), you're breaking the idea that one URL root is one resource. Oy, I've messed this all up haven't I?
In REST principles, each URL-root is one resource. You can do things from that resource, like rendering a certain view based on some bit of data, or you can add/modify data using a certain verb, or you can make flapjacks if that's your style. But all Person will always be at http://server.domain/app/Person, and not "some person commands are on http://server.domain/app/Person and some person commands are on http://server.domain/app/Department" because then you're just going to throw your arms up in the air and go "well how do I know where all to find people actions?!?!"
That, in a nutshell, is why you don't want to put some methods for accessing data on one controller (rendering the view) and some methods for accessing data on another controller (JSON) for the same resource-type.
Now that I've put all that braindump into a post, which parts am I fuzzy on? Feel free to edit the post and insert some **what do you mean here?** or **you seem to be jumping around on this point a lot** or whatever you feel is appropriate.