From 47757d66e81d04248f8c1e52c280312d49ff03ac Mon Sep 17 00:00:00 2001 From: Oskar Kapusta Date: Wed, 25 Sep 2013 17:43:38 +0200 Subject: [PATCH 1/7] sha1 auth --- lib/casino_core/authenticator/activerecord.rb | 22 ++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/lib/casino_core/authenticator/activerecord.rb b/lib/casino_core/authenticator/activerecord.rb index 046ea45..88579c4 100644 --- a/lib/casino_core/authenticator/activerecord.rb +++ b/lib/casino_core/authenticator/activerecord.rb @@ -1,6 +1,7 @@ require 'active_record' require 'unix_crypt' require 'bcrypt' +require 'digest/sha1' class CASinoCore::Authenticator::ActiveRecord @@ -23,11 +24,11 @@ class #{self.class.to_s}::#{@options[:table].classify} < AuthDatabase def validate(username, password) @model.verify_active_connections! - user = @model.send("find_by_#{@options[:username_column]}!", username) - password_from_database = user.send(@options[:password_column]) + @user = @model.send("find_by_#{@options[:username_column]}!", username) + password_from_database = @user.send(@options[:password_column]) if valid_password?(password, password_from_database) - { username: user.send(@options[:username_column]), extra_attributes: extra_attributes(user) } + { username: @user.send(@options[:username_column]), extra_attributes: extra_attributes(@user) } else false end @@ -37,12 +38,18 @@ def validate(username, password) end private + def secure_digest(*args) + Digest::SHA1.hexdigest(args.flatten.join('--')) + end + def valid_password?(password, password_from_database) return false if password_from_database.blank? magic = password_from_database.split('$')[1] case magic when /\A2a?\z/ valid_password_with_bcrypt?(password, password_from_database) + when /\Asha?\z/ + valid_password_with_sha1_crypt?(password, password_from_database) else valid_password_with_unix_crypt?(password, password_from_database) end @@ -57,6 +64,15 @@ def valid_password_with_unix_crypt?(password, password_from_database) UnixCrypt.valid?(password, password_from_database) end + def valid_password_with_sha1_crypt?(password, password_from_database) + site_auth_key = digest = @options[:pepper].to_s + salt = @user.salt + 10.times do + digest = secure_digest(digest, salt, password, site_auth_key) + end + digest == password_from_database + end + def extra_attributes(user) attributes = {} extra_attributes_option.each do |attribute_name, database_column| From a8504ecf28ff345d544c63fc819c1486ce0d4798 Mon Sep 17 00:00:00 2001 From: Oskar Kapusta Date: Thu, 26 Sep 2013 09:01:23 +0200 Subject: [PATCH 2/7] password_from_database.split()[2] --- lib/casino_core/authenticator/activerecord.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/casino_core/authenticator/activerecord.rb b/lib/casino_core/authenticator/activerecord.rb index 88579c4..4425c94 100644 --- a/lib/casino_core/authenticator/activerecord.rb +++ b/lib/casino_core/authenticator/activerecord.rb @@ -70,7 +70,7 @@ def valid_password_with_sha1_crypt?(password, password_from_database) 10.times do digest = secure_digest(digest, salt, password, site_auth_key) end - digest == password_from_database + digest == password_from_database.split('$')[2] end def extra_attributes(user) From 062ac8dda3f8cca2b036a54a8a968c43a25eaee6 Mon Sep 17 00:00:00 2001 From: Oskar Kapusta Date: Thu, 26 Sep 2013 12:22:22 +0200 Subject: [PATCH 3/7] specs --- .../authenticator/activerecord_spec.rb | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/spec/casino_core/authenticator/activerecord_spec.rb b/spec/casino_core/authenticator/activerecord_spec.rb index a4abfac..184a22d 100644 --- a/spec/casino_core/authenticator/activerecord_spec.rb +++ b/spec/casino_core/authenticator/activerecord_spec.rb @@ -30,6 +30,7 @@ t.string :username t.string :password t.string :mail_address + t.string :salt end end end @@ -130,6 +131,21 @@ end end + context 'support for sha1 restful-authentication' do + let(:pepper) { '9df92c193273ae9adf804195641b50828dee0088' } + before do + CASinoCore::Authenticator::ActiveRecord::User.create!( + username: 'test4', + password: '$sha$a5a2725edcb9f8f5764047dc37c0a0c279dba699', + mail_address: 'mail@example.org', + salt: 'b1676d830c1558b584491089239f3ff448e5277e') + end + + it 'is able to handle sha1 restful-authentication password hashes' do + @authenticator.validate('test4', 'kapastry').should be_instance_of(Hash) + end + end + end end From 524b97944b62492a757aa9d7450e71da5ea13a3d Mon Sep 17 00:00:00 2001 From: Oskar Kapusta Date: Thu, 26 Sep 2013 15:41:35 +0200 Subject: [PATCH 4/7] hide pass --- lib/casino_core/authenticator/activerecord.rb | 15 +++++++-------- .../authenticator/activerecord_spec.rb | 4 ++-- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/lib/casino_core/authenticator/activerecord.rb b/lib/casino_core/authenticator/activerecord.rb index 4425c94..94c27d7 100644 --- a/lib/casino_core/authenticator/activerecord.rb +++ b/lib/casino_core/authenticator/activerecord.rb @@ -24,11 +24,11 @@ class #{self.class.to_s}::#{@options[:table].classify} < AuthDatabase def validate(username, password) @model.verify_active_connections! - @user = @model.send("find_by_#{@options[:username_column]}!", username) - password_from_database = @user.send(@options[:password_column]) + user = @model.send("find_by_#{@options[:username_column]}!", username) + password_from_database = user.send(@options[:password_column]) - if valid_password?(password, password_from_database) - { username: @user.send(@options[:username_column]), extra_attributes: extra_attributes(@user) } + if valid_password?(password, password_from_database, user.salt) + { username: user.send(@options[:username_column]), extra_attributes: extra_attributes(user) } else false end @@ -42,14 +42,14 @@ def secure_digest(*args) Digest::SHA1.hexdigest(args.flatten.join('--')) end - def valid_password?(password, password_from_database) + def valid_password?(password, password_from_database, salt=nil) return false if password_from_database.blank? magic = password_from_database.split('$')[1] case magic when /\A2a?\z/ valid_password_with_bcrypt?(password, password_from_database) when /\Asha?\z/ - valid_password_with_sha1_crypt?(password, password_from_database) + valid_password_with_sha1_crypt?(password, password_from_database, salt) else valid_password_with_unix_crypt?(password, password_from_database) end @@ -64,9 +64,8 @@ def valid_password_with_unix_crypt?(password, password_from_database) UnixCrypt.valid?(password, password_from_database) end - def valid_password_with_sha1_crypt?(password, password_from_database) + def valid_password_with_sha1_crypt?(password, password_from_database, salt) site_auth_key = digest = @options[:pepper].to_s - salt = @user.salt 10.times do digest = secure_digest(digest, salt, password, site_auth_key) end diff --git a/spec/casino_core/authenticator/activerecord_spec.rb b/spec/casino_core/authenticator/activerecord_spec.rb index 184a22d..52ccc5f 100644 --- a/spec/casino_core/authenticator/activerecord_spec.rb +++ b/spec/casino_core/authenticator/activerecord_spec.rb @@ -136,13 +136,13 @@ before do CASinoCore::Authenticator::ActiveRecord::User.create!( username: 'test4', - password: '$sha$a5a2725edcb9f8f5764047dc37c0a0c279dba699', + password: '$sha$2986d3bb945c0d03901fb7ec7e1405e5d9846271', mail_address: 'mail@example.org', salt: 'b1676d830c1558b584491089239f3ff448e5277e') end it 'is able to handle sha1 restful-authentication password hashes' do - @authenticator.validate('test4', 'kapastry').should be_instance_of(Hash) + @authenticator.validate('test4', 'password').should be_instance_of(Hash) end end From 26a8acd10f8241edf2c47ab729e5cac8680c1f6b Mon Sep 17 00:00:00 2001 From: Oskar Kapusta Date: Thu, 26 Sep 2013 15:46:40 +0200 Subject: [PATCH 5/7] try salt --- lib/casino_core/authenticator/activerecord.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/casino_core/authenticator/activerecord.rb b/lib/casino_core/authenticator/activerecord.rb index 94c27d7..e2fb725 100644 --- a/lib/casino_core/authenticator/activerecord.rb +++ b/lib/casino_core/authenticator/activerecord.rb @@ -27,7 +27,7 @@ def validate(username, password) user = @model.send("find_by_#{@options[:username_column]}!", username) password_from_database = user.send(@options[:password_column]) - if valid_password?(password, password_from_database, user.salt) + if valid_password?(password, password_from_database, (user.salt if user.respond_to?(:salt))) { username: user.send(@options[:username_column]), extra_attributes: extra_attributes(user) } else false From 72e155f7da9155b9fba2ec30e2dac600ec7414ca Mon Sep 17 00:00:00 2001 From: Oskar Kapusta Date: Mon, 30 Sep 2013 16:44:34 +0200 Subject: [PATCH 6/7] changed salt to site_auth_key due to conflict --- lib/casino_core/authenticator/activerecord.rb | 2 +- spec/casino_core/authenticator/activerecord_spec.rb | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/casino_core/authenticator/activerecord.rb b/lib/casino_core/authenticator/activerecord.rb index e2fb725..277b859 100644 --- a/lib/casino_core/authenticator/activerecord.rb +++ b/lib/casino_core/authenticator/activerecord.rb @@ -65,7 +65,7 @@ def valid_password_with_unix_crypt?(password, password_from_database) end def valid_password_with_sha1_crypt?(password, password_from_database, salt) - site_auth_key = digest = @options[:pepper].to_s + site_auth_key = digest = @options[:site_auth_key].to_s 10.times do digest = secure_digest(digest, salt, password, site_auth_key) end diff --git a/spec/casino_core/authenticator/activerecord_spec.rb b/spec/casino_core/authenticator/activerecord_spec.rb index 52ccc5f..c9dd7d9 100644 --- a/spec/casino_core/authenticator/activerecord_spec.rb +++ b/spec/casino_core/authenticator/activerecord_spec.rb @@ -5,6 +5,7 @@ let(:pepper) { nil } let(:extra_attributes) {{ email: 'mail_address' }} + let(:site_auth_key) { '9df92c193273ae9adf804195641b50828dee0088' } let(:options) do { connection: { @@ -15,6 +16,7 @@ username_column: 'username', password_column: 'password', pepper: pepper, + site_auth_key: site_auth_key, extra_attributes: extra_attributes } end @@ -132,7 +134,6 @@ end context 'support for sha1 restful-authentication' do - let(:pepper) { '9df92c193273ae9adf804195641b50828dee0088' } before do CASinoCore::Authenticator::ActiveRecord::User.create!( username: 'test4', From 571f7195510515312eb1c80a0daa02a84f099ad8 Mon Sep 17 00:00:00 2001 From: Oskar Kapusta Date: Fri, 11 Oct 2013 16:00:20 +0200 Subject: [PATCH 7/7] support for login by username and/or email --- lib/casino_core/authenticator/activerecord.rb | 5 ++++- .../authenticator/activerecord_spec.rb | 15 +++++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/lib/casino_core/authenticator/activerecord.rb b/lib/casino_core/authenticator/activerecord.rb index 277b859..970f874 100644 --- a/lib/casino_core/authenticator/activerecord.rb +++ b/lib/casino_core/authenticator/activerecord.rb @@ -24,7 +24,10 @@ class #{self.class.to_s}::#{@options[:table].classify} < AuthDatabase def validate(username, password) @model.verify_active_connections! - user = @model.send("find_by_#{@options[:username_column]}!", username) + user = @model.send("find_by_#{@options[:username_column]}", username) + unless user + user = @model.send("find_by_#{@options[:email_column]}!", username) + end password_from_database = user.send(@options[:password_column]) if valid_password?(password, password_from_database, (user.salt if user.respond_to?(:salt))) diff --git a/spec/casino_core/authenticator/activerecord_spec.rb b/spec/casino_core/authenticator/activerecord_spec.rb index c9dd7d9..1039099 100644 --- a/spec/casino_core/authenticator/activerecord_spec.rb +++ b/spec/casino_core/authenticator/activerecord_spec.rb @@ -15,6 +15,7 @@ table: 'users', username_column: 'username', password_column: 'password', + email_column: 'email', pepper: pepper, site_auth_key: site_auth_key, extra_attributes: extra_attributes @@ -33,6 +34,7 @@ t.string :password t.string :mail_address t.string :salt + t.string :email end end end @@ -147,6 +149,19 @@ end end + context 'support for login by username and/or email' do + before do + CASinoCore::Authenticator::ActiveRecord::User.create!( + username: 'test5', + password: '$2a$10$q9nu9AfeUCkwMeDaFlhOQ.2L0UK0tpYIq8JjJDzphO7qy1vdU9.Se', + email: 'test5@copper.io' + ) + end + it 'allows login using email' do + @authenticator.validate('test5@copper.io', 'testpassword4').should be_instance_of(Hash) + end + end + end end