Merge branch 'impersonate' into 'master'
refactor login as to be impersonation with better login/logout Modifies the existing "login as" feature to be called impersonation. This also adds: * Application keep track of who is impersonating the user so they can revert back to the original user without having to log out. * Stores the user profile via `HTTP_REFERER` so you get redirected back to the person you have impersonated once you stop. ## Screenshots: ![](http://sindacio.us/i/2015-10-28_17-52-41.png) ![](http://sindacio.us/i/2015-10-28_17-53-08.png) See merge request !1702
This commit is contained in:
commit
aec9f211e5
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
|
||||
|
|
|
@ -222,6 +222,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
|
||||
|
@ -231,7 +233,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