Devise login custom endpoint, current_user session id - ruby-on-rails

I have a mobile application that needs to login to a legacy Rails 3.2 app.
I have an endpoint that the mobile app makes a POST request to passing the username and password.
I want to verify the password and sign in the user and then need to save the now signed user's session id.
I have tried the following:
user = User.find_by_username(params[:username])
if user.valid_password?(params[:password])
sign_in(:user, user)
session_id = request.session_options[:id]
p "session id: #{session_id}"
current_user.logins.create({ session_id: session_id })
end
When I check my redis store that session id being stored is different from the session_id I print out. I read somewhere that this is because rails creates a session id for the request and then once you sign in you get a new session id to prevent fake requests. How can I get the signed in user's session_id?

Related

Devise token auth another user login

I am developing an application through Rails.
I need the ability to login to another user with admin account in devise token auth gem
When user log in, authHeaders are stored in the browser cookie.
Determine user by authHeaders value.
ex)
{ %22access-token%22:%22"access-token value"%22%2C
%22token-type%22:%22Bearer%22%2C
%22client%22:%22"client value"%22%2C
%22expiry%22:%"expiry value"%22%2C
%22uid%22:%22"uid value"%22}
in my controller
returns a new token value when admin clicks user id
def login_as
user = User.find(params[:user_id])
user_new_token_data = user.create_new_auth_token
## return new access-token, token-type, client, expiry, uid in browser cookies format same value
end
I want to change the return value to a browser cookie value and log in as another user, but I do not know how to put it in the cookie.
I would appreciate your help. Thank you

Authenticate active admin user in grape api endpoint

So here are the components of my application
admin panel is on myapp.com/admin built with active admin. then I have a dashboard for users at dashboard.myapp.com built with AngularJs and then I have api built with grape at myapp.com/api.
I have a feature on my admin panel where an admin can log in on the dashboard as another user. we call this capture_session. basically the users session is captured by admin and we drop a cookie admin_capture whose value is the id of the admin_user.
now here is what I want to achieve. in one of my grape api endpoints I need validate that the session is captured and that the admin user who has captured the session is also logged in on the admin panel.
now figuring out whether the session is captured or not is easy as I already have a cookie for that. but how can I verify that the admin user is logged in?
as active admin methods and helpers cannot be called in grape api endpoint.
can I achieve this with cookies or sessions? any help will be highly appreciated
Thanks
So here is how I solved this..
I set another cookie admin_session with the encrypted session and then returned the same cookie as header from the dashboard.
In the grape endpoint I decrypted the session and got the admin user's id and initial part of the encrypted password. and used this information to verify admin.
here is the code.
admin_id = ADMIN_ID_HEADER
admin_session = ADMIN_SESSION_HEADER
admin_user = AdminUser.find_by_id(admin_id)
return unless admin_id.present? && admin_session.present? && admin_user.present?
salt = Rails.application.config.action_dispatch.encrypted_cookie_salt
signed_salt = Rails.application.config.action_dispatch.encrypted_signed_cookie_salt
key_generator = ActiveSupport::KeyGenerator.new(ENV['SECRET_KEY_BASE'], :iterations => 1000)
secret = key_generator.generate_key(salt)
signed_secret = key_generator.generate_key(signed_salt)
encryptor = ActiveSupport::MessageEncryptor.new(secret, signed_secret, :serializer => ActiveSupport::MessageEncryptor::NullSerializer)
session_data = JSON.parse(encryptor.decrypt_and_verify(CGI::unescape(admin_session))) rescue {}

Where is the Session Stored in Rails?

In Rails, I have implemented the below code for user auth (confirmed to be correct). However, I wanted to confirm my thinking for this strange session[:session_token]. is this the "cookie" that is stored in the browser?
class ApplicationController < ActionController::Base
protect_from_forgery with: :exception
helper_method :current_user, :signed_in?
private
def current_user
#current_user ||= User.find_by_session_token(session[:session_token])
end
def signed_in?
!!current_user
end
def sign_in(user)
#current_user = user
session[:session_token] = user.reset_token!
end
def sign_out
current_user.try(:reset_token!)
session[:session_token] = nil
end
def require_signed_in!
redirect_to new_session_url unless signed_in?
end
end
My understanding so far of how this works is that whenever the browser/client sends a request to rails, the cookie (with the session[:session_token]) is also sent over, thus allowing the current_user method to find the user. Is my understanding correct? This is strange to me because there's a gap of knowledge of how exactly the browser/client gets access to the session cookie when we declare it in ApplicationController (Rails-side).
You are pretty much there. Although, I have a feeling you might be confusing apples with oranges...
Sessions:
Very often in dynamic web sites one would want to store user data between HTTP requests (because http is stateless and you can't otherwise associate a request to any other request), but you don't want that data to be readable and/or editable on the client-side inside of the URL (like.. yourwebsite.com/yourPage?cookie=12345&id=678), and so on..., because you don't want the client to play around with that data without passing through your server-side code.
One way to solve this problem is to store that data server-side, give it a "session_token"(as you called it), and let the client only know (and pass back at every http request) that token. This is how the session is implemented.
Cookies:
The most common technique for implementing sessions in Rails involve using cookies, which are small pieces of text placed on the user’s browser. Because cookies persist from one page to the next, they can store information (such as a session_token or whatever else you want) that can be used by the application to retrieve the logged-in user from the database.
Where is the Session Stored in Rails?
Using both of the above concepts I can now tell you that the default session store inside of Rails is CookieStore, which is about 4KB in size.
To put it simply...
def sign_in(user)
#current_user = user
session[:session_token] = user.reset_token!
end
...method that you defined places the user into a temporary session.
Then the idea is that the following...
def current_user
#current_user ||= User.find_by_session_token(session[:session_token])
end
...method would find and retrieve the user from the database corresponding to the session token and initialize it to a variable you specified.
Additional info:
You should also note that there is an important difference between Rails's session and cookies helper methods...
They both generate cookies, however, session[...] method generates temporary cookies, which should expire upon the browser exit, and cookies[...] method creates persistent cookies, which do not.
Additionally, I would suggest having a look at Section 2 of Ruby on Rails Security guide. You might find it useful.
Hope this helps you out.
Session is stored in server side. And,
Cookie is stored in client side (in browser cookie). And,
When client/browser send a request to rails server, every time cookies are sent to rails server.
When a session is set in rails server, like: session[:user_id] = 4,
Rails store it in server side.
Session is saved in server side like key value pair (like json object)
For each browser, Rails set a session identifier in cookie, so that, Rails can find the correct session information for a request.
Without session identifier in cookie, Rails do not know, what session belongs to what browser.
So, session will not work without cookie.
Edit: Explain: sessions are stored server side
Suppose, I am using your web application, and after login I will be redirected to home page.
I open login page, input username and password, and click login button.
The form is submitted to sessions#login action.
in sessions#login - you check username and password - and set session[:session_token]:
if username and password is correct
random_unique_identifier_string = #user.remember_token
session[:session_token] = random_unique_identifier_string
redirect_to root_url
end
When server run this code session[:session_token], server need an unique identifier for each browser session.
So, server generate an unique identifier for this browser, such as: abc123
Server set all session variables in a place (may be in some folder or in database), label this folder as abc123.
Now server send a cookie request to browser - to set cookie _ebook_session = abc123.
(I see, if my app name is ebook, in rails, cookie name is like: _ebook_session)
Now the page redirect to home page.
** Note: Everything above happen in single request **
Now, in my browser, I want to open some page that need authentication (suppose, dashboard page).
You added before_action: require_signed_in! in dashboard controller.
So, when I open dashboard page in my browser, browser by default send all cookies with every request. so _ebook_session cookie is sent to server. Your server gets the value of _ebook_session cookie is abc123. Now your application know we need to look in abc123 folder for session. Now you can get value of session[:session_token] from abc123 folder.
** I have explained second request above **
Each browser needs unique session identifier.
Important: _ebook_session cookie will be set in browser in first request. If we already have _ebook_session cookie set in a browser, we do not need to set it again, second, third and next requests in that specific browser.
I hope, you understand.

Rails3 User Changed Password, how do I change the current session password?

I have the need to let the user change their password. I'd like to switch the password in the session to reflect this new password, without logging them out.
def set_auth username, password
# test username and password here?
auth_object = AuthCookie.new
auth_object.set_username username
auth_object.set_password password
session[:user_login] = auth_object
end
I use something like the above, but it doesn't seem to work in changing the current session's password to the new one the use just entered.
What am I doing wrong?
Don't save your whole auth object in the session, the most important thing is you should not save password info in the session. Rails default session storage is cookie based, just base64 encode string. So if you save user password info in the session, there is security problem.
Just put the user identify in the session, for example, the user_id. session[:user_id] = user_id

In Ruby on Rails Restful Authentication, why does current_user check the HTTP username and password?

In Restful Authentication, lib/authenticated_system.rb,
why does current_user do a login_from_basic_auth, which does a authenticate_with_http_basic, which is to check the HTTP user provided login name and password?
I thought the login form is in /session/new (or /login), and then it POST to /session, which will go to the sessions controller, create action, and there, it
verifies the login name and password provided by the user.
This is line 8 of lib/authenticated_system.rb
def current_<%= file_name %>
#current_user ||= (login_from_session
|| login_from_basic_auth
|| login_from_cookie) unless #current_user == false
end
So the question is, if the login name and password was previously verified, then why checking it in current_user?
This function indicates that there are three ways to authenticate in your system:
Using a POST request from /session/new or /login.
Using BASIC HTTP authentication (a popup or URL provided username and password).
Using a remember me cookie so that sessions can persist even when session cookies are destroyed or the browser is restarted.
Even though your basic login happens with a POST request from /session/new or /login, the only thing that POST request actually does is set the session user id (probably session[:user_id]). Once that session[:user_id] has been set, you no longer need to login to perform a request, because you are authenticated. From this point forward the actual authentication happens by checking the session[:user_id] to see if someone has already logged in.
Here is a more detailed authentication lifecycle (for login):
User visits /login.
User enters password and username and submits form.
Password is checked, if authenticated the session[:user_id] is set.
User visits another page.
To check if the user is authenticated, current_user is called.
login_from_session is called and the user corresponding to session[:user_id] is returned.
The user is considered authenticated.
Here is a more detailed authentication lifecycle (for HTTP BASIC authentication):
A user visits http://username:password#www.example.com.
To check if the user is authenticated, current_user is called.
login_from_session is called, but session[:user_id] is nil, so nil is returned.
login_from_basic_auth is called, and username:password is present, so the corresponding user is returned.
The user is considered authenticated.
Here is a more detailed authentication lifecycle (remember me cookie):
A user has previously logged in and chosen the 'remember me' option.
A user closes their browser and then re-opens it and visits your site.
login_from_session is called, but session[:user_id] is nil, so nil is returned.
login_from_basic_auth is called, but username and password are missing, so nil is returned.
login_from_cookie is called and a cookie is found and used to return a user.
The user is considered authenticated.

Resources