I have a Rails app with carrierwave uploaders configured to use carrierwave-aws on an S3 bucket.
The permissions for that bucket WERE bad, but hopefully I fixed them and now uploads seem to work fine (and I checked the permissions of a single file, public read is checked)
The Rails app is using cloudfront, which has been configured to handle "normal" assets (css, js, etc.) and with carrierwave-aws.
However I am still getting 401 errors, and worse, when this happens a HTTP Basic auth popu appears on screen, asking for a password for my distribution
"NetworkError: 401 Unauthorized - https://xxxxxxx.cloudfront.net/uploads/user/avatar/xxxxxx/thumb_avatar.jpg"
The above error triggers an HTTP Basic auth windows asking for the user/pw for xxx.cloudfront.net
If this is linked, it turns out I indeed do have this kind of auth on my Rails website itself (before we move on to production).
On CloudFront, I have configured two origins : my Rails server (and css/js are ok so I guess this ons is fine) and The S3 Bucket (don't know how I can really test this one though)
So
How can I check My Rails -> Carrierwave-aws -> CloudFront pipeline is working fine ? (Uploads are fine, I just can't read from the browser after an upload)
How can I disable HTTP Basic Auth from the website in case a 401 error appears ?
EDIT : I setup Basic Auth in Rails ApplicationController
def authenticate
if ENV["HTTP_BASIC_AUTH"] == "true"
authenticate_or_request_with_http_basic do |username, password|
username == "wxx" && password == "xxx!" or
end
end
end
A 401 HTTP response is, of course, supposed to trigger a browser pop-up prompt. If you don't want that, your solution is not to require auth in your application.
But, it seems like the solution that would be most helpful to you at this point would be to go ahead and enable pass-through of the browser's attempt to send credentials back to the origin server. To do this, CloudFront needs to forward the Authorization: header to your origin. By default, this request header (like most request headers) us discarded by CloudFront and not sent to the origin.
Whitelist this header in the appropriate cache behavior so that CloudFront will forward it and your access control mechanism should work as expected.
Remember that changes to CloudFront distributions take a few minutes. Wait for the distribution to return to the deployed status before testing.
Related
I am implementing a cloudfront solution and would like to test / run it on my staging server, however staging is "protected" from the outside world by basic_auth.
I have tried entering a URL with the basic_auth username / password in it e.g user:pass#example-staging.com but CloudFront rejects this URL.
How can I allow Cloudfront / an origin to access my staging server?
(I am hosting on heroku, using rails 4)
Because of the way web content caching works, most HTTP request headers are not forwarded from CloudFront to the origin server by default, including the Authorization header needed for basic auth.
You'll need to whitelist the Authorization header in the appropriate cache behavior(s).
http://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/distribution-web-values-specify.html#DownloadDistValuesWhitelistHeaders
I am preparing to work on a project where I need to display a dashboard from an online application. Unfortunately, the use of an API is currently not possible. The dashboard can be embedded in an iFrame. However, when it is displayed it will prompt the user viewing the dashboard to login to an account.
I have one paid account to this service. Are there any rails gems to login to the service before the iFrame is processed?
Or would a proxy within my rails app be a better route to go?
Any pointers are appreciated!
Neither a Rails gems nor a proxy within your rails will work and they same have the same limitation.
They are both running on the back-end, server side.
The authentication you need is client side.
Unless you mean proxy the ENTIRE thing, the auth request and all subsequent requests and user interactions with this dashboard. That should work but (see below)
The way authentication works (pretty much universally) is: once you log in to any system, it stores a cookie on your browser and then the browser sends that cookie for every subsequent request.
If you authenticate on the backend, that cookie will be sent to your rails code and will die there, and the users browser will never know about it.
Also - it is not possible to do the auth server side and capture the cookie and then have the user browse the site with their browser directly, for two reasons:
Sometimes auth cookies use information about the browser or HTTP client to encrypt the cookie, so sending the same cookie from a different client wont work
You can not tell a browser to send a cookie to a domain different than your own.
So your options are, off the top of my head right now:
If there is a login page that accepts form submissions from other domains, you could try to simulate a form submission directly to that sites "after login" page. (The page the user gets directed to once they fill up the login form). Any modern web framework as XSRF protection (Cross Site Request Forgery protection) and will disallow this approach for security reasons.
See if the auth this site uses has any kind of OAUTH, Single Sign On (SSO) or similar type of authentication integration that you can do. (Similar to an API, so you may have already explored this option)
Proxy all requests to this site through your server. You will have to rewrite the entire HTML so that all images, CSS, stylesheets, and all other assets are also routed through the proxy or else the URLs are rewritten in the HTML to not be relative. You might hit various walls if a site wasn't designed for this use case. From things like the site using relative URL's for assets that you aren't proxying, the site referencing non-relative URL's causing cross-domain errors, etc. Note its really hard to re-write every single last assets reference, its not only the HTML you're worried about, Javascript can have URL's in it too, and CSS can as well.
You could write a bookmarklet or a browser extension that logs the user into the site.
Have everyone install Lastpass
Have everyone install the TamperMonkey browser extension (and others like it for other browser), and write a small User Script to run custom javascript automatically to log the user in on that site
Scrape that site for the info you need and serve it on your own site.
OK I'm out of ideas. :)
We have a Rails application that is the API component running on api.domain.com and a front-end application in Ember.js running on www.domain.com.
When Ember.js sends a POST request to a route in the API, /events, we want the API to set a cookie to remember a unique user identifier.
Hence this method in the Events controller:
def set_tracking_cookie
cookies[:our_company_distinct] = {
value: create_identifier,
expires: 1.year.from_now,
domain: :all
}
end
As you see, the cookie is set on the entire domain, and is set to expire in a year.
The point is that the next time Ember queries the API, it will be able to read this cookie. However, this is not the case.
Each time the front-end queries the API, the API is unable to find the cookie, nor does it show in the cookies in my developer tools.
The Ember requests set the Access-Control-Allow-Credentials header to true, and I can confirm that the cookie is indeed sent in the response from the API with the correct values for domain, name, path, expiry, etc.
Am I missing something?
Thanks!
For anyone else going through a problem sending/receiving cookies in this way, here are some things I found helpful when I was debugging and ultimately fixed the problem:
When you use the Chrome's (or any other browser's) devtools, examine each request and check it to see if the cookie is being sent from the API on the request where you expect it to be sent, and if all subsequent requests from Ember (or whatever other JS framework for that matter) send this request. In Chrome, go to "Network > [request] > Cookies". Ensure that the front end is sending the cookie properly and that it indeed receives it properly.
We found that this was the best way of adding support for the CORS cookies to Ember was to be done like so: http://discuss.emberjs.com/t/ember-data-and-cors/3690
As far I understand, custom origin server with cloudfront only works if cloudfront is able to access files from my website url:
eg: www.domain.com/hello.html
However, my website has a login requirement in order to view hello.html. How can I have the login mechanism and still cache my real hello.html page in cloudfront using custom origin server?
I am using Ruby on Rails btw, but this is applicable to other stacks as well.
I'm pretty sure this is not possible. As you said, CloudFront has be to able to access the file to serve and cache it. I never saw an option to tell CloudFront to use a password to access the file.
An idea: maybe you can check in your Rails app, before you require the user to enter a password, if the request comes from CloudFront (I'm sure there are some headers indicating that) and, if so, bypass the login requirement?
Edit:
It says in the docs:
Do not configure your origin server to request client authentication.
One thing I'm pretty sure set though is the User Agent. Check for user_agent =~ /cloudfront/iand bypass authentication?
I'm having a ton of issues with Devise, using OmniAuth, to authenticate my Rails app. I relaunch my server and open up a new tab in Incognito mode (so that the cookies are cleared) and load my app. I log in, and then go through to the app.
When I get to a page that calls an authenticated action via AJAX, it asks for a username and password via HTTP Basic Authentication. I've disabled this in my devise.rb.
config.http_authenticatable = false
config.http_authenticatable_on_xhr = false
When I then go back to a previous page, it redirects me to the login page and asks for a login. This also happens when I visit a page that doesn't require authentication and then go back to an authenticated page.
This is getting immensely frustrating. I've unpacked Devise and Warden to my vendor/gems directory so that I can try to debug it, but I honestly can't figure out where to begin. Any help would be hugely appreciated.
Your AJAX call probably isn't setting the CSRF token. You might need to update your UJS gem (jquery-rails probably) or manually set the X-CSRF-Token HTTP header to the value of the tag. See this question: Devise session immediately expiring on .js call [AJAX]. You can test if this is the problem by disabling CSRF protection temporarily by chucking config.allow_forgery_protection = false in config/application.rb.
If you go the manual route, you should probably grab the value of the 'authenticity_token' meta tag first, and use that as the name of the actual token meta tag, rather than hard coding the reference to 'csrf-token'.
I would recommend updating to Rails 3.0.10 or 3.1 if you can. I was still having problems on 3.0.7.