Dmitrii Golub
11 years ago
12 changed files with 223 additions and 55 deletions
@ -1,8 +1,15 @@
|
||||
class TwoFactorAuthenticationAddTo<%= table_name.camelize %> < ActiveRecord::Migration |
||||
def change |
||||
def up |
||||
change_table :<%= table_name %> do |t| |
||||
t.string :second_factor_pass_code , :limit => 32 |
||||
t.string :otp_secret_key |
||||
t.integer :second_factor_attempts_count, :default => 0 |
||||
end |
||||
|
||||
add_index :<%= table_name %>, :otp_secret_key, :unique => true |
||||
end |
||||
|
||||
def down |
||||
remove_column :<%= table_name %>, :otp_secret_key |
||||
remove_column :<%= table_name %>, :second_factor_attempts_count |
||||
end |
||||
end |
||||
|
@ -1,10 +1,7 @@
|
||||
Warden::Manager.after_authentication do |user, auth, options| |
||||
if user.respond_to?(:need_two_factor_authentication?) |
||||
if auth.session(options[:scope])[:need_two_factor_authentication] = user.need_two_factor_authentication?(auth.request) |
||||
code = user.generate_two_factor_code |
||||
user.second_factor_pass_code = Digest::MD5.hexdigest(code) |
||||
user.save |
||||
user.send_two_factor_authentication_code(code) |
||||
user.send_two_factor_authentication_code |
||||
end |
||||
end |
||||
end |
||||
|
@ -0,0 +1,70 @@
|
||||
require 'spec_helper' |
||||
include AuthenticatedModelHelper |
||||
|
||||
|
||||
describe Devise::Models::TwoFactorAuthenticatable, '#otp_code' do |
||||
let(:instance) { AuthenticatedModelHelper.create_new_user } |
||||
subject { instance.otp_code(time) } |
||||
let(:time) { 1392852456 } |
||||
|
||||
it "should return an error if no secret is set" do |
||||
expect { |
||||
subject |
||||
}.to raise_error |
||||
end |
||||
|
||||
context "secret is set" do |
||||
before :each do |
||||
instance.otp_secret_key = "2z6hxkdwi3uvrnpn" |
||||
end |
||||
|
||||
it "should not return an error" do |
||||
subject |
||||
end |
||||
|
||||
context "with a known time" do |
||||
let(:time) { 1392852756 } |
||||
|
||||
it "should return a known result" do |
||||
expect(subject).to eq(562202) |
||||
end |
||||
end |
||||
end |
||||
end |
||||
|
||||
describe Devise::Models::TwoFactorAuthenticatable, '#authenticate_otp' do |
||||
let(:instance) { AuthenticatedModelHelper.create_new_user } |
||||
|
||||
before :each do |
||||
instance.otp_secret_key = "2z6hxkdwi3uvrnpn" |
||||
end |
||||
|
||||
def do_invoke code, options = {} |
||||
instance.authenticate_otp(code, options) |
||||
end |
||||
|
||||
it "should be able to authenticate a recently created code" do |
||||
code = instance.otp_code |
||||
expect(do_invoke(code)).to eq(true) |
||||
end |
||||
|
||||
it "should not authenticate an old code" do |
||||
code = instance.otp_code(1.minutes.ago.to_i) |
||||
expect(do_invoke(code)).to eq(false) |
||||
end |
||||
end |
||||
|
||||
describe Devise::Models::TwoFactorAuthenticatable, '#send_two_factor_authentication_code' do |
||||
|
||||
it "should raise an error by default" do |
||||
instance = AuthenticatedModelHelper.create_new_user |
||||
expect { |
||||
instance.send_two_factor_authentication_code |
||||
}.to raise_error(NotImplementedError) |
||||
end |
||||
|
||||
it "should be overrideable" do |
||||
instance = AuthenticatedModelHelper.create_new_user_with_overrides |
||||
expect(instance.send_two_factor_authentication_code).to eq("Code sent") |
||||
end |
||||
end |
@ -0,0 +1,21 @@
|
||||
require "rubygems" |
||||
require "bundler/setup" |
||||
|
||||
require 'two_factor_authentication' |
||||
|
||||
|
||||
Dir["#{Dir.pwd}/spec/support/**/*.rb"].each {|f| require f} |
||||
|
||||
|
||||
# See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration |
||||
RSpec.configure do |config| |
||||
config.treat_symbols_as_metadata_keys_with_true_values = true |
||||
config.run_all_when_everything_filtered = true |
||||
config.filter_run :focus |
||||
|
||||
# Run specs in random order to surface order dependencies. If you find an |
||||
# order dependency and want to debug it, you can fix the order by providing |
||||
# the seed, which is printed after each run. |
||||
# --seed 1234 |
||||
config.order = 'random' |
||||
end |
@ -0,0 +1,29 @@
|
||||
module AuthenticatedModelHelper |
||||
|
||||
class User |
||||
extend ActiveModel::Callbacks |
||||
include ActiveModel::Validations |
||||
include Devise::Models::TwoFactorAuthenticatable |
||||
|
||||
define_model_callbacks :create |
||||
attr_accessor :otp_secret_key, :email |
||||
|
||||
has_one_time_password |
||||
end |
||||
|
||||
class UserWithOverrides < User |
||||
|
||||
def send_two_factor_authentication_code |
||||
"Code sent" |
||||
end |
||||
end |
||||
|
||||
def create_new_user |
||||
User.new |
||||
end |
||||
|
||||
def create_new_user_with_overrides |
||||
UserWithOverrides.new |
||||
end |
||||
|
||||
end |
Loading…
Reference in new issue