diff --git a/app/controllers/devise_token_auth/concerns/set_user_by_token.rb b/app/controllers/devise_token_auth/concerns/set_user_by_token.rb index 721dfe764..099be68f4 100644 --- a/app/controllers/devise_token_auth/concerns/set_user_by_token.rb +++ b/app/controllers/devise_token_auth/concerns/set_user_by_token.rb @@ -21,19 +21,26 @@ def set_user_by_token(mapping=nil) # no default user defined return unless rc - # user has already been found and authenticated - return @resource if @resource and @resource.class == rc - # parse header for values necessary for authentication uid = request.headers['uid'] || params['uid'] @token = request.headers['access-token'] || params['access-token'] @client_id = request.headers['client'] || params['client'] - return false unless @token - # client_id isn't required, set to 'default' if absent @client_id ||= 'default' + # check for an existing user, authenticated via warden/devise + devise_warden_user = warden.user(rc.to_s.underscore.to_sym) + if devise_warden_user && devise_warden_user.tokens[@client_id].nil? + @resource = devise_warden_user + @resource.create_new_auth_token + end + + # user has already been found and authenticated + return @resource if @resource and @resource.class == rc + + return false unless @token + # mitigate timing attacks by finding by uid instead of auth token user = uid && rc.find_by_uid(uid) diff --git a/test/controllers/demo_user_controller_test.rb b/test/controllers/demo_user_controller_test.rb index 81720de3f..364a90355 100644 --- a/test/controllers/demo_user_controller_test.rb +++ b/test/controllers/demo_user_controller_test.rb @@ -7,6 +7,7 @@ # was the appropriate message delivered in the json payload? class DemoUserControllerTest < ActionDispatch::IntegrationTest + include Warden::Test::Helpers describe DemoUserController do describe "Token access" do before do @@ -258,5 +259,57 @@ class DemoUserControllerTest < ActionDispatch::IntegrationTest end end end + + describe 'Existing Warden authentication' do + before do + @resource = users(:confirmed_email_user) + @resource.skip_confirmation! + @resource.save! + login_as( @resource, :scope => :user) + + # no auth headers sent, testing that warden authenticates correctly. + get '/demo/members_only', {}, nil + + @resp_token = response.headers['access-token'] + @resp_client_id = response.headers['client'] + @resp_expiry = response.headers['expiry'] + @resp_uid = response.headers['uid'] + end + + describe 'devise mappings' do + it 'should define current_user' do + assert_equal @resource, @controller.current_user + end + + it 'should define user_signed_in?' do + assert @controller.user_signed_in? + end + + it 'should not define current_mang' do + refute_equal @resource, @controller.current_mang + end + end + + it 'should return success status' do + assert_equal 200, response.status + end + + it 'should receive new token after successful request' do + assert @resp_token + end + + it 'should set the token expiry in the auth header' do + assert @resp_expiry + end + + it 'should return the client id in the auth header' do + assert @resp_client_id + end + + it "should return the user's uid in the auth header" do + assert @resp_uid + end + end + end end