getting bad request from ruby on rails ssl post - ruby-on-rails-3

Looked at: Escaping parameters in set_form_data POST, and Ruby on Rails HTTPS Post Bad Request
def send_request(params)
host = "https://hc.mercurydev.net"
uri = URI.parse(host)
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
xml = build_xml_for_checkout(params)
http.start do |http|
req = Net::HTTP::Post.new('http://www.mercurypay.com/InitializePayment')
header = {'Host' => 'hc.mercurydev.net', 'Content-Type' => 'text/xml; charset=utf-8', 'Content-Length' => 'length', 'SOAPAction' => 'http://www.mercurypay.com/InitializePayment'}
req.set_form_data(header, xml)
response = http.request(req)
end
end
This is the first time I have had to build my own post request in ruby, I am sure that I am missing something simple, but what?
-- I have confirmation that the xml is 100% good, so it has to be something in my header or in how I'm building the request.
Edit: After looking at ruby-api-doc: I came up with this:
uri = URI.parse(host)
Net::HTTP.start(uri.hostname, uri.port,
:use_ssl => uri.scheme == 'https').start do |http|
req = Net::HTTP::Post.new uri.path
req.body = xml
req.set_form_data(header)
res = http.request req
end
Which returns (even if I restart my server) that I have an open HTTP session.

So ended up with this:
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
req = Net::HTTP::Post.new(uri.request_uri)
req.body = xml.to_s
req.initialize_http_header(header)
response = http.request(req)
The key that I was missing was the initialize_http_header() once I got that in there the soap api accepted my submission and then is was just an issue of making sure my syntax was correct.

Related

Why my request works with postman but not with vue.js axios?

I've made a back using Flask, and a front using vue.js,
Why I make the request with postman it returns what I want but not with axios ...
for exemple :
this.$axios
.post('http://127.0.0.1:5000/getUserDataByMail', { mail: 'test#test.com' })
.then(response => {
console.log('this.userData')
console.log(response.data)
this.userData = response
}
)
Is treated by :
#app.route('/getUserDataByMail', methods = ['GET', 'POST'])
def getUserDataByMail():
args = request.args
mail = args['mail']
return jsonify(mail)
cur = mysql.connection.cursor()
dataCur = cur.execute('select * from userdata where email like "' + mail + '"')
if dataCur > 0:
data = cur.fetchall()
cur.close()
return jsonify(data)
cur.close()
But this result in an error 400 ...
POSThttp://127.0.0.1:5000/getUserDataByMail [HTTP/1.0 400 BAD REQUEST 4ms]
Uncaught (in promise) Error: Request failed with status code 400
Help me I'm losing my mind ! (:
Axios by default posts an application/json request body.
To read JSON payloads in Flask, you use request.json
content = request.json
mail = content["mail"]
I can only assume Postman works because you were posting an application/x-www-form-urlencoded request body or using URL query parameters.
To match what you're doing in Axios, make sure you post JSON

Cookies not stored with React native and Flask/ Flask jwt-extended

I am using Flask and flask-jwt-extended in order to do the authentication on my server.
When I use Postman, all my cookies are setup correctly. However, when I use a browser and react-native, none of the cookies are stored.
Environment:
Flask Backend: 127.0.0.1:5000
React-Native Front: 127.0.0.1:19006
Here is my Flask config:
JWT_SECRET_KEY = os.getenv("JWT_SECRET_KEY", 'local-secret')
JWT_TOKEN_LOCATION = ['cookies']
JWT_ACCESS_TOKEN_EXPIRES = datetime.timedelta(seconds=1800)
JWT_COOKIE_SECURE = False
CORS_HEADERS = "Content-Type"
JWT_REFRESH_TOKEN_EXPIRES = datetime.timedelta(days=15)
JWT_COOKIE_CSRF_PROTECT = True # set_refresh_cookies() will now also set the non-httponly CSRF cookies
JWT_CSRF_CHECK_FORM = True
JWT_ACCESS_CSRF_HEADER_NAME = "X-CSRF-TOKEN-ACCESS"
JWT_REFRESH_CSRF_HEADER_NAME = "X-CSRF-TOKEN-REFRESH"
SSL_REDIRECT = False
jwt = JWTManager()
app = Flask(__name__)
app.config.from_object(APP_CONFIG[CONFIG_ENV])
cors = CORS(app, resources={r"/*": {"origins": "http://127.0.0.1:19006"}}, supports_credentials=True)
APP_CONFIG[CONFIG_ENV].init_app(app)
jwt.init_app(app)
Here is how I store cookies (classic, and working with postman):
access_token = create_access_token(identity = token_identity)
refresh_token = create_refresh_token(identity = token_identity)
resp = jsonify({"access_token": access_token, "refresh_token": refresh_token})
set_access_cookies(resp, access_token)
set_refresh_cookies(resp, refresh_token)
However, whenever I am using the browser (127.0.0.1:19006) with react-native to make requests, cookies are never stored.
Any ideas where the problem can come from?
After many hours of struggle, the solution was simpler than I thought:
In the front code (react-native), I had to add:
credentials: "include"
in my fetch requests.
See: https://developers.google.com/web/updates/2015/03/introduction-to-fetch
You are likely running into a web browser security mechanism called the same origin policy, where it is treating those two urls and two different domains and thus not saving the cookies. You could use a webpack proxy/apache/nginx to serve both the api and the frontend from the same domain, or possibly look into a CORS setting to allow this setup to work.
I also had this problem. This is what I did:
Front-end:
Add credentials: "include" when doing fetch requests:
fetch(domain + "/createAccount", {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
},
credentials: 'include',
body: JSON.stringify(inputData),
})
.....
Backend:
Ensure that you set Access-Control-Allow-Origin to your url http://localhost:3000, Access-Control-Allow-Credentials to True and samesite to None and secure to True.
resp = Response(
.......
)
resp.headers.add('Access-Control-Allow-Origin', 'http://localhost:3000')
resp.headers.add('Access-Control-Allow-Credentials', 'true')
resp.set_cookie('token', value=encoded_jwt, httponly= True, expires = TOKEN_EXPIRY_DATE, samesite='None', secure=True)

Google app api with freshdesk api error

On using the freshdesk api from google app script getting an error
"{"code":"invalid_content_type","message":"Content-Type header is set to . It should be set to application/json"}"
The code used for this
function hd_getTickets(){//using v2
var API_KEY = 'xxxxxxxxxxxxxx';
var headers = {'Content-type': 'application/json','Authorization': 'Basic ' + Utilities.base64Encode(API_KEY + ':X') };
var data = { "query":"\"priority:3\"" };
var ENDPOINT = 'https://xxxxxxx.freshdesk.com/api/v2';
var url = ENDPOINT + '/search/tickets';
var options = { 'method': 'get', muteHttpExceptions: true,'headers': headers,'payload' : JSON.stringify(data)};
var response = UrlFetchApp.fetch(url, options);
}
Changing the endpoint and removing the payload from options work so assuming authorization and header is fine
var url = ENDPOINT + '/tickets';
var options = {'method':'get','headers':headers, muteHttpExceptions: true};
Using postman this works
https://xxxxxxx.freshdesk.com/api/v2/search/tickets?query="priority:3"
with header set as
Content-Type:application/json
Authorization:Basic xxxxxxxxxxxxxxxx
You are sending a GET request to the API with the Payload variable in the options.
In my opinion payloads are used for POST requests.
Construct the URL with the query parameters and send it without the Payload.
Example: 'https://domain.freshdesk.com/api/v2/search/tickets?query="priority:3"'
See details here: HTTP GET with request body
Freshdesk API Doc: https://developers.freshdesk.com/api/#filter_tickets
Two issues found
1) web site does not support payload based get.
2) google apps doesn't support special characters in url.
Adding parameters to the original url and encoding the double quotes works.
var ENDPOINT = 'https://xxxxxx.freshdesk.com/api/v2';
var query ='query='+encodeURIComponent("\"priority")+":1"+encodeURIComponent("\"");
var url = ENDPOINT + '/search/tickets?'+query;
var options = {'method': 'get', muteHttpExceptions: true,'headers': headers};
var response = UrlFetchApp.fetch(url, options);

Rspec for REST API call

Im trying to implement rspec for a http call... But I have not succeeded so far..
http = Net::HTTP.new("secured site url", "443")
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
response = http.get("/query params",initheader = {'Accept' =>'application/xml'})
return response
I would need an rspec for this..Though Im new to this, I tried many ways but it says expected: 1 time received: 0 times
Here is all what I have written :
it "should be success" do
#mock_http = mock("http")
#mock_http.should_receive(:new).with("secured site url")
end
Please correct me if Im wrong.. Any help is appreciated! Thanks
Of course you have to activate the method in which the new statement is called so your code should look something like:
it "should be success" do
#mock_http = mock("http")
Net::HTTP.should_receive(:new).with("secured site url", "443")
some_method
end
def some_method
http = Net::HTTP.new("secured site url", "443")
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
response = http.get("/query params",initheader = {'Accept' =>'application/xml'})
return response
end

Posting a gist to github.com in ruby not working

I am trying to create a new gist on github.com by posting the the URL. I have done this in C# and it works fine, but when I try to replicate in ruby on rails the post never seems to work I am always just redirected to the gists/new URL which indicates that the post was not accepted. I figure I am just missing something fundamental in ruby.
require 'net/https'
require 'open-uri'
url = URI.parse('https://gist.github.com/gists')
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
req = Net::HTTP::Post.new(url.path)
req.form_data = "file_name[gistfile1]=testclip.txt&description=Test Clip&file_contents[gistfile1]=This is my test clip&login=uname&token=secret"
http.start{|h| h.request(req)}['Location']
I'm out on a limb here, but I'm guessing it has to do with the SSL verify mode. You'll either need to keep from verifying:
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
or give it something to verify against:
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_PEER
http.cert = OpenSSL::X509::Certificate.new(ca_cert)
Take a look at the ca_cert method at Defunkt's Gist gem for more info (you'll need a bundle).