Skip to content
This repository has been archived by the owner on Jun 27, 2023. It is now read-only.

Temp Fix to restrict access for unconfirmed users #992

Closed
wants to merge 6 commits into from
Closed
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
150 changes: 78 additions & 72 deletions app/models/ability.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
# frozen_string_literal: true
# See the wiki for details:
# https://github.com/ryanb/cancan/wiki/Defining-Abilities

class Ability
include CanCan::Ability
Expand All @@ -10,102 +8,110 @@ def initialize(user)

alias_action :create, :read, :update, :destroy, to: :crud

can :crud, User, id: user.id
can :crud, User if user.admin?
can :read, User
can :update, User, id: user.id
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure I understood correctly, but admins seem to be losing the ability to update users here. Is that correct?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the failing spec comes from here. Is there a reason we're removing admin access from crud'ing users?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Admin can still crud User, it has moved to line 38.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My apologies! Dunno how I missed that...

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But the admin call is guarded behind a if user.confirmed?. I feel we should keep the current behaviour. If anything, we want admins to be able to fix a user's typo'd email address as a response to a support request ticket.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • if user.confirmed? checks here if the admin user is confirmed. Which they should be, right?
  • I added very verbose expectations to check if an admin user can crud everyone.
  • And I tested manually if an admin user can update someone else's account. They can, and the new specs cover that now...

can :resend_confirmation_instruction, User, id: user.id
can :resend_confirmation_instruction, User if user.admin?
can :read, Team
can :read, Project
can :read, :feed_entry

# visibility of email address in user profile
can :read_email, User, id: user.id if !user.hide_email?
can :read_email, User if user.admin?
can :read_email, User do |other_user|
user.confirmed? && (supervises?(other_user, user) || !other_user.hide_email?)
end

can :crud, Team do |team|
user.admin? || signed_in?(user) && team.new_record? || on_team?(user, team)
def signed_in?(user)
user.persisted?
end

can :update_conference_preferences, Team do |team|
team.accepted? && team.students.include?(user)
def on_team?(user, team)
user.teams.include?(team)
end

can :see_offered_conferences, Team do |team|
user.admin? || team.students.include?(user) || team.supervisors.include?(user)
def on_team_for_season?(user, season)
season && user.roles.student.joins(:team).pluck(:season_id).include?(season.id)
end

can :accept_or_reject_conference_offer, Team do |team|
team.students.include?(user)
def supervises?(user, supervisor)
user.teams.in_current_season.any? { |team| team.supervisors.include?(supervisor) }
end

cannot :create, Team do |team|
on_team_for_season?(user, team.season) || !user.confirmed?
end
if user.confirmed?

can :join, Team do |team|
team.helpdesk_team? and signed_in?(user) and user.confirmed? and not on_team?(user, team)
end
can :crud, User, id: user.id
can :crud, User if user.admin?
can :resend_confirmation_instruction, User if user.admin?

can :crud, Role do |role|
user.admin? || on_team?(user, role.team)
end
# visibility of email address in user profile
can :read_email, User, id: user.id if !user.hide_email?
can :read_email, User if user.admin?
can :read_email, User do |other_user|
user.confirmed? && (supervises?(other_user, user) || !other_user.hide_email?)
end

can :crud, Source do |repo|
user.admin? || on_team?(user, repo.team)
end
can :crud, Team do |team|
user.admin? || signed_in?(user) && team.new_record? || on_team?(user, team)
end

can :supervise, Team do |team|
user.roles.organizer.any? || team.supervisors.include?(user)
end
can :update_conference_preferences, Team do |team|
team.accepted? && team.students.include?(user)
end

can :crud, ConferencePreference do |preference|
user.admin? || (preference.team.students.include? user)
end
can :see_offered_conferences, Team do |team|
user.admin? || team.students.include?(user) || team.supervisors.include?(user)
end

can :crud, Conference if user.admin? || user.current_student?
can :accept_or_reject_conference_offer, Team do |team|
team.students.include?(user)
end

# todo add mailing controller and view for users in their namespace, where applicable
can :read, Mailing do |mailing|
mailing.recipient? user
end
cannot :create, Team do |team|
on_team_for_season?(user, team.season) || !user.confirmed?
end

can :crud, :comments if user.admin?
can :read, :users_info if user.admin? || user.supervisor?
can :join, Team do |team|
team.helpdesk_team? and signed_in?(user) and user.confirmed? and not on_team?(user, team)
end

# projects
can :crud, Project do |project|
user.admin? ||
(user.confirmed? && user == project.submitter)
end
can :use_as_template, Project do |project|
user == project.submitter && !project.season&.current?
end
can :crud, Role do |role|
user.admin? || on_team?(user, role.team)
end

can :create, Project if user.confirmed?
cannot :create, Project if !user.confirmed?
can :crud, Source do |repo|
user.admin? || on_team?(user, repo.team)
end

# activities
can :read, :feed_entry
can :read, :mailing if signed_in?(user)
can :supervise, Team do |team|
user.roles.organizer.any? || team.supervisors.include?(user)
end

# applications
can :create, :application_draft if user.student? && user.application_drafts.in_current_season.none?
end
can :crud, ConferencePreference do |preference|
user.admin? || (preference.team.students.include? user)
end

def signed_in?(user)
user.persisted?
end
can :crud, Conference if user.admin? || user.current_student?

def on_team?(user, team)
user.teams.include?(team)
end
# todo add mailing controller and view for users in their namespace, where applicable
can :read, Mailing do |mailing|
mailing.recipient? user
end

def on_team_for_season?(user, season)
season && user.roles.student.joins(:team).pluck(:season_id).include?(season.id)
end
can :crud, :comments if user.admin?
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not related to this PR specifically, and we should probably open a separate issue for this: it seems we're not testing this ability in the project comments (or anywhere I could find).

We used to have this in the teams show page, but it was removed meanwhile:

- if can? :crud, :comments
.comments
a href='#' Hide comments
= render partial: 'comments/form', object: @team, as: :team
ul
= render @team.comments, as: :comment

I've not used CanCanCan a lot in the past.. do we usually use the controller helpers or just view helpers?

Should I create the issue or do we want to fix it in this PR?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We use both helpers ( PR #993 is all about the controller helpers :-) )
If it's okay with you, I'd prefer to keep the PR's as clean as possible. And collect issues for every step layed out in the Overhaul: Breakdown (#991) . So we can use that as a reference all the way.
The crud comments issue will be part of the CommentsController Overhaul (listed in nr 5 in 991). Or afterwards, in the restructuring of the Ability. I'll add it. Thanks!!

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Of course! Thank you for your patience - I'm still figuring out how we structure things! 😊

can :read, :users_info if user.admin? || user.supervisor?

def supervises?(user, supervisor)
user.teams.in_current_season.any? { |team| team.supervisors.include?(supervisor) }
end
# projects
can :crud, Project do |project|
user.admin? ||
(user.confirmed? && user == project.submitter)
end
can :use_as_template, Project do |project|
user == project.submitter && !project.season&.current?
end

can :create, Project if user.confirmed?
cannot :create, Project if !user.confirmed?

# activities
can :read, :mailing if signed_in?(user)

# applications
can :create, :application_draft if user.student? && user.application_drafts.in_current_season.none?
end
end
end
2 changes: 1 addition & 1 deletion spec/controllers/mailings_controller_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

describe 'GET index' do
context 'with user logged in' do
include_context 'with user logged in'
include_context 'with confirmed user logged in'

it 'renders the index' do
get :index
Expand Down
1 change: 1 addition & 0 deletions spec/controllers/organizers/teams_controller_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
let(:valid_attributes) { build(:team).attributes.merge(roles_attributes: [{ name: 'coach', github_handle: 'tobias' }]) }

before do
user.confirm
user.roles.create(name: 'student', team: team)
end

Expand Down
72 changes: 72 additions & 0 deletions spec/features/users/guest_users_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
require 'rails_helper'

RSpec.describe 'Guest Users', type: :feature do
let!(:user) { create(:user) } # not the guest user; don't sign_in user
let!(:project) { create(:project, :in_current_season, :accepted, submitter: user) }
let!(:team1) { create(:team, name: 'Cheesy forever') }
let!(:activity) { create(:status_update, :published, team: team1) }
let(:out_of_season) { Season.current.starts_at - 1.week }
let(:summer_season) { Season.current.starts_at + 1.week }

context "when visiting public pages" do

context 'all year' do
before { Timecop.travel(out_of_season) }
after { Timecop.return }

it 'has restricted access to Activities page' do
visit root_path
expect(page).to have_css('h1', text: 'Activities')
find('.title', match: :smart).click
expect(page).to have_content(activity.title)
expect(page).to have_content('You must be logged in to add a comment.')
end

it 'has restricted access to Community page' do
visit community_path
expect(page).to have_css('h1', text: 'Community')
find_link(user.name, match: :first).click
expect(page).to have_content("About me")
expect(page).to have_link("All participants")
expect(page).not_to have_link("Edit") # check
end

it 'has access to Projects page' do
visit projects_path
expect(page).to have_css('h1', text: 'Projects') # can be empty table
end

it 'has a menu with public links' do
visit root_path
expect(page).to have_link("Activities")
find_link("Summer of Code").click
expect(page).to have_link("Teams")
expect(page).to have_link("Community")
expect(page).to have_link("Help")
end

it 'has access to sign in link' do
visit root_path
expect(page).to have_link('Sign in')
# story continues in sign_in_confirmed_user || sign_in_unconfirmed_user || sign_in_fail
end
end

context 'in season' do
before do
Timecop.travel(summer_season)
allow_any_instance_of(Project).to receive(:selected).and_return(:project)
end
after { Timecop.return }

it 'has access to Projects index and show' do
pending 'Stub needs updating; project not visible on page'
visit projects_path
expect(page).to have_css('h1', text: 'Projects')
find_link(project.name, match: :smart).click
expect(page).to have_content project.description
expect(page).not_to have_link("Edit")
end
end
end
end
14 changes: 6 additions & 8 deletions spec/models/ability_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,9 @@

describe 'she/he is not allowed to CRUD on someone else account' do
let(:other_user) { create(:user) }
it { expect(ability).not_to be_able_to(:show, other_user) }

it { expect(ability).to be_able_to(:show, other_user) }
it { expect(ability).not_to be_able_to(:update, other_user) }
end


Expand Down Expand Up @@ -69,6 +71,7 @@
allow(user).to receive(:confirmed?).and_return(false)
end
it 'allows to see not hidden email address' do
pending "Fails. Unconfirmed user has no access"
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

??? This spec is failing, but I am not sure if we even want it to pass for this conditions?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm. You're right. All an unconfirmed user should, in theory, be able to do is edit their email address.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about we keep it pending for now? I expect that it will solve itself in the upcoming Overhaul steps.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I agree. Is there a way to mark this as a TODO? Or is the pending enough, do you reckon?

Copy link
Member Author

@emcoding emcoding May 14, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am currently collecting all the todo's, and will add them when we have finished the discussion in #991 . Don't want to add too much detail to that.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fair point!

other_user.hide_email = false
expect(ability).to be_able_to(:read_email, other_user)
end
Expand All @@ -92,7 +95,6 @@
end
end
end

end

describe 'who is disallowed to see email address in user profile' do
Expand Down Expand Up @@ -127,10 +129,8 @@
end
end
end

end


context 'resend_confirmation_instruction' do
let(:other_user) { create(:user) }

Expand Down Expand Up @@ -167,7 +167,6 @@
let!(:other_user) { create(:user)}
let!(:conference_preference) { create(:conference_preference, team: team)}
it { expect(ability).not_to be_able_to(:crud, other_user) }

end
end

Expand Down Expand Up @@ -314,6 +313,7 @@
end
end
end

context 'when user guest (not persisted)' do
let(:user) { build :user }

Expand Down Expand Up @@ -365,7 +365,6 @@
user.save
expect(subject).not_to be_able_to :crud, Project.new(submitter: user)
end

end

context 'create' do
Expand All @@ -379,11 +378,10 @@
user.save
expect(subject).not_to be_able_to :create, Project.new
end

end

context 'when using a project as a template' do
let(:user) { build :user }
let(:user) { create :user }

context 'for the original project submitter' do
let(:project) { build :project, submitter: user }
Expand Down
8 changes: 8 additions & 0 deletions spec/support/shared_contexts/with_confirmed_user_logged_in.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
RSpec.shared_context 'with confirmed user logged in' do
let(:current_user) { create(:user) }

before do
allow(controller).to receive(:current_user).and_return(current_user)
allow(current_user).to receive(:confirmed?).and_return(true)
end
end