ionic doesn't keep session on serve - ruby-on-rails

I'm trying to save user in a session using
session[:user_id] = user_id # comes from ionic via get
but when i'm trying to send another $http.get request, I'm getting:
ActionDispatch::Request::Session:0x7fa8882b2ae0 not yet loaded # when I print session
nil # when I print session[:user_id]
If I run it from my android device it works fine.
Also tries to give it expired_at but still no luck.
Headers:
Access-Control-Allow-Credentials:true
Access-Control-Allow-Methods:GET, POST, OPTIONS
Access-Control-Allow-Origin:http://localhost:8100
Access-Control-Max-Age:1728000
Cache-Control:max-age=0, private, must-revalidate
Connection:close
ETag:W/"b8f8b488bd2e233c017c98f592099e7b"
Server:thin
Set-Cookie:_MyAppServer_session=REVtSTJMYXR0TDRSVSs0VEdvNEF3a2RjR21Hei8wRFBpdFkyR3VOQTgyeXNLNGFvYjdsWjFudG9MNk51NkR2Y25DMUFmL1RsZUhmdHhUeUxTSnJPcHc9PS0tUHlTS3BYT1VOMnFSem4zS1JaeGErUT09--de9f966344e4e90810e428f53bd6cf2783ccf835; path=/; HttpOnly
Vary:Origin

I add $http.defaults.withCredentials = true; to the ionic js.
XmlHttpRequest CORS POST sent without cookies

Related

How can I stop sending a preflight request on a redirect?

I discovered that six years ago, the previous developer commented out this line of code (Ruby, Rails):
#protect_from_forgery
I replaced it with the default:
protect_from_forgery with: :exception
and now I mysteriously get the following error when I try to add items to my cart while logged out:
Access to XMLHttpRequest at 'https://id.foo-staging.com/openid/checklogin?return_to=http%3A%2F%2Flocalhost.foo-staging.com%3A3000%2Fcart%2Fitems' (redirected from 'http://localhost.foo-staging.com:3000/cart/items') from origin 'http://localhost.foo-staging.com:3000' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: Redirect is not allowed for a preflight request.
I've pinned down that this is happening because of the following lines:
def get_user_identity_from_open_id_server
redirect_to "#{OPEN_ID_PROVIDER_URL}/openid/checklogin?return_to=#{Rack::Utils.escape(request.url)}"
end
def open_id_authentication
#stuff
get_user_identity_from_open_id_server
end
before_filter :open_id_authentication
I understand what causes a preflight request, at a very high level, thanks to the documentation. But I don't think I'm doing any of those things.
* the request method is anything other than GET, HEAD, or POST
* you’ve set custom request headers other than Accept, Accept-Language, Content-Language, Content-Type, DPR, Downlink, Save-Data, Viewport-Width, or Width
* the Content-Type request header has a value other than application/x-www-form-urlencoded, multipart/form-data, or text/plain
So my initial question is how do I determine what is triggering the preflight request, and then maybe I can figure out how to prevent it from happening. Is this a situation that I can change on my end, or does something need to change on id.foo-staging.com (which I don't have access to, but could probably ask the right person to fix it for me).
I've been Googling all day, and nothing seems to make any sense to me, especially because I can't pin down precisely what's wrong.
I can solve the issue with this code:
skip_before_filter :open_id_authentication, :only => [:create], :if => :current_user and :anonymous_cart
But I have to assume that this is unsafe, from a security standpoint?
ETA: This is what I see on the Network tab for this request:
General:
Request URL: https://id.foo-staging.com/openid/checklogin?return_to=http%3A%2F%2Flocalhost.foo-staging.com%3A3000%2Fcart%2Fitems
Referrer Policy: no-referrer-when-downgrade
Request Headers:
Provisional headers are shown
Access-Control-Request-Headers: x-requested-with
Access-Control-Request-Method: GET
Origin: http://localhost.foo-staging.com:3000
Referer: http://localhost.foo-staging.com:3000/p/Product0/1?id=1&slug=Product0
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36
Query String Parameters:
return_to: http://localhost.foo-staging.com:3000/cart/items
I presume the problem is the x-requested-with request header. But I don't know how to resolve this.
EATA:
Many JavaScript frameworks such as JQuery will automatically send this header along with any AJAX requests. This header cannot be sent cross-domain:
I guess my only option is to figure out how to rewrite this without AJAX?
To avoid the preflight request you have to remove x-requested-with header but the error that you have is because the response location in the preflight call is different from the Origin.
To fix the problem, update your code to use the new URL as reported by the redirect, thereby avoiding the redirect.

Set-Cookie in response header is not working

I have my backend(Ruby On Rails) running at port number 3000 with login endpoint(http://localhost:3000/login).I also have angular server running on port 4200.So with angular I am hitting login endpoint and upon successful login, response is sent back with Set-cookie option(authentication token is set).But it is not set in the browser.Below is the response header i am receiving:
Access-Control-Allow-Credentials:true
Access-Control-Allow-Headers:*
Access-Control-Allow-Methods:POST, GET, OPTIONS
Access-Control-Allow-Origin:http://localhost:4200
Access-Control-Max-Age:1728000
Cache-Control:max-age=0, private, must-revalidate
Content-Type:application/json; charset=utf-8
ETag:W/"9dae161444bc908fd3289f4ed0fb15ed"
Set-Cookie:auth_token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoyLCJleHAiOjE1MDU4NDM0Nzh9.0E22wlacZWvmazpdJPLC4oRq3QM-8DX-npQu3w-U8Vs; path=/
Transfer-Encoding:chunked
Vary:Origin
X-Request-Id:267cfe1f-e60c-40b5-9a7b-4801d358cfd4
X-Runtime:0.273751
Request Headers
view source
While if I hit that API with Postman then the cookie is saved without problem.

Rails 4: How to set cookies in redirect?

I have a controller that attempts takes form inputs, set values in a cookie and then redirect to a page that will pull from that cookie.
The problem is that the cookie is never set in the redirect headers.
Notes: I've tested in Chrome and FF. Rails version is 4.0.13. Setting cookies w/o a redirect works as expected.
Here's the controller code:
def create
request.cookies[:foo] = "bar"
# also tried:
# cookies[:foo]="bar"
# cookies.signed[:foo]="bar"
# cookies[:foo] = {
# value: "bar",
# expires: 1.month.from_now,
# domain: ".myapplicationhostname.com"
# }
redirect_to root_url
end
The response header on the redirect doesn't contain a Set-Cookie attribute and as such, the cookie values aren't available in the controller/action in the redirected-to path.
I've found some contradictory evidence that some browsers don't accept cookies in redirects, but it appears that that's not the case anymore? And anyways, neither FF or Chrome are showing a Set-Cookie in the response header, so it doesn't appear this is a browser issue.
Here's the header response from cURL, note the lack of Set-Cookie:
HTTP/1.1 302 Moved Temporarily
X-Frame-Options: SAMEORIGIN
X-XSS-Protection: 1; mode=block
X-Content-Type-Options: nosniff
X-UA-Compatible: chrome=1
Location: http://app.mydomain.com:3000/
Content-Type: text/html; charset=utf-8
Cache-Control: no-cache
X-Request-Id: 1fc1c7e5-7489-4720-bb70-28588f3abcb6
X-Runtime: 4.688166
Connection: close
Server: thin 1.6.2 codename Doc Brown
How do I get rails to set cookies (or at least set the header) on redirects?
It appears that the cause of this is actually CSRF protection kicking in. The controller had instantiated a NullCookieJar which prevents the writing of cookies when there's a potentially forged POST.
This is because my controller was being set up to respond to an off-site form, thus no access to the CSRF token.
So, if you're running into this when submitting an off-site form to your Rails app, you'll need to disable the CSRF check or write your own verification method as described in the answer to the SO question: "Receive POST from External Form".
Summarized here:
Disabling Check
skip_before_filter :verify_authenticity_token, only: :my_action
Custom Check
skip_before_filter :verify_authenticity_token, :only => :my_action
before_filter :verify_custom_authenticity_token, :only => :my_action
def verify_custom_authenticity_token
# checks whether the request comes from a trusted source
end

localhost cookies not set

I'm trying to set a cookie in my application.
Here's the code that sets the cookie:
public HttpResponseMessage LogIn(UserLoginVM user)
{
// Do login stuff
var cookie = new CookieHeaderValue("STUPID-COOKIE", "12345");
cookie.Domain = Request.RequestUri.Host;
cookie.Path = "/";
cookie.HttpOnly = true;
// Get user's profile
HttpResponseMessage res = Request.CreateResponse<UserProfileVM>(HttpStatusCode.OK, profile);
res.Headers.AddCookies(new CookieHeaderValue[] { cookie });
return res;
}
The response from the server is the following:
HTTP/1.1 200 OK
Cache-Control: no-cache
Pragma: no-cache
Content-Type: application/json; charset=utf-8
Expires: -1
Server: Microsoft-IIS/8.0
Set-Cookie: STUPID-COOKIE=12345; domain=localhost; path=/; httponly
Access-Control-Allow-Origin: *
X-AspNet-Version: 4.0.30319
X-SourceFiles: =?UTF-8?B?QzpcUFJPSkVDVFNcU2Ftc2tpcC5TZXJ2aWNlV2ViTmV3XFNhbXNraXAuQXV0aEFQSVxTYW1za2lwLkF1dGhBUElcbG9naW4=?=
X-Powered-By: ASP.NET
Date: Wed, 18 Feb 2015 11:58:07 GMT
Content-Length: 8019
Notice the following header:
Set-Cookie: STUPID-COOKIE=12345; domain=localhost; path=/; httponly
However, when I go under "Cookies" in "Resources" tab in Chrome, nothing is set. Also when I send a request to the server no cookie is in the headers.
Here's the code that reads the cookie:
CookieHeaderValue cookie = Request.Headers.GetCookies("STUPID-COOKIE").FirstOrDefault();
cookie variable is always null.
My application is running on http://localhost:53998 and the authentication service is running on http://localhost:60858
My Chrome version is 40.0.2214.111.
Here's a GIF demonstrating the problem:
http://i.imgur.com/q7lkXBz.gif
Edit: This seems to be non-specific to Chrome. This doesn't work on FireFox (v35) either. GIF: http://i.imgur.com/ZewnEtc.gif
I ran into this issue today and Gaui's answer was quite useful to me, bearing in mind ideally you do not want to open up your server to CORS requests from any site. I'm in my dev environment and my server and client are on different origins since they are on different ports on localhost. Also I'm using .net core 3.0
My issue was caused by my server not sending cookies to my client side as my CORS settings were blocking the sending of cookie to my domain this was evident by the server not using the header Access-Control-Allow-Credentials: true. To resolve this I configured my server in Startup.cs to allow requests from my client side to allow credentials (A credential is a cookie's authorization headers or TLS client certificates).
var allowedOrigins = new[] {"localhost:3000"}; // Ideally comes from appsettings
app.UseCors(builder =>
builder.WithOrigins(allowedOrigins).AllowCredentials().AllowAnyMethod().AllowAnyHeader().Build());
For the cookie options; I found that the you do not have to set Domain if you do not want to, Secure works even when the site is not using https.
Google chrome now supports cookies on localhost, I believe it didn't used to as a lot of older SO posts have users who faced that issue.
On the client side, you need to configure it to accept cookies as well, as in Gaui's answer above. I was using fetch, and so had to add the option:
credentials: 'include'
Which tells fetch to retrieve cookies across domains. See the docs here
I highly suspect that localhost is not a valid domain name so Chrome rejects it. If you simply remove 'domain=localhost' from the Set-Cookie then it will work and Chrome will assign the domain to localhost for you.
I would personally create a local domain name like "test.dev" and add it to your Windows hosts file, 127.0.0.1 test.dev
I finally managed to solve this.
In the response from the API I had to add Access-Control-Allow-Credentials: true headers, or by adding the following in the WebApiConfig class:
public static void Register(HttpConfiguration config)
{
var cors = new EnableCorsAttribute("*", "*", "*");
cors.SupportsCredentials = true;
config.EnableCors(cors);
}
Then I had to enable it on the client-side, by setting the withCredentials property in the XMLHTTPRequest object to true. In AngularJS app config function you can do the following:
$httpProvider.defaults.withCredentials = true;
Also, for Chrome, I had to omit the Domain (or set it as null).
Hope this helps others struggling with this.

Rails 3.2 HTTP streaming fails (Thin server on Windows)

I'm trying to get my pages to stream but I'm getting the following error:
Error 321 (net::ERR_INVALID_CHUNKED_ENCODING): Unknown error
I've tried in both Chrome, IE and Firefox.
def login
redirect_to_stored and return if session[:user]
if request.post?
if session[:user] = User.authenticate(params[:login], params[:password])
redirect_to_stored(notice: 'Login successful') and return
else
flash_now :alert => "Login unsuccessful"
end
end
on_document_load "$('#login').focus();"
render :layout => 'login', :stream => true
end
I get the following response headers:
Cache-Control:must-revalidate, private, max-age=0
Connection:close
Content-Type:text/html; charset=utf-8
Server:thin 1.5.0 codename Knife
Set-Cookie:_rails3.website_session=biglongstringhere; path=/; expires=Sat, 02-Mar-2013 01:44:38 GMT; HttpOnly
Set-Cookie:__profilin=p%3Dt; path=/
Set-Cookie:__profilin=p%3Dt; path=/
Transfer-Encoding:chunked
X-MiniProfiler-Ids:[a bunch of stuff in here (this isn't the actual text)]
X-Request-Id:695da38a40064d87cbd463c83fef0a88
X-Runtime:0.034002
X-UA-Compatible:IE=Edge
Looking in Chrome's inspector, the file 'login' shows the Status as 'failed' but when clicking it, the Status Code is 200 OK. Another thing I've noticed is that if I put the following in before the original render call, the response displays OK, but Chrome inspector still thinks the Status response was in error (like the 1st time). Is the connection being closed before the rest of the body has a chance to be delivered? I don't understand what's wrong here.
render(:text => 'test', :stream => true) and return
As an addendum, the rails log does not show any errors. It renders everything just fine.
I have two servers; one at work and one at home. The one at home doesn't use nginx or any downstream application to communicate with Thin. Thin on its own produces an error...but using nginx in front, the files are served appropriately. Strangely though, when I don't have any streaming explicitly enabled in my rails app, the files are still served as Content Type: chunked.
Heck, even my public website is being served as chunked...but I never had streaming enabled in Rails...so that must mean the final result is chunked but not the actual rendering of the html. How can I actually test this then?

Resources