diff --git a/Gemfile b/Gemfile index 7fd10bbe..0ba84054 100644 --- a/Gemfile +++ b/Gemfile @@ -16,7 +16,7 @@ gem "actionwebservice", :git => "git://github.com/dejan/actionwebservice.git" gem "rubycas-client" gem "ruby-openid", :require => "openid" gem "sqlite3" - +gem 'bcrypt-ruby', '~> 2.1.4' gem "webrat", ">=0.7.0", :groups => [:cucumber, :test] gem "database_cleaner", ">=0.5.0", :groups => [:cucumber, :selenium] diff --git a/Gemfile.lock b/Gemfile.lock index 5dfd12ba..7ca0f70e 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -24,6 +24,7 @@ GEM activeresource (2.3.14) activesupport (= 2.3.14) activesupport (2.3.14) + bcrypt-ruby (2.1.4) builder (3.0.0) cgi_multipart_eof_fix (2.5.0) cucumber (1.0.2) @@ -96,6 +97,7 @@ DEPENDENCIES ZenTest (>= 4.0.0) aasm (= 2.2.0) actionwebservice! + bcrypt-ruby (~> 2.1.4) cucumber-rails (~> 0.3.0) database_cleaner (>= 0.5.0) flexmock diff --git a/app/models/user.rb b/app/models/user.rb index c249f3c4..3a070dfe 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -123,7 +123,8 @@ class User < ActiveRecord::Base return nil if candidate.nil? if Tracks::Config.auth_schemes.include?('database') - return candidate if candidate.auth_type == 'database' && candidate.crypted_password == sha1(pass) + return candidate if candidate.auth_type == 'database' && + BCrypt::Password.new(candidate.crypted_password) == salted(pass) end if Tracks::Config.auth_schemes.include?('ldap') @@ -190,7 +191,7 @@ class User < ActiveRecord::Base end def generate_token - self.token = Digest::SHA1.hexdigest "#{Time.now.to_i}#{rand}" + self.token = self.class.sha1 "#{Time.now.to_i}#{rand}" end def remember_token? @@ -212,13 +213,21 @@ class User < ActiveRecord::Base protected + def self.salted(s) + "#{Tracks::Config.salt}--#{s}--" + end + def self.sha1(s) - Digest::SHA1.hexdigest("#{Tracks::Config.salt}--#{s}--") + Digest::SHA1.hexdigest salted s + end + + def self.hash(s) + BCrypt::Password.create salted s end def crypt_password return if password.blank? - write_attribute("crypted_password", self.class.sha1(password)) if password == password_confirmation + write_attribute("crypted_password", self.class.hash(password)) if password == password_confirmation end def password_required? @@ -229,10 +238,6 @@ protected auth_type == 'open_id' end - def password_matches?(pass) - crypted_password == sha1(pass) - end - def normalize_open_id_url return if open_id_url.nil? diff --git a/spec/fixtures/users.yml b/spec/fixtures/users.yml index 5d027653..dbb1cf19 100644 --- a/spec/fixtures/users.yml +++ b/spec/fixtures/users.yml @@ -1,7 +1,7 @@ # Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html admin_user: login: admin - crypted_password: <%= Digest::SHA1.hexdigest("#{Tracks::Config.salt}--abracadabra--") %> + crypted_password: <%= BCrypt::Password.create("#{Tracks::Config.salt}--abracadabra--").to_s %> token: <%= Digest::SHA1.hexdigest("adminSat Feb 25 17:14:00 GMT 20060.236961325863376") %> is_admin: true first_name: Admin @@ -10,7 +10,7 @@ admin_user: other_user: login: jane - crypted_password: <%= Digest::SHA1.hexdigest("#{Tracks::Config.salt}--sesame--") %> + crypted_password: <%= BCrypt::Password.create("#{Tracks::Config.salt}--sesame--").to_s %> token: <%= Digest::SHA1.hexdigest("janeSun Feb 19 14:42:45 GMT 20060.408173979260027") %> is_admin: false first_name: Jane diff --git a/test/fixtures/users.yml b/test/fixtures/users.yml index 010cfcc4..e747c8dd 100644 --- a/test/fixtures/users.yml +++ b/test/fixtures/users.yml @@ -2,7 +2,7 @@ admin_user: id: 1 login: admin - crypted_password: <%= Digest::SHA1.hexdigest("#{Tracks::Config.salt}--abracadabra--") %> + crypted_password: <%= BCrypt::Password.create("#{Tracks::Config.salt}--abracadabra--") %> token: <%= Digest::SHA1.hexdigest("adminSat Feb 25 17:14:00 GMT 20060.236961325863376") %> is_admin: true first_name: Admin @@ -12,7 +12,7 @@ admin_user: other_user: id: 2 login: jane - crypted_password: <%= Digest::SHA1.hexdigest("#{Tracks::Config.salt}--sesame--") %> + crypted_password: <%= BCrypt::Password.create("#{Tracks::Config.salt}--sesame--") %> token: <%= Digest::SHA1.hexdigest("janeSun Feb 19 14:42:45 GMT 20060.408173979260027") %> is_admin: false first_name: Jane @@ -32,7 +32,7 @@ ldap_user: sms_user: id: 4 login: sms_user - crypted_password: <%= Digest::SHA1.hexdigest("#{Tracks::Config.salt}--sesame--") %> + crypted_password: <%= BCrypt::Password.create("#{Tracks::Config.salt}--sesame--") %> token: <%= Digest::SHA1.hexdigest("sms_userSun Feb 19 14:42:45 GMT 20060.408173979260027") %> is_admin: false first_name: SMS diff --git a/test/functional/users_controller_test.rb b/test/functional/users_controller_test.rb index 99999ab7..54af1f22 100644 --- a/test/functional/users_controller_test.rb +++ b/test/functional/users_controller_test.rb @@ -68,7 +68,7 @@ class UsersControllerTest < ActionController::TestCase post :update_password, :updateuser => {:password => 'newpassword', :password_confirmation => 'newpassword'} assert_redirected_to preferences_path @updated_user = User.find(users(:admin_user).id) - assert_equal @updated_user.crypted_password, Digest::SHA1.hexdigest("#{Tracks::Config.salt}--newpassword--") + assert_not_nil User.authenticate(@updated_user.login, 'newpassword') assert_equal "Password updated.", flash[:notice] end diff --git a/test/unit/user_test.rb b/test/unit/user_test.rb index 968bd2ab..a1946295 100644 --- a/test/unit/user_test.rb +++ b/test/unit/user_test.rb @@ -33,7 +33,7 @@ class UserTest < ActiveSupport::TestCase assert_kind_of User, @admin_user assert_equal 1, @admin_user.id assert_equal "admin", @admin_user.login - assert_equal "#{Digest::SHA1.hexdigest("#{Tracks::Config.salt}--abracadabra--")}", @admin_user.crypted_password + assert_not_nil @admin_user.crypted_password assert_not_nil @admin_user.token assert @admin_user.is_admin end @@ -43,7 +43,7 @@ class UserTest < ActiveSupport::TestCase assert_kind_of User, @other_user assert_equal 2, @other_user.id assert_equal "jane", @other_user.login - assert_equal "#{Digest::SHA1.hexdigest("#{Tracks::Config.salt}--sesame--")}", @other_user.crypted_password + assert_not_nil @other_user.crypted_password assert_not_nil @other_user.token assert @other_user.is_admin == false || @other_user.is_admin == 0 end