diff --git a/app/controllers/session_controller.rb b/app/controllers/session_controller.rb index 617130453aa..b48ee8a8f14 100644 --- a/app/controllers/session_controller.rb +++ b/app/controllers/session_controller.rb @@ -365,12 +365,19 @@ class SessionController < ApplicationController end def one_time_password - otp_username = $redis.get "otp_#{params[:token]}" + @otp_username = otp_username = $redis.get "otp_#{params[:token]}" if otp_username && user = User.find_by_username(otp_username) - log_on_user(user) - $redis.del "otp_#{params[:token]}" - return redirect_to path("/") + if current_user&.username == otp_username + $redis.del "otp_#{params[:token]}" + return redirect_to path("/") + elsif request.post? + log_on_user(user) + $redis.del "otp_#{params[:token]}" + return redirect_to path("/") + else + # Display the form + end else @error = I18n.t('user_api_key.invalid_token') end diff --git a/app/views/session/one_time_password.html.erb b/app/views/session/one_time_password.html.erb index a0faef79d98..e86e371298f 100644 --- a/app/views/session/one_time_password.html.erb +++ b/app/views/session/one_time_password.html.erb @@ -2,4 +2,10 @@
<%= t("user_api_key.otp_confirmation.logging_in_as", username: @otp_username) %>
+ <%= submit_tag(t("user_api_key.otp_confirmation.confirm_button"), class: "btn btn-primary") %> + <%end%> <%end%> diff --git a/config/locales/server.en.yml b/config/locales/server.en.yml index 04de4f106b2..2140b1f407a 100644 --- a/config/locales/server.en.yml +++ b/config/locales/server.en.yml @@ -939,6 +939,10 @@ en: description: '"%{application_name}" is requesting the following access to your account:' instructions: 'We just generated a new user API key for you to use with "%{application_name}", please paste the following key into your application:' otp_description: 'Would you like to allow "%{application_name}" to access this site?' + otp_confirmation: + confirm_title: Continue to %{site_name} + logging_in_as: Logging in as %{username} + confirm_button: Finish Login no_trust_level: "Sorry, you do not have the required trust level to access the user API" generic_error: "Sorry, we are unable to issue user API keys, this feature may be disabled by the site admin" scopes: diff --git a/config/routes.rb b/config/routes.rb index f9e57a66500..d6132b9da29 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -340,6 +340,7 @@ Discourse::Application.routes.draw do get "session/email-login/:token" => "session#email_login_info" post "session/email-login/:token" => "session#email_login" get "session/otp/:token" => "session#one_time_password", constraints: { token: /[0-9a-f]+/ } + post "session/otp/:token" => "session#one_time_password", constraints: { token: /[0-9a-f]+/ } get "composer_messages" => "composer_messages#index" post "composer/parse_html" => "composer#parse_html" diff --git a/spec/requests/session_controller_spec.rb b/spec/requests/session_controller_spec.rb index e329b5e77e1..f3491ef5bdc 100644 --- a/spec/requests/session_controller_spec.rb +++ b/spec/requests/session_controller_spec.rb @@ -1369,9 +1369,40 @@ RSpec.describe SessionController do get "/session/otp/asd1231dasd123" expect(response.status).to eq(404) + + post "/session/otp/asd1231dasd123" + + expect(response.status).to eq(404) end context 'when token is valid' do + it "should display the form for GET" do + token = SecureRandom.hex + $redis.setex "otp_#{token}", 10.minutes, user.username + + get "/session/otp/#{token}" + + expect(response.status).to eq(200) + expect(response.body).to include( + I18n.t("user_api_key.otp_confirmation.logging_in_as", username: user.username) + ) + expect($redis.get("otp_#{token}")).to eq(user.username) + + expect(session[:current_user_id]).to eq(nil) + end + + it "should redirect on GET if already logged in" do + sign_in(user) + token = SecureRandom.hex + $redis.setex "otp_#{token}", 10.minutes, user.username + + get "/session/otp/#{token}" + expect(response.status).to eq(302) + + expect($redis.get("otp_#{token}")).to eq(nil) + expect(session[:current_user_id]).to eq(user.id) + end + it 'should authenticate user and delete token' do user = Fabricate(:user) @@ -1381,7 +1412,7 @@ RSpec.describe SessionController do token = SecureRandom.hex $redis.setex "otp_#{token}", 10.minutes, user.username - get "/session/otp/#{token}" + post "/session/otp/#{token}" expect(response.status).to eq(302) expect(response).to redirect_to("/")