rack-cors fails fine uploader preflight - ruby-on-rails

I'm trying to use fine uploader from my react frontend, to upload to my rails 5 backend.
rack-cors is second in my middlewares list:
use Webpacker::DevServerProxy
use Rack::Cors
use Rack::Sendfile
use ActionDispatch::Static
use ActionDispatch::Executor
use ActiveSupport::Cache::Strategy::LocalCache::Middleware
use Rack::Runtime
use ActionDispatch::RequestId
use ActionDispatch::RemoteIp
use Rails::Rack::Logger
use ActionDispatch::ShowExceptions
use WebConsole::Middleware
use ActionDispatch::DebugExceptions
use ActionDispatch::Reloader
use ActionDispatch::Callbacks
use ActiveRecord::Migration::CheckPending
use Rack::Head
use Rack::ConditionalGet
use Rack::ETag
use Warden::Manager
run Project::Application.routes
When fine uploader tries to upload an image, I get in the console:
Failed to load http://localhost:5000/item/1374/image: Response to preflight
request doesn't pass access control check: No 'Access-Control-Allow-Origin'
header is present on the requested resource. Origin 'http://lvh.me:3000' is
therefore not allowed access.
I can see the preflight (options) http request, with the following data:
GENERAL
Request URL:http://localhost:5000/item/1374/image
Request Method:OPTIONS
Status Code:200 OK
Remote Address:127.0.0.1:5000
Referrer Policy:no-referrer-when-downgrade
RESPONSE HEADERS:
HTTP/1.1 200 OK
Content-Type: text/plain
Transfer-Encoding: chunked
REQUEST HEADERS:
OPTIONS /item/1374/image HTTP/1.1
Host: localhost:5000
Connection: keep-alive
Pragma: no-cache
Cache-Control: no-cache
Access-Control-Request-Method: update
Origin: http://lvh.me:3000
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.186 Safari/537.36
Access-Control-Request-Headers: cache-control,x-requested-with
Accept: */*
DNT: 1
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9,it;q=0.8
this is the cors debug log of the same call:
{"Access-Control-Allow-Origin"=>"http://lvh.me:3000", "Access-Control-Allow-Methods"=>"GET, POST, PUT, PATCH, DELETE, OPTIONS, HEAD", "Access-Control-Expose-Headers"=>"access-token, expiry, token-type, uid, client, Access-Control-Allow-Origin", "Access-Control-Max-Age"=>"1728000", "Access-Control-Allow-Credentials"=>"true"}
Incoming Headers:
Origin: http://lvh.me:3000
Access-Control-Request-Method: update
Access-Control-Request-Headers: cache-control,x-requested-with
Preflight Headers:
Content-Type: text/plain
my config/initializers/cors.rb looks like:
Rails.application.config.middleware.insert_before 0, Rack::Cors, debug: true, logger: (-> { Rails.logger }) do
allow do
origins 'localhost:3000',
'http://localhost:3000',
'127.0.0.1:3000',
/\Ahttp:\/\/192\.168\.0\.\d{1,3}(:\d+)?\z/,
'http://lvh.me:3000'
resource '*',
headers: :any,
expose: %w[access-token expiry token-type uid client Access-Control-Allow-Origin],
credentials: true,
methods: %i[get post put patch delete options head]
end
end
I also tried with origin '*' and credentials: false, but got the same result.
I don't understand where the problem could be..

my fault, I was requesting an update, but was allowing only put and patch.
I changed the request to a put, and now I'm one step closer to walhalla.

Related

Cloudfront CORS blocking fonts

All the assets except for the fonts load nicely,
and whenever I go to my site I keep getting messages like this one:
Access to Font at
'https://xxxxxxxxxx.cloudfront.net/assets/fontawesome-webfont.woff2'
from origin 'https://example.com' has been blocked by CORS policy: No
'Access-Control-Allow-Origin' header is present on the requested
resource. Origin 'https://example.com' is therefore not allowed
access.
As you can see CURL command indicates that no headers are present.
curl -H "Origin: https://example.com" -I https://xxxxxxxxx.cloudfront.net/assets/fontawesome-webfont.woff2
HTTP/1.1 200 OK
Content-Length: 77160
Connection: keep-alive
Status: 200 OK
X-Rack-Cache: stale, valid, store
Cache-Control: public, must-revalidate
Date: Fri, 14 Apr 2017 08:01:26 GMT
X-Content-Digest: d6f48cba7d076fb6f2fd6ba993a75b9dc1ecbf0c
ETag: "2adefcbc041e7d18fcf2d417879dc5a09997aa64d675b7a3c4b6ce33da13f3fe"
X-Runtime: 0.366713
X-Request-Id: 87c9d883-e443-4756-86f9-66b40ed573f6
X-Powered-By: Phusion Passenger Enterprise 5.1.2
Server: nginx/1.10.2 + Phusion Passenger 5.1.2
Via: 1.1 vegur, 1.1 f0eecbf6390179377707b707ebaa1e8b.cloudfront.net (CloudFront)
Age: 86645
Vary: Accept-Encoding
X-Cache: Hit from cloudfront
X-Amz-Cf-Id: FNjQGvROcAdqT6u6PaN3OgEE34mnSsixHNm6WqzWq2boWWYYzVmZPw==
Here's AWS Origin configuration
And this is the behaviour that includes the above origin:
I even included rack-cors to the initializers within the project for the purpose but with no luck.
if defined? Rack::Cors
Rails.configuration.middleware.insert_before 0, Rack::Cors do
allow do
origins '*'
resource '/assets/*', headers: :any, methods: [:get, :post, :delete, :put, :patch, :options, :head], max_age: 0
end
end
end
Why is this so and how can I fix it? Thank you in advance.
As of version 5.0, Rails allows for setting custom HTTP Headers for assets and you don't have to add dependencies like the font_assets gem. In order to set Access-Control-Allow-Origin to your font, just add the following codde to config/environments/production.rb:
config.public_file_server.headers = {
'Access-Control-Allow-Origin' => '*'
}
Update on 07/25/2018:
The header value could also be a specific domain, like the following:
config.public_file_server.headers = {
'Access-Control-Allow-Origin' => 'https://www.example.org'
}
I think most common solution is to use font_assets gem. Configuration is pretty straightforward. In config/environments/production.rb add this
config.font_assets = "http://YOUR_ASSET_HOST"
Unfortunately I cannot explain this in more details, but that's what we use in our project and it works fine.

Can't get Travis API token using Github token

According to Travis API documentation, for getting Travis API token I need send POST HTTP request on special address:
POST /auth/github HTTP/1.1
User-Agent: MyClient/1.0.0
Accept: application/vnd.travis-ci.2+json
Host: api.travis-ci.org
Content-Type: application/json
Content-Length: 37
{"github_token":"YOUR GITHUB TOKEN"}
But when I do this I receive 403 error with Unexpected 'y' message.
Any ideas what I'm doing wrong? Or there is something specific with Travis API?
I made it work like this:
http post https://api.travis-ci.org/auth/github Content-Type:application/json User-Agent:TravisMyClient/1.0.0 Accept:application/vnd.travis-ci.2+json github_token=<enter_your_github_token>
im using HTTPie instead of curl.

Swagger UI Not adding Header to Requests

I am using Swagger 2.0 and Swagger UI 3.0.3.
In my api_definition.yaml I have the following before my paths:
swagger: '2.0'
################################################################################
# Host, Base Path, Schemes and Content Types #
################################################################################
# Metadata
info:
version: v1
title: Microservice
description: Microservice API!
host: sandbox
basePath: '/apps/fiji/v1'
schemes:
- http
securityDefinitions:
apikey:
type: apiKey
name: X-Access-Token
in: header
security:
- apikey: []
produces:
- application/json
consumes:
- application/json
This adds an Authorize button the the Swagger UI where the user can paste in their API key. I would like this API key to be sent in the request header of every request. This does not happen though and I'm not sure why. Am I missing something?
EDIT:
The request seems to send and I get back 401 Unauthorized.
Chrome Dev Tools shows the following Request Headers:
GET /apps/fiji/v1/getCPICountries HTTP/1.1
Host: sandbox
Connection: keep-alive
accept: application/json
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36
content-type: application/json
Referer: http://sandbox/apps/fiji/vendor/swagger-ui/dist/index.html?url=http://sandbox/apps/fiji/swagger/api_definition.yaml
Accept-Encoding: gzip, deflate, sdch
Accept-Language: en-US,en;q=0.8
I have the paths set up as:
# API Paths
paths:
# getCPICountries endpoint
/getCPICountries:
# HTTP operations
get:
# Describe this verb here. Note: you can use markdown
description: |
Returns a list of countries and country codes
produces:
- application/json
security:
- auth:
- role_admin
# Expected responses for this operation:
responses:
# Response code
200:
description: Successful response
# A schema describing your response object.
# Use JSON Schema format
schema:
properties:
data:
type: array
items:
$ref: '#/definitions/CPIResponse'
And definitions as follows:
definitions:
CPIResponse:
type: object
UserObject:
type: object
properties:
email:
type: string
id:
type: number
orgId:
type: number
firstName:
type: string
lastName:
type: string
The problem was that I override security in my paths. I need to remove the following:
security:
- auth:
- role_admin

EmberJS calls to an MVC Web API result in a CORS message when authorization fails

I am using EmberJS to communicate with an MVC Web API using Auth0 for authorization. When I have a valid bearer token I can communicate and retrieve data from the Web API just fine. When the token expires the Web API returns an an expected 401 the following message is displayed in the browser console:
No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:4200'
The ajaxError method of the RESTAdapter is called as expected, but the jqXHR.status field is 0.
export default
DS.RESTAdapter.extend({
namespace: 'api',
host: webApiUrl,
headers: function() {
return {
"Authorization": 'Bearer ' + localStorage.getItem('userToken'),
};
}.property().volatile(),
ajaxError: function(jqXHR) {
var error = this._super(jqXHR);
if (jqXHR && jqXHR.status === 401) {
Ember.Logger.info("Not Authorized");
}
Ember.Logger.info("Error " + jqXHR.status + " calling API redirecting to login.");
}
});
Here is a sample of the response returned from the API:
HTTP/1.1 401 Unauthorized
Cache-Control: no-cache
Pragma: no-cache
Content-Type: application/json; charset=utf-8
Expires: -1
Server: Microsoft-IIS/8.0
X-AspNet-Version: 4.0.30319
X-SourceFiles: =?UTF-8?B?QzpcU291cmNlXFBheWNvckRldlxTb3VyY2VcSW50ZWdyYXRpb25cR2VuZXJhbFxNYWluXFBheWNvci5JbnRlZ3JhdGlvbi5PcGVyYXRpb25zXFBheWNvci5JbnRlZ3JhdGlvbi5PcGVyYXRpb25zLkFwaVxhcGlcbG9nZ2luZ0V2ZW50cw==?=
X-Powered-By: ASP.NET
Date: Fri, 30 Jan 2015 16:45:35 GMT
Content-Length: 927
I have tried XML and plan/text Content-types, but the result is the same.
I don't believe this is an actual CORS issue because this problem only occurs when the API returns an error; otherwise I'm downloading and displaying the data just fine.
Does anyone know what the issue might be?
Thanks in advance.
I was having the same issue and it was a CORS issue.
I'm not sure what backend your api server is but mine is a Rails API and the solution was to move the CORS middleware to the top of the middleware stack
config.middleware.insert_before 0, 'Rack::Cors' do
allow do
origins '*'
resource '*', :headers => :any, :methods => [:get, :post, :options]
end
end
The issue is a bit confusing because before fixing the problem if I made a request using cURL I receive the correct response with the right headers etc
$ curl -I -X GET -H 'Accept: application/json' http://api.example.dev/foo
HTTP/1.1 401 Unauthorized
X-Frame-Options: SAMEORIGIN
X-XSS-Protection: 1; mode=block
X-Content-Type-Options: nosniff
X-Pacu-Media-Type: v1
Content-Type: application/json; charset=utf-8
X-Rack-CORS: preflight-hit; no-origin
X-Request-Id: def30b49-895f-4581-82ec-87bcfb6c44e5
X-Runtime: 0.010945
Date: Sun, 22 Feb 2015 03:30:35 GMT
Connection: close
and the correct error message
$ curl -X GET -H 'Accept: application/json' http://api.example.dev/foo
{"errors":[{"id":"01ac93be-ea7a-4d8e-b86b-9ea1f4136b11","title":"unauthorized","detail":"The access token is invalid","status":"401"}
The problem is that cURL is not making a cross site request and therefore CORS isn't needed. When attempting to connect using jQuery the request would fail with the following error in the browser's dev console.
No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:4200' is therefore not allowed access. The response had HTTP status code 401.
The response status was 401 but the response body was empty and the jqXHR.status was set to 0.
Again the reason was because my Rails backend CORS middleware needed to be at the top of the rack stack order. In Rails since I am using the Routes Engine as an exceptions app config.exceptions_app = self.routes I needed the CORS middleware to load before it in ActionDispatch::ShowExceptions

Forward TCP connection to HTTP on Nginx

I'm running an app which accepts data from GPS loggers, being this data sent via SMS, HTTP or TCP. I was using the HTTP connection to transmit the data, which was straightforward to receive through a GET request on my Rails app.
For battery saving purposes, we changed the connection to pure TCP and nginx is not accepting these requests for now:
From nginx's access.log:
HTTP:
xx.xx.xx.xxx - - [03/Mar/2013:20:17:45 -0500] "GET /?imei=123456789012345&rmc=$GPRMC,035106.000,A,4145.1451,N,08506.8784,W,1.56,176.49,010213,,*13,3656mV,AUTO HTTP/1.1" 302 247 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_2) AppleWebKit/537.22 (KHTML, like Gecko) Chrome/25.0.1364.152 Safari/537.22"
TCP:
xx.xx.xx.xxx - - [03/Mar/2013:18:31:22 -0500] "imei=123456789012345&rmc=$GPRMC,233012.000,A,4221.6614,N,07106.1014,W,17.25,218.94,030313,,*21,4102mV,AUTO,310,260,ADB7,13EF,057,310,260,0000,0000,044,310,260,0000,0000,055,310,260,0000,0000,05A,310,260,0000,0000,059,310,260,0000,0000,05E,0,0,0000,0000,000,2" 400 172 "-" "-"
Does anyone know a way to filter these TCP requests on Nginx and process them as HTTP GET requests to be available through a Rails app?
Thanks in advance
Answer:
I was able to achieve this by creating a custom proxy, using em-proxy and faraday:
require 'em-proxy'
require 'faraday'
Proxy.start(:host => "0.0.0.0", :port => 8080, :debug => false) do |conn|
conn.on_data do |data|
http = Faraday.new(:url => 'http://example.com') do |faraday|
faraday.request :url_encoded # form-encode POST params
faraday.response :logger # log requests to STDOUT
faraday.adapter Faraday.default_adapter # make requests with Net::HTTP
end
http.get "/upload?#{data}"
end
end
You should look at websockets. Nginx now has native support for them, but there is an older module for Nginx that does the work as well.
Here's an older question about this with both solutions provided.
Nginx is a HTTP server so it expects clients to speak HTTP. It is not possible to have a client speaking a non-HTTP protocol to nginx in the manner you're describing (ok, maybe you could write a custom module to do it, but that seems silly).
I think what you need to do is write your own proxy server which will convert the raw TCP protocol into HTTP requests. Your GPS loggers would talk to the proxy which would then talk to nginx. This ought to be fairly simple since the TCP payload appears to just be a urlencoded string, so you could just use those directly.

Resources