SECURITY: Prefix session key and validate token format.
This commit is contained in:
parent
3a010c34cc
commit
ed125975a1
3 changed files with 32 additions and 11 deletions
|
@ -205,13 +205,17 @@ class UsersController < ApplicationController
|
||||||
def password_reset
|
def password_reset
|
||||||
expires_now()
|
expires_now()
|
||||||
|
|
||||||
@user = EmailToken.confirm(params[:token])
|
if EmailToken.valid_token_format?(params[:token])
|
||||||
|
@user = EmailToken.confirm(params[:token])
|
||||||
|
|
||||||
if @user
|
if @user
|
||||||
session[params[:token]] = @user.id
|
session["password-#{params[:token]}"] = @user.id
|
||||||
|
else
|
||||||
|
user_id = session["password-#{params[:token]}"]
|
||||||
|
@user = User.find(user_id) if user_id
|
||||||
|
end
|
||||||
else
|
else
|
||||||
user_id = session[params[:token]]
|
@invalid_token = true
|
||||||
@user = User.find(user_id) if user_id
|
|
||||||
end
|
end
|
||||||
|
|
||||||
if !@user
|
if !@user
|
||||||
|
|
|
@ -39,9 +39,12 @@ class EmailToken < ActiveRecord::Base
|
||||||
SecureRandom.hex(EmailToken.token_length)
|
SecureRandom.hex(EmailToken.token_length)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def self.valid_token_format?(token)
|
||||||
|
return token.present? && token =~ /[a-f0-9]{#{token.length/2}}/i
|
||||||
|
end
|
||||||
|
|
||||||
def self.confirm(token)
|
def self.confirm(token)
|
||||||
return unless token.present?
|
return unless valid_token_format?(token)
|
||||||
return unless token.length/2 == EmailToken.token_length
|
|
||||||
|
|
||||||
email_token = EmailToken.where("token = ? and expired = FALSE AND ((NOT confirmed AND created_at >= ?) OR (confirmed AND created_at >= ?))", token, EmailToken.valid_after, EmailToken.confirm_valid_after).includes(:user).first
|
email_token = EmailToken.where("token = ? and expired = FALSE AND ((NOT confirmed AND created_at >= ?) OR (confirmed AND created_at >= ?))", token, EmailToken.valid_after, EmailToken.confirm_valid_after).includes(:user).first
|
||||||
return if email_token.blank?
|
return if email_token.blank?
|
||||||
|
|
|
@ -243,7 +243,7 @@ describe UsersController do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'invalid token' do
|
context 'missing token' do
|
||||||
before do
|
before do
|
||||||
get :password_reset, token: SecureRandom.hex
|
get :password_reset, token: SecureRandom.hex
|
||||||
end
|
end
|
||||||
|
@ -251,9 +251,22 @@ describe UsersController do
|
||||||
it 'disallows login' do
|
it 'disallows login' do
|
||||||
flash[:error].should be_present
|
flash[:error].should be_present
|
||||||
session[:current_user_id].should be_blank
|
session[:current_user_id].should be_blank
|
||||||
|
assigns[:invalid_token].should be_nil
|
||||||
response.should be_success
|
response.should be_success
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'invalid token' do
|
||||||
|
before do
|
||||||
|
get :password_reset, token: "evil_trout!"
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'disallows login' do
|
||||||
|
flash[:error].should be_present
|
||||||
|
session[:current_user_id].should be_blank
|
||||||
|
assigns[:invalid_token].should be_true
|
||||||
|
response.should be_success
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'valid token' do
|
context 'valid token' do
|
||||||
|
@ -269,18 +282,19 @@ describe UsersController do
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'submit change' do
|
context 'submit change' do
|
||||||
|
let(:token) { EmailToken.generate_token }
|
||||||
before do
|
before do
|
||||||
EmailToken.expects(:confirm).with('asdfasdf').returns(user)
|
EmailToken.expects(:confirm).with(token).returns(user)
|
||||||
end
|
end
|
||||||
|
|
||||||
it "logs in the user" do
|
it "logs in the user" do
|
||||||
put :password_reset, token: 'asdfasdf', password: 'newpassword'
|
put :password_reset, token: token, password: 'newpassword'
|
||||||
session[:current_user_id].should be_present
|
session[:current_user_id].should be_present
|
||||||
end
|
end
|
||||||
|
|
||||||
it "doesn't log in the user when not approved" do
|
it "doesn't log in the user when not approved" do
|
||||||
SiteSetting.expects(:must_approve_users?).returns(true)
|
SiteSetting.expects(:must_approve_users?).returns(true)
|
||||||
put :password_reset, token: 'asdfasdf', password: 'newpassword'
|
put :password_reset, token: token, password: 'newpassword'
|
||||||
session[:current_user_id].should be_blank
|
session[:current_user_id].should be_blank
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
Reference in a new issue