Skip to content
Browse files

Added encryptable_test

1 parent 55f0b09 commit 711716dd1bbebfcfb915425bfc8c630d97b13ce9 Rodrigo Flores committed
View
1 .gitignore
@@ -14,3 +14,4 @@ spec/reports
test/tmp
test/version_tmp
tmp
+*.sqlite
View
9 Gemfile
@@ -3,5 +3,12 @@ source 'https://rubygems.org'
# Specify your gem's dependencies in encryptor.gemspec
gemspec
+gem 'devise', :git => "git@github.com:plataformatec/devise.git", :branch => "removing_encryptable"
gem 'minitest'
-gem 'rails'
+gem 'rails'
+gem 'sqlite3'
+
+gem 'pry'
+gem 'pry-doc'
+gem 'pry-nav'
+gem 'awesome_print'
View
37 Gemfile.lock
@@ -1,3 +1,14 @@
+GIT
+ remote: git@github.com:plataformatec/devise.git
+ revision: 5f440dfe130d2696fc396c6227d34803af727e05
+ branch: removing_encryptable
+ specs:
+ devise (2.1.0.rc)
+ bcrypt-ruby (~> 3.0)
+ orm_adapter (~> 0.0.7)
+ railties (~> 3.1)
+ warden (~> 1.1.1)
+
PATH
remote: .
specs:
@@ -35,13 +46,10 @@ GEM
i18n (~> 0.6)
multi_json (~> 1.0)
arel (3.0.2)
+ awesome_print (1.0.2)
bcrypt-ruby (3.0.1)
builder (3.0.0)
- devise (2.1.0.rc)
- bcrypt-ruby (~> 3.0)
- orm_adapter (~> 0.0.3)
- railties (~> 3.1)
- warden (~> 1.1.1)
+ coderay (1.0.6)
erubis (2.7.0)
hike (1.2.1)
i18n (0.6.0)
@@ -51,11 +59,21 @@ GEM
i18n (>= 0.4.0)
mime-types (~> 1.16)
treetop (~> 1.4.8)
+ method_source (0.7.1)
mime-types (1.18)
minitest (2.5.1)
multi_json (1.3.4)
orm_adapter (0.0.7)
polyglot (0.3.3)
+ pry (0.9.9.4)
+ coderay (~> 1.0.5)
+ method_source (~> 0.7.1)
+ slop (>= 2.4.4, < 3)
+ pry-doc (0.4.1)
+ pry (>= 0.9.0)
+ yard (~> 0.7.4)
+ pry-nav (0.2.1)
+ pry (~> 0.9.9)
rack (1.4.1)
rack-cache (1.2)
rack (>= 0.4)
@@ -81,10 +99,12 @@ GEM
rake (0.9.2.2)
rdoc (3.12)
json (~> 1.4)
+ slop (2.4.4)
sprockets (2.1.3)
hike (~> 1.2)
rack (~> 1.0)
tilt (~> 1.1, != 1.3.0)
+ sqlite3 (1.3.6)
thor (0.14.6)
tilt (1.3.3)
treetop (1.4.10)
@@ -93,11 +113,18 @@ GEM
tzinfo (0.3.33)
warden (1.1.1)
rack (>= 1.0)
+ yard (0.7.5)
PLATFORMS
ruby
DEPENDENCIES
+ awesome_print
+ devise!
devise_encryptable!
minitest
+ pry
+ pry-doc
+ pry-nav
rails
+ sqlite3
View
65 lib/devise/encryptable/encryptable.rb
@@ -27,6 +27,71 @@ module Encryptors
autoload :Sha1, 'devise/encryptable/encryptors/sha1'
autoload :Sha512, 'devise/encryptable/encryptors/sha512'
end
+
+ extend ActiveSupport::Concern
+
+ included do
+ attr_reader :password, :current_password
+ attr_accessor :password_confirmation
+ end
+
+ def self.required_fields(klass)
+ [:password_salt]
+ end
+
+ # Generates password salt when setting the password.
+ def password=(new_password)
+ self.password_salt = self.class.password_salt if new_password.present?
+ super
+ end
+
+ # Validates the password considering the salt.
+ def valid_password?(password)
+ puts "I'm here"
+ return false if encrypted_password.blank?
+ encryptor_class.compare(encrypted_password, password, self.class.stretches, authenticatable_salt, self.class.pepper)
+ end
+
+ # Overrides authenticatable salt to use the new password_salt
+ # column. authenticatable_salt is used by `valid_password?`
+ # and by other modules whenever there is a need for a random
+ # token based on the user password.
+ def authenticatable_salt
+ self.password_salt
+ end
+
+ protected
+
+ # Digests the password using the configured encryptor.
+ def password_digest(password)
+ if password_salt.present?
+ encryptor_class.digest(password, self.class.stretches, authenticatable_salt, self.class.pepper)
+ end
+ end
+
+ def encryptor_class
+ self.class.encryptor_class
+ end
+
+ module ClassMethods
+ Devise::Models.config(self, :encryptor)
+
+ # Returns the class for the configured encryptor.
+ def encryptor_class
+ @encryptor_class ||= case encryptor
+ when :bcrypt
+ raise "In order to use bcrypt as encryptor, simply remove :encryptable from your devise model"
+ when nil
+ raise "You need to give an :encryptor as option in order to use :encryptable"
+ else
+ Devise::Encryptable::Encryptors.const_get(encryptor.to_s.classify)
+ end
+ end
+
+ def password_salt
+ self.encryptor_class.salt(self.stretches)
+ end
+ end
end
end
View
2 lib/devise/encryptable/model.rb
@@ -68,7 +68,7 @@ def encryptor_class
when nil
raise "You need to give an :encryptor as option in order to use :encryptable"
else
- Devise::Encryptors.const_get(encryptor.to_s.classify)
+ Devise::Encryptable::Encryptors.const_get(encryptor.to_s.classify)
end
end
View
99 test/devise/encryptable/encryptable_test.rb
@@ -0,0 +1,99 @@
+require "test_helper"
+
+class EncryptableTest < ActiveSupport::TestCase
+ def assert_same_content(result, expected)
+ assert expected.size == result.size, "the arrays doesn't have the same size"
+ expected.each do |element|
+ assert result.include?(element), "The array doesn't include '#{element}'."
+ end
+ end
+
+ def encrypt_password(admin, pepper=Admin.pepper, stretches=Admin.stretches, encryptor=Admin.encryptor_class)
+ encryptor.digest('123456', stretches, admin.password_salt, pepper)
+ end
+
+ def swap_with_encryptor(klass, encryptor, options={})
+ klass.instance_variable_set(:@encryptor_class, nil)
+
+ swap klass, options.merge(:encryptor => encryptor) do
+ begin
+ yield
+ ensure
+ klass.instance_variable_set(:@encryptor_class, nil)
+ end
+ end
+ end
+
+ def generate_unique_email
+ @@email_count ||= 0
+ @@email_count += 1
+ "test#{@@email_count}@example.com"
+ end
+
+ def valid_attributes(attributes={})
+ { :username => "usertest",
+ :email => generate_unique_email,
+ :password => '123456',
+ :password_confirmation => '123456' }.update(attributes)
+ end
+
+ def create_admin(attributes={})
+ valid_attributes = valid_attributes(attributes)
+ valid_attributes.delete(:username)
+ Admin.create!(valid_attributes)
+ end
+
+ test 'should generate salt while setting password' do
+ assert_present create_admin.password_salt
+ end
+
+ test 'should not change password salt when updating' do
+ admin = create_admin
+ salt = admin.password_salt
+ admin.expects(:password_salt=).never
+ admin.save!
+ assert_equal salt, admin.password_salt
+ end
+
+ test 'should generate a base64 hash using SecureRandom for password salt' do
+ swap_with_encryptor Admin, :sha1 do
+ SecureRandom.expects(:base64).with(15).returns('01lI').twice
+ salt = create_admin.password_salt
+ assert_not_equal '01lI', salt
+ assert_equal 4, salt.size
+ end
+ end
+
+ test 'should not generate salt if password is blank' do
+ assert_blank create_admin(:password => nil).password_salt
+ assert_blank create_admin(:password => '').password_salt
+ end
+
+ test 'should encrypt password again if password has changed' do
+ admin = create_admin
+ encrypted_password = admin.encrypted_password
+ admin.password = admin.password_confirmation = 'new_password'
+ admin.save!
+ assert_not_equal encrypted_password, admin.encrypted_password
+ end
+
+ test 'should respect encryptor configuration' do
+ swap_with_encryptor Admin, :sha512 do
+ admin = create_admin
+ assert_equal admin.encrypted_password, encrypt_password(admin, Admin.pepper, Admin.stretches, Devise::Encryptable::Encryptors::Sha512)
+ end
+ end
+
+ test 'should not validate password when salt is nil' do
+ admin = create_admin
+ admin.password_salt = nil
+ admin.save
+ assert_not admin.valid_password?('123456')
+ end
+
+ test 'required_fields should contain the fields that Devise uses' do
+ assert_same_content Devise::Models::Encryptable.required_fields(Admin), [
+ :password_salt
+ ]
+ end
+end
View
7 test/devise/encryptable/encryptors_test.rb
@@ -1,9 +1,4 @@
-require "rubygems"
-require "bundler/setup"
-Bundler.require(:default)
-
-require "minitest/autorun"
-require "minitest/unit"
+require "test_helper"
def swap(object, new_values)
old_values = {}
View
15 test/rails_app/.gitignore
@@ -0,0 +1,15 @@
+# See http://help.github.com/ignore-files/ for more about ignoring files.
+#
+# If you find yourself ignoring temporary files generated by your text editor
+# or operating system, you probably want to add a global ignore instead:
+# git config --global core.excludesfile ~/.gitignore_global
+
+# Ignore bundler config
+/.bundle
+
+# Ignore the default SQLite database.
+/db/*.sqlite3
+
+# Ignore all logfiles and tempfiles.
+/log/*.log
+/tmp
View
7 test/rails_app/Rakefile
@@ -0,0 +1,7 @@
+#!/usr/bin/env rake
+# Add your own tasks in files placed in lib/tasks ending in .rake,
+# for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
+
+require File.expand_path('../config/application', __FILE__)
+
+RailsApp::Application.load_tasks
View
0 test/rails_app/app/models/.gitkeep
No changes.
View
7 test/rails_app/app/models/admin.rb
@@ -0,0 +1,7 @@
+class Admin < ActiveRecord::Base
+ devise :database_authenticatable, :encryptable
+
+ @encryptor = :sha512
+
+ attr_accessible :email, :password, :password_confirmation
+end
View
5 test/rails_app/app/models/user.rb
@@ -0,0 +1,5 @@
+class User < ActiveRecord::Base
+ devise :encryptable, :database_authenticatable
+
+ attr_accessible :email, :password, :password_confirmation
+end
View
4 test/rails_app/config.ru
@@ -0,0 +1,4 @@
+# This file is used by Rack-based servers to start the application.
+
+require ::File.expand_path('../config/environment', __FILE__)
+run RailsApp::Application
View
59 test/rails_app/config/application.rb
@@ -0,0 +1,59 @@
+require File.expand_path('../boot', __FILE__)
+
+require 'rails/all'
+
+if defined?(Bundler)
+ # If you precompile assets before deploying to production, use this line
+ Bundler.require(*Rails.groups(:assets => %w(development test)))
+ # If you want your assets lazily compiled in production, use this line
+ # Bundler.require(:default, :assets, Rails.env)
+end
+
+module RailsApp
+ class Application < Rails::Application
+ # Settings in config/environments/* take precedence over those specified here.
+ # Application configuration should go into files in config/initializers
+ # -- all .rb files in that directory are automatically loaded.
+
+ # Custom directories with classes and modules you want to be autoloadable.
+ # config.autoload_paths += %W(#{config.root}/extras)
+
+ # Only load the plugins named here, in the order given (default is alphabetical).
+ # :all can be used as a placeholder for all plugins not explicitly named.
+ # config.plugins = [ :exception_notification, :ssl_requirement, :all ]
+
+ # Activate observers that should always be running.
+ # config.active_record.observers = :cacher, :garbage_collector, :forum_observer
+
+ # Set Time.zone default to the specified zone and make Active Record auto-convert to this zone.
+ # Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC.
+ # config.time_zone = 'Central Time (US & Canada)'
+
+ # The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded.
+ # config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s]
+ # config.i18n.default_locale = :de
+
+ # Configure the default encoding used in templates for Ruby 1.9.
+ config.encoding = "utf-8"
+
+ # Configure sensitive parameters which will be filtered from the log file.
+ config.filter_parameters += [:password]
+
+ # Use SQL instead of Active Record's schema dumper when creating the database.
+ # This is necessary if your schema can't be completely dumped by the schema dumper,
+ # like if you have constraints or database-specific column types
+ # config.active_record.schema_format = :sql
+
+ # Enforce whitelist mode for mass assignment.
+ # This will create an empty whitelist of attributes available for mass-assignment for all models
+ # in your app. As such, your models will need to explicitly whitelist or blacklist accessible
+ # parameters by using an attr_accessible or attr_protected declaration.
+ config.active_record.whitelist_attributes = true
+
+ # Enable the asset pipeline
+ config.assets.enabled = true
+
+ # Version of your assets, change this if you want to expire all your assets
+ config.assets.version = '1.0'
+ end
+end
View
6 test/rails_app/config/boot.rb
@@ -0,0 +1,6 @@
+require 'rubygems'
+
+# Set up gems listed in the Gemfile.
+ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__)
+
+require 'bundler/setup' if File.exists?(ENV['BUNDLE_GEMFILE'])
View
3 test/rails_app/config/database.yml
@@ -0,0 +1,3 @@
+development:
+ adapter: 'sqlite3'
+ database: 'db/development.sqlite'
View
5 test/rails_app/config/environment.rb
@@ -0,0 +1,5 @@
+# Load the rails application
+require File.expand_path('../application', __FILE__)
+
+# Initialize the rails application
+RailsApp::Application.initialize!
View
37 test/rails_app/config/environments/development.rb
@@ -0,0 +1,37 @@
+RailsApp::Application.configure do
+ # Settings specified here will take precedence over those in config/application.rb
+
+ # In the development environment your application's code is reloaded on
+ # every request. This slows down response time but is perfect for development
+ # since you don't have to restart the web server when you make code changes.
+ config.cache_classes = false
+
+ # Log error messages when you accidentally call methods on nil.
+ config.whiny_nils = true
+
+ # Show full error reports and disable caching
+ config.consider_all_requests_local = true
+ config.action_controller.perform_caching = false
+
+ # Don't care if the mailer can't send
+ config.action_mailer.raise_delivery_errors = false
+
+ # Print deprecation notices to the Rails logger
+ config.active_support.deprecation = :log
+
+ # Only use best-standards-support built into browsers
+ config.action_dispatch.best_standards_support = :builtin
+
+ # Raise exception on mass assignment protection for Active Record models
+ config.active_record.mass_assignment_sanitizer = :strict
+
+ # Log the query plan for queries taking more than this (works
+ # with SQLite, MySQL, and PostgreSQL)
+ config.active_record.auto_explain_threshold_in_seconds = 0.5
+
+ # Do not compress assets
+ config.assets.compress = false
+
+ # Expands the lines which load the assets
+ config.assets.debug = true
+end
View
67 test/rails_app/config/environments/production.rb
@@ -0,0 +1,67 @@
+RailsApp::Application.configure do
+ # Settings specified here will take precedence over those in config/application.rb
+
+ # Code is not reloaded between requests
+ config.cache_classes = true
+
+ # Full error reports are disabled and caching is turned on
+ config.consider_all_requests_local = false
+ config.action_controller.perform_caching = true
+
+ # Disable Rails's static asset server (Apache or nginx will already do this)
+ config.serve_static_assets = false
+
+ # Compress JavaScripts and CSS
+ config.assets.compress = true
+
+ # Don't fallback to assets pipeline if a precompiled asset is missed
+ config.assets.compile = false
+
+ # Generate digests for assets URLs
+ config.assets.digest = true
+
+ # Defaults to Rails.root.join("public/assets")
+ # config.assets.manifest = YOUR_PATH
+
+ # Specifies the header that your server uses for sending files
+ # config.action_dispatch.x_sendfile_header = "X-Sendfile" # for apache
+ # config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for nginx
+
+ # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies.
+ # config.force_ssl = true
+
+ # See everything in the log (default is :info)
+ # config.log_level = :debug
+
+ # Prepend all log lines with the following tags
+ # config.log_tags = [ :subdomain, :uuid ]
+
+ # Use a different logger for distributed setups
+ # config.logger = ActiveSupport::TaggedLogging.new(SyslogLogger.new)
+
+ # Use a different cache store in production
+ # config.cache_store = :mem_cache_store
+
+ # Enable serving of images, stylesheets, and JavaScripts from an asset server
+ # config.action_controller.asset_host = "http://assets.example.com"
+
+ # Precompile additional assets (application.js, application.css, and all non-JS/CSS are already added)
+ # config.assets.precompile += %w( search.js )
+
+ # Disable delivery errors, bad email addresses will be ignored
+ # config.action_mailer.raise_delivery_errors = false
+
+ # Enable threaded mode
+ # config.threadsafe!
+
+ # Enable locale fallbacks for I18n (makes lookups for any locale fall back to
+ # the I18n.default_locale when a translation can not be found)
+ config.i18n.fallbacks = true
+
+ # Send deprecation notices to registered listeners
+ config.active_support.deprecation = :notify
+
+ # Log the query plan for queries taking more than this (works
+ # with SQLite, MySQL, and PostgreSQL)
+ # config.active_record.auto_explain_threshold_in_seconds = 0.5
+end
View
37 test/rails_app/config/environments/test.rb
@@ -0,0 +1,37 @@
+RailsApp::Application.configure do
+ # Settings specified here will take precedence over those in config/application.rb
+
+ # The test environment is used exclusively to run your application's
+ # test suite. You never need to work with it otherwise. Remember that
+ # your test database is "scratch space" for the test suite and is wiped
+ # and recreated between test runs. Don't rely on the data there!
+ config.cache_classes = true
+
+ # Configure static asset server for tests with Cache-Control for performance
+ config.serve_static_assets = true
+ config.static_cache_control = "public, max-age=3600"
+
+ # Log error messages when you accidentally call methods on nil
+ config.whiny_nils = true
+
+ # Show full error reports and disable caching
+ config.consider_all_requests_local = true
+ config.action_controller.perform_caching = false
+
+ # Raise exceptions instead of rendering exception templates
+ config.action_dispatch.show_exceptions = false
+
+ # Disable request forgery protection in test environment
+ config.action_controller.allow_forgery_protection = false
+
+ # Tell Action Mailer not to deliver emails to the real world.
+ # The :test delivery method accumulates sent emails in the
+ # ActionMailer::Base.deliveries array.
+ config.action_mailer.delivery_method = :test
+
+ # Raise exception on mass assignment protection for Active Record models
+ config.active_record.mass_assignment_sanitizer = :strict
+
+ # Print deprecation notices to the stderr
+ config.active_support.deprecation = :stderr
+end
View
16 test/rails_app/config/initializers/devise.rb
@@ -0,0 +1,16 @@
+Devise.setup do |config|
+ config.mailer_sender = "please-change-me-at-config-initializers-devise@example.com"
+
+ config.apply_schema = false
+
+ require 'devise/orm/active_record'
+
+ config.case_insensitive_keys = [ :email ]
+
+ config.strip_whitespace_keys = [ :email ]
+ config.skip_session_storage = [:http_auth]
+
+ config.stretches = Rails.env.test? ? 1 : 10
+
+ config.encryptor = :sha512
+end
View
77 test/rails_app/db/migrate/20120508165529_create_tables.rb
@@ -0,0 +1,77 @@
+class CreateTables < ActiveRecord::Migration
+ def self.up
+ create_table :users do |t|
+ t.string :username
+ t.string :facebook_token
+
+ ## Database authenticatable
+ t.string :email, :null => false, :default => ""
+ t.string :encrypted_password, :null => false, :default => ""
+
+ ## Recoverable
+ t.string :reset_password_token
+ t.datetime :reset_password_sent_at
+
+ ## Rememberable
+ t.datetime :remember_created_at
+
+ ## Trackable
+ t.integer :sign_in_count, :default => 0
+ t.datetime :current_sign_in_at
+ t.datetime :last_sign_in_at
+ t.string :current_sign_in_ip
+ t.string :last_sign_in_ip
+
+ ## Encryptable
+ # t.string :password_salt
+
+ ## Confirmable
+ t.string :confirmation_token
+ t.datetime :confirmed_at
+ t.datetime :confirmation_sent_at
+ # t.string :unconfirmed_email # Only if using reconfirmable
+
+ ## Lockable
+ t.integer :failed_attempts, :default => 0 # Only if lock strategy is :failed_attempts
+ t.string :unlock_token # Only if unlock strategy is :email or :both
+ t.datetime :locked_at
+
+ ## Token authenticatable
+ t.string :authentication_token
+
+ t.timestamps
+ end
+
+ create_table :admins do |t|
+ ## Database authenticatable
+ t.string :email, :null => true
+ t.string :encrypted_password, :null => true
+
+ ## Recoverable
+ t.string :reset_password_token
+ t.datetime :reset_password_sent_at
+
+ ## Rememberable
+ t.datetime :remember_created_at
+
+ ## Confirmable
+ t.string :confirmation_token
+ t.datetime :confirmed_at
+ t.datetime :confirmation_sent_at
+ t.string :unconfirmed_email # Only if using reconfirmable
+
+ ## Encryptable
+ t.string :password_salt
+
+ ## Lockable
+ t.datetime :locked_at
+
+ t.timestamps
+ end
+ end
+
+ def self.down
+ drop_table :users
+ drop_table :admins
+ end
+end
View
7 test/rails_app/db/seeds.rb
@@ -0,0 +1,7 @@
+# This file should contain all the record creation needed to seed the database with its default values.
+# The data can then be loaded with the rake db:seed (or created alongside the db with db:setup).
+#
+# Examples:
+#
+# cities = City.create([{ name: 'Chicago' }, { name: 'Copenhagen' }])
+# Mayor.create(name: 'Emanuel', city: cities.first)
View
13 test/test_helper.rb
@@ -0,0 +1,13 @@
+require "rubygems"
+require "bundler/setup"
+Bundler.require(:default)
+
+require "minitest/autorun"
+require "minitest/unit"
+
+require "rails_app/config/environment"
+
+ActiveRecord::Migration.verbose = false
+ActiveRecord::Base.logger = Logger.new(nil)
+
+ActiveRecord::Migrator.migrate(File.expand_path("test/rails_app/db/migrate"))

0 comments on commit 711716d

Please sign in to comment.
Something went wrong with that request. Please try again.