So I have sort of a weird situation going on. I am using the Facebooker plugin for rails where I want users to be able to login and logout with their facebook profiles. However, once users logout, if I refresh the page, it logs them back in. This is only when users log in with facebook connect.
I think the problem is that a rogue cookie is just re-instantiating the session and thus my best guess is to manually destroy the cookies but to be honest I'm not entirely sure of how to do this. I printed out my cookie list (from request.cookies) both before and after I click logout. After logout is clicked, I still have this cookie lingering...but don't know how to delete it.
fbsetting_0b78c8f2c95ce671470bdcb1c19e5070 {"connectState":1,"oneLineStorySetting":1,"shortStorySetting":1,"inFacebook":false}
After playing around with it a little more, that cookie isn't even there...but upon refreshing the page I am logged in again.
I'm doing this all on localhost...not sure if that should cause a problem or not.
Any ideas?
This is what I have in users controller
def logout_facebook
clear_facebook_session_information
redirect_to root_url
end
and this is how it is triggered
<%= fb_logout_link("Logout out", "#{root_url}users/logout_facebook")%>
This is how I got it to remove the cookies on the local side.
Note: don't forget to add a route to the logout_facebook method in your routes.
Destroying local cookies isn't enough to terminate a Facebook Connect session. The connect JS library will recreate destroyed cookies as long as you still have an active session on the facebook.com domain -- and those cookies are inaccessible to you.
All log-outs must be handled by calling the logout function in the connect library.
e.g.,
<script>$H.fbconnect.logout();</script>
To delete a cookie, you need to set the cookie again with an expiration date in the past.
a million thanks for the clean and full-proof solution to such a frazzled functionality. I've been literally going Blank over last 2 weeks since I came across the fact true to I believe almost all NEW-facebooker users, "facebook connect logging out completely". Or maybe just it was just a lack of documentation or some code excerpt I wasn't able to find till date in facebooker cover docs.
Anyway away from all that, moving to the solution which made me achieve it... Following to #James B method above.
Obviously I am assuming you all have read facebooker installation, configuration & usage instructions http://github.com/mmangino/facebooker.
I also have used a plugin "authlogic_facebook_connect" which you can find at github.com page of kalasjocke/authlogic_facebook_connect.
Now I assume you already configured your application to work with facebook connect by using fb_login_button or authlogic_facebook_login_button. Clicking it you'd see a popup to log yourself into both your facebook account and into the local account of your app. Once you login you'd be getting a facebook_session to handle saving a new user in your DB (only if you wish to).
By default you'd not be getting birthday and email address of users in the facebook_session as response from facebook. To get them you need something like this in your initialization javascript in the body tag of the rhtml page...
<%= fb_connect_javascript_tag %> <%=
init_fb_connect "XFBML",{
:app_settings=>" {
permsToRequestOnConnect :
'email,user_birthday' }"} %>
<%= authlogic_facebook_login_button %>
Now finally what I did for getting logged out of both Facebook and my site.
Inside the header of your application or wherever the LOGIN, LOGOUT, loggedin users's name etc will display...
:delete
%>
The two logout buttons are for different kind of users.. a. who registered directly on your site, b. who registerd to your site via facebook
Route for logout_both in routes.rb
map.connect "/logout_both",
:controller=>"users",
:action=>"logout_both"
The action for logout_both inside users_controller.rb
def logout_both
current_user_session.destroy
#clear_facebook_session_information
flash[:notice] = "Logout successful!"
redirect_to root_path end #End of method logout_both
You need to make sure that there are no filters defined in the controller which could restrict logout_both action to be executed without a session.
Oh yes and if you're wondering why that "clear_facebook_session_information" is commented in the action. Then don't worry, you're already logged out of facebook before entering this action, this line is no longer needed. Boss we're using "fb_logout_link" which first logs you out and then redirects you to this new action.
Well, that's about it. If this doesn't do it........ get your hands dirty like I am doing.. dig in.. solve it yourself. Facebooker is deep but has a definite END!!!
Again many thanks to mangino & kalasjocke for making facebook connect almost no painful for rails.
One clarification people... in my Answer above.. There is a hick, which is.. After logout, if you refresh the page.. it would again show you logged in on your site.. however you're successfully logged out of Facebook.
I was wrong, ONE BIG CLARIFICATION...... As a matter of fact you DO NEED THESE TWO LINES IN YOUR "logout_both" action
def logout_both <br/>
current_user_session.destroy<br/>
clear_facebook_session_information #MANDATORY TO COMPLETELY CLEAR COOKIES<br/>
reset_session # TO BE 100% sure you can use it optionally<br/>
flash[:notice] = "Logout successful!"<br/>
redirect_to root_path <br/>
end
Related
Regarding a Ruby on Rails 4.2.5 + Devise 3.4.1 app.
Some of the marketing around our app requires UTM codes. Sometimes, the marketing links point to resources that require a login to view. The problem is that when Devise redirects to the login screen, the UTM codes are removed, and Analytics counts the lead as an internal link, rather than crediting the UTM info properly.
Is there any easy way to fix this? And if not, a pointer to the right direction on what needs doing would be great.
In it's default configuration, Devise shouldn't be stripping out any parameters when redirecting after a successful login. The original URL is stored on auth failure, and then the stored URL is used verbatim as the redirect location after successful login.
So:
# /path?utm_campaign=test
# => redirects to /user/login on auth challenge
# => redirects back to /path?utm_campaign=test on login
Are you overriding after_sign_in_path_for by any chance? If so, it's worth looking at the original code, and ensure that you are retaining stored_location_for(resource_or_scope) - which effects the behaviour described above.
An idea would be rendering the login form via ajax on the marketing page and instead of redirecting to the login page, have the login page come to you.
def marketing_landing_page
unless user_signed_signed_in?
render :new
end
end
:new as in devise/sessions/new
I need to control access to my whole Ruby on Rails app, allowing only some selected users to see it while it's under development.
I'm not looking into a full authentication system, but something much simpler, where I can add an email address to a restricted-users list, send an email to it and let that user see the app, rejecting any other user.
I have tried to use the WWWhisper add-on in Heroku (the app is hosted there) as it's just what I would need, but it doesn't seem to be available outside of the US.
I think I will have to build it myself, but, before, I wanted to make sure that there isn't a simpler solution already available. Any ideas? Thanks in advance.
If your access requirement is "having got an invitation email" then i think your simplest option is to have something like this
#in application.rb
before_filter :require_invite
protected
def require_invite
session[:invite_token] ||= params[:invite_token]
unless session[:invite_token] == "<SOME SECRET KEY STRING>"
redirect_to external_home_path and return
end
end
end
where external_home_path is some holding page for people who haven't got an invite, which says "Sorry you need an invite token blah blah". You'll need to add this to the controller which handles the external home page, to avoid a circular redirect.
skip_before_filter :require_invite, :only => [:external_home]
Then you just need to send people an invite with a link like
http://example.com?invite_token=<SOME SECRET KEY STRING>
Obviously this isn't very secure but it's as secure as the "have i seen the email" criterion.
When you go live you can take this before_filter out.
I'm working on an app which allows the user to browse the site and log in from any page (login link is in the common header). Once a successful login occurs, the user is currently redirected from the login page to root_url.
It would be more friendly to redirect_to the original page. I attempted to store the named route of the originating page into session, but those appear to be objects, so unable to pass. Also, not all routes come with the named helpers. On the other hand, when I pass the literal path as a string to the redirect_to, e.g. 'orders/index', Rails interprets the /action as an id parameter and errors out.
Would would be the Rails way to do this? Thanks!
You can get the URL of the page a user is coming from by using request.referrer inside your controller.
(Rails 5 Update) You can use redirect_back to return the user to the page they just came from.
redirect_back(fallback_location: root_path)
This method requires you set a fallback location because the location is pulled from the browser and it's not always guaranteed to be set.
See the rails guides for more on redirect_back
I'm a bit stumped on how (and where) to write some rspec tests for the "stay signed in" functionality you see all over, including on the google login.
The examples I found on the web weren't much help. Specifically I want to test these two scenarios.
1
a) user signs in with valid credentials without having clicked "stay
signed in"
b) user closes the browser, re-opens it and requests a protect page.
The user should not see the protected page.
The user should see the page asking them to signed in.
2
a) user signs in with valid credentials and having clicked "stay
signed in"
b) user closes the browser, re-opens it and requests a protected page.
The user should not see the page asking them to sign in.
The user should be taken to the protected page.
My first attempt at solving the problem involved simulating a browser close by deleting the user_id I stored in the session (since it gets deleted on browser close). However, these tests failed because I was working in the request spec folder and have no access there to the session variables. My earlier related question: session available in some rspec files and not others. how come?
What is the best way to do these test with rspec?
I think you should try standard rails method for integration tests - open_session.
Personally I never did that and can't give you tested code.
See multiple sessions example on rails guides.
There are two problems here, that I think belong into different tests:
User cannot access protected page when not logged in. That's a controller test.
User gets logged in automatically even after the session has been destroyed, so long the "remember" me flag was set in the cookie.
For #1, you can try something like:
describe UsersController do
context "when not logged in" do
context "GET users/edit" do
it "redirects to login" do
get :edit, :id => 123
response.should redirect_to login_path
end
end
end
end
You can make a more general test case that asserts all actions which aren't explicitly listed, so that you don't have test gaps if the access code later becomes more permissive by accident. But that's a more subtle point.
For #2 you can write a request spec that sets the "remember me flag", then logs out, then logs in again and checks that you get to the page you expected. Drive all this from the browser by filling out credentials, checking the remember me box, clicking buttons.
The question is: Why? Why do you want to test this? Are you using a home-grown login system? Highly discouraged, unless you're a top-notch security expert. If you're not using a home-grown system, but instead Devise which comes tested, then don't re-test the library functionality. Just only test your application code, such as access rights to certain pages, which is covered by #1. You can also take a look at the tests that come with Devise how they test for this condition.
Hope this helps.
Update To clarify the request spec for #2. As mentioned in the other answer by #cutalion (who deserves the credit for the right answer), the mechanism for verifying that login can persist across session closing is built into the ActionDispatch IntegrationTest framework with open_session.
See Rails docs IntegrationTest API which includes examples. A blog post expanding on the use of a custom DSL.
This still seems to be a recurring problem in 2018. Some basic documentation is clearly missing. I finally found a solution: "Show me the cookies" gem.
Switching the Capybara driver clears the session, so one possibility would be changing the driver in the middle of a test to simulate browser close/open. But getting an alternative driver (for example selenium, or selenium_chrome) to work is not trivial, and besides this method would probably delete all cookies.
Also this simple command resets the session: Capybara.reset_sessions! But the problem again is that it not only destroys the session cookie but also permanent cookies. So it's useless for testing "Remember me" functionality.
I finally settled on Show me the cookies gem. It was very simple to install and implement. I just followed the provided directions for rspec. The command expire_cookies provides a satisfying simulation of quitting and opening a browser.
I have an action named 'login' that shows the login form.
The form posts to the 'signin' action.
I haven't implemented the authentication logic yet, so I tried this:
def signin
redirect_to login
end
So when the login form posts, it just redirects back to the login page again.
Cannot redirect to nil!
but its not working, why?
You almost had it
redirect_to login_url
Good for you for trying to build your own authentication system. But if you do eventually plan on going to production, please consider using an established authentication system (such as Devise) unless you REALLY know what you're doing, and know all the security issues like the back of your hand. Get started here http://guides.rubyonrails.org/security.html
Why build the auth from scratch when openid, or basic auth, plugins have already been built? That's just where I would go with it.