mirror of
https://github.com/TracksApp/tracks.git
synced 2025-12-16 15:20:13 +01:00
Hash passwords with BCrypt instead of SHA1
BCrypt is regarded as a more secure alternative to hashing using message
digest algorithms, such as MD5 and SHA families [0, 1, 2]. Apart from
built-in salting it is adaptable to the increasing power of modern
processing units, which makes it more secure against brute-force cracking.
This commit makes all passwords hashed using BCrypt. The session tokens
remain generated using SHA1. Tests were updated, `rake test:units` and
`rake test:functionals` didn't report any regressions.
[0] http://bcrypt.sourceforge.net/
[1] http://en.wikipedia.org/w/index.php?title=Bcrypt&oldid=439692871
[2] eab1c72/README.md
This commit is contained in:
parent
0b88c72570
commit
95f0f71441
7 changed files with 24 additions and 17 deletions
2
Gemfile
2
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]
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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?
|
||||
|
||||
|
|
|
|||
4
spec/fixtures/users.yml
vendored
4
spec/fixtures/users.yml
vendored
|
|
@ -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
|
||||
|
|
|
|||
6
test/fixtures/users.yml
vendored
6
test/fixtures/users.yml
vendored
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue