Commit 3bb626f9 authored by James Newton's avatar James Newton

refactor login as to be impersonation with better login/logout

Modifies the existing "login as" feature to be called impersonation, as
well as keeping track of who is impersonating to revert back to that
user without having to log out.
parent 98cc695a
......@@ -118,6 +118,10 @@ header {
}
}
}
.impersonation i {
color: $red-normal;
}
}
@mixin collapsed-header {
......
......@@ -8,4 +8,10 @@ class Admin::ApplicationController < ApplicationController
def authenticate_admin!
return render_404 unless current_user.is_admin?
end
def authorize_impersonator!
if session[:impersonator_id]
User.find_by!(username: session[:impersonator_id]).admin?
end
end
end
class Admin::ImpersonationController < Admin::ApplicationController
skip_before_action :authenticate_admin!, only: :destroy
before_action :user
before_action :authorize_impersonator!
def create
session[:impersonator_id] = current_user.username
session[:impersonator_return_to] = request.env['HTTP_REFERER']
warden.set_user(user, scope: 'user')
flash[:alert] = "You are impersonating #{user.username}."
redirect_to root_path
end
def destroy
redirect = session[:impersonator_return_to]
warden.set_user(user, scope: 'user')
session[:impersonator_return_to] = nil
session[:impersonator_id] = nil
redirect_to redirect || root_path
end
def user
@user ||= User.find_by!(username: params[:id] || session[:impersonator_id])
end
end
......@@ -63,12 +63,6 @@ def confirm
end
end
def login_as
sign_in(user)
flash[:alert] = "Logged in as #{user.username}"
redirect_to root_path
end
def disable_two_factor
user.disable_two_factor!
redirect_to admin_user_path(user),
......
......@@ -7,7 +7,7 @@
.pull-right
- unless @user == current_user
= link_to 'Log in as this user', login_as_admin_user_path(@user), method: :post, class: "btn btn-grouped btn-info"
= link_to 'Impersonate', impersonate_admin_user_path(@user), method: :post, class: "btn btn-grouped btn-info"
= link_to edit_admin_user_path(@user), class: "btn btn-grouped" do
%i.fa.fa-pencil-square-o
Edit
......
......@@ -13,6 +13,10 @@
%li.visible-sm.visible-xs
= link_to search_path, title: 'Search', data: {toggle: 'tooltip', placement: 'bottom'} do
= icon('search')
- if session[:impersonator_id]
%li.impersonation
= link_to stop_impersonation_admin_users_path, method: :delete, title: 'Stop impersonation', data: { toggle: 'tooltip', placement: 'bottom' } do
= icon('user-secret fw')
- if current_user.is_admin?
%li
= link_to admin_root_path, title: 'Admin area', data: {toggle: 'tooltip', placement: 'bottom'} do
......
......@@ -212,6 +212,8 @@
resources :keys, only: [:show, :destroy]
resources :identities, only: [:index, :edit, :update, :destroy]
delete 'stop_impersonation' => 'impersonation#destroy', on: :collection
member do
get :projects
get :keys
......@@ -221,7 +223,7 @@
put :unblock
put :unlock
put :confirm
post :login_as
post 'impersonate' => 'impersonation#create'
patch :disable_two_factor
delete 'remove/:email_id', action: 'remove_email', as: 'remove_email'
end
......
......@@ -7,21 +7,6 @@
sign_in(admin)
end
describe 'POST login_as' do
let(:user) { create(:user) }
it 'logs admin as another user' do
expect(warden.authenticate(scope: :user)).not_to eq(user)
post :login_as, id: user.username
expect(warden.authenticate(scope: :user)).to eq(user)
end
it 'redirects user to homepage' do
post :login_as, id: user.username
expect(response).to redirect_to(root_path)
end
end
describe 'DELETE #user with projects' do
let(:user) { create(:user) }
let(:project) { create(:project, namespace: user.namespace) }
......
......@@ -111,24 +111,50 @@
expect(page).to have_content(@user.name)
end
describe 'Login as another user' do
it 'should show login button for other users and check that it works' do
another_user = create(:user)
describe 'Impersonation' do
let(:another_user) { create(:user) }
before { visit admin_user_path(another_user) }
visit admin_user_path(another_user)
click_link 'Log in as this user'
context 'before impersonating' do
it 'shows impersonate button for other users' do
expect(page).to have_content('Impersonate')
end
expect(page).to have_content("Logged in as #{another_user.username}")
it 'should not show impersonate button for admin itself' do
visit admin_user_path(@user)
page.within '.sidebar-user .username' do
expect(page).to have_content(another_user.username)
expect(page).not_to have_content('Impersonate')
end
end
it 'should not show login button for admin itself' do
visit admin_user_path(@user)
expect(page).not_to have_content('Log in as this user')
context 'when impersonating' do
before { click_link 'Impersonate' }
it 'logs in as the user when impersonate is clicked' do
page.within '.sidebar-user .username' do
expect(page).to have_content(another_user.username)
end
end
it 'sees impersonation log out icon' do
icon = first('.fa.fa-user-secret')
expect(icon).to_not eql nil
end
it 'can log out of impersonated user back to original user' do
find(:css, 'li.impersonation a').click
page.within '.sidebar-user .username' do
expect(page).to have_content(@user.username)
end
end
it 'is redirected back to the impersonated users page in the admin after stopping' do
find(:css, 'li.impersonation a').click
expect(current_path).to eql "/admin/users/#{another_user.username}"
end
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