FEATURE: magic login route for admin when SSO is enabled

This commit is contained in:
Arpit Jalan 2015-04-27 16:29:48 +05:30
parent 10270593a4
commit 2932284293
6 changed files with 136 additions and 2 deletions

View file

@ -6,7 +6,7 @@ require_dependency 'rate_limiter'
class UsersController < ApplicationController
skip_before_filter :authorize_mini_profiler, only: [:avatar]
skip_before_filter :check_xhr, only: [:show, :password_reset, :update, :account_created, :activate_account, :perform_account_activation, :authorize_email, :user_preferences_redirect, :avatar, :my_redirect, :toggle_anon]
skip_before_filter :check_xhr, only: [:show, :password_reset, :update, :account_created, :activate_account, :perform_account_activation, :authorize_email, :user_preferences_redirect, :avatar, :my_redirect, :toggle_anon, :admin_login]
before_filter :ensure_logged_in, only: [:username, :update, :change_email, :user_preferences_redirect, :upload_user_image, :pick_avatar, :destroy_user_image, :destroy, :check_emails]
before_filter :respond_to_suspicious_request, only: [:create]
@ -23,7 +23,8 @@ class UsersController < ApplicationController
:perform_account_activation,
:send_activation_email,
:authorize_email,
:password_reset]
:password_reset,
:admin_login]
def index
end
@ -344,6 +345,46 @@ class UsersController < ApplicationController
@success = I18n.t(message)
end
def admin_login
unless SiteSetting.enable_sso && !current_user
return redirect_to path("/")
end
if request.put?
RateLimiter.new(nil, "admin-login-hr-#{request.remote_ip}", 6, 1.hour).performed!
RateLimiter.new(nil, "admin-login-min-#{request.remote_ip}", 3, 1.minute).performed!
user = User.where(email: params[:email], admin: true).where.not(id: Discourse::SYSTEM_USER_ID).first
if user
email_token = user.email_tokens.create(email: user.email)
Jobs.enqueue(:user_email, type: :admin_login, user_id: user.id, email_token: email_token.token)
@message = I18n.t("admin_login.success")
else
@message = I18n.t("admin_login.error")
end
elsif params[:token].present?
# token recieved, try to login
if EmailToken.valid_token_format?(params[:token])
@user = EmailToken.confirm(params[:token])
if @user && @user.admin?
# Log in user
log_on_user(@user)
return redirect_to path("/")
else
@message = I18n.t("admin_login.error")
end
else
@message = I18n.t("admin_login.error")
end
end
render layout: false
rescue RateLimiter::LimitExceeded
@message = I18n.t("rate_limiter.slow_down")
render layout: false
end
def toggle_anon
user = AnonymousShadowCreator.get_master(current_user) ||
AnonymousShadowCreator.get(current_user)

View file

@ -31,6 +31,12 @@ class UserNotifications < ActionMailer::Base
email_token: opts[:email_token])
end
def admin_login(user, opts={})
build_email( user.email,
template: "user_notifications.admin_login",
email_token: opts[:email_token])
end
def account_created(user, opts={})
build_email( user.email, template: "user_notifications.account_created", email_token: opts[:email_token])
end

View file

@ -0,0 +1,16 @@
<html>
<head>
<title>Admin Login</title>
</head>
<body>
<% if @message %>
<%= @message %>
<% else %>
<%=form_tag({}, method: :put) do %>
<%= label_tag(:email, t('admin_login.email_input')) %>
<%= text_field_tag(:email) %><br><br>
<%= submit_tag t('admin_login.submit_button') %>
<% end %>
<% end %>
</body>
</html>

View file

@ -1906,6 +1906,16 @@ en:
Click the following link to choose a password:
%{base_url}/users/password-reset/%{email_token}
admin_login:
subject_template: "[%{site_name}] Login"
text_body_template: |
Somebody asked to login to your account on [%{site_name}](%{base_url}).
If you did not make this request, you can safely ignore this email.
Click the following link to login:
%{base_url}/users/admin-login/%{email_token}
account_created:
subject_template: "[%{site_name}] Your New Account"
text_body_template: |
@ -2442,3 +2452,9 @@ en:
leader: |
Blah blah blah
Blah blah blah
admin_login:
success: "Email Sent"
error: "Error!"
email_input: "Admin Email"
submit_button: "Send Email"

View file

@ -229,6 +229,10 @@ Discourse::Application.routes.draw do
get "privacy" => "static#show", id: "privacy", as: 'privacy'
get "signup" => "list#latest"
get "users/admin-login" => "users#admin_login"
put "users/admin-login" => "users#admin_login"
get "users/admin-login/:token" => "users#admin_login"
post "users/toggle-anon" => "users#toggle_anon"
post "users/read-faq" => "users#read_faq"
get "users/search/users" => "users#search_users"

View file

@ -315,6 +315,57 @@ describe UsersController do
end
end
describe '.admin_login' do
let(:admin) { Fabricate(:admin) }
let(:user) { Fabricate(:user) }
context 'enqueues mail' do
it 'enqueues mail with admin email and sso enabled' do
SiteSetting.enable_sso = true
Jobs.expects(:enqueue).with(:user_email, has_entries(type: :admin_login, user_id: admin.id))
put :admin_login, email: admin.email
end
it 'does not enqueue mail with admin email and sso disabled' do
SiteSetting.enable_sso = false
Jobs.expects(:enqueue).never
put :admin_login, email: admin.email
end
it 'does not enqueue mail with normal user email and sso enabled' do
SiteSetting.enable_sso = true
Jobs.expects(:enqueue).never
put :admin_login, email: user.email
end
end
context 'logs in admin' do
it 'does not log in admin with invalid token' do
SiteSetting.enable_sso = true
get :admin_login, token: "invalid"
expect(session[:current_user_id]).to be_blank
end
it 'does not log in admin with valid token and SSO disabled' do
SiteSetting.enable_sso = false
token = admin.email_tokens.create(email: admin.email).token
get :admin_login, token: token
expect(response).to redirect_to('/')
expect(session[:current_user_id]).to be_blank
end
it 'logs in admin with valid token and SSO enabled' do
SiteSetting.enable_sso = true
token = admin.email_tokens.create(email: admin.email).token
get :admin_login, token: token
expect(response).to redirect_to('/')
expect(session[:current_user_id]).to eq(admin.id)
end
end
end
describe '#toggle_anon' do
it 'allows you to toggle anon if enabled' do
SiteSetting.allow_anonymous_posting = true