RESTful service for PUT/PATCH with image upload - testing with Postman - rest

I am trying to test an app with RESTful services via Postman (awaiting the front-end to be implemented).
The GET/POST and DELETE requests work as expected, but when it comes to PUT and PATCH I'm completely stuck.
I have a simple form with several inputs and files (pdf & image). With the POST request I simply use the "form-data" body to add all needed parameters. But when I try to test the PUT one, "form-data" detects nothing - with or without a "Content-Type" = "multipart/form-data" set in the header.
The PUT only works with the "x-www-form-urlencoded" option for the body, but then I cannot or don't know how to add both files, as I don't have the ability to choose from "Text/File" anymore via Postman's dropdown. Again, adding Content-Type doesn't help a bit.
I tried simulating POST with a "_method"="PUT" both as a URL parameter and as a form input, but it just creates new item instead of updating existing one (with correct route applied).
# Updated with the routes (standard Laravel routes for RESTful services)
GET | api/v1/Collection | api.v1.collection.index
POST | api/v1/collection | api.v1.collection.store
GET | api/v1/collection/create | api.v1.collection.create
GET | api/v1/collection/{item} | api.v1.collection.show
PUT | api/v1/collection/{item} | api.v1.collection.update
DELETE | api/v1/collection/{item} | api.v1.collection.destroy
GET | api/v1/collection/{item}/edit | api.v1.collection.edit
I realize I have to use a hidden input with _method/PUT as key-value, but I have no idea where to add it in Postman. I can only see two options: text input or file.
What am I missing?
I can provide screenshots upon request. Thanks.

Related

Owasp Zap Testing rest api

Is that possible to testing rest-api via OWASP ZAP ?
Url to attack worked just for GET requests.
For example, my api controllers work with only token. I have TokenController and this controller require POST data via JSON data include password and login. Can I someway testing this controller via OWASP ?
The short answer is yes. The long answer - it's complicated :)
Testing REST API is a bit harder than testing web API - you'll have to give Zap information about your API - which endpoints it has, parameters, etc. Can you share more about you're API? Does it have OpenAPI/Swagger document? Do you have existing tests? You can use either one of those for this task.
I gave a talk about how this can be achieved - you can find the recording here.
It possible to automate API testint with OWASP ZAP, but to perform the tests, I see two options: Offer some usage pattern, for example OpenAPI for ZAP consider extracting the information. And a second option would be to run an automated test to capture ZAP as passive scan information, and after that you can test the session information.
We recommend using the OpenAPI documentation.
The cucumber test would look like this:
Feature: Security
This feature is to test pokemon service security
Scenario: Validate passive and active scan
Given I import context from open API specification "/v2/api-docs"
And I remove alerts
| url |
| http://.*/v2/api-docs* |
And I import scan policy "javaclean" from file "javaclean.policy"
When I run active scan
And I generate security test HTML report with name "java-clean-security-report"
Then the number of risks per category should not be greater than
| low | medium | high | informational |
| 0 | 0 | 0 | 0 |
I am develop step for ZAP, view in the GitHub: https://github.com/osvaldjr/easy-cucumber/wiki/Security-steps
Example step for import OpenAPI docs:
#Given("^I import context from open API specification \"([^\"]*)\"$")
public void iImportContextFromOpenAPISpecification(String path)
throws ClientApiException, InterruptedException {
String url = getTargetUrl() + path;
log.info("Import Open API from url: " + url);
zapProxyApi.openapi.importUrl(url, null);
waitPassiveScanRunning();
verifyThatTheProxyHasCapturedHostInformation();
}
View others steps in: https://github.com/osvaldjr/easy-cucumber/blob/master/src/main/java/io/github/osvaldjr/stepdefinitions/steps/SecuritySteps.java

SOAPUI ReadyAPI resource parameter in URL

Is there a way to have a parameter at the end of the URL for a Rest request?
This is the URL:
http://localhost:8000/my_user/1000
I've tried to use a parameter for the 1000, like so:
http://localhost:8000/my_user/${#Project#id_test}
This doesn't render 1000 at the end.
Is there a way to do this?
There are REST resource parameter types.
In your case, style should be Template. That should resolve the issue.
To give an example:
While adding a new REST Resource from API use below url instead of plain text value.
In the request you would see as below:
Now, in your test cases, you can use the property expression (the one you were using in the question) i.e., ${#Project#id_test} for value field/column as underline in the above image.
You may also go thru documentation if needed.
What you're trying to achieve is possible, though I'm not sure about the value you have supplied.
When you set up a RESTful Test Project is SoapUI, you define the root/base url under test.
When you set up the service call in SoapUI, you define the GET, POST settings. In the same place, you can add parameters. Click on the Request tab and you should see an empty table with headings, Name, Value, Style, Level.
You can add your parameter here.
E.g.
Name | Value | Style | Level
id | Smith | QUERY | RESOURCE
When you run the service call and you not sure your request is correct, click on the Raw tab and that will show what SoapUI is actually sending to your service.

Brakeman unprotected redirect for Rails, S3, Paperclip

I'm getting this warning from Brakeman. As they say,redirects which rely on user-supplied values can be used to “spoof” websites or hide malicious links in otherwise harmless-looking URLs. They can also allow access to restricted areas of a site if the destination is not validated.
| Confidence | Class | Method | Warning Type | Message
| High | DocumentsController | download | Redirect | Possible unprotected redirect near line 46: redirect_to(+Document.find(params[:id]).f
In my controller I created a method download that takes the file URL (file stored on Amazon S3 and the URL in my database thanks to Paperclip) and creates a URL (ie. document_url) that will last 3 seconds (for the user to download) thanks to .expiring_url(3)
def download
#document = Document.find(params[:id])
document_url = #document.file.expiring_url(3)
if URI.parse(document_url).host.include? "domain.com"
redirect_to document_url, only_path: true
else
document_url = nil
end
end
I have been trying pass Brakeman's validation without success. As you can see above, I tried to check if the my domain is present in the URL but it did not change the report on Brakeman.
Any idea how to proceed?
I have the similar problem. I passed the warning by utilizing strong parameters like below, though I'm not sure why it works.
redirect_to referer_param
def referer_param
params.require(:referer)
end

How to use scaffolding and RESTfulness together in Grails 2.3

Official Grails documentation says that
Version 2.0.x of the scaffolding plugin includes different scaffolding
templates that are aligned with the new REST APIs introcued in Grails
2.3 and above.
(taken from here http://grails.org/doc/latest/guide/scaffolding.html)
But I can't make (or I don't understand the concept) work RESTfulness together with scaffolding.
Let's start from scratch:
grails create-app myapp
cd myapp/
grails create-domain-class Book
grails create-scaffold-controller myapp.Book
Add a field to the domain class
class Book {
String text
static constraints = {
}
}
and run the app with grails run-app.
Surfing on the http://localhost:8080/myapp/ shows that scaffolding works great:
http://localhost:8080/myapp/book/index page shows books list
http://localhost:8080/myapp/book/show/1 page show details for the book with id = 1
http://localhost:8080/myapp/book/create page creates a book
and so force, good old scaffolding.
Let's see what about REST.
Official docs say I should use URLs like http://localhost:8080/myapp/books/... for the REST but any attempt to access the app, like this curl -i -H "Accept: application/json" localhost:8080/myapp/books/1 returns 404 with bunch of HTML.
Ok, let's read docs carefully:
The easiest way to create a RESTful API in Grails is to expose a
domain class as a REST resource. This can be done by adding the
grails.rest.Resource transformation to any domain class
No problem, now the Book class heading is
import grails.rest.*
#Resource(uri='/books') class Book {
Now surfing on the http://localhost:8080/myapp/ shows that scaffolding is broken:
http://localhost:8080/myapp/book/index page shows books list
http://localhost:8080/myapp/book/create page shows xml output <?xml version="1.0" encoding="UTF-8"?><book><text /></book>
and so force, bad new xml output.
I'd played with #Resource and "/books"(resources:"book") in URLMappings.groovy but hadn't found any working solution which makes possible scaffolding and RESTfulness work back-to-back. Indeed, I managed to make them work separately.
Update
I'd found the way how to achieve the desired goal. The way I found is:
Mark the Book class with #Resource(uri = "/books").
Remove scaffold controller BookController.
Create dedicated controller with scaffolding for the Book: class HumanBookController {static scaffold = Book}
Now scaffold GUI pages with URLs like http://localhost:8080/myapp/humanBook/index work pretty well. Either json requests are handled well with URLs like http://localhost:8080/myapp/books/1. But it's not elegant to have 2 controllers doing same things for common web and json.
You can do this:
import grails.rest.RestfulController
class BookController extends RestfulController {
static responseFormats = ['html', 'json']
BookController() {
super(Book)
}
}
And then in the UrlMappings.groovy:
"/books"(resources:"book")
"/$controller/$action?/$id?(.${format})?"{
constraints {
// apply constraints here
}
}
No need to add #Resource in the domain.
You can now have /books/1.json or /books/1.html to point to the right places. You might still need to do grails generate-view Book to have the view generated. But although you need to generate the views for html, you keep only single controller and path.
I had the same problems as yours.
That might be a trivial solution and not for every case, but try updating your Grails version.
As for me: Grails 2.3.4 -> Grails 2.3.6 worked.
Hope that help anyone.
I'm currently using Grails 2.4.0, the solution came by doing this:
Controller: BookController { static scaffold = true }
Domain: Book { .... } // WITHOUT #Resource
The result is that you can:
/book.json to get a list JSONized
/book/index to get an HTML standard scaffolding
/book/create html scaffold for a new item
/book/show/1 html scaffold edit item 1
/book/show/1.json JSON for item id: 1
I'ts wicked, i know. I found this and it get me going.
With Grails 2.4.4 I was able to get the scaffolding working with single controller using the following steps:
Added a URL to Resource mapping in UrlMappings.groovy, e.g. "/books"(resources:"book")
Inserted static scaffold = true into the generated controller
I did not verify if the following made a difference, but I also set grails.mime.disable.accept.header.userAgents = [] and grails.mime.use.accept.header = true in Config.groovy (the latter is presumably the new default value).
Both of the scaffolded REST and UI interfaces are working fine with the following tests:
GET /app//1 (passing Accept header)
GET /app//1.json (no Accept header)
POST /app/ (with payload as json or form encoded)
DELETE /app//1
PUT /app//1 (with json payload. form payload updated the object, but sent back 302 redirects)
EDIT
Removed the Resource annotation step and clarified the URL mapping setup
The URI assigned in the URL mapping is not the same as the default URI for the controller. For example, "books" instead of "book". After adding this mapping, the URI for the controller will default to the URI in UrlMapping, but the original URI will continue to work.
The generated controller is a Restful controller because it implements actions aware of requests like:
curl -i -X GET yourDomain:8080/yourApp/books.json
It returns a list of books in json format. (10 books, assuming that you created test data, did you?)
You can append a parameter like:
curl -i -X GET yourDomain:8080/yourApp/books.xml?40
By default you will get the html format. You need to append .json or .xml to get the correct data.
You can to use the Accept header too
curl -i -X GET -H "Accept: application/xml" yourDomain/books/1
returns details of book with id=1 in xml format. Finally
curl -i -X POST -H "Content-Type: application/json" -d "{name: 'Book'}" yourDomain/books
creates a new book and
curl -i -X PUT -H "Content-Type: application/json" -d "{name: 'Book'}" yourDomain/books/1
updates name of book with id=1
All resources need to be exposes through and url. The url is not generated for you, you should write it on UrlMappings file:
"/v1/books"(resources: "book")
Where the first string "/v1/books" is the uri and the second string "book" is the controller name following the grails convention. (The preceding v1 string is because I always put version number to my API URIs)
| GET | /v1/books | Action: index |
| GET | /v1/books/create | Action: create |
| POST | /v1/books | Action: save |
| GET | /v1/books/${id} | Action: show |
| GET | /v1/books/${id}/edit | Action: edit |
| PUT | /v1/books/${id} | Action: update |
| DELETE | /v1/books/${id} | Action: delete |
All that should be required is #Resource annotation with the uri on the Domain class. If you want specific formats (default format is first), also include the formats:
#Resource(uri='/books', formats=['json', 'xml'])
That should be it. If ypu are still having trouble finding your dynamic #Resource endpoint, try running:
grails url-mappings-report
That will give you a nice summary of all urls, including those backed by scaffolded controllers for #Resource domains. I have found that I tend to make silly mistakes when trying to "guess" the URL - using the report output ensures you and grails are in agreement.

How can I add parameters to the url as part of the path in a SOAP UI REST request?

I'm creating a test case for a REST API in soapUI 4.5 where I'm going to use the content from step X to make a new call in step Y.
Ideally I'd create the REST request with some parameters, say A and B, and say that these parameters should be used in the URL:
http://myapi.com/v1/stuff/A/B
Then I'd do a property transfer step and simply set values extracted from step X into A and B.
It looks as if soapUI only lets me create querystring parameters, like this:
http://myapi.com/v1/stuff?ParamA=A&ParamB=B
This works of course, but I'd like to be able to call it both ways, to verify they're both working.
Am I missing something?
I am not a soapui expert by any means, but have just worked through a very similar scenario, so this might help you out.
Part 1: Create a paramatized resource
In my service, I have a resource called stuff:
http://{host}/stuff
I create a child resource with the below values:
Resource Name: Get stuff by ID
Resource Path/Endpoint: {stuffId}
and before clicking ok, click Extract Params - this will populate the Parameters table with an entry like:
Name | Default value | Style | Location
stuffId | stuffId | TEMPLATE | RESOURCE
then click ok. You now have a resource that allows you to dynamically supply an id:
http://{host}/stuff/{id}
you would need to repeat this to create the B parameter above (or you could create A and B as two parameters to the single resource if you never call /stuff/A without also supplying B).
Part 2: Create the test case
Now in the test case, you need to retrieve A, transfer the property, and then send a request to the above resource using the property:
In the test case, create the request to retrieve the response containing A
Right click the testcase and add a Properties step. Add a property to store the value of A.
From the response in the Outline view, right click the value of A and select "Transfer to > Property", select the property you just created and hit ok
Create a new request, using the new paramatized resource created in the first part. In the place of the id, put a reference to the property which is holding the value of A in this format:
${propertyName}
I might have done something wrong, but my test initially fails on the property transfer with "Missing source property". In the Source are of the PropertyTransfer step, I needed to set the property to ResponseAsXml
Hope this helps!