Rails ActionController ignores request headers - ruby-on-rails

I have a simple controller method that logs headers via ActionController's #headers method:
class ThingsController < ActionController::Base
def show
Rails.logger.info headers
render json: {response: 'success'}
end
end
However, when I call this controller method via curl with headers, they are not logged:
curl "http://localhost:3000/things/1” \
-H "access-token XXX" \
-H "token-type Bearer" \
-H "client YYY" \
-H "expiry 1234" \
-H "uid test#test" \
Instead, the following headers are logged:
{"X-Frame-Options"=>"SAMEORIGIN", "X-XSS-Protection"=>"1; mode=block", "X-Content-Type-Options"=>"nosniff"}
I thought my Rails 5 app's CORS policy might be to blame, so I installed the rack-cors gem and configured it in the initializer below. Unfortunately, it did not change the result.
Rails.application.config.middleware.insert_before 0, Rack::Cors do
allow do
origins '*'
resource '*',
headers: :any,
methods: %i(get post put patch delete options head)
end
end

I don't think this has anything to do with CORS.
In Rails 5.2, the ActionController instance method #headers is delegated to the response object.
https://github.com/rails/rails/blob/v5.2.0/actionpack/lib/action_controller/metal.rb#L150
delegate :headers, :status=, :location=, :content_type=,
:status, :location, :content_type, to: "#_response"
To access the request headers, you can do so via the request object. http://api.rubyonrails.org/classes/ActionDispatch/Request.html#method-i-headers
Additionally, your cURL syntax needs to change to delimit the key from the value.
curl "http://localhost:3000/things/1” \
-H "access-token: XXX" \
-H "token-type: Bearer" \
-H "client: YYY" \
-H "expiry: 1234" \
-H "uid: test#test" \
Per the Rack spec (and RFC 3875), headers sent by the client are prefixed with HTTP_ and all occurrences of - are replaced with _.
To log the headers you specified via cURL:
class ThingsController < ActionController::Base
def show
Rails.logger.info {
request.headers.env.slice(
"HTTP_ACCESS_TOKEN",
"HTTP_TOKEN_TYPE",
"HTTP_CLIENT",
"HTTP_EXPIRY",
"HTTP_UID"
)
}
render json: {response: 'success'}
end
end

Related

How to send url-encoded form data using Faraday's post method?

I'm trying to setup Faraday to make requests to a Twilio API. I can make the requests via Postman setting up the key/values in the request body as x-www-form-urlencoded data.
When I try to replicate the cURL I make on Postman in Rails I get an error as if the key/value pairs I send in the payload are not recognized
The following cURL request works in Postman:
curl --location --request POST 'https://api.twilio.com/2010-04-01/Accounts/TOKEN1234/Messages.json' \
--header 'Authorization: Basic AUTH_TOKEN==' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'From=whatsapp:+5491112312312' \
--data-urlencode 'Body=Hello. Your order is on the way' \
--data-urlencode 'To=whatsapp:+541132132121'
My Faraday connector looks like this:
class Twilio::SubAccountConnector
attr_reader :sid, :auth_token, :phone, :api_url
def initialize(account)
#sid = account.twilio_configuration.sid
#auth_token = account.twilio_configuration.auth_token
#phone = account.twilio_configuration.phone
#api_url = "https://api.twilio.com/2010-04-01/Accounts/#{sid}/Messages.json"
end
def form_data
{
from: "whatsapp:+5491112312312",
body: "Hello. Your order is on the way",
to: "whatsapp:+541132132121",
}
end
def send_whatsapp_notification
connector.post do |req|
req.body = form_data
end
end
private
def connector(url = api_url)
Faraday.new(url: url) do |faraday|
faraday.request :basic_auth, sid, auth_token
faraday.request :url_encoded
faraday.response :json
faraday.adapter Faraday.default_adapter # make requests with Net::HTTP
end
end
end
This is the request body in the Faraday request:
request_body=
"{\"From\":\"whatsapp:+5491112312312\",\"Body\":\"Hello. Your order is on the way\",\"To\":\"whatsapp:+541132132121\"}"
I'm getting the following error in the response body, so I suppose I'm doing something wrong with the way I'm sending the payload as the key/value pairs are not recognized.
response_body={"code"=>21604, "message"=>"A 'To' phone number is required.", "more_info"=>"https://www.twilio.com/docs/errors/21604", "status"=>400}>
Am I missing something in the connector method so the payload is encoded correctly?
The issue is that the parameters should start with capital letters. Your Faraday request is otherwise correct, but your form_data method should look like:
def form_data
{
From: "whatsapp:+5491112312312",
Body: "Hello. Your order is on the way",
To: "whatsapp:+541132132121",
}
end

How do I convert this curl command to Ruby rest-client put request?

I have this curl command which I need to covert to PUT request
curl https://example.com/api/v2/students/id.json \
-d '{"student":{"description":{"body":"Adding a new test description"}}}' \
-H "Content-Type: application/json" \
-v -u test#gmail.com:Abcd1234 \
-X PUT
Trial
I tried this PUT, but it doesn't work. It doesn't throw any error, but it does not add the description.
put(
"https://example.com/api/v2/students/id.json",
{:student => {:description => {:body => 'Adding a new test description.'}}},
{ 'Authorization' => "Basic #{authorization_token}" }
)
In your curl example, you provided the body as a (JSON-formatted) string:
curl ... \
-d '{"student":{"description":{"body":"Adding a new test description"}}}' \
...
The direct equivalent in rest-client would also use a (JSON-formatted) string:
put( ...,
'{"student":{"description":{"body":"Adding a new test description"}}}',
...
)
According to the README:
rest-client does not speak JSON natively, so serialize your payload to a string before passing it to rest-client.
You can use the rest-client log to show the actual HTTP request sent, and compare it with what curl sends.
How to debug/display request sent using RestClient
How to display request headers with command line curl
curl https://example.com/api/v2/students/id.json \
-d '{"student":{"description":{"body":"Adding a new test description"}}}' \
-H "Content-Type: application/json" \
-v -u test#gmail.com:Abcd1234 \
-X PUT
use
put(
"https://test%40gmail.com:Abcd1234#example.com/api/v2/students/id.json",
{student: {description: {body: 'Adding a new test description.'}}},
#{'student': {'description': {'body': 'Adding a new test description.'}}},
#{:student => {:description => {:body => 'Adding a new test description.'}}}.to_json,
{content_type: :json, accept: :json}
)

No route matches?

I'm getting a "No route matches" exception in one of my tests (and using curl from the command line) one of my routes (POST /users/confirm). The curl's I've tried are as follows, neither of them work and receive the same exceptions outlined in the below notes:
curl -X POST -H "Content-Type: application/json; version=1" \
-d '{ user: { "token":"1deb36b4e6a7ba6d9203" } }' \
http://localhost:3000/appname/users/confirm
curl -X POST -H "Content-Type: application/json; version=1" \
-d '{ "token":"1deb36b4e6a7ba6d9203" }' \
http://localhost:3000/appname/users/confirm
My test is as follows. I have config.wrap_parameters = true in my /config/application.rb file...
Here is my User UsersController#confirm action along with my strong params. I params.require(:user).permit(:token) as opposed to simply params.permit(:token) because, as stated above, I have config.wrap_parameters = true in my /config/application.rb file...
This is my route entry...
Here is the output from rails routes (app name removed)...
I have config.wrap_parameters = true in my /config/application.rb file...
Oddly enough, if I change my params in my test to post :confirm, params: { token: #user.confirmation_token }, I get the following error instead:
At a loss. Any thoughts?
It turns out I didn't need :token in my route after all. Changed it to this, and all is well:
post '/appname/users/confirm/', to: 'users#confirm', as: 'appname_users_confirm'

Using Rest Client to post a curl in rails

I want to traduce this curl into rest client sintax:
curl https://sandbox-api.openpay.mx/v1/mzdtln0bmtms6o3kck8f/customers/ag4nktpdzebjiye1tlze/cards \
-u sk_e568c42a6c384b7ab02cd47d2e407cab: \
-H "Content-type: application/json" \
-X POST -d '{
"token_id":"tokgslwpdcrkhlgxqi9a",
"device_session_id":"8VIoXj0hN5dswYHQ9X1mVCiB72M7FY9o"
}'
The hash I already have it in a variable and the keys or id´s are static so I paste them wherever I need to. This is what I´ve done so far but it doesn't work:
response_hash=RestClient.post "https://sandbox-api.openpay.mx/v1/mdxnu1gfjwib8cmw1c7d/customers/#{current_user.customer_id}/cards \
-u sk_083fee2c29d94fad85d92c46cec26b5a:",
{params: request_hash},
content_type: :json, accept: :json
Can someone help me traduce it?
Try this:
begin
RestClient.post(
"https://sk_e568c42a6c384b7ab02cd47d2e407cab:#sandbox-api.openpay.mx/v1/mzdtln0bmtms6o3kck8f/customers/ag4nktpdzebjiye1tlze/cards",
{ token_id: 'tokgslwpdcrkhlgxqi9a', device_session_id: '8VIoXj0hN5dswYHQ9X1mVCiB72M7FY9o' }.to_json,
{ content_type: :json, accept: :json }
)
rescue RestClient::ExceptionWithResponse => e
# do something with e.response.body
end

Devise with Simple Token Authentication

i am using the following gem and devise now, since devise remove the support for token authentication.
https://github.com/gonzalo-bulnes/simple_token_authentication
What i am missing here is that, I have all the configuration setup but when i hit http://localhost:3000/user/sign_in.json using the RestConsole Tester on Google.
I am getting the following error:
ActionController::InvalidAuthenticityToken at /users/sign_in.json
ActionController::InvalidAuthenticityToken
actionpack (4.0.2)
lib/action_controller/metal/request_forgery_protection.rb, line 163
def initialize(controller)
#controller = controller
end
def handle_unverified_request
raise ActionController::InvalidAuthenticityToken
end
end
end
protected
Any ideas?
Your POST is failing a CSRF token check. You can validate this is the case by temporarily removing protect_from_forgery from your application_controller.rb which should make this work.
This article provides a solution for overriding that check on a specific controller, which should be safe for login requests.
You could try this
Authenticate:
curl -H 'Content-Type: application/json' \
-H 'Accept: application/json' \
-X POST http://localhost:3000/users/sign_in \
-d '{"user" : { "email" : "test#example.com", "password" : "password"}}' \
-c cookie
Show:
curl -H 'Content-Type: application/json' \
-H 'Accept: application/json' \
-X GET http://localhost:3000/pages/1.xml \
-b cookie
That works for me.

Resources