Ruby Rest-client keeps correcting the uri - ruby-on-rails

I'm using rest-client to make a post request to a certain address. Unfortunately rest-client keeps correcting the web adres from 'https' to 'http'. Which then gives back an error.
I already looked at the documentation whether this maybe was a setting for the gem. Anyone knows how I can 'force' rest-client to access the desired address.
Thx in advance!
used code is:
uri = 'https://sandbox.api.online.unit4.nl/V19/OAuth/Token'
payload = {
code: params[:code],
client_id: '#{#client_id}',
client_secret: '#{#client_secret}',
redirect_uri: '#{#client_redirect_url}',
grant_type: 'authorization_code'
}
response = RestClient::Request.execute(method: :post, url: uri, headers: {params: payload})
curl:
> GET /V19/OAuth/Token HTTP/1.1
> Host: sandbox.api.online.unit4.nl
> User-Agent: curl/7.54.0
> Accept: */*
>
< HTTP/1.1 400 Bad Request
< content-length: 27
< content-type: application/json; charset=utf-8
< date: Wed, 06 Dec 2017 15:21:44 GMT
< p3p: CP="NON CUR OTPi OUR NOR UNI"
< server: Microsoft-IIS/7.5
< x-aspnetmvc-version: 5.2
< cache-control: no-cache, no-store, max-age=0, must-revalidate
< access-control-allow-origin: *
< x-powered-by: ASP.NET
< x-aspnet-version: 4.0.30319
< pragma: no-cache
< Set-Cookie: PD_STATEFUL_88eb7504-dfe9-11e2-8624-005056af4a32=sandbox.api.online.unit4.nl; Path=/
< Set-Cookie: LB_online_unit4=1493375404.20480.0000; path=/

Could be that your variables aren't getting interpolated. With single quotes '#{#variable}' doesn't work. Try switching the single quotes to double quotes ('' => ""). What is happening is that instead of sending the actual client id and secret, you are sending the string #{#client_id}.
Try
uri = 'https://sandbox.api.online.unit4.nl/V19/OAuth/Token'
payload = {
code: params[:code],
client_id: #client_id,
client_secret: #client_secret,
redirect_uri: #client_redirect_url,
grant_type: 'authorization_code'
}
response = RestClient::Request.execute(method: :post, url: uri, headers: {params: payload})

Related

Axios not sending headers to rails controllers

I am on Rails 5.1.7 with a react frontend with react-rails gem
My problem looks like what is explained here just that my react components are server rendered so I can not access data from the client from the component.
So I have created the following file:
import axios from 'axios'
export default function() {
const csrfToken = document.querySelector("meta[name=csrf-token]").content;
axios.defaults.headers.common['X-CSRF-Token'] = csrfTokens;
}
and I import in in application.js as:
import setupCSRFToken from '../setupCSRFToken'
and then calling the exported function.
The problem is that checking the headers the controller does not receive anything:
(byebug) request.headers['X-CSRF-Token']
nil
so the problem must be related with how axios is configurated. I did install it with:
yarn add axios
in the developer console I get:
xhr.js:179 POST http://localhost:3000/es/roomlist_reorder 422 (Unprocessable Entity)
dispatchXhrRequest # xhr.js:179
xhrAdapter # xhr.js:20
dispatchRequest # dispatchRequest.js:40
Promise.then (async)
request # Axios.js:64
Axios.<computed> # Axios.js:88
wrap # bind.js:11
RoomList._this.getOrder # roomlist.jsx:33
RoomList._this.filterRooms # roomlist.jsx:47
RoomList._this.handleOrderBy # roomlist.jsx:51
callCallback # react-dom.development.js:191
invokeGuardedCallbackDev # react-dom.development.js:240
invokeGuardedCallback # react-dom.development.js:293
invokeGuardedCallbackAndCatchFirstError # react-dom.development.js:308
executeDispatch # react-dom.development.js:393
executeDispatchesInOrder # react-dom.development.js:418
executeDispatchesAndRelease # react-dom.development.js:3303
executeDispatchesAndReleaseTopLevel # react-dom.development.js:3312
forEachAccumulated # react-dom.development.js:3284
runEventsInBatch # react-dom.development.js:3329
runExtractedPluginEventsInBatch # react-dom.development.js:3539
handleTopLevel # react-dom.development.js:3583
batchedEventUpdates$1 # react-dom.development.js:21731
batchedEventUpdates # react-dom.development.js:800
dispatchEventForLegacyPluginEventSystem # react-dom.development.js:3593
attemptToDispatchEvent # react-dom.development.js:4313
dispatchEvent # react-dom.development.js:4234
unstable_runWithPriority # scheduler.development.js:661
runWithPriority$1 # react-dom.development.js:11079
discreteUpdates$1 # react-dom.development.js:21748
discreteUpdates # react-dom.development.js:813
dispatchDiscreteEvent # react-dom.development.js:4213
roomlist.jsx:40 Error: Request failed with status code 422
at createError (createError.js:17)
at settle (settle.js:19)
at XMLHttpRequest.handleLoad (xhr.js:69)
headers:
Request URL: http://localhost:3000/es/roomlist_reorder
Request Method: POST
Status Code: 422 Unprocessable Entity
Remote Address: [::1]:3000
Referrer Policy: strict-origin-when-cross-origin
Content-Type: text/html; charset=UTF-8
Transfer-Encoding: chunked
X-Request-Id: 2de02308-5eff-4e68-8a07-f39dfdf
X-Runtime: 0.145234
X-Web-Console-Mount-Point: /__web_console
X-Web-Console-Session-Id: 57baf1f81457b91c49fa8
Accept: application/json, text/plain, */*
Accept-Encoding: gzip, deflate, br
Accept-Language: en-GB,en-US;q=0.9,en;q=0.8
Connection: keep-alive
Content-Length: 24
Content-Type: application/json;charset=UTF-8
....
request headers:
:authority: m.stripe.com
:method: POST
:path: /6
:scheme: https
accept: */*
accept-encoding: gzip, deflate, br
accept-language: en-GB,en-US;q=0.9,en;q=0.8
content-length: 656
content-type: text/plain;charset=UTF-8
cookie: private_machine_identifier=tKQmcfYNS9%BJ86cfKvXcvBodWTYUWwUkE%3D; m=306ba65-c03-4b-8257-2b6d9bde3d44;
session=sess_I4LBSZAr2S0DM8i
origin: https://m.stripe.network
referer: https://m.stripe.network/
sec-ch-ua: "\\Not;A\"Brand";v="99", "Google Chrome";v="85", "Chromium";v="85"
sec-ch-ua-mobile: ?0
sec-fetch-dest: empty
sec-fetch-mode: cors
sec-fetch-site: cross-site

create_session doesn't set SET-COOKIE header

i was under the assumption that create_session if the endpoint.ex was configured to use the cookie store, would set the SET-COOKIE response header
# The session will be stored in the cookie and signed,
# this means its contents can be read but not tampered with.
# Set :encryption_salt if you would also like to encrypt it.
plug Plug.Session,
log: :debug,
store: :cookie,
key: "some_key",
signing_salt: "some_salt"
this is my authentication controller ( just a part of it)
def callback(%{ assigns: %{ ueberauth_auth: auth } } = conn, params) do
params = build_params(auth)
user = find_or_create_user params
conn = put_session(conn, :current_user, user)
IO.inspect conn.resp_headers
IO.inspect get_session(conn, :current_user)
render conn, "index.html"
#Helpers.redirect!(conn, "/")
end
def build_params(auth) do
%{email: auth.info.email, github_token: auth.credentials.token, github_user: auth.info.nickname}
end
def find_or_create_user(params) do
case DBRepo.get_by(User, email: params.email) do
nil ->
User.changeset(%User{}, params)
|> DBRepo.insert
results ->
results
end
end
IO.inspect conn.resp_headers
returns
[{"cache-control", "max-age=0, private, must-revalidate"}, {"x-request-id", "vh8l2deodne1k2iloa4c3e4qdpmh857n"}, {"x-frame-options", "SAMEORIGIN"}, {"x-xss-protection", "1; mode=block"}, {"x-content-type-options", "nosniff"}]
IO.inspect get_session(conn, :current_user)
returns the user as expected
You don't see the session cookie in resp_headers because Plug.Session sets that cookie just before the response is actually sent, using Plug.Conn.register_before_send. If you make a request using any HTTP client (browser, curl, etc), you'll see the Set-Cookie header.
defmodule MyApp.PageController do
use MyApp.Web, :controller
def index(conn, _params) do
conn
|> put_session(:foo, :bar)
|> text("")
end
end
$ curl -I localhost:4000
HTTP/1.1 200 OK
server: Cowboy
date: Mon, 20 Feb 2017 08:57:36 GMT
content-length: 0
set-cookie: _my_app_key=SFMyNTY.g3QAAAABbQAAAANmb29kAANiYXI.F0G6lsgPxsYjq97tonLy1gRkOBUVcfwqKZdozgGRG-c; path=/; HttpOnly
content-type: text/plain; charset=utf-8
cache-control: max-age=0, private, must-revalidate
x-request-id: uoplksup9ndakf5sdr5shpjsjhvu849v
x-frame-options: SAMEORIGIN
x-xss-protection: 1; mode=block
x-content-type-options: nosniff

Why am I unable to sign out using devise_token_auth and curl?

I'm using rails-api with devise_token_auth for authentication. I am able to sign in without issue via:
curl -i http://localhost:3000/api/v1/auth/sign_in -F email="user#nowhere.org" -F password="password"
However, sign out fails with a 404 and the error "User was not found or was not logged in." via:
curl -X DELETE -i http://localhost:3000/api/v1/auth/sign_out
I have tried variations of this command with multiple combinations of parameters and header values, such as:
curl -X DELETE -i http://localhost:3000/api/v1/auth/sign_out -F email="user#nowhere.org" -H Access-Token="Ae1yaTYLkSAgdhz3LtPAZg" -H Client="9AmYF6NS8tP6EOD5nPSuxw" -H Expiry="1443073493" -H Uid="user#nowhere.org" -H Token-Type="Bearer"
To no avail. A similarly constructed RSpec test also fails with the same response and error, and the logs indicate the request was processed via DeviseTokenAuth::SessionsController#destroy as JSON.
Of course, I'm not actually using curl for authentication; just verification of the request structure before writing the relevant code.
Answering my own question, I wasn't returning certain sign_in response header values correctly with the sign_out request.
I found a related post which pointed out some of the critical headers. The trick is to capture the access-token, client, and uid header values from the sign_in response, then include them as parameters in the sign_out request:
curl -i -X DELETE http://localhost:3000/api/v1/auth/sign_out -F access-token="Ae1yaTYLkSAgdhz3LtPAZg" -F client="9AmYF6NS8tP6EOD5nPSuxw" -F uid="user#nowhere.org"
Here's an RSpec test to illustrate and verify:
require 'rails_helper'
RSpec.describe "Authentication", type: :request do
it "logs a user out" do
user = User.create!(
name: "Some Dude",
email: "user#nowhere.org",
password: "password",
confirmed_at: Date.today
)
# initial sign in to generate a token and response
post api_v1_user_session_path, {
email: user.email,
password: user.password
}
expect(user.reload.tokens.count).to eq 1
# sign out request using header values from sign in response
delete destroy_api_v1_user_session_path, {
"access-token": response.header["access-token"],
client: response.header["client"],
uid: response.header["uid"]
}
response_body = JSON.load(response.body)
expect(response_body["errors"]).to be_blank
expect(response.status).to eq 200
# user token should be deleted following sign out
expect(user.reload.tokens.count).to eq 0
end
end
In details, do the following steps:
Step 1:
curl -v -H 'Content-Type: application/json' -H 'Accept: application/json' -X POST http://localhost:3000/api/v1/auth/sign_in -d "{\"email\":\"user#example.com\",\"password\":\"password\"}"
You'll get a response like this:
* Trying ::1...
* Connected to localhost (::1) port 3000 (#0)
> POST /api/v1/auth/sign_in HTTP/1.1
> Host: localhost:3000
> User-Agent: curl/7.43.0
> Content-Type: application/json
> Accept: application/json
> Content-Length: 50
>
* upload completely sent off: 50 out of 50 bytes
< HTTP/1.1 200 OK
< X-Frame-Options: SAMEORIGIN
< X-Xss-Protection: 1; mode=block
< X-Content-Type-Options: nosniff
< Access-Token: BqXcWQi0-9faLyxP1LnUKw
< Token-Type: Bearer
< Client: dYSqVgM9VT6fV9Y5MFWpJQ
< Expiry: 1465679853
< Uid: user#example.com
< Content-Type: application/json; charset=utf-8
< Etag: W/"9ad6a23f014a744a7ec83b4e0e9d27aa"
< Cache-Control: max-age=0, private, must-revalidate
< X-Request-Id: 6566bd38-1ad7-491a-a1ab-e41458b9b704
< X-Runtime: 0.184807
< Server: WEBrick/1.3.1 (Ruby/2.3.0/2015-12-25)
< Date: Sat, 28 May 2016 21:17:33 GMT
< Content-Length: 135
< Connection: Keep-Alive
<
* Connection #0 to host localhost left intact
{"data":{"id":6,"provider":"email","uid":"user#example.com","name":"testuser","nickname":null,"image":null,"email":"user#example.com"}}%
Step 2:
Now, you want to sign the user out.
curl -i -X DELETE http://localhost:3000/api/v1/auth/sign_out -F access-token="BqXcWQi0-9faLyxP1LnUKw" -F client="dYSqVgM9VT6fV9Y5MFWpJQ" -F uid="user#example.com"
You'll get a response like this:
HTTP/1.1 200 OK
X-Frame-Options: SAMEORIGIN
X-Xss-Protection: 1; mode=block
X-Content-Type-Options: nosniff
Content-Type: application/json; charset=utf-8
Etag: W/"7363e85fe9edee6f053a4b319588c086"
Cache-Control: max-age=0, private, must-revalidate
X-Request-Id: 8f7a297a-6a72-4c9d-a210-48c29fb4bfe0
X-Runtime: 0.095060
Server: WEBrick/1.3.1 (Ruby/2.3.0/2015-12-25)
Date: Sat, 28 May 2016 21:19:18 GMT
Content-Length: 16
Connection: Keep-Alive
{"success":true}%
In step 2, I've added the access-token and client as per the response that we received in step 1 (Access-Token: BqXcWQi0-9faLyxP1LnUKw and Client: dYSqVgM9VT6fV9Y5MFWpJQ).
That's it! :)
I took the help of #user3006381's answer! All credits to him.

rails won't send_data as file

I'm having problems with Rails method: send_data
Here's my action:
def export
send_data(current_user.contacts.to_csv,
type: 'text/csv; charset=utf-8; header=present',
disposition: 'attachment; filename=contacts.csv'
)
end
This will not promt for a download, it just render the result on the screen. I've tried both pow and thin servers.
I can't figure out what I'm doing wrong?
I'm using rails 4.0.0.beta
EDIT:
CURL headers:
< HTTP/1.1 200 OK
< X-Frame-Options: SAMEORIGIN
< X-XSS-Protection: 1; mode=block
< X-Content-Type-Options: nosniff
< X-UA-Compatible: chrome=1
< X-XHR-Current-Location: /contacts/export
< Content-Disposition: attachment; filename=contacts.csv
< Content-Transfer-Encoding: binary
< Content-Type: text/csv; charset=utf-8; header=present
< Cache-Control: private
< ETag: "48d3d8bd1c8d25cafb82ab705e4875ab"
< Set-Cookie: request_method=GET; path=/
< X-Request-Id: c2588883-f3f9-4f68-8a8c-0de758c47288
< X-Runtime: 0.185206
< Connection: close
< Server: thin 1.5.0 codename Knife
The answers here, are for turbolinks classic.
There is a newer notation on newer versions of turbolinks:
Disabled
https://github.com/turbolinks/turbolinks#disabling-turbolinks-on-specific-links
I figured it out.
It was turbolinks that was messing it all up. I added data-no-turbolink to the export link and now it works as expected.
send_data has an option hash, so type, disposition and filename need to be set in a hash:
def export
send_data(current_user.contacts.to_csv,
type: 'text/csv', disposition: 'attachment', filename: 'contacts.csv')
end

OAuth with Digg API

I'm attempting to get Rails to play nice with the Digg API's OAuth. I'm using the oauth gem (ruby one, not the rails one).
My code looks approximately like this:
#consumer = OAuth::Consumer.new(API_KEY, API_SECRET,
:scheme => :header,
:http_method => :post,
:oauth_callback => "http://locahost:3000",
:request_token_url => 'http://services.digg.com/1.0/endpoint?method=oauth.getRequestToken',
:access_token_url => 'http://services.digg.com/1.0/endpoint?method=oauth.getAccessToken',
:authorize_url => 'http://digg.com/oauth/authorize')
#request_token = DiggController.consumer.get_request_token({
:oauth_callback => "http://xx.xxx.xxx.x:3000/digg/callback"
}, {
'Content-Type' => 'application/x-www-form-urlencoded'
})
session[:request_token] = #request_token.token
session[:request_token_secret] = #request_token.secret
redirect_to #request_token.authorize_url
Which is by-the-book in terms of what the gem documentation gave me. However, Digg spits a "400 Bad Request" error back at me when #consumer.get_request_token is called. I can't figure out what I'm doing wrong. Any ideas?
Edit: Code updated and Wireshark output added. My error is now "401 Authorization Required".
Output from Wireshark:
POST /1.0/endpoint?method=oauth.getRequestToken HTTP/1.1
Accept: */*
Connection: close
User-Agent: OAuth gem v0.3.6
Content-Type: application/x-www-form-urlencoded
Authorization: OAuth oauth_nonce="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
oauth_callback="http%3A%2F%2Fxx.xxx.xxx.x%3A3000%2Fdigg%2Fcallback",
oauth_signature_method="HMAC-SHA1",
oauth_timestamp="1268687137",
oauth_consumer_key="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
oauth_signature="xxx%2Bxxxxxxxxxxxxxxx%2Fxxxxxxx%3D", oauth_version="1.0"
Content-Length: 48
Host: services.digg.com
Content-Type=application%2fx-www-form-urlencoded
HTTP/1.1 401 Authorization Required
Date: Mon, 15 Mar 2010 21:05:37 GMT
Server: Apache
X-Powered-By: PHP/5.2.9-digg8
Cache-control: private
X-RateLimit-Current: 1
X-RateLimit-Max: 1000
X-RateLimit-Reset: 3600
X-Digg-Api-Version: 1.0
Accept-Ranges: bytes
Content-Length: 111
Keep-Alive: timeout=5, max=9998
Connection: Keep-Alive
Content-Type: text/xml;charset=utf-8
<?xml version="1.0" encoding="UTF-8"?>
<error code="5001" message="Invalid
signature" timestamp="1268687137"/>
Incidentally, the callback parameter should not be localhost:3000 but rather your public IP address (making sure to also open up port 3000 for external connections in your computer and/or router firewall(s)), or be left to the default (out-of-band.)
Examine the contents of the OAuth::Unauthorized exception which gets thrown (or use a sniffer such as tcpdump or Wireshark) to get additional details about the HTTP 400 error (they are probably having issues with some of your parameters.)

Resources