Commit 6efe9c2f authored by Alexis Reigel's avatar Alexis Reigel

atom links with rss token instead of private token

parent c1b5c806
......@@ -11,6 +11,7 @@ class ApplicationController < ActionController::Base
include EnforcesTwoFactorAuthentication
before_action :authenticate_user_from_private_token!
before_action :authenticate_user_from_rss_token!
before_action :authenticate_user!
before_action :validate_user_service_ticket!
before_action :check_password_expiration
......@@ -72,13 +73,20 @@ class ApplicationController < ActionController::Base
user = User.find_by_authentication_token(token) || User.find_by_personal_access_token(token)
if user && can?(user, :log_in)
# Notice we are passing store false, so the user is not
# actually stored in the session and a token is needed
# for every request. If you want the token to work as a
# sign in token, you can simply remove store: false.
sign_in user, store: false
end
sessionless_sign_in(user)
end
# This filter handles authentication for atom request with an rss_token
def authenticate_user_from_rss_token!
return unless request.format.atom?
token = params[:rss_token].presence
return unless token.present?
user = User.find_by_rss_token(token)
sessionless_sign_in(user)
end
def log_exception(exception)
......@@ -282,4 +290,14 @@ class ApplicationController < ActionController::Base
ensure
Gitlab::I18n.reset_locale
end
def sessionless_sign_in(user)
if user && can?(user, :log_in)
# Notice we are passing store false, so the user is not
# actually stored in the session and a token is needed
# for every request. If you want the token to work as a
# sign in token, you can simply remove store: false.
sign_in user, store: false
end
end
end
module RssHelper
def rss_url_options
{ format: :atom, private_token: current_user.try(:private_token) }
{ format: :atom, rss_token: current_user.try(:rss_token) }
end
end
......@@ -99,6 +99,42 @@ describe ApplicationController do
end
end
describe '#authenticate_user_from_rss_token' do
describe "authenticating a user from an rss token" do
controller(described_class) do
def index
render text: 'authenticated'
end
end
context "when the 'rss_token' param is populated with the rss token" do
context 'when the request format is atom' do
it "logs the user in" do
get :index, rss_token: user.rss_token, format: :atom
expect(response).to have_http_status 200
expect(response.body).to eq 'authenticated'
end
end
context 'when the request format is not atom' do
it "doesn't log the user in" do
get :index, rss_token: user.rss_token
expect(response.status).not_to have_http_status 200
expect(response.body).not_to eq 'authenticated'
end
end
end
context "when the 'rss_token' param is populated with an invalid rss token" do
it "doesn't log the user" do
get :index, rss_token: "token"
expect(response.status).not_to eq 200
expect(response.body).not_to eq 'authenticated'
end
end
end
end
describe '#route_not_found' do
it 'renders 404 if authenticated' do
allow(controller).to receive(:current_user).and_return(user)
......
......@@ -20,13 +20,20 @@ describe "Dashboard Issues Feed", feature: true do
expect(body).to have_selector('title', text: "#{user.name} issues")
end
it "renders atom feed via rss token" do
visit issues_dashboard_path(:atom, rss_token: user.rss_token)
expect(response_headers['Content-Type']).to have_content('application/atom+xml')
expect(body).to have_selector('title', text: "#{user.name} issues")
end
it "renders atom feed with url parameters" do
visit issues_dashboard_path(:atom, private_token: user.private_token, state: 'opened', assignee_id: user.id)
visit issues_dashboard_path(:atom, rss_token: user.rss_token, state: 'opened', assignee_id: user.id)
link = find('link[type="application/atom+xml"]')
params = CGI.parse(URI.parse(link[:href]).query)
expect(params).to include('private_token' => [user.private_token])
expect(params).to include('rss_token' => [user.rss_token])
expect(params).to include('state' => ['opened'])
expect(params).to include('assignee_id' => [user.id.to_s])
end
......@@ -35,7 +42,7 @@ describe "Dashboard Issues Feed", feature: true do
let!(:issue2) { create(:issue, author: user, assignees: [assignee], project: project2, description: 'test desc') }
it "renders issue fields" do
visit issues_dashboard_path(:atom, private_token: user.private_token)
visit issues_dashboard_path(:atom, rss_token: user.rss_token)
entry = find(:xpath, "//feed/entry[contains(summary/text(),'#{issue2.title}')]")
......@@ -58,7 +65,7 @@ describe "Dashboard Issues Feed", feature: true do
end
it "renders issue label and milestone info" do
visit issues_dashboard_path(:atom, private_token: user.private_token)
visit issues_dashboard_path(:atom, rss_token: user.rss_token)
entry = find(:xpath, "//feed/entry[contains(summary/text(),'#{issue1.title}')]")
......
......@@ -11,6 +11,13 @@ describe "Dashboard Feed", feature: true do
end
end
context "projects atom feed via rss token" do
it "renders projects atom feed" do
visit dashboard_projects_path(:atom, rss_token: user.rss_token)
expect(body).to have_selector('feed title')
end
end
context 'feed content' do
let(:project) { create(:project) }
let(:issue) { create(:issue, project: project, author: user, description: '') }
......@@ -20,7 +27,7 @@ describe "Dashboard Feed", feature: true do
project.team << [user, :master]
issue_event(issue, user)
note_event(note, user)
visit dashboard_projects_path(:atom, private_token: user.private_token)
visit dashboard_projects_path(:atom, rss_token: user.rss_token)
end
it "has issue opened event" do
......
......@@ -43,25 +43,40 @@ describe 'Issues Feed', feature: true do
end
end
context 'when authenticated via rss token' do
it 'renders atom feed' do
visit namespace_project_issues_path(project.namespace, project, :atom,
rss_token: user.rss_token)
expect(response_headers['Content-Type']).
to have_content('application/atom+xml')
expect(body).to have_selector('title', text: "#{project.name} issues")
expect(body).to have_selector('author email', text: issue.author_public_email)
expect(body).to have_selector('assignees assignee email', text: issue.assignees.first.public_email)
expect(body).to have_selector('assignee email', text: issue.assignees.first.public_email)
expect(body).to have_selector('entry summary', text: issue.title)
end
end
it "renders atom feed with url parameters for project issues" do
visit namespace_project_issues_path(project.namespace, project,
:atom, private_token: user.private_token, state: 'opened', assignee_id: user.id)
:atom, rss_token: user.rss_token, state: 'opened', assignee_id: user.id)
link = find('link[type="application/atom+xml"]')
params = CGI.parse(URI.parse(link[:href]).query)
expect(params).to include('private_token' => [user.private_token])
expect(params).to include('rss_token' => [user.rss_token])
expect(params).to include('state' => ['opened'])
expect(params).to include('assignee_id' => [user.id.to_s])
end
it "renders atom feed with url parameters for group issues" do
visit issues_group_path(group, :atom, private_token: user.private_token, state: 'opened', assignee_id: user.id)
visit issues_group_path(group, :atom, rss_token: user.rss_token, state: 'opened', assignee_id: user.id)
link = find('link[type="application/atom+xml"]')
params = CGI.parse(URI.parse(link[:href]).query)
expect(params).to include('private_token' => [user.private_token])
expect(params).to include('rss_token' => [user.rss_token])
expect(params).to include('state' => ['opened'])
expect(params).to include('assignee_id' => [user.id.to_s])
end
......
......@@ -11,6 +11,13 @@ describe "User Feed", feature: true do
end
end
context 'user atom feed via rss token' do
it "renders user atom feed" do
visit user_path(user, :atom, rss_token: user.rss_token)
expect(body).to have_selector('feed title')
end
end
context 'feed content' do
let(:project) { create(:project) }
let(:issue) do
......@@ -40,7 +47,7 @@ describe "User Feed", feature: true do
issue_event(issue, user)
note_event(note, user)
merge_request_event(merge_request, user)
visit user_path(user, :atom, private_token: user.private_token)
visit user_path(user, :atom, rss_token: user.rss_token)
end
it 'has issue opened event' do
......
......@@ -5,7 +5,7 @@ RSpec.describe 'Dashboard Activity', feature: true do
login_as(create :user)
visit activity_dashboard_path
end
it_behaves_like "it has an RSS button with current_user's private token"
it_behaves_like "an autodiscoverable RSS feed with current_user's private token"
it_behaves_like "it has an RSS button with current_user's rss token"
it_behaves_like "an autodiscoverable RSS feed with current_user's rss token"
end
......@@ -62,6 +62,6 @@ RSpec.describe 'Dashboard Issues', feature: true do
expect(page).to have_content(other_issue.title)
end
it_behaves_like "it has an RSS button with current_user's private token"
it_behaves_like "an autodiscoverable RSS feed with current_user's private token"
it_behaves_like "it has an RSS button with current_user's rss token"
it_behaves_like "an autodiscoverable RSS feed with current_user's rss token"
end
......@@ -31,5 +31,5 @@ RSpec.describe 'Dashboard Projects', feature: true do
end
end
it_behaves_like "an autodiscoverable RSS feed with current_user's private token"
it_behaves_like "an autodiscoverable RSS feed with current_user's rss token"
end
......@@ -53,10 +53,10 @@ describe "Dashboard Issues filtering", feature: true, js: true do
auto_discovery_link = find('link[type="application/atom+xml"]', visible: false)
auto_discovery_params = CGI.parse(URI.parse(auto_discovery_link[:href]).query)
expect(params).to include('private_token' => [user.private_token])
expect(params).to include('rss_token' => [user.rss_token])
expect(params).to include('milestone_title' => [''])
expect(params).to include('assignee_id' => [user.id.to_s])
expect(auto_discovery_params).to include('private_token' => [user.private_token])
expect(auto_discovery_params).to include('rss_token' => [user.rss_token])
expect(auto_discovery_params).to include('milestone_title' => [''])
expect(auto_discovery_params).to include('assignee_id' => [user.id.to_s])
end
......
......@@ -11,8 +11,8 @@ feature 'Group activity page', feature: true do
visit path
end
it_behaves_like "it has an RSS button with current_user's private token"
it_behaves_like "an autodiscoverable RSS feed with current_user's private token"
it_behaves_like "it has an RSS button with current_user's rss token"
it_behaves_like "an autodiscoverable RSS feed with current_user's rss token"
end
context 'when signed out' do
......@@ -20,7 +20,7 @@ feature 'Group activity page', feature: true do
visit path
end
it_behaves_like "it has an RSS button without a private token"
it_behaves_like "an autodiscoverable RSS feed without a private token"
it_behaves_like "it has an RSS button without an rss token"
it_behaves_like "an autodiscoverable RSS feed without an rss token"
end
end
......@@ -12,15 +12,15 @@ feature 'Group issues page', feature: true do
context 'when signed in' do
let(:user) { user_in_group }
it_behaves_like "it has an RSS button with current_user's private token"
it_behaves_like "an autodiscoverable RSS feed with current_user's private token"
it_behaves_like "it has an RSS button with current_user's rss token"
it_behaves_like "an autodiscoverable RSS feed with current_user's rss token"
end
context 'when signed out' do
let(:user) { nil }
it_behaves_like "it has an RSS button without a private token"
it_behaves_like "an autodiscoverable RSS feed without a private token"
it_behaves_like "it has an RSS button without an rss token"
it_behaves_like "an autodiscoverable RSS feed without an rss token"
end
end
......
......@@ -11,7 +11,7 @@ feature 'Group show page', feature: true do
visit path
end
it_behaves_like "an autodiscoverable RSS feed with current_user's private token"
it_behaves_like "an autodiscoverable RSS feed with current_user's rss token"
end
context 'when signed out' do
......@@ -19,6 +19,6 @@ feature 'Group show page', feature: true do
visit path
end
it_behaves_like "an autodiscoverable RSS feed without a private token"
it_behaves_like "an autodiscoverable RSS feed without an rss token"
end
end
......@@ -810,10 +810,10 @@ describe 'Filter issues', js: true, feature: true do
auto_discovery_link = find('link[type="application/atom+xml"]', visible: false)
auto_discovery_params = CGI.parse(URI.parse(auto_discovery_link[:href]).query)
expect(params).to include('private_token' => [user.private_token])
expect(params).to include('rss_token' => [user.rss_token])
expect(params).to include('milestone_title' => [milestone.title])
expect(params).to include('assignee_id' => [user.id.to_s])
expect(auto_discovery_params).to include('private_token' => [user.private_token])
expect(auto_discovery_params).to include('rss_token' => [user.rss_token])
expect(auto_discovery_params).to include('milestone_title' => [milestone.title])
expect(auto_discovery_params).to include('assignee_id' => [user.id.to_s])
end
......@@ -825,10 +825,10 @@ describe 'Filter issues', js: true, feature: true do
auto_discovery_link = find('link[type="application/atom+xml"]', visible: false)
auto_discovery_params = CGI.parse(URI.parse(auto_discovery_link[:href]).query)
expect(params).to include('private_token' => [user.private_token])
expect(params).to include('rss_token' => [user.rss_token])
expect(params).to include('milestone_title' => [milestone.title])
expect(params).to include('assignee_id' => [user.id.to_s])
expect(auto_discovery_params).to include('private_token' => [user.private_token])
expect(auto_discovery_params).to include('rss_token' => [user.rss_token])
expect(auto_discovery_params).to include('milestone_title' => [milestone.title])
expect(auto_discovery_params).to include('assignee_id' => [user.id.to_s])
end
......
......@@ -16,7 +16,7 @@ feature 'Project Activity RSS' do
visit path
end
it_behaves_like "it has an RSS button with current_user's private token"
it_behaves_like "it has an RSS button with current_user's rss token"
end
context 'when signed out' do
......@@ -24,6 +24,6 @@ feature 'Project Activity RSS' do
visit path
end
it_behaves_like "it has an RSS button without a private token"
it_behaves_like "it has an RSS button without an rss token"
end
end
......@@ -12,8 +12,8 @@ feature 'Project Commits RSS' do
visit path
end
it_behaves_like "it has an RSS button with current_user's private token"
it_behaves_like "an autodiscoverable RSS feed with current_user's private token"
it_behaves_like "it has an RSS button with current_user's rss token"
it_behaves_like "an autodiscoverable RSS feed with current_user's rss token"
end
context 'when signed out' do
......@@ -21,7 +21,7 @@ feature 'Project Commits RSS' do
visit path
end
it_behaves_like "it has an RSS button without a private token"
it_behaves_like "an autodiscoverable RSS feed without a private token"
it_behaves_like "it has an RSS button without an rss token"
it_behaves_like "an autodiscoverable RSS feed without an rss token"
end
end
......@@ -16,8 +16,8 @@ feature 'Project Issues RSS' do
visit path
end
it_behaves_like "it has an RSS button with current_user's private token"
it_behaves_like "an autodiscoverable RSS feed with current_user's private token"
it_behaves_like "it has an RSS button with current_user's rss token"
it_behaves_like "an autodiscoverable RSS feed with current_user's rss token"
end
context 'when signed out' do
......@@ -25,7 +25,7 @@ feature 'Project Issues RSS' do
visit path
end
it_behaves_like "it has an RSS button without a private token"
it_behaves_like "an autodiscoverable RSS feed without a private token"
it_behaves_like "it has an RSS button without an rss token"
it_behaves_like "an autodiscoverable RSS feed without an rss token"
end
end
......@@ -12,7 +12,7 @@ feature 'Project RSS' do
visit path
end
it_behaves_like "an autodiscoverable RSS feed with current_user's private token"
it_behaves_like "an autodiscoverable RSS feed with current_user's rss token"
end
context 'when signed out' do
......@@ -20,6 +20,6 @@ feature 'Project RSS' do
visit path
end
it_behaves_like "an autodiscoverable RSS feed without a private token"
it_behaves_like "an autodiscoverable RSS feed without an rss token"
end
end
......@@ -12,7 +12,7 @@ feature 'Project Tree RSS' do
visit path
end
it_behaves_like "an autodiscoverable RSS feed with current_user's private token"
it_behaves_like "an autodiscoverable RSS feed with current_user's rss token"
end
context 'when signed out' do
......@@ -20,6 +20,6 @@ feature 'Project Tree RSS' do
visit path
end
it_behaves_like "an autodiscoverable RSS feed without a private token"
it_behaves_like "an autodiscoverable RSS feed without an rss token"
end
end
......@@ -9,7 +9,7 @@ feature 'User RSS' do
visit path
end
it_behaves_like "it has an RSS button with current_user's private token"
it_behaves_like "it has an RSS button with current_user's rss token"
end
context 'when signed out' do
......@@ -17,6 +17,6 @@ feature 'User RSS' do
visit path
end
it_behaves_like "it has an RSS button without a private token"
it_behaves_like "it has an RSS button without an rss token"
end
end
......@@ -3,17 +3,17 @@ require 'spec_helper'
describe RssHelper do
describe '#rss_url_options' do
context 'when signed in' do
it "includes the current_user's private_token" do
it "includes the current_user's rss_token" do
current_user = create(:user)
allow(helper).to receive(:current_user).and_return(current_user)
expect(helper.rss_url_options).to include private_token: current_user.private_token
expect(helper.rss_url_options).to include rss_token: current_user.rss_token
end
end
context 'when signed out' do
it "does not have a private_token" do
it "does not have an rss_token" do
allow(helper).to receive(:current_user).and_return(nil)
expect(helper.rss_url_options[:private_token]).to be_nil
expect(helper.rss_url_options[:rss_token]).to be_nil
end
end
end
......
shared_examples "an autodiscoverable RSS feed with current_user's private token" do
it "has an RSS autodiscovery link tag with current_user's private token" do
expect(page).to have_css("link[type*='atom+xml'][href*='private_token=#{Thread.current[:current_user].private_token}']", visible: false)
shared_examples "an autodiscoverable RSS feed with current_user's rss token" do
it "has an RSS autodiscovery link tag with current_user's rss token" do
expect(page).to have_css("link[type*='atom+xml'][href*='rss_token=#{Thread.current[:current_user].rss_token}']", visible: false)
end
end
shared_examples "it has an RSS button with current_user's private token" do
it "shows the RSS button with current_user's private token" do
expect(page).to have_css("a:has(.fa-rss)[href*='private_token=#{Thread.current[:current_user].private_token}']")
shared_examples "it has an RSS button with current_user's rss token" do
it "shows the RSS button with current_user's rss token" do
expect(page).to have_css("a:has(.fa-rss)[href*='rss_token=#{Thread.current[:current_user].rss_token}']")
end
end
shared_examples "an autodiscoverable RSS feed without a private token" do
it "has an RSS autodiscovery link tag without a private token" do
expect(page).to have_css("link[type*='atom+xml']:not([href*='private_token'])", visible: false)
shared_examples "an autodiscoverable RSS feed without an rss token" do
it "has an RSS autodiscovery link tag without an rss token" do
expect(page).to have_css("link[type*='atom+xml']:not([href*='rss_token'])", visible: false)
end
end
shared_examples "it has an RSS button without a private token" do
it "shows the RSS button without a private token" do
expect(page).to have_css("a:has(.fa-rss):not([href*='private_token'])")
shared_examples "it has an RSS button without an rss token" do
it "shows the RSS button without an rss token" do
expect(page).to have_css("a:has(.fa-rss):not([href*='rss_token'])")
end
end
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment