Make extra parameters passed in URL as optional - django

I have this URL path('user/delete/<int:pk>/', views.UserDeleteView.as_view(), name='delete_user'),
to delete a selected user via passing the pk of the user to be accessed by the DeleteView . However, I want to delete multiple users by using a form with checkboxes. For that, I have used a separate view.
my question is that is there any way that I can make this <int:pk> as optional parameter so that I can use the same view for POST as well as GET requests. Just in case I want to use the POST method for the same URL. Can this be done? Someone said it can be done optional in Ruby on Rails. Is there any way to do this here in Django?

You can define two paths, one with the primary key, and another one without the primary key:
path('user/delete/', views.UserDeleteView.as_view(), name='delete_user'),
path('user/delete/<int:pk>/', views.UserDeleteView.as_view(), name='delete_user_id'),
We thus have two views here: 'delete_user' that takes no pk, and 'delete_user_id' that takes a primary key. Both direct to the same UserDeleteView.
You can inject a value for the missing parameter, by using the kwargs= parameter:
path('user/delete/', views.UserDeleteView.as_view(), name='delete_user', kwargs={'pk': None}),
path('user/delete/<int:pk>/', views.UserDeleteView.as_view(), name='delete_user_id'),
That being said, using GET requests are supposed to have no side effects. That is how the HTTP protocol [wiki] is designed:
The GET method requests a representation of the specified resource. Requests using GET should only retrieve data and should have no other effect. (This is also true of some other HTTP methods.) The W3C has published guidance principles on this distinction, saying, "Web application design should be informed by the above principles, but also by the relevant limitations.".
The W3 organization has also guidelines when to use GET or POST:
Use GET if:
The interaction is more like a question (i.e., it is a safe operation such as a query, read operation, or lookup).
Use POST if:
The interaction is more like an order, or
The interaction changes the state of the resource in a way that the user would perceive (e.g., a subscription to a service), or
The user be held accountable for the results of the interaction.
If you want to delete items, you usually make a DELETE or a POST request. Django for example will protect such requests with a CSRF token, to prevent cross-site request forgery [wiki].
I therefore strongly recommend that you only allow POST/DELETE requests for these views, of course with extra checks to see if the user is authorized to make the changes.

Related

Scope of returned resource highly depandant on user role encoded in JWT token - is it RESTful?

I'm working on API that tries to stay in RESTful principles, although one requirement keeps bugging me.
We use JWT based authentication. Inside JWT claims we store roles of the user. Now our main GET endpoint (let's call it ListAllOffers for simplicity) behaves differently depending on what role the user have:
if API recognizes admin via JWT it responds with full list of Offers
if API recognizes ordinary user via JWT it responds with narrowed list of Offers (depending on relation in DB)
My concerns is: is it ok according to REST principles or any unwritten REST practices? I am used to modify response object according to argument from url, params from querystring or alternatively via header values. Altering JSON response basing JWT seems not explicit enough that is feels some kinda strange.
Bonus question: is it against any of REST principles how should this requirement be implemented.
You'll find lots of APIs have resources where the value changes depending on the authenticated user (see GitHub's API).
When it comes to REST the endpoint must always reference the same resource. However, you may choose to represent that resource in any way you wish. Masking some of the offers because the user is not an admin has not changed the resource only the representation you are giving to that user.
While the REST specification doesn't have any specific examples of changing representations due to authorisation it is still a worthwhile read.
If you are concerned about changing the representation implicitly there are a few options available that would make it more explicit whilst still following RESTful standards.
You could add a query parameter that explicitly requests only the current user's offers: /offers?show=mine.
If the offers are 'owner' by a user you could also do something like: /users/{username}/offers. Here a user would be authorised only for their own offers. An admin would of course be authorised for any.
Overall the key point is this: an endpoint must always represent the same resource but how it represents it is up to you.

Why use URL parameters over request body in API?

When making an API endpoint in Django Rest Framework for example, why would I ever use URL parameters to receive data rather than just putting everything in the request data?
I don't get the difference between the two.
Putting some query data in the URL allows the URL to store the "state" of your web application.
For example a state can be "I queried how do I make cheese on stackoverflow", and the URL would be https://stackoverflow.com/search?q=how+do+make+cheese.
This allows the web app to interact as expected with browser tools like Refresh, Go Back, etc. Without the state stored in the URL, refreshing the page might just take you back to the homepage, instead of showing you the same query results (the expected behaviour).
Additionally, you can copy & paste the URL. When someone clicks on it, they will be taken directly to that specific state.
On the other hand, you shouldn't use the URL to store/send sensitive data (as it can easily be seen, use the body instead), and you should make sure reloading an "action" URL won't execute the action again (like paying for a product twice!).
The URL parameters and body parameters server different purpose. The REST API grammar says
GET Method is used when you want to retrieve data back and don't want to update any of the record in system. The GET method will not pass body parameter and hence whatever filter parameters passed to API will be through URL parameters.
POST/PUT Method is used whenever you want to update your database. The value could be single parameter or even no input but you have to use POST/PUT method, if you are trying to update database record(s).

RESTful API for users' data

I would like to develop a website, with reusable API - and REST-sty;e one should suite quite well.
Lets say that each user can store information about books they like. So I have many users, and each of them can have many books.
As I suppose, I would get list of books by some kind of request as below:
GET /book
But.
User should list only his books, not all of them, that are stored on the server. So how to do this properly?
As I read through many SO Q&A, it seems to be not RESTful to leverage standard authentication with cookies and session id (like it is common with PHP or others), because it preserves state on the server.
Then, first request (GET /book) would not return any results (user not logged in), and after logging, it would return list of this user's books.
Another solution I came across, is to append credentials to every request, like:
GET /book?user=john&pass=1234
Despite of TLS (HTTPS) requirement of that (because of plaintext data), it just seems wrong. Seems like redundancy, bandwith waste, each-request validation etc.
My question is:
If I am not wrong, how to do this good way? Both from the good programming point of view, and performance/network usage prespective?
And maybe REST is not suitable for user owned data?
EDIT:
And OAuth and similar solutions seem way too complicated (and they add overhead too, I think?).
You can add a first mandatory REST method to get an authentication token, so you can require this token in all other REST requests and use it to filter the results.
Use the Authorization header to pass credential information. If OAuth is too complex, use Basic auth over SSL... like so:
GET /user HTTP/1.1
Authorization: Basic ZmlkZGxlcnBpYW5pc3Q6aGVsbG93b3JsZA==
Accept: application/json
(other headers here)
Though I'd definitely recommend a URL that's unique to your user, such as this one:
GET /users/fiddlerpianist/books HTTP/1.1
Note that, in a stateless RESTful service, there is no concept of login or logout. The Authorization header would be passed from the client with every request.

jax-rs rest webservice authentication and authorization

I have a web application that needs to allow users using different webclients (browser, native mobile app, etc) to register. After signing in they can access restricted content or their own content (like entries they create, etc).
What I did so far: I created a jax-rs rest webservice (I'm hosting my application on glassfish) that exposes the following methods:
register - user POST's his desired username/password/email/etc; if username/email is unique, an entry for this user is created in the database (I'm using Hibernate for persistence)
login - user POST's username and password. If they are ok a UUID is created and returned to the user (this will be used as a token for future requests). I have a table called logedusers, with userID, token, validSince as columns.
Here is where it gets confusing for me.
Let's say that I have another method, getUserEntries, that should return all the entries made by the user. To make this clearer, there will be a Entry table with the following fields: entryId, userId, text.
What is the best approach here?
What i do now, is I make a get request and pass in the token like this:
localhost:8080/myApp/getUserEntries?token=erf34c34
Afterwards, if the token is valid, I get the userID from the logedusers table and based on that userId, get all the entries and return them as json.
Something like this:
#GET
#Path("getUserEntries")
#Produces(MediaType.APPLICATION_JSON)
public Response getUserEntries(#QueryParam("token") String token) {
String userId=getUserIdFromToken(token);
if (userId == null){
return Response.status(Response.Status.UNAUTHORIZED).build();
} else {
//get some data associated with that userId, put it in the response object and send it back
return Response.ok().entity(response).build();
}
}
However, what happens if I have more methods that provide data if they are called by a valid user?
I'd have to do this check at the beginning of every method.
I want to make this authorization process transparent
So, two major questions here:
Is this design ok? The whole authenticate with user/pass, server creates and stores and sends token to the user, user sends token on future requests.
What do I do if i have many endpoints that need to determine the identity of the calling user? Can I mark them with some annotations, use some sort of security provider / authenticator (where I can add my own logic for validating - eg check to see if the token isn't older than 5 days, etc).
Thanks
Is this design ok? The whole authenticate with user/pass, server creates and stores and sends token to the user, user sends token on future requests.
It's somewhat OK. The conceptual level isn't too bad (provided you're OK with self-registration at all) but the interface needs a lot of tweaking. While yes, POST to register and login is correct, for the rest of your webapp you should be pulling the identity information out of the context if you need it, and using role-based access control at the method level where you can.
Note that your container has a whole set of authentication and authorization-support mechanisms built in. Use them.
What do I do if i have many endpoints that need to determine the identity of the calling user? Can I mark them with some annotations, use some sort of security provider / authenticator (where I can add my own logic for validating - eg check to see if the token isn't older than 5 days, etc).
Do they need the identity? Or do they just need to know that the user is allowed to access them? If the latter, the easiest method is to put a suitable #RolesAllowed annotation on the method, at which point (with suitable configuration; see the JEE5 security docs). If the former, you need to get the HttpServletRequest object for the current action and call its getUserPrincipal() method to get the user's identity (or null if they've not logged in yet). This SO question describes how to go about getting the request object; there are a few possible ways to do it but I recommend injection via a #Resource annotation.
What I wouldn't do is allow users to normally provide their own identity via a #QueryParam; that's just wildly open to abuse. You can allow them to ask about other users that way, but then you need to decide whether you are going to tell them anything or not based on whether the current user is permitted to know anything about the other user. That's the sort of complex security problem that comes up in a real app, and is a good point for needing the current verified user identity.

Django Middleware + URL's

Can a middleware check to see if a value is in the url, such as an image id ("/image/152/"), and if it is then do some checks to make sure the current user has permission to view that image and if not redirect to another url?
I had to roll my own permissions for this site I am working on and I don't want to clog up almost every view I write for the whole site with the same code, so I thought a middleware would be a good idea for this, but I'm not sure how to go about doing it.
Yes, this is possible. The django middleware docs for process_request indicate that:
def process_request(self, request)
request is an HttpRequest object. This method is called on each request, before Django decides which view to execute.
process_request() should return either None or an HttpResponse object. If it returns None, Django will continue processing this request, executing any other middleware and, then, the appropriate view. If it returns an HttpResponse object, Django won't bother calling ANY other request, view or exception middleware, or the appropriate view; it'll return that HttpResponse.
The HttpRequest object has a path attribute that will give you the URL that was requested.
If you prefer, however, note that you can also extend Django's system for authentication backends to populate the user in the request with permissions based on any arbitrary criteria, such as perhaps your hand-rolled permissions scheme. This way, you can leverage the default authentication decorators (#permission_required and #user_passes_test), and other apps/the admin site will be able to honour your permissions as well. The User object and permissions created do not need to reside in Django's user/permission tables, and can be created virtually on login; I've had a fair amount of success with this.
See Writing an authentication backend if this appeals.
If you implement authorization (Permission system) in middleware, you will end up with two options:
Check URL and allow to access
Check URL and reject access
If your requirement is that much simple, it is fine, since you don't have to touch views.
But in general, Permission system is much complex than that, for example:
User can access FOO/show_all/
But, he can't see or access foo instance, i.e, FOO/show/foo_1/
Since, he can't access foo_1 instance, we should not show them in show_all
(all foo instances)
If you want implement above 3 together, I suggest you write your own custom authorization backend for Django. All you need to do is implement few methods (your specific logic) and attach as backend.