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.
This commit is contained in:
parent
98cc695afb
commit
3bb626f91c
9 changed files with 88 additions and 35 deletions
|
@ -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
|
||||
|
|
32
app/controllers/admin/impersonation_controller.rb
Normal file
32
app/controllers/admin/impersonation_controller.rb
Normal file
|
@ -0,0 +1,32 @@
|
|||
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 @@ class Admin::UsersController < Admin::ApplicationController
|
|||
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 @@ Gitlab::Application.routes.draw do
|
|||
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 @@ Gitlab::Application.routes.draw do
|
|||
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 @@ describe Admin::UsersController do
|
|||
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 @@ describe "Admin::Users", feature: true do
|
|||
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)
|
||||
context 'before impersonating' do
|
||||
it 'shows impersonate button for other users' do
|
||||
expect(page).to have_content('Impersonate')
|
||||
end
|
||||
|
||||
click_link 'Log in as this user'
|
||||
it 'should not show impersonate button for admin itself' do
|
||||
visit admin_user_path(@user)
|
||||
|
||||
expect(page).to have_content("Logged in as #{another_user.username}")
|
||||
|
||||
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
|
||||
|
||||
|
|
Loading…
Reference in a new issue