RESTful API design need validation - restful-url

I want to develop restful API related to user authentication. please suggest if my URL designs looks ok. as a background information, these API use an LDAP directory such as microsoft AD.
user registration
POST /auth/register
payload : {username: "", password: ""}
user login
POST /auth/login
payload : {username: "", password: ""}
password change
PUT /auth/password_reset
payload : {username: "", old_password: "", new_password:""}
deactivate user
DELETE /auth/de_activate/{user_name}
activate a user
PUT /auth/de_activate/{user_name}
I do understand that I am using verbs in the URL. However, since these APIs create some resource [register API] as well as perform some actions [login api], I went ahead with the URLS above. I would appreciate any inputs through.
Regards
Prasad Katti

These are the changes I would make. I know that you know already that the URL paths should be nouns and your verbs should be GET, POST, DELETE, etc. to indicate that you want to view, create or delete a resource.
Instead of:
POST /auth/register do POST /registrations
Instead of:
POST auth/login do POST /logins or POST sessions
Your password reset route is okay, but I don't believe the action matches the resource.
Instead of:
PUT auth/password_reset do POST /password_resets
And yes, PUT actions are supposed to update or replace the resource, but what other resources do you have that require you to send the old and new values? The one above is still accurate, since you are creating a "password reset" which sets off a workflow of actions that may require people to check their email and click a link, but I think that doing PUT /passwords is misleading due to the payload that is required.
Instead of:
DELETE /auth/de_activate/{username} do DELETE /users/{username} or DELETE /users/{userId} or even PUT /users/{username} with {"active": false}. Personally, I think that hard vs soft deletes should be transparent through your API though.
And instead of:
PUT /auth/de_activate/{username} do PUT /users/{username} with {"active": true} or POST /users/{username}/reactivations.
The purpose of RESTful standards is to make a consistent and predictable API for clients. All it is really is a set of guidelines. It's not super-strict or anything so ultimately it's left up to your best judgement. These are just the adjustments I would make.

Related

How to implement valid restful api for non CRUD feature

I'd like to implement a valid Restful API.
I have a resource called "Jobs" and also I implemented CRUD [GET, POST, PUT...] for example: GET: /api/jobs/1 or POST: /api/jobs/ with a body {...}
Now I'd like to add a method to start a job number 1234.
How can i implement this? what should be the URI? What should be the HTTP verb?
Can someone give me an example
You can create a new resource
POST /started-jobs?jobId=1234
You can edit the state of the job inline:
PUT /jobs/1234
{
"state": "started",
..
}
You can use a micro-PUT
PUT /jobs/1234/state
started
That's just off the top of my head. There are surely other options. Which one is best? That requires more information on what you're trying to accomplish.

Set params hash value using link_to without affecting url in Rails 4

When I submit a form, a number of parameters are set without showing up in the url.
I would like to do the same thing with link_to:
<%= link_to((purchase.paid ? 'yes' : 'no'), {action: :index, hidden_id: purchase.id}) %>
produces the url 'http://localhost:3000/purchases?hidden_id=1'. I would like to link to the url 'http://localhost:3000/purchases' while still setting params[:hidden_id] so I can access it in the controller, as if I had submitted a form.
My routes.rb file is as follows:
root to: 'products#index'
resources :products
resources :purchases
match ':controller/(:action/(:id))', controller: :shop, via: [:get,:post]
In answering this, is there anything I should know here about the difference in the way these two things are handled? Is it something about get vs post requests or is there some other principle involved which I'm not grasping?
Yes, it's to do with Get vs Post requests.
A Get request can only send parameters in the URL itself. A post request can also be sent to a URL that includes parameters in the URL itself, but it can also send parameters 'under the hood' so to speak.
So if your routes were set up to allow it, you could send either a get or a post request to http://localhost:3000/purchases?hidden_id=1, but only the post request could include additional parameters under the hood.
Anything else you should know about the difference in the way these two are handled? Yes. In most web frameworks, when you see the parameters server-side, they will be split up into GET params and POST params. Rails doesn't make this distinction, and puts them both in the same params hash. (I think this is silly, but whatever).
Also, a get request can be sent simply by entering the URL in your browser and hitting enter. A post request will generally only be executed by a user submitting a form on a web page. For this reason, get requests are not meant to change any content in your database. They should be for viewing information only. So, eg, if you have a button to delete a resource (eg. a blog post or something) it should be submitted via post. (more info on that at Why shouldn't data be modified on an HTTP GET request?)
Lastly, Rails provides an option in it's link_to helper to allow you to easily make the 'link' use a post request. See the method option at http://api.rubyonrails.org/classes/ActionView/Helpers/UrlHelper.html#method-i-link_to. This basically uses javascript to prevent the normal action of clicking the link (which would be a get request), and submit a post request instead.

Is it safe to accept URL parameters for populating the `url_for` method?

I am using Ruby on Rails 4.1.1 and I am thinking to accept parameters (through URL query strings) that are passed directly to the url_for method, this way:
# URL in the browser
http://www.myapp.com?redirect_to[controller]=users&redirect_to[action]=show&redirect_to[id]=1
# Controller
...
redirect_to url_for(params[:redirect_to].merge(:only_path => true))
Adopting the above approach users can be redirected after performing an action. However, I think people can enter arbitraryparams that can lead to security issues...
Is it safe to accept URL parameters for populating the url_for method? What are pitfalls? What can happen in the worst case?
By logging params during requests to my application I noted Rails adds always :controller and action parameters. Maybe that confirms url_for can be used the above way since it is protected internally and works as-like Rails is intended to.
This it is safe internally as Ruby On Rails will only be issuing a HTTP redirect response.
As you are using only_path this will protect you from an Open redirect vulnerability. This is where an email is sent by an attacker containing a link in the following format (say your site is example.com).
https://example.com?foo=bar&bar=foo&redirect=http://evil.com
As the user checks the URL and sees it is on the example.com domain they beleive it is safe so click the link. However, if there's an open redirect then the user ends up on evil.com which could ask for their example.com password without the user noticing.
Redirecting to a relative path only on your site fixes any vulnerability.
In your case you are giving users control of your controller, action and parameters. As long as your GET methods are safe (i.e. no side-effects), an attacker could not use this by creating a crafted link that the user opens.
In summary, from the information provided I don't see any risk from phishing URLs to your application.
Rails redirect_to sets the HTTP status code to 302 Found which tells the browser to GET the new path as you defined it by url_for. GET is a considered a safe method in contrast to
... methods such as POST, PUT, DELETE and PATCH [which] are intended for
actions that may cause side effects either on the server, or external
side effects ...
The only problem would have been if someone could gain access to methods such as create and destroy. Since these methods use HTTP methods other than GET (respectively POST and DELETE) it should be no problem.
Another danger here is if you go beyond CRUD methods of REST and have a custom method which responses to GET and changes the database state:
routes.rb
resources something do
member do
get :my_action
end
end
SomethingController
def my_action
# delte some records
end
For future ref:
Rails has a number of security measurements which may also interest you.
It's not exactly an answer, just wanted to point out that you shouldn't use something like
url_for(params)
because one could pass host and port as params and thus the url could lead to another site and it can get worse if it gets cached or something.
Don't know if it threatens anything, but hey, it's worth pointing out

Generating secret URLs for a resource in rails

I've created a task management app that consists of lists and tasks. Users can only view their own lists and tasks. I would like to add the ability for a user to share a list if they like. Here are the steps I would like to accomplish:
User clicks a link from /list/show to share the list
User receives a secret URL to share: myapp.com/lists/1/23534512345234523 or whatever.
Secret URL redirects to a view other than /lists/show. Something like /lists/1/23534512345234523 which would be routed to /lists/secret_show or whatev.
Only users who have that url can see the information on that page.
Hope that is making sense. I imagine I would have to update the list record with a unique token to list.token. Then I would some how have to recieve the incoming URL and through a new action
lists#secret_share
def secret_share
...
end
Where I filtered for the list record by list.token and routed to secret_share. Then perhaps in the view I could simply restrict the view by the presence of the token in the URL.
Thoughts?
Whatever "secret URL" you hand out should not redirect to the real URL or you're going to create all kinds of opportunities for information leakage. It should be a strictly alternate URL.
Using routing for this seems like a good idea instead of using a separate controller. In your route you might want to pass an additional parameter to indicate this is a "secret" URL, like :secret => true where the value in question is something that cannot be submitted by the user to fake things out. User parameters are always strings, for instance, so using true should be a safe alternative.
This special parameter might disable access checking on your controller so that the page can be viewed by people that don't normally have access. You could also show a different layout using the layout method in your controller.

Why use HTTP PUT and DELETE methods instead of POST?

new_story GET /story/new(.:format) {:action=>"new", :controller=>"stories"}
edit_story GET /story/edit(.:format) {:action=>"edit", :controller=>"stories"}
story GET /story(.:format) {:action=>"show", :controller=>"stories"}
PUT /story(.:format) {:action=>"update", :controller=>"stories"}
DELETE /story(.:format) {:action=>"destroy", :controller=>"stories"}
POST /story(.:format) {:action=>"create", :controller=>"stories"}
In web development I have done with other technologies, I only ever used GET and POST methods, but with RESTful routes in Rails, by default the PUT and DELETE methods are used for the update and destroy actions. What's the advantage or need for using PUT and DELETE? I assume these methods are just another way of doing POST - but why not just stick with POST?
The advantage is mostly semantic, and can also simplify URLs to an extent. The different HTTP methods map to different actions:
POST => create a new object
DELETE => delete an object
PUT => modify an object
GET => view an object
Then, in theory, you can use the same URL, but interact with it using different methods; the method used to access the resource defines the actual type of operation.
In practice, though, most browsers only support HTTP GET and POST. Rails uses some "trickery" in HTML forms to act as though a PUT or DELETE request was sent, even though Rails is still using GET or POST for these methods. (This explains why you might not have used DELETE or PUT on other platforms.)
I just wanted to add something to the accepted answer because his definition of the http verbs are incorrect. They all have a spec which "should" be followed and you can create/update/delete with multiple http verbs based on the specs.
I am going to highlight some of the important bits in the RFC 2616 by W3
I'm going to start with PUT because in my opinion it has the most confusion surrounding it.
PUT is used for both create/update PUT updates by completely replacing the resource on the server with the resource sent in the request
For example
You make this call to my api
PUT /api/person
{
Name: John,
email: jdoe#hra.com
}
my Server has this resource living on the server
{
Name: Jane,
email: jdoe#hra.com
}
Now my existing resource is completely replaced by what you sent over and this is what I have on my server.
{
Name: John,
email: jdoe#hra.com
}
So if you PUT and only send an email in the body
PUT /api/person
{
email: jdoe#hra.com
}
My Server will completely replace the entity
{
Name: Jane,
email: jdoe#hra.com
}
With
{
email: jdoe#hra.com
}
And Name will be gone. Partial updates are for PATCH but I use POST for that anyway.
One of the main reasons why we create/update with put is because it is idempotent.
It's just a fancy term and the basic definition of it is multiple identical requests are the same for a single request.
Example
Suppose I PUT a file to api/file if the origin server does not find that file it will create one. If it does find a file it will completely replace the old file with the one I sent over. This ensures that one file is ever created and updated. If no file exists and you call PUT 5 times, the first time it creates a file then the other 4 times it replaces the file with what you send over. If you call a POST 5 times to create it will create 5 files.
You PUT to that exact URI. If you don't you have to send a 301 (Moved Permanently) to the user and allow then make a choice whether or not to redirect the request. Most times the server you PUT to usually hosts the resource and takes care of updating it
Those are the major points in when to use PUT
As far as POST is concerned
You can also create/update and then some...
As I mentioned above there are a few key differences.
Post is more General. In what ways? some other examples include a gateway to other protocols, it could take the response and send it to some data handler out in the middle of yonder, or it can extend some sort of functionality.
Post doesn't have the restriction of "To the exact URI or notifiy" for examplePOST can append a resource to an existing collection and decide where it's stored.
Now what about Delete Why don't I just POST?
When you DELETE, the server SHOULD NOT respond with success unless you delete the resource or move it to an inaccessible location at the time the response is sent.
Why is that important? What if you call DELETE but the resource has to go through "APPROVAL" before being deleted? If the delete can be rejected you can't send a successful error code and if you do follow the basic specs on this it's confusing to the caller. Just an example I'm sure you can think of many others.
I just highlighted some of the major points on when to use the common Http verbs
Here's the "methods" section of the HTTP 1.1 spec; it defines lots of methods, and they all have different benefits and tradeoffs. POST is the most flexible, but the tradeoffs are numerous: it's not cacheable (so the rest of the internet can't help you scale), it isn't safe or idempotent so the client can't just resend it gets an error, and it is no longer clear exactly what you're trying to accomplish (because it's so flexible). I'm sure there are others but that ought to be sufficient. Given all that, if the HTTP spec defines a method that does exactly what you want your request to do, there's no reason to send a POST instead.
The reason POST is so common is that, historically at least, web browsers only supported GET and POST. Since GET is defined to be safe and idempotent (even though many applications don't adhere to that), the only safe way to modify data was to send a POST. With the rise of AJAX and non-browser clients, that is no longer true.
BTW, the mapping #mipadi gave is the standard mapping, but it isn't the only valid one. Amazon S3, for instance, uses PUT to create resources. The only reason to use POST is if the client doesn't have sufficient knowledge to create the resource, e.g., you back your resources with a relational database and use artificial surrogate keys.
That'd be kind of like asking why "delete" a file when you could just set its contents to zero bytes and the file system would just treat that as a delete. HTTP has supported verbs other than GET/POST forever but the way SOAP evolved kinda twisted the original meaning of those verbs. REST is a simpler, back to basics approach that uses the verbs as they were intended instead of inventing some new verb concept inside of the payload.

Resources