describe "Authentication using Tiddle strategy", type: :request do context "with valid email and token" do before do @user = User.create!(email: "test@example.com", password: "12345678") @token = Tiddle.create_and_return_token(@user, FakeRequest.new) end it "allows to access endpoints which require authentication" do get( secrets_path, headers: { "X-USER-EMAIL" => "test@example.com", "X-USER-TOKEN" => @token } ) expect(response.status).to eq 200 end describe "touching token" do context "when token was last used more than hour ago" do before do @user.authentication_tokens.last .update_attribute(:last_used_at, 2.hours.ago) end it "updates last_used_at field" do expect do get( secrets_path, headers: { "X-USER-EMAIL" => "test@example.com", "X-USER-TOKEN" => @token } ) end.to(change { @user.reload.authentication_tokens.last.last_used_at }) end end context "when token was last used less than hour ago" do before do @user.authentication_tokens.last.update_attribute(:last_used_at, 30.minutes.ago) end it "does not update last_used_at field" do expect do get( secrets_path, headers: { "X-USER-EMAIL" => "test@example.com", "X-USER-TOKEN" => @token } ) end.not_to(change { @user.authentication_tokens.last.last_used_at }) end end end context "when email contains uppercase letters" do it "converts email to lower case and authenticates user" do get( secrets_path, headers: { "X-USER-EMAIL" => "TEST@example.com", "X-USER-TOKEN" => @token } ) expect(response.status).to eq 200 end end end context "with invalid email and valid token" do before do @user = User.create!(email: "test@example.com", password: "12345678") @token = Tiddle.create_and_return_token(@user, FakeRequest.new) end it "does not allow to access endpoints which require authentication" do get( secrets_path, headers: { "X-USER-EMAIL" => "wrong@example.com", "X-USER-TOKEN" => @token } ) expect(response.status).to eq 401 end end context "with valid email and invalid token" do before do @user = User.create!(email: "test@example.com", password: "12345678") @token = Tiddle.create_and_return_token(@user, FakeRequest.new) end it "does not allow to access endpoints which require authentication" do get( secrets_path, headers: { "X-USER-EMAIL" => "test@example.com", "X-USER-TOKEN" => "wrong" } ) expect(response.status).to eq 401 end end context "when no headers are passed" do it "does not allow to access endpoints which require authentication" do get secrets_path, headers: {} expect(response.status).to eq 401 end end context "when model name consists of two words" do before do @admin_user = AdminUser.create!(email: "test@example.com", password: "12345678") @token = Tiddle.create_and_return_token(@admin_user, FakeRequest.new) end it "allows to access endpoints which require authentication" do get( long_secrets_path, headers: { "X-ADMIN-USER-EMAIL" => "test@example.com", "X-ADMIN-USER-TOKEN" => @token } ) expect(response.status).to eq 200 end end context "when the model name is composed of a namespace" do before do @user = Namespace::NamespacedUser.create!( email: "test@example.com", password: "12345678" ) @token = Tiddle.create_and_return_token(@user, FakeRequest.new) end it "allows to access endpoints which require authentication" do get( namespaced_users_path, headers: { "X-NAMESPACE--NAMESPACED-USER-EMAIL" => "test@example.com", "X-NAMESPACE--NAMESPACED-USER-TOKEN" => @token } ) expect(response.status).to eq 200 end end describe "using field other than email" do before do Devise.setup do |config| config.authentication_keys = [:nick_name] end @user = User.create!( email: "test@example.com", password: "12345678", nick_name: "test" ) @token = Tiddle.create_and_return_token(@user, FakeRequest.new) end after do Devise.setup do |config| config.authentication_keys = [:email] end end it "allows to access endpoints which require authentication with valid \ nick name and token" do get( secrets_path, headers: { "X-USER-NICK-NAME" => "test", "X-USER-TOKEN" => @token } ) expect(response.status).to eq 200 end end context "when token has expires_in set up" do before do @user = User.create!(email: "test@example.com", password: "12345678") @token = Tiddle.create_and_return_token(@user, FakeRequest.new, expires_in: 1.week) end describe "token is not expired" do it "does allow to access endpoints which require authentication" do get( secrets_path, headers: { "X-USER-EMAIL" => "test@example.com", "X-USER-TOKEN" => @token } ) expect(response.status).to eq 200 end end describe "token is expired" do before do token = @user.authentication_tokens.max_by(&:id) token.update_attribute(:last_used_at, 1.month.ago) end it "does not allow to access endpoints which require authentication" do get( secrets_path, headers: { "X-USER-EMAIL" => "test@example.com", "X-USER-TOKEN" => @token } ) expect(response.status).to eq 401 end end context "with value lower than 24 hours" do before do @token = Tiddle.create_and_return_token(@user, FakeRequest.new, expires_in: 1.hour) end context "and token was last used a minute ago" do before do @user.authentication_tokens.last.update_attribute(:last_used_at, 1.minute.ago) end it "does not update last_used_at field" do expect do get( secrets_path, headers: { "X-USER-EMAIL" => "test@example.com", "X-USER-TOKEN" => @token } ) end.not_to(change { @user.authentication_tokens.last.reload.last_used_at }) end end context "and token was last used 5 minutes ago" do before do @user.authentication_tokens.last.update_attribute(:last_used_at, 5.minute.ago) end it "updates last_used_at field" do expect do get( secrets_path, headers: { "X-USER-EMAIL" => "test@example.com", "X-USER-TOKEN" => @token } ) end.to(change { @user.authentication_tokens.last.reload.last_used_at }) end end end context "with value lower than 1 hour" do before do @token = Tiddle.create_and_return_token(@user, FakeRequest.new, expires_in: 30.minutes) end context "and token was last used less than a minute ago" do before do @user.authentication_tokens.last.update_attribute(:last_used_at, 30.seconds.ago) end it "does not update last_used_at field" do expect do get( secrets_path, headers: { "X-USER-EMAIL" => "test@example.com", "X-USER-TOKEN" => @token } ) end.not_to(change { @user.authentication_tokens.last.reload.last_used_at }) end end context "and token was last used a minute ago" do before do @user.authentication_tokens.last.update_attribute(:last_used_at, 1.minute.ago) end it "updates last_used_at field" do expect do get( secrets_path, headers: { "X-USER-EMAIL" => "test@example.com", "X-USER-TOKEN" => @token } ) end.to(change { @user.authentication_tokens.last.reload.last_used_at }) end end end end end