api keys: require reauthentication when working with API keys.
Require the user to re-enter their password before they can view, create, update, or delete their API keys. This works by tracking the timestamp of the user's last password re-entry in a `last_authenticated_at` session cookie, and redirecting the user to a password confirmation page if they haven't re-entered their password in the last hour. This is modeled after Github's Sudo mode.
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
class ApiKeysController < ApplicationController
|
||||
before_action :requires_reauthentication
|
||||
respond_to :html, :json, :xml
|
||||
|
||||
def new
|
||||
|
||||
@@ -189,6 +189,15 @@ class ApplicationController < ActionController::Base
|
||||
params.fetch(PolicyFinder.new(record).param_key, {})
|
||||
end
|
||||
|
||||
def requires_reauthentication
|
||||
return if CurrentUser.user.is_anonymous?
|
||||
|
||||
last_authenticated_at = session[:last_authenticated_at]
|
||||
if last_authenticated_at.blank? || Time.parse(last_authenticated_at) < 60.minutes.ago
|
||||
redirect_to confirm_password_session_path(url: request.fullpath)
|
||||
end
|
||||
end
|
||||
|
||||
# Remove blank `search` params from the url.
|
||||
#
|
||||
# /tags?search[name]=touhou&search[category]=&search[order]=
|
||||
|
||||
@@ -6,6 +6,9 @@ class SessionsController < ApplicationController
|
||||
@user = User.new
|
||||
end
|
||||
|
||||
def confirm_password
|
||||
end
|
||||
|
||||
def create
|
||||
name, password, url = params.fetch(:session, params).slice(:name, :password, :url).values
|
||||
user = SessionLoader.new(request).login(name, password)
|
||||
|
||||
@@ -14,6 +14,7 @@ class SessionLoader
|
||||
|
||||
if user.present? && user.authenticate_password(password)
|
||||
session[:user_id] = user.id
|
||||
session[:last_authenticated_at] = Time.now.utc.to_s
|
||||
|
||||
UserEvent.build_from_request(user, :login, request)
|
||||
user.last_logged_in_at = Time.now
|
||||
@@ -31,6 +32,7 @@ class SessionLoader
|
||||
|
||||
def logout
|
||||
session.delete(:user_id)
|
||||
session.delete(:last_authenticated_at)
|
||||
return if CurrentUser.user.is_anonymous?
|
||||
UserEvent.create_from_request!(CurrentUser.user, :logout, request)
|
||||
end
|
||||
|
||||
17
app/views/sessions/confirm_password.html.erb
Normal file
17
app/views/sessions/confirm_password.html.erb
Normal file
@@ -0,0 +1,17 @@
|
||||
<% page_title "Confirm password" %>
|
||||
<%= render "secondary_links" %>
|
||||
|
||||
<div id="c-sessions">
|
||||
<div id="a-confirm-password">
|
||||
<h1>Confirm password</h1>
|
||||
|
||||
<p>You must re-enter your password to continue.</p>
|
||||
|
||||
<%= simple_form_for(:session, url: session_path) do |f| %>
|
||||
<%= f.input :url, as: :hidden, input_html: { value: params[:url] } %>
|
||||
<%= f.input :name, as: :hidden, input_html: { value: CurrentUser.user.name } %>
|
||||
<%= f.input :password, hint: link_to("Forgot password?", password_reset_path), input_html: { autocomplete: "password" } %>
|
||||
<%= f.submit "Continue" %>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
@@ -225,6 +225,7 @@ Rails.application.routes.draw do
|
||||
resources :robots, only: [:index]
|
||||
resources :saved_searches, :except => [:show]
|
||||
resource :session, only: [:new, :create, :destroy] do
|
||||
get :confirm_password, on: :collection
|
||||
get :sign_out, on: :collection
|
||||
end
|
||||
resource :source, :only => [:show]
|
||||
|
||||
@@ -35,6 +35,15 @@ class ApiKeysControllerTest < ActionDispatch::IntegrationTest
|
||||
assert_response :success
|
||||
assert_nil response.parsed_body.first["key"]
|
||||
end
|
||||
|
||||
should "redirect to the confirm password page if the user hasn't recently authenticated" do
|
||||
post session_path, params: { name: @user.name, password: @user.password }
|
||||
travel_to 2.hours.from_now do
|
||||
get user_api_keys_path(@user.id)
|
||||
end
|
||||
|
||||
assert_redirected_to confirm_password_session_path(url: user_api_keys_path(@user.id))
|
||||
end
|
||||
end
|
||||
|
||||
context "#new action" do
|
||||
|
||||
Reference in New Issue
Block a user