diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb
index d4a6d09e4..3858dd11c 100644
--- a/app/controllers/users_controller.rb
+++ b/app/controllers/users_controller.rb
@@ -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)
diff --git a/app/mailers/user_notifications.rb b/app/mailers/user_notifications.rb
index 74295249e..ef6e8ae07 100644
--- a/app/mailers/user_notifications.rb
+++ b/app/mailers/user_notifications.rb
@@ -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
diff --git a/app/views/users/admin_login.html.erb b/app/views/users/admin_login.html.erb
new file mode 100644
index 000000000..2eaa56e6b
--- /dev/null
+++ b/app/views/users/admin_login.html.erb
@@ -0,0 +1,16 @@
+
+
+ Admin Login
+
+
+ <% if @message %>
+ <%= @message %>
+ <% else %>
+ <%=form_tag({}, method: :put) do %>
+ <%= label_tag(:email, t('admin_login.email_input')) %>
+ <%= text_field_tag(:email) %>
+ <%= submit_tag t('admin_login.submit_button') %>
+ <% end %>
+ <% end %>
+
+
diff --git a/config/locales/server.en.yml b/config/locales/server.en.yml
index 36960de79..e63605de4 100644
--- a/config/locales/server.en.yml
+++ b/config/locales/server.en.yml
@@ -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"
diff --git a/config/routes.rb b/config/routes.rb
index d71ecc3c5..5c68f055c 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -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"
diff --git a/spec/controllers/users_controller_spec.rb b/spec/controllers/users_controller_spec.rb
index 902ce8fb0..a1b7e4b09 100644
--- a/spec/controllers/users_controller_spec.rb
+++ b/spec/controllers/users_controller_spec.rb
@@ -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