Getting data out of devise - ruby-on-rails

I'm migrating away from rails. I will be using the same domain, so I'll get the _session_id cookie that rails uses and I can bring over the old sessions table.I would like to use this to extract data (the user_id) from the old session. I can not tell how to do this outside of rails.
Within a controller there's current_user of course or session["warden.user.user.key"], but how can I take the id, decrypt the data in the table, and pull stuff out on my own (besides running the old rails application and creating a route on that that returns the info I need and hitting it from my new application)?

I'm not entirely sure this is the best way, but I was intrigued so went down the rabbit hole. This works for my 4.1.10 app where sessions are stored in the cookie. You'll want to look at action pack's EncryptedCookieJar class and active support's CachingKeyGenerator and MessageEncryptor classes for details.
Obviously you'll need to replace the two strings that start "THE VALUE…".
key_generator = ActiveSupport::KeyGenerator.new('THE VALUE OF SECRET_KEY_BASE FROM config/secrets.yml', iterations: 1000)
caching_key_generator = ActiveSupport::CachingKeyGenerator.new(key_generator)
caching_key_generator.generate_key('encrypted cookie')
caching_key_generator.generate_key('signed encrypted cookie')
secret = caching_key_generator.generate_key('encrypted cookie')
sign_secret = caching_key_generator.generate_key('signed encrypted cookie')
encryptor = ActiveSupport::MessageEncryptor.new(secret, sign_secret, serializer: ActionDispatch::Cookies::NullSerializer)
session_value = CGI::unescape('THE VALUE OF THE SESSION COOKIE')
serialized_result = encryptor.decrypt_and_verify(session_value)
result = Marshal.load(serialized_result)
The result, for me, is a hash that looks exactly the session hash in Rails.
If it doesn't work for you, you may be using a different serializer so need to replace Marshal.load with whatever you need. Just take a look at serialized_result and see.

Related

Rails how to check size of current session (cookies)

I was happily throwing things into the session instead of direct saving into the database (like in multistep forms) and thought those 4kb is more than enough. Since I use Devise I thought it uses some session storage but felt safe until I tried to p session and OH!!! My terminal couldn't event print all data from it. That data is hard to understand - there are some items that I pass to it, but also some local routes and other weird things.
So no I wonder how to check the size of it at some stages? I found similar question but following that I get #encryptor as undefined / nil..
Also tried:
#encryptor = ActiveSupport::MessageEncryptor.new(secret, cipher: encrypted_cookie_cipher, serializer: SERIALIZER)
data = session.to_hash.delete_if { |k,v| v.nil? }
data = #encryptor.encrypt_and_sign(serialize(name, data))
p data.bytesize
But then secret is undefined:
undefined local variable or method `secret'
I also tried to find a way to display the cookie-size with rails, without success.
But another way to check the size of your current session cookie is the developer tool in the browser.
There you can see all cookies with some information and its sizes.
It's maybe not the best way, but better than nothing.

Rails - Store API data throughout session

I am rails fresher, In my rails application am fetching some large data from one site through API, each time I load page it takes time to fetch and display the data, is there any way to store this data throughout session?
Yes, for sure. You can just store it in memcached or redis. Community has an awesome gem for key value storages Moneta
You don't posted the code, so all of the below is just an assumption.
You could just create a new session_id (or use existing one). Then just create new element in store with it and use it when you will need to.
session_id = SecureRandom.hex
store = Moneta.new(:Memcached, server: 'localhost:11211')
store[session_id] = 'value'
store[session_id] = {a: 1, b: 2}
store[session_id] = MarshallableRubyObject.new
Store can be expirable or you can just delete it when you don't need it anymore.

Why Rails 4.1 cookie session serializer converts nested session keys from symbols to strings?

My old application happens to use nested session keys like this:
session[:nested] = {some_id: 123}
This worked nicely in Rails version 4.0 and older, but with Rails 4.1 it is broken: nested session keys are de-serialized as strings, so I no longer can reference those nested values by a symbol as follows:
session[:nested][:some_id]
However, top-level session keys still work fine:
# First action that puts values into session.
def set_session_vars
session[:some_id] = 321
session[:nested] = {some_id: 123}
end
# Second action that loads values from session.
def set_session_vars
root_id = session[:some_id] # => 321, works as expected.
nested_id = session[:nested][:some_id] # => nil, THIS DOES NOT!
end
I understand that Rails 4.1 brings a rather significant change to the way session is serialized - it no longer uses Marshal.dump, instead it uses basic JSON serializer which doesn't serialize objects as is. It should however work fine for basic types like integers and strings which I use.
I tried using a "hybrid" session serializer, but that doesn't work either:
Rails.application.config.action_dispatch.cookies_serializer = :hybrid
Question: what can you recommend besides "don't use nested session keys"?
Thank you,
Alex.
I was faced with same problem. I know this isn't the answer which you want, but it works.
nested_id = session[:nested]['some_id'] # => 321
EDIT
After all, I changed :cookie_store to :active_record_store at config\initializers\session_store.rb
You don't need to change other code.
nested_id = session[:nested][:some_id] # => 321

Rails session id generation and verification code location

Where is Rails generating the session id that it gives a user over a cookie? How is it verifying the session id given over a cookie? Does it save the session id, or does it use some hash function based on secret_token?
According to the Rails guide:
The session id is a 32 byte long MD5 hash value.
A session id consists of the hash value of a random string. The random string is the current time, a random number between 0 and 1, the process id number of the Ruby interpreter (also basically a random number) and a constant string. Currently it is not feasible to brute-force Rails' session ids. To date MD5 is uncompromised, but there have been collisions, so it is theoretically possible to create another input text with the same hash value. But this has had no security impact to date.
I found no links to the code that does this. I searched for uses of rand and srand, MD5 and such but found nothing useful. The closest I found was in actionpack/lib/action_dispatch/middleware/session/abstract_store.rb which does the following:
def generate_sid
sid = SecureRandom.hex(16)
sid.encode!(Encoding::UTF_8)
sid
end
This matches up with the format of session id I find in the session cookie, but not with the documentation in the guide. This also doesn't explain how sessions are verified.
According to this blog session id's are not stored or validated on the server side, but then how does it distinguish a session id that is valid or not?
Does someone know where the code that does this is, or a good guide for this? Thanks!
Other References:
Rails 3 ActiveRecordStore session_id tampering
You are correct, generate_sid1 is in charge of creating a session ID for new sessions.
When a session is first created, it generates a session id, sets it in your cookie, and caches it in CacheStore2. Once you make a request with a cookie, it re-builds the CookieStore and checks to make sure that the session id exists in the cache. If it exists, then it trusts the sesson. If it does not exist, then it does not trust the session. Since the session id is a 32 byte long value, it would be very difficult to guess an active session id that is in the cache.
It turns out that SecureRandom.hex calls SecureRandom.random_bytes which is what the paragraph from the Rails guide is describing. It may perhaps have been better for them to reference the SecureRandom function in use, as newer versions may change this algorithm.
Notice the use of current time, pid and so forth.
def self.random_bytes(n=nil)
n = n ? n.to_int : 16
if defined? OpenSSL::Random
#pid = 0 if !defined?(#pid)
pid = $$
if #pid != pid
now = Time.now
ary = [now.to_i, now.nsec, #pid, pid]
OpenSSL::Random.seed(ary.to_s)
#pid = pid
end
return OpenSSL::Random.random_bytes(n)
end
...
end
https://github.com/ruby/ruby/blob/v1_9_3_547/lib/securerandom.rb#L56

How to store find_by_sql_results in session variable

Here is my controller code to check login details of a user
def validateLogin
#email = params[:userEmail1]
#pass = params[:userPassword1]
if params[:userEmail1] != nil
valid_user = Userprofile.find_by_sql(["select * from userprofiles where userEmail=? and userPassword=?", #email, #pass])
if valid_user.count > 0
session[:email] = #email
session[:uid] = valid_user.id
session[:userType] = valid_user.userType # usertype is a column in userprofiles table
# But here i am not receiving the usertype it gives error that undefined variable usertype.
redirect_to "/userhomes/"
else
flash[:message] = "Either email or password is incorrect"
redirect_to '/'
end
else
flash[:message]="Fields can not be blank"
render :action=>'defaults'
end
Please help
session[:userType] = valid_user.userType
# Error: (usertype is a column in userprofiles table)
But here i am not receiving the usertype it gives error that undefined variable usertype.
You are seeing this error because you receive an array of objects from find_by_sql. You even check the size of the array in your if clause.
From your code I think you expect only one returned object. But you still need to get it from the array like so:
profiles = Userprofile.find_by_sql(["select * from userprofiles where userEmail=? and userPassword=?", #email, #pass])
if profiles.count > 0
user_profile = profiles[0]
#... your other stuff
end
Another variant which also much better uses Rails idioms and especially ActiveRecord as is was inteded to be used is to let it construct the SQL by itself which is generally safer, less prone to errors and cacheble.
You didn't write which version of Rails you are using, but for Rails 2.3.x, it looks like this
user_profile = Userprofile.first(:conditions => {:userEmail => #email, :userPassword => #pass})
For Rails 3.x, it looks like this:
user_profile = Userprofile.where(:userEmail => #email, :userPassword => #pass).first
Both variants expect that you have a model called Userprofile, which you generally require to effectively work with database objects in Rails. What both queries do is to create a new model instance from the first row returned from your query (that's what the first does).
Generally, you should get a book or some guide on the internet and learn how to properly use ActivRecord. Note that the API has seriously changed between Rails 2.3 and Rails 3 so make sure to use a guide for your actual Rails version.
And as a final advice, you shouldn't store actual ActiveRecord objects in the session. They would need to be serialized on store and de-serialized on access. What makes it hard (or impossible to track object references.
Also, Rails uses the cookie session store by default, which means that the whole session data is stored in a cookie on the client. The data therein in fully readyabkle to anyone with access to the cookie as it is only signed to restrict tampering with the data, but it is not encrypted. Thus, in your case anyone would be able to ready the (unecrypted) password.
Instead of storing the model object, you should store it's id instead and get the actual (and up-to-date) object from the database instead on each request. This is much easier, saves you from cache inconsistencies (what happens if the user changes her password) and is probably faster than to transfer a huge session cookie from the client on each request.

Resources