Commit aec9f211 authored by Dmitriy Zaporozhets's avatar Dmitriy Zaporozhets

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
parents da8ca8b2 3bb626f9
...@@ -118,6 +118,10 @@ header { ...@@ -118,6 +118,10 @@ header {
} }
} }
} }
.impersonation i {
color: $red-normal;
}
} }
@mixin collapsed-header { @mixin collapsed-header {
......
...@@ -8,4 +8,10 @@ class Admin::ApplicationController < ApplicationController ...@@ -8,4 +8,10 @@ class Admin::ApplicationController < ApplicationController
def authenticate_admin! def authenticate_admin!
return render_404 unless current_user.is_admin? return render_404 unless current_user.is_admin?
end end
def authorize_impersonator!
if session[:impersonator_id]
User.find_by!(username: session[:impersonator_id]).admin?
end
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 @@ class Admin::UsersController < Admin::ApplicationController ...@@ -63,12 +63,6 @@ class Admin::UsersController < Admin::ApplicationController
end end
end end
def login_as
sign_in(user)
flash[:alert] = "Logged in as #{user.username}"
redirect_to root_path
end
def disable_two_factor def disable_two_factor
user.disable_two_factor! user.disable_two_factor!
redirect_to admin_user_path(user), redirect_to admin_user_path(user),
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
.pull-right .pull-right
- unless @user == current_user - 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 = link_to edit_admin_user_path(@user), class: "btn btn-grouped" do
%i.fa.fa-pencil-square-o %i.fa.fa-pencil-square-o
Edit Edit
......
...@@ -13,6 +13,10 @@ ...@@ -13,6 +13,10 @@
%li.visible-sm.visible-xs %li.visible-sm.visible-xs
= link_to search_path, title: 'Search', data: {toggle: 'tooltip', placement: 'bottom'} do = link_to search_path, title: 'Search', data: {toggle: 'tooltip', placement: 'bottom'} do
= icon('search') = 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? - if current_user.is_admin?
%li %li
= link_to admin_root_path, title: 'Admin area', data: {toggle: 'tooltip', placement: 'bottom'} do = link_to admin_root_path, title: 'Admin area', data: {toggle: 'tooltip', placement: 'bottom'} do
......
...@@ -222,6 +222,8 @@ Gitlab::Application.routes.draw do ...@@ -222,6 +222,8 @@ Gitlab::Application.routes.draw do
resources :keys, only: [:show, :destroy] resources :keys, only: [:show, :destroy]
resources :identities, only: [:index, :edit, :update, :destroy] resources :identities, only: [:index, :edit, :update, :destroy]
delete 'stop_impersonation' => 'impersonation#destroy', on: :collection
member do member do
get :projects get :projects
get :keys get :keys
...@@ -231,7 +233,7 @@ Gitlab::Application.routes.draw do ...@@ -231,7 +233,7 @@ Gitlab::Application.routes.draw do
put :unblock put :unblock
put :unlock put :unlock
put :confirm put :confirm
post :login_as post 'impersonate' => 'impersonation#create'
patch :disable_two_factor patch :disable_two_factor
delete 'remove/:email_id', action: 'remove_email', as: 'remove_email' delete 'remove/:email_id', action: 'remove_email', as: 'remove_email'
end end
......
...@@ -7,21 +7,6 @@ describe Admin::UsersController do ...@@ -7,21 +7,6 @@ describe Admin::UsersController do
sign_in(admin) sign_in(admin)
end 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 describe 'DELETE #user with projects' do
let(:user) { create(:user) } let(:user) { create(:user) }
let(:project) { create(:project, namespace: user.namespace) } let(:project) { create(:project, namespace: user.namespace) }
......
...@@ -111,24 +111,50 @@ describe "Admin::Users", feature: true do ...@@ -111,24 +111,50 @@ describe "Admin::Users", feature: true do
expect(page).to have_content(@user.name) expect(page).to have_content(@user.name)
end end
describe 'Login as another user' do describe 'Impersonation' do
it 'should show login button for other users and check that it works' do let(:another_user) { create(:user) }
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
click_link 'Log in as this user' 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).not_to have_content('Impersonate')
expect(page).to have_content(another_user.username)
end end
end end
it 'should not show login button for admin itself' do context 'when impersonating' do
visit admin_user_path(@user) before { click_link 'Impersonate' }
expect(page).not_to have_content('Log in as this user')
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
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