wardencommunity / warden

General Rack Authentication Framework
MIT License
2.48k stars 204 forks source link

User session lost after post request #132

Open stephan-nordnes-eriksen opened 8 years ago

stephan-nordnes-eriksen commented 8 years ago

It appears that my env['warden'].user is lost if my app receives a post request.

This is the test methods I am using:

get '/amiloggedin' do
    puts "get user"
    puts env['warden'].user.inspect
    puts env['HTTP_COOKIE'] 
    env['warden'].authenticate!

    "You are logged in"
  end

  post '/amiloggedin' do 
    puts "post user"
    puts env['warden'].user.inspect
    puts env['HTTP_COOKIE']
    env['warden'].authenticate!

    "Logged in after post request"
  end

The HTTP_COOKIE is the same for both requests, but for some reason the warden user is lost when I send a post request. It is lost for that request and further all requests (including get requests).

This is my a strategy:


Warden::Strategies.add(:password) do
  def valid?
    params['user'] && params['user']['email'] && params['user']['password']
  end

  def authenticate!
    user = User.first(email: params['user']['email'])

    if user.nil?
      throw(:warden, message: "The email you entered does not exist.")
    elsif user.authenticate(params['user']['password'])
      success!(user)
    else
      throw(:warden, message: "The email and password combination ")
    end
  end
end

This is my user model:

DataMapper.setup(:default, "sqlite://#{Dir.pwd}/db/db.sqlite")

class User
  include DataMapper::Resource

  property :id, Serial, key: true
  property :username, String, length: 128

  #property :password, BCryptHash, :required => true, :length => 5..200
  property :password, BCryptHash, :required => true

  attr_accessor :password_confirmation
  validates_confirmation_of :password, :confirm => :password_confirmation
  validates_length_of :password_confirmation, :min => 6

  property :email, String, :required => true, :unique => true,
    :format   => :email_address,
    :messages => {
      :presence  => "We need your email address.",
      :is_unique => "We already have that email.",
      :format    => "Doesn't look like an email address to me ..."
    }

  def authenticate(attempted_password)
    # The BCrypt class, which `self.password` is an instance of, has `==` defined to compare a
    # test plain text string to the encrypted string and converts `attempted_password` to a BCrypt
    # for the comparison.
    #
    # But don't take my word for it, check out the source: https://github.com/codahale/bcrypt-ruby/blob/master/lib/bcrypt/password.rb#L64-L67
    if self.password == attempted_password
      true
    else
      false
    end
  end
end

# Tell DataMapper the models are done being defined
DataMapper.finalize

# Update the database to match the properties of User.
DataMapper.auto_upgrade!

# Create a test User
if User.count == 0
  @user = User.create(username: "admin")
  @user.password = "admin"
  @user.save
end

Is there something wrong with my strategy?

hassox commented 8 years ago

I don't see anything immediately wrong. It sounds like your session is being rotated out from under you. Can you confirm the contents of your session are what you expect?

stephan-nordnes-eriksen commented 8 years ago

As I understand it, the env["HTTP_COOKIE"] is what should be the same between each request.

This is my test logic right now:

get '/amiloggedin' do
    puts "!!!get!!!!!user!!!!!!"
    puts env['warden'].user.inspect
    puts "!!!!!!!!!!!!!!!!"
    puts env['HTTP_COOKIE'] 
    env['warden'].authenticate!

    "You are logged in"
  end

  post '/amiloggedin' do 
    puts "!!!post!!!!!user!!!!!!"
    env['warden'].authenticated?
    puts env['warden'].user.inspect
    puts "!!!!!!!!!!!!!!!!"
    puts env['HTTP_COOKIE']
    env['warden'].authenticate!

    "Logged in"

  end

This results in the following output:

!!!get!!!!!user!!!!!!
#<User @id=5 @username=nil @password="$2a$10$7ESe1/E0eYsHtWpDEoESCuWZARvl8sSMYcmBsAd9naseRwpfmPjgq" @email="test2@test.com">
!!!!!!!!!!!!!!!!
sid=80gujPBEanwRFAP3EksUHOdes1_iKMDZDqO4xkA0rm6nqh0rADo-_jpKjsWNusF86roDztXbdAXHHD_Lr5FMLA_Shqcd-uGJLEziPrnNXGRwoPy3P6ww0BD23KcjkiHSeOGpyvDgzT9Gaph0AO-HSSL7ktnaZPHWyu72AGNu37k; _csrf=s%3A-rHM4NIgqsydQPu9RWH_f-28.P97jnEZgxRKRShBIXMLriNTNbbRx9C5jwMgGA4K240Q; connect.sid=s%3AtLO0MsT_PokGg8aKlGjwHGAc4i_bcv73.AZieI6q9y8VKh%2FX9zs6xKRQJx4vooTfCfnVxd41DiyU; _csrfToken=7Zr5rZY4-qiqX-ZxC85d74rc5jHvPJidnf4c; _ga=GA1.1.1414499867.1448402810; rack.session=BAh7CUkiCWNzcmYGOgZFRkkiJTEyYWRjZDQyOThlMjY0YjhiMjdiYzRhMDI1%0AY2ZkMTc3BjsARkkiDXRyYWNraW5nBjsARnsHSSIUSFRUUF9VU0VSX0FHRU5U%0ABjsAVEkiLTAxOTNiYmM1YjlkYzg3NGZlMWI5YWRjZWM5MmU1NTY0ZWIxM2Iy%0ANWQGOwBGSSIZSFRUUF9BQ0NFUFRfTEFOR1VBR0UGOwBUSSItYjJmMjQ1YTIw%0AZWUxNDhhOWQ3ZmE1MDBjOTY2ZWQxN2ZkY2EyOWMyNQY7AEZJIhx3YXJkZW4u%0AdXNlci5kZWZhdWx0LmtleQY7AFRpCkkiD3Nlc3Npb25faWQGOwBUSSJFYzEx%0AZTE4ZTIyOTUxMzgxOWI0N2Y2MzFjNWY4YTdiZjE2YjQwZTEzNThlOWI0ZDcy%0AYTExODE1NGIyMDcyYzEzZAY7AEY%3D%0A--2d72b4ae2a0868e811e881773296e79c6eff7cda
!!!post!!!!!user!!!!!!
nil
!!!!!!!!!!!!!!!!
sid=80gujPBEanwRFAP3EksUHOdes1_iKMDZDqO4xkA0rm6nqh0rADo-_jpKjsWNusF86roDztXbdAXHHD_Lr5FMLA_Shqcd-uGJLEziPrnNXGRwoPy3P6ww0BD23KcjkiHSeOGpyvDgzT9Gaph0AO-HSSL7ktnaZPHWyu72AGNu37k; _csrf=s%3A-rHM4NIgqsydQPu9RWH_f-28.P97jnEZgxRKRShBIXMLriNTNbbRx9C5jwMgGA4K240Q; connect.sid=s%3AtLO0MsT_PokGg8aKlGjwHGAc4i_bcv73.AZieI6q9y8VKh%2FX9zs6xKRQJx4vooTfCfnVxd41DiyU; _csrfToken=7Zr5rZY4-qiqX-ZxC85d74rc5jHvPJidnf4c; _ga=GA1.1.1414499867.1448402810; rack.session=BAh7CUkiCWNzcmYGOgZFRkkiJTEyYWRjZDQyOThlMjY0YjhiMjdiYzRhMDI1%0AY2ZkMTc3BjsARkkiDXRyYWNraW5nBjsARnsHSSIUSFRUUF9VU0VSX0FHRU5U%0ABjsAVEkiLTAxOTNiYmM1YjlkYzg3NGZlMWI5YWRjZWM5MmU1NTY0ZWIxM2Iy%0ANWQGOwBGSSIZSFRUUF9BQ0NFUFRfTEFOR1VBR0UGOwBUSSItYjJmMjQ1YTIw%0AZWUxNDhhOWQ3ZmE1MDBjOTY2ZWQxN2ZkY2EyOWMyNQY7AEZJIhx3YXJkZW4u%0AdXNlci5kZWZhdWx0LmtleQY7AFRpCkkiD3Nlc3Npb25faWQGOwBUSSJFYzEx%0AZTE4ZTIyOTUxMzgxOWI0N2Y2MzFjNWY4YTdiZjE2YjQwZTEzNThlOWI0ZDcy%0AYTExODE1NGIyMDcyYzEzZAY7AEY%3D%0A--2d72b4ae2a0868e811e881773296e79c6eff7cda

I can run however many GET requests I want and still get the same result, but when I run one post, to any url, i get that env['warden'].user is nil. Very strange.

stephan-nordnes-eriksen commented 8 years ago

Any news on this?

jsmestad commented 7 years ago

@stephan-nordnes-eriksen I think we'd need a full test case to really dig in. My first guess is there is something going on with your test environment, but cannot know for sure without a sample project showing the error

LarryFransson commented 6 years ago

Has there been any activity on this? I'm seeing it also. I can authenticate, but as soon as I try to visit any other URL in the app, the user is nil. I have attached a demo project (as simple as I could keep it) that exhibits the behavior. bundle and rackup or padrino s to start. I've been using Ruby 2.5.0. demo.zip

jsmestad commented 6 years ago

@LarryFransson you mind tossing this zip into a github repo? I cant download a random zip file on my machine 🔐

LarryFransson commented 6 years ago

Sure thing. Here you go: https://github.com/LarryFransson/demo

jsmestad commented 6 years ago

@LarryFransson sounds good. I should have time later this week to take a look.

mhuconcern commented 6 years ago

Has there been any update on this ? Facing similar issues

Update: I fixed this on my repo by serializing_from_session and into_session through warden

smasry commented 3 years ago

Is it possible you have a domain set on your cookie that doesn't match what your test domain is running as?

ryana commented 3 years ago

FTR I don't think this is a problem with Warden. I don't have a solution but I want to share a related story in case anyone else runs into things and finds this thread like we did.

We have a react app sitting on top of a Grape API. The app works flawlessly almost everywhere except once place: when someone clicks a link to the app from a DM inside the Instagram mobile app, which is then opened in an instance of a iOS WKWebView.

Even worse, the issue is not consistently repeatable. Close to 90% of the time there is no issue, but ~10% of the time users get half way into our onboarding flow and then get stuck with a 401 when trying to POST. The oddest thing. Part of our flow includes getting a code emailed to you, and the place where the auth goes haywire is always after someone switches out of the IG app and over to their mail client to get the code. I think IG might be doing something funky with how it instantiates it's WKWebView that is causing cookies to be cleared under some circumstances when going back into the app.