Browse Source

happy path feature specs for two factor auth

master
Ross Kaffenberger 11 years ago
parent
commit
f46a62720c
  1. 1
      app/controllers/devise/two_factor_authentication_controller.rb
  2. 1
      config/locales/en.yml
  3. 42
      spec/features/two_factor_authenticatable_spec.rb
  4. 12
      spec/rails_app/app/controllers/home_controller.rb
  5. 4
      spec/rails_app/app/models/user.rb
  6. 5
      spec/rails_app/app/views/home/dashboard.html.erb
  7. 3
      spec/rails_app/app/views/home/index.html.erb
  8. 4
      spec/rails_app/app/views/layouts/application.html.erb
  9. 2
      spec/rails_app/config/application.rb
  10. 2
      spec/rails_app/config/routes.rb
  11. 8
      spec/spec_helper.rb
  12. 34
      spec/support/authenticated_model_helper.rb
  13. 9
      spec/support/capybara.rb
  14. 13
      spec/support/features_spec_helper.rb
  15. 3
      two_factor_authentication.gemspec

1
app/controllers/devise/two_factor_authentication_controller.rb

@ -11,6 +11,7 @@ class Devise::TwoFactorAuthenticationController < DeviseController
if resource.authenticate_otp(params[:code]) if resource.authenticate_otp(params[:code])
warden.session(resource_name)[:need_two_factor_authentication] = false warden.session(resource_name)[:need_two_factor_authentication] = false
sign_in resource_name, resource, :bypass => true sign_in resource_name, resource, :bypass => true
set_flash_message :notice, :success
redirect_to stored_location_for(resource_name) || :root redirect_to stored_location_for(resource_name) || :root
resource.update_attribute(:second_factor_attempts_count, 0) resource.update_attribute(:second_factor_attempts_count, 0)
else else

1
config/locales/en.yml

@ -1,4 +1,5 @@
en: en:
devise: devise:
two_factor_authentication: two_factor_authentication:
success: "Two factor authentication successful."
attempt_failed: "Attempt failed." attempt_failed: "Attempt failed."

42
spec/features/two_factor_authenticatable_spec.rb

@ -0,0 +1,42 @@
require 'spec_helper'
feature "User of two factor authentication" do
scenario "must be logged in" do
visit user_two_factor_authentication_path
page.should have_content("Welcome Home")
end
context "when logged in" do
let(:user) { create_user }
background do
login_as user
end
scenario "can fill in TFA code" do
visit user_two_factor_authentication_path
page.should have_content("Enter your personal code")
fill_in "code", with: user.otp_code
click_button "Submit"
within(".flash.notice") do
expect(page).to have_content("Two factor authentication successful.")
end
end
scenario "is redirected to TFA when path requires authentication" do
visit dashboard_path
expect(page).to_not have_content("Your Personal Dashboard")
fill_in "code", with: user.otp_code
click_button "Submit"
expect(page).to have_content("Your Personal Dashboard")
end
end
end

12
spec/rails_app/app/controllers/home_controller.rb

@ -1,4 +1,16 @@
class HomeController < ApplicationController class HomeController < ApplicationController
prepend_before_filter :store_location, only: :dashboard
before_filter :authenticate_user!, only: :dashboard
def index def index
end end
def dashboard
end
private
def store_location
store_location_for(:user, dashboard_path)
end
end end

4
spec/rails_app/app/models/user.rb

@ -4,4 +4,8 @@ class User < ActiveRecord::Base
:two_factor_authenticatable :two_factor_authenticatable
has_one_time_password has_one_time_password
def send_two_factor_authentication_code
# No op
end
end end

5
spec/rails_app/app/views/home/dashboard.html.erb

@ -0,0 +1,5 @@
<h1>Your Personal Dashboard</h1>
<p>Your email is <%= current_user.email %></p>
<p>You will only be able to see this page after successfully completing two factor authentication</p>

3
spec/rails_app/app/views/home/index.html.erb

@ -1,2 +1,3 @@
<h1>Home#index</h1> <h1>Welcome Home</h1>
<p>Find me in app/views/home/index.html.erb</p> <p>Find me in app/views/home/index.html.erb</p>

4
spec/rails_app/app/views/layouts/application.html.erb

@ -7,8 +7,8 @@
<%= csrf_meta_tags %> <%= csrf_meta_tags %>
</head> </head>
<body> <body>
<p class="notice"><%= notice %></p> <p class="flash notice"><%= notice %></p>
<p class="alert"><%= alert %></p> <p class="flash alert"><%= alert %></p>
<%= yield %> <%= yield %>
</body> </body>
</html> </html>

2
spec/rails_app/config/application.rb

@ -55,6 +55,8 @@ module Dummy
config.assets.version = '1.0' config.assets.version = '1.0'
config.action_mailer.default_url_options = { host: 'localhost:3000' } config.action_mailer.default_url_options = { host: 'localhost:3000' }
config.i18n.enforce_available_locales = false
end end
end end

2
spec/rails_app/config/routes.rb

@ -1,6 +1,8 @@
Dummy::Application.routes.draw do Dummy::Application.routes.draw do
root to: "home#index" root to: "home#index"
match "/dashboard", to: "home#dashboard", as: :dashboard
devise_for :users devise_for :users
# The priority is based upon order of creation: # The priority is based upon order of creation:

8
spec/spec_helper.rb

@ -1,9 +1,7 @@
ENV["RAILS_ENV"] ||= "test" ENV["RAILS_ENV"] ||= "test"
require File.expand_path("../rails_app/config/environment.rb", __FILE__) require File.expand_path("../rails_app/config/environment.rb", __FILE__)
require 'two_factor_authentication' require 'rspec/rails'
Dir["#{Dir.pwd}/spec/support/**/*.rb"].each {|f| require f}
# See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
RSpec.configure do |config| RSpec.configure do |config|
@ -11,9 +9,13 @@ RSpec.configure do |config|
config.run_all_when_everything_filtered = true config.run_all_when_everything_filtered = true
config.filter_run :focus config.filter_run :focus
config.use_transactional_examples = true
# Run specs in random order to surface order dependencies. If you find an # 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 # order dependency and want to debug it, you can fix the order by providing
# the seed, which is printed after each run. # the seed, which is printed after each run.
# --seed 1234 # --seed 1234
config.order = 'random' config.order = 'random'
end end
Dir["#{Dir.pwd}/spec/support/**/*.rb"].each {|f| require f}

34
spec/support/authenticated_model_helper.rb

@ -1,18 +1,48 @@
module AuthenticatedModelHelper module AuthenticatedModelHelper
class UserWithOverrides < User class POROUser
extend ActiveModel::Callbacks
include ActiveModel::Validations
include Devise::Models::TwoFactorAuthenticatable
define_model_callbacks :create
attr_accessor :otp_secret_key, :email, :second_factor_attempts_count
has_one_time_password
end
class UserWithOverrides < POROUser
def send_two_factor_authentication_code def send_two_factor_authentication_code
"Code sent" "Code sent"
end end
end end
def create_new_user def create_new_user
User.new POROUser.new
end end
def create_new_user_with_overrides def create_new_user_with_overrides
UserWithOverrides.new UserWithOverrides.new
end end
def create_user(attributes={})
User.create!(valid_attributes(attributes))
end
def valid_attributes(attributes={})
{
email: generate_unique_email,
password: 'password',
password_confirmation: 'password'
}.merge(attributes)
end
def generate_unique_email
@@email_count ||= 0
@@email_count += 1
"user#{@@email_count}@example.com"
end
end end
RSpec.configuration.send(:include, AuthenticatedModelHelper)

9
spec/support/capybara.rb

@ -0,0 +1,9 @@
require 'capybara/rspec'
Capybara.app = Dummy::Application
RSpec.configure do |config|
config.before(:each, :feature) do
end
end

13
spec/support/features_spec_helper.rb

@ -0,0 +1,13 @@
require 'warden'
module FeaturesSpecHelper
def warden
request.env['warden']
end
end
RSpec.configure do |config|
config.include Warden::Test::Helpers, type: :feature
config.include FeaturesSpecHelper, type: :feature
end

3
two_factor_authentication.gemspec

@ -29,7 +29,8 @@ Gem::Specification.new do |s|
s.add_runtime_dependency 'randexp' s.add_runtime_dependency 'randexp'
s.add_runtime_dependency 'rotp' s.add_runtime_dependency 'rotp'
s.add_development_dependency 'rspec-rails'
s.add_development_dependency 'bundler' s.add_development_dependency 'bundler'
s.add_development_dependency 'rake' s.add_development_dependency 'rake'
s.add_development_dependency 'rspec-rails'
s.add_development_dependency 'capybara'
end end

Loading…
Cancel
Save