merb-auth-more 1.0.15 → 1.1.0.pre
Sign up to get free protection for your applications and to get access to all the features.
- data/Rakefile +46 -51
- data/lib/merb-auth-more.rb +3 -1
- data/lib/merb-auth-more/mixins/bcrypt_user.rb +72 -0
- data/lib/merb-auth-more/mixins/redirect_back.rb +1 -1
- data/lib/merb-auth-more/mixins/salted_user.rb +8 -8
- data/lib/merb-auth-more/mixins/salted_user/dm_salted_user.rb +5 -2
- data/lib/merb-auth-more/mixins/salted_user/relaxdb_salted_user.rb +5 -2
- data/lib/merb-auth-more/mixins/salted_user/sq_salted_user.rb +39 -18
- data/lib/merb-auth-more/strategies/basic/basic_auth.rb +1 -0
- data/lib/merb-auth-more/strategies/basic/openid.rb +1 -0
- data/lib/merb-auth-more/strategies/basic/password_form.rb +1 -0
- data/lib/merb-auth-more/version.rb +7 -0
- data/spec/mixins/dm_bcrypt_user_spec.rb +42 -0
- data/spec/mixins/dm_salted_user_spec.rb +42 -0
- data/spec/mixins/redirect_back_spec.rb +53 -32
- data/spec/mixins/sq_bcrypt_user_spec.rb +43 -0
- data/spec/mixins/sq_salted_user_spec.rb +44 -0
- data/spec/shared_user_spec.rb +117 -0
- data/spec/spec.opts +2 -0
- data/spec/spec_helper.rb +29 -8
- metadata +55 -20
- data/spec/merb-auth-more_spec.rb +0 -4
- data/spec/mixins/salted_user_spec.rb +0 -105
data/Rakefile
CHANGED
@@ -1,59 +1,54 @@
|
|
1
|
-
require
|
2
|
-
|
3
|
-
RUBY_FORGE_PROJECT = "merb-auth"
|
4
|
-
GEM_NAME = "merb-auth-more"
|
5
|
-
PKG_BUILD = ENV['PKG_BUILD'] ? '.' + ENV['PKG_BUILD'] : ''
|
6
|
-
GEM_VERSION = Merb::VERSION + PKG_BUILD
|
7
|
-
|
8
|
-
AUTHOR = "Daniel Neighman"
|
9
|
-
EMAIL = "has.sox@gmail.com"
|
10
|
-
HOMEPAGE = "http://merbivore.com/"
|
11
|
-
SUMMARY = "Additional resources for use with the merb-auth-core authentication framework."
|
12
|
-
|
13
|
-
spec = Gem::Specification.new do |s|
|
14
|
-
s.rubyforge_project = 'merb'
|
15
|
-
s.name = GEM_NAME
|
16
|
-
s.version = GEM_VERSION
|
17
|
-
s.platform = Gem::Platform::RUBY
|
18
|
-
s.has_rdoc = true
|
19
|
-
s.extra_rdoc_files = ["README.textile", "LICENSE", 'TODO']
|
20
|
-
s.summary = SUMMARY
|
21
|
-
s.description = s.summary
|
22
|
-
s.author = AUTHOR
|
23
|
-
s.email = EMAIL
|
24
|
-
s.homepage = HOMEPAGE
|
25
|
-
s.add_dependency("merb-auth-core", ">= #{Merb::VERSION}")
|
26
|
-
s.require_path = 'lib'
|
27
|
-
s.files = %w(LICENSE README.textile Rakefile TODO) + Dir.glob("{lib,spec}/**/*")
|
28
|
-
|
29
|
-
end
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
30
3
|
|
31
|
-
|
32
|
-
|
33
|
-
end
|
4
|
+
# Load merb-auth-core version information
|
5
|
+
require File.expand_path('../../merb-auth-core/lib/merb-auth-core/version', __FILE__)
|
34
6
|
|
35
|
-
|
36
|
-
|
37
|
-
Merb::RakeHelper.install(GEM_NAME, :version => GEM_VERSION)
|
38
|
-
end
|
7
|
+
# Load this library's version information
|
8
|
+
require File.expand_path('../lib/merb-auth-more/version', __FILE__)
|
39
9
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
10
|
+
begin
|
11
|
+
|
12
|
+
gem 'jeweler', '~> 1.4'
|
13
|
+
require 'jeweler'
|
14
|
+
|
15
|
+
Jeweler::Tasks.new do |gemspec|
|
16
|
+
|
17
|
+
gemspec.version = Merb::Auth::More::VERSION.dup
|
18
|
+
|
19
|
+
gemspec.name = "merb-auth-more"
|
20
|
+
gemspec.description = "Addons for merb-auth-core"
|
21
|
+
gemspec.summary = "Additional resources for use with the merb-auth-core authentication framework."
|
22
|
+
|
23
|
+
gemspec.authors = [ "Daniel Neighman" ]
|
24
|
+
gemspec.email = "has.sox@gmail.com"
|
25
|
+
gemspec.homepage = "http://merbivore.com/"
|
26
|
+
|
27
|
+
gemspec.files = %w(LICENSE Rakefile README.textile TODO) + Dir['{lib,spec}/**/*']
|
28
|
+
|
29
|
+
# Runtime dependencies
|
30
|
+
gemspec.add_dependency 'merb-auth-core', "~> #{Merb::Auth::Core::VERSION}"
|
31
|
+
|
32
|
+
# Development dependencies
|
33
|
+
gemspec.add_development_dependency 'rspec', ">= 1.2.9"
|
44
34
|
|
45
|
-
desc "Create a gemspec file"
|
46
|
-
task :gemspec do
|
47
|
-
File.open("#{GEM_NAME}.gemspec", "w") do |file|
|
48
|
-
file.puts spec.to_ruby
|
49
35
|
end
|
36
|
+
|
37
|
+
Jeweler::GemcutterTasks.new
|
38
|
+
|
39
|
+
rescue LoadError
|
40
|
+
puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
|
41
|
+
end
|
42
|
+
|
43
|
+
require 'spec/rake/spectask'
|
44
|
+
Spec::Rake::SpecTask.new(:spec) do |spec|
|
45
|
+
spec.spec_opts << '--options' << 'spec/spec.opts' if File.exists?('spec/spec.opts')
|
46
|
+
spec.libs << 'lib' << 'spec'
|
47
|
+
spec.spec_files = FileList['spec/**/*_spec.rb']
|
50
48
|
end
|
51
49
|
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
t.rcov = false
|
57
|
-
t.rcov_opts << '--sort' << 'coverage' << '--sort-reverse'
|
58
|
-
t.rcov_opts << '--only-uncovered'
|
50
|
+
Spec::Rake::SpecTask.new(:rcov) do |spec|
|
51
|
+
spec.libs << 'lib' << 'spec'
|
52
|
+
spec.pattern = 'spec/**/*_spec.rb'
|
53
|
+
spec.rcov = true
|
59
54
|
end
|
data/lib/merb-auth-more.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'merb-auth-core'
|
2
|
+
|
1
3
|
# make sure we're running inside Merb
|
2
4
|
if defined?(Merb::Plugins)
|
3
5
|
# Merb gives you a Merb::Plugins.config hash...feel free to put your stuff in your piece of it
|
@@ -21,4 +23,4 @@ if defined?(Merb::Plugins)
|
|
21
23
|
end
|
22
24
|
|
23
25
|
Merb::Plugins.add_rakefiles "merb-auth-more/merbtasks"
|
24
|
-
end
|
26
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
require 'bcrypt'
|
2
|
+
require 'merb-auth-more/strategies/abstract_password'
|
3
|
+
|
4
|
+
class Merb::Authentication
|
5
|
+
module Mixins
|
6
|
+
# This mixin provides basic salted user password encryption.
|
7
|
+
#
|
8
|
+
# Added properties:
|
9
|
+
# :crypted_password, String
|
10
|
+
#
|
11
|
+
# To use it simply require it and include it into your user class.
|
12
|
+
#
|
13
|
+
# class User
|
14
|
+
# include Merb::Authentication::Mixins::SaltedUser
|
15
|
+
#
|
16
|
+
# end
|
17
|
+
#
|
18
|
+
module BCryptUser
|
19
|
+
|
20
|
+
def self.included(base)
|
21
|
+
base.class_eval do
|
22
|
+
attr_accessor :password, :password_confirmation
|
23
|
+
|
24
|
+
|
25
|
+
include Merb::Authentication::Mixins::BCryptUser::InstanceMethods
|
26
|
+
|
27
|
+
|
28
|
+
path = File.expand_path(File.dirname(__FILE__)) / "salted_user"
|
29
|
+
if defined?(DataMapper) && DataMapper::Resource > self
|
30
|
+
require path / "dm_salted_user"
|
31
|
+
extend(Merb::Authentication::Mixins::SaltedUser::DMClassMethods)
|
32
|
+
elsif defined?(ActiveRecord) && ancestors.include?(ActiveRecord::Base)
|
33
|
+
require path / "ar_salted_user"
|
34
|
+
extend(Merb::Authentication::Mixins::SaltedUser::ARClassMethods)
|
35
|
+
elsif defined?(Sequel) && ancestors.include?(Sequel::Model)
|
36
|
+
require path / "sq_salted_user"
|
37
|
+
extend(Merb::Authentication::Mixins::SaltedUser::SQClassMethods)
|
38
|
+
elsif defined?(RelaxDB) && ancestors.include?(RelaxDB::Document)
|
39
|
+
require path / "relaxdb_salted_user"
|
40
|
+
extend(Merb::Authentication::Mixins::SaltedUser::RDBClassMethods)
|
41
|
+
end
|
42
|
+
|
43
|
+
end # base.class_eval
|
44
|
+
end # self.included
|
45
|
+
|
46
|
+
|
47
|
+
module InstanceMethods
|
48
|
+
|
49
|
+
def authenticated?(password)
|
50
|
+
bcrypt_password == password
|
51
|
+
end
|
52
|
+
|
53
|
+
def bcrypt_password
|
54
|
+
@bcrypt_password ||= BCrypt::Password.new(crypted_password)
|
55
|
+
end
|
56
|
+
|
57
|
+
def password_required?
|
58
|
+
crypted_password.blank? || !password.blank?
|
59
|
+
end
|
60
|
+
|
61
|
+
def encrypt_password
|
62
|
+
return if password.blank?
|
63
|
+
cost = Merb::Plugins.config[:"merb-auth"][:bcrypt_cost] || BCrypt::Engine::DEFAULT_COST
|
64
|
+
self.crypted_password = BCrypt::Password.create(password, :cost => cost)
|
65
|
+
end
|
66
|
+
|
67
|
+
end # InstanceMethods
|
68
|
+
|
69
|
+
end # SaltedUser
|
70
|
+
end # Mixins
|
71
|
+
end # Merb::Authentication
|
72
|
+
|
@@ -51,7 +51,7 @@ module Merb::Authentication::Mixins
|
|
51
51
|
def _set_return_to
|
52
52
|
unless request.exceptions.blank?
|
53
53
|
session[:return_to] ||= []
|
54
|
-
session[:return_to] << request.uri
|
54
|
+
session[:return_to] << "#{Merb::Config[:path_prefix]}#{request.uri}"
|
55
55
|
session[:return_to]
|
56
56
|
end
|
57
57
|
end
|
@@ -1,5 +1,5 @@
|
|
1
|
-
require
|
2
|
-
require
|
1
|
+
require 'digest/sha1'
|
2
|
+
require 'merb-auth-more/strategies/abstract_password'
|
3
3
|
|
4
4
|
class Merb::Authentication
|
5
5
|
module Mixins
|
@@ -25,18 +25,18 @@ class Merb::Authentication
|
|
25
25
|
include Merb::Authentication::Mixins::SaltedUser::InstanceMethods
|
26
26
|
extend Merb::Authentication::Mixins::SaltedUser::ClassMethods
|
27
27
|
|
28
|
-
path =
|
28
|
+
path = "merb-auth-more/mixins/salted_user"
|
29
29
|
if defined?(DataMapper) && DataMapper::Resource > self
|
30
|
-
require path
|
30
|
+
require "#{path}/dm_salted_user"
|
31
31
|
extend(Merb::Authentication::Mixins::SaltedUser::DMClassMethods)
|
32
32
|
elsif defined?(ActiveRecord) && ancestors.include?(ActiveRecord::Base)
|
33
|
-
require path
|
33
|
+
require "#{path}/ar_salted_user"
|
34
34
|
extend(Merb::Authentication::Mixins::SaltedUser::ARClassMethods)
|
35
35
|
elsif defined?(Sequel) && ancestors.include?(Sequel::Model)
|
36
|
-
require path
|
36
|
+
require "#{path}/sq_salted_user"
|
37
37
|
extend(Merb::Authentication::Mixins::SaltedUser::SQClassMethods)
|
38
38
|
elsif defined?(RelaxDB) && ancestors.include?(RelaxDB::Document)
|
39
|
-
require path
|
39
|
+
require "#{path}/relaxdb_salted_user"
|
40
40
|
extend(Merb::Authentication::Mixins::SaltedUser::RDBClassMethods)
|
41
41
|
end
|
42
42
|
|
@@ -66,7 +66,7 @@ class Merb::Authentication
|
|
66
66
|
|
67
67
|
def encrypt_password
|
68
68
|
return if password.blank?
|
69
|
-
self.salt = Digest::SHA1.hexdigest("--#{Time.now.to_s}--#{Merb::Authentication::Strategies::Basic::Base.login_param}--") if
|
69
|
+
self.salt = Digest::SHA1.hexdigest("--#{Time.now.to_s}--#{Merb::Authentication::Strategies::Basic::Base.login_param}--") if salt.blank?
|
70
70
|
self.crypted_password = encrypt(password)
|
71
71
|
end
|
72
72
|
|
@@ -4,9 +4,12 @@ class Merb::Authentication
|
|
4
4
|
module DMClassMethods
|
5
5
|
def self.extended(base)
|
6
6
|
base.class_eval do
|
7
|
-
|
7
|
+
|
8
8
|
property :crypted_password, String, :length => 60
|
9
|
-
|
9
|
+
|
10
|
+
if Merb::Authentication::Mixins::SaltedUser > base
|
11
|
+
property :salt, String
|
12
|
+
end
|
10
13
|
|
11
14
|
validates_present :password, :if => proc{|m| m.password_required?}
|
12
15
|
validates_is_confirmed :password, :if => proc{|m| m.password_required?}
|
@@ -1,21 +1,48 @@
|
|
1
|
+
require 'merb_sequel'
|
2
|
+
|
1
3
|
class Merb::Authentication
|
2
4
|
module Mixins
|
3
5
|
module SaltedUser
|
6
|
+
|
7
|
+
module SQ3Hooks
|
8
|
+
def before_save
|
9
|
+
return false if super == false
|
10
|
+
encrypt_password
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
module SQ3Validations
|
15
|
+
def validate
|
16
|
+
validates_presence(:password) if password_required?
|
17
|
+
validates_presence(:password_confirmation) if password_required?
|
18
|
+
errors.add(:password, "Passwords are not the same") if password != password_confirmation
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
module SQInstanceMethods
|
23
|
+
unless Sequel::Model.instance_methods.include?(:new_record?)
|
24
|
+
def new_record?
|
25
|
+
self.new?
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
if Merb::Orms::Sequel.new_sequel?
|
30
|
+
include Merb::Authentication::Mixins::SaltedUser::SQ3Hooks
|
31
|
+
include Merb::Authentication::Mixins::SaltedUser::SQ3Validations
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
4
35
|
module SQClassMethods
|
5
|
-
|
6
36
|
def self.extended(base)
|
7
37
|
base.class_eval do
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
end # base.class_eval
|
18
|
-
|
38
|
+
unless Merb::Orms::Sequel.new_sequel?
|
39
|
+
before_save :encrypt_password
|
40
|
+
validates_presence_of :password, :if => :password_required?
|
41
|
+
validates_presence_of :password_confirmation, :if => :password_required?
|
42
|
+
validates_confirmation_of :password, :if => :password_required?
|
43
|
+
end
|
44
|
+
include Merb::Authentication::Mixins::SaltedUser::SQInstanceMethods
|
45
|
+
end
|
19
46
|
end # self.extended
|
20
47
|
|
21
48
|
def authenticate(login, password)
|
@@ -24,12 +51,6 @@ class Merb::Authentication
|
|
24
51
|
end
|
25
52
|
end # SQClassMethods
|
26
53
|
|
27
|
-
module SQInstanceMethods
|
28
|
-
def new_record?
|
29
|
-
new?
|
30
|
-
end
|
31
|
-
end
|
32
|
-
|
33
54
|
end # SaltedUser
|
34
55
|
end # Mixins
|
35
56
|
end # Merb::Authentication
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'dm-core'
|
3
|
+
require 'dm-validations'
|
4
|
+
require 'merb-auth-more/mixins/bcrypt_user'
|
5
|
+
|
6
|
+
describe "A DataMapper Bcrypt User" do
|
7
|
+
|
8
|
+
include UserHelper
|
9
|
+
|
10
|
+
before(:all) do
|
11
|
+
|
12
|
+
DataMapper.setup(:default, "sqlite3::memory:")
|
13
|
+
|
14
|
+
class DataMapperBcryptUser
|
15
|
+
|
16
|
+
include DataMapper::Resource
|
17
|
+
include Merb::Authentication::Mixins::BCryptUser
|
18
|
+
|
19
|
+
property :id, Serial
|
20
|
+
property :email, String
|
21
|
+
property :login, String
|
22
|
+
|
23
|
+
end
|
24
|
+
|
25
|
+
DataMapper.auto_migrate!
|
26
|
+
|
27
|
+
end
|
28
|
+
|
29
|
+
before(:each) do
|
30
|
+
@user_class = DataMapperBcryptUser
|
31
|
+
@user_class.create(valid_user_params)
|
32
|
+
@new_user = @user_class.new(valid_user_params)
|
33
|
+
end
|
34
|
+
|
35
|
+
after(:each) do
|
36
|
+
DataMapperBcryptUser.all.destroy!
|
37
|
+
end
|
38
|
+
|
39
|
+
it_should_behave_like 'every encrypted user'
|
40
|
+
it_should_behave_like 'every bcrypt user'
|
41
|
+
|
42
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'dm-core'
|
3
|
+
require 'dm-validations'
|
4
|
+
require 'merb-auth-more/mixins/salted_user'
|
5
|
+
|
6
|
+
describe "A DataMapper Salted User" do
|
7
|
+
|
8
|
+
include UserHelper
|
9
|
+
|
10
|
+
before(:all) do
|
11
|
+
|
12
|
+
DataMapper.setup(:default, "sqlite3::memory:")
|
13
|
+
|
14
|
+
class DataMapperSaltedUser
|
15
|
+
|
16
|
+
include DataMapper::Resource
|
17
|
+
include Merb::Authentication::Mixins::SaltedUser
|
18
|
+
|
19
|
+
property :id, Serial
|
20
|
+
property :email, String
|
21
|
+
property :login, String
|
22
|
+
|
23
|
+
end
|
24
|
+
|
25
|
+
DataMapper.auto_migrate!
|
26
|
+
|
27
|
+
end
|
28
|
+
|
29
|
+
before(:each) do
|
30
|
+
@user_class = DataMapperSaltedUser
|
31
|
+
@user_class.create(valid_user_params)
|
32
|
+
@new_user = @user_class.new(valid_user_params)
|
33
|
+
end
|
34
|
+
|
35
|
+
after(:each) do
|
36
|
+
DataMapperSaltedUser.all.destroy!
|
37
|
+
end
|
38
|
+
|
39
|
+
it_should_behave_like 'every encrypted user'
|
40
|
+
it_should_behave_like 'every salted user'
|
41
|
+
|
42
|
+
end
|
@@ -1,5 +1,43 @@
|
|
1
|
-
require
|
2
|
-
require
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'merb-auth-more/mixins/redirect_back'
|
3
|
+
|
4
|
+
|
5
|
+
describe "every call to redirect_back", :shared => true do
|
6
|
+
|
7
|
+
it "should set the return_to in the session when sent to the exceptions controller from a failed login" do
|
8
|
+
r = request("/go_back")
|
9
|
+
r.status.should == Merb::Controller::Unauthenticated.status
|
10
|
+
r2 = login
|
11
|
+
r2.should redirect_to(@return_to_after_failed_login)
|
12
|
+
end
|
13
|
+
|
14
|
+
it "should not set the return_to in the session when deliberately going to unauthenticated" do
|
15
|
+
r = login
|
16
|
+
r.should redirect_to("/")
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should still redirect to the original even if it's failed many times" do
|
20
|
+
request("/go_back")
|
21
|
+
request("/login", :method => "put", :params => {:pass_auth => false})
|
22
|
+
request("/login", :method => "put", :params => {:pass_auth => false})
|
23
|
+
request("/login", :method => "put", :params => {:pass_auth => false})
|
24
|
+
r = login
|
25
|
+
r.should redirect_to(@return_to_after_failed_login)
|
26
|
+
end
|
27
|
+
|
28
|
+
it "should not redirect back to a previous redirect back after being logged out" do
|
29
|
+
request("/go_back")
|
30
|
+
request("/login", :method => "put", :params => {:pass_auth => false})
|
31
|
+
request("/login", :method => "put", :params => {:pass_auth => false})
|
32
|
+
request("/login", :method => "put", :params => {:pass_auth => false})
|
33
|
+
r = login
|
34
|
+
r.should redirect_to(@return_to_after_failed_login)
|
35
|
+
request("/logout", :method => "delete")
|
36
|
+
r = login
|
37
|
+
r.should redirect_to("/")
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
3
41
|
|
4
42
|
describe "redirect_back" do
|
5
43
|
|
@@ -60,38 +98,21 @@ describe "redirect_back" do
|
|
60
98
|
def login
|
61
99
|
request("/login", :method => "put", :params => {:pass_auth => true})
|
62
100
|
end
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
it "should not set the return_to in the session when deliberately going to unauthenticated" do
|
72
|
-
r = login
|
73
|
-
r.should redirect_to("/")
|
74
|
-
end
|
75
|
-
|
76
|
-
it "should still redirect to the original even if it's failed many times" do
|
77
|
-
request("/go_back")
|
78
|
-
request("/login", :method => "put", :params => {:pass_auth => false})
|
79
|
-
request("/login", :method => "put", :params => {:pass_auth => false})
|
80
|
-
request("/login", :method => "put", :params => {:pass_auth => false})
|
81
|
-
r = login
|
82
|
-
r.should redirect_to("/go_back")
|
101
|
+
|
102
|
+
describe "without Merb::Config[:path_prefix]" do
|
103
|
+
before(:all) do
|
104
|
+
Merb::Config[:path_prefix] = nil
|
105
|
+
@return_to_after_failed_login = '/go_back'
|
106
|
+
end
|
107
|
+
it_should_behave_like 'every call to redirect_back'
|
83
108
|
end
|
84
109
|
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
r.should redirect_to("/go_back")
|
92
|
-
request("/logout", :method => "delete")
|
93
|
-
r = login
|
94
|
-
r.should redirect_to("/")
|
110
|
+
describe "without Merb::Config[:path_prefix]" do
|
111
|
+
before(:all) do
|
112
|
+
Merb::Config[:path_prefix] = '/myapp'
|
113
|
+
@return_to_after_failed_login = '/myapp/go_back'
|
114
|
+
end
|
115
|
+
it_should_behave_like 'every call to redirect_back'
|
95
116
|
end
|
96
117
|
|
97
118
|
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'sequel'
|
3
|
+
require 'merb_sequel'
|
4
|
+
require 'merb-auth-more/mixins/bcrypt_user'
|
5
|
+
|
6
|
+
DB = Sequel.sqlite unless Object.const_defined?('DB')
|
7
|
+
|
8
|
+
describe "A Sequel Bcrypt User" do
|
9
|
+
|
10
|
+
include UserHelper
|
11
|
+
|
12
|
+
before(:all) do
|
13
|
+
|
14
|
+
DB.drop_table(:users) if DB.table_exists? :users
|
15
|
+
DB.create_table :users do
|
16
|
+
primary_key :id
|
17
|
+
column :email, :string
|
18
|
+
column :login, :string
|
19
|
+
column :crypted_password, :string
|
20
|
+
end
|
21
|
+
|
22
|
+
class SequelBcryptUser < Sequel::Model
|
23
|
+
set_dataset :users
|
24
|
+
plugin(:validation_helpers) if Merb::Orms::Sequel.new_sequel?
|
25
|
+
include Merb::Authentication::Mixins::BCryptUser
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
|
30
|
+
before(:each) do
|
31
|
+
@user_class = SequelBcryptUser
|
32
|
+
@user_class.create(valid_user_params)
|
33
|
+
@new_user = @user_class.new(valid_user_params)
|
34
|
+
end
|
35
|
+
|
36
|
+
after(:each) do
|
37
|
+
SequelBcryptUser.delete
|
38
|
+
end
|
39
|
+
|
40
|
+
it_should_behave_like 'every encrypted user'
|
41
|
+
it_should_behave_like 'every bcrypt user'
|
42
|
+
|
43
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'sequel'
|
3
|
+
require 'merb_sequel'
|
4
|
+
require 'merb-auth-more/mixins/salted_user'
|
5
|
+
|
6
|
+
DB = Sequel.sqlite unless Object.const_defined?('DB')
|
7
|
+
|
8
|
+
describe "A Sequel Salted User" do
|
9
|
+
|
10
|
+
include UserHelper
|
11
|
+
|
12
|
+
before(:all) do
|
13
|
+
|
14
|
+
DB.drop_table(:users) if DB.table_exists? :users
|
15
|
+
DB.create_table :users do
|
16
|
+
primary_key :id
|
17
|
+
column :email, :string
|
18
|
+
column :login, :string
|
19
|
+
column :crypted_password, :string
|
20
|
+
column :salt, :string
|
21
|
+
end
|
22
|
+
|
23
|
+
class SequelSaltedUser < Sequel::Model
|
24
|
+
set_dataset :users
|
25
|
+
plugin(:validation_helpers) if Merb::Orms::Sequel.new_sequel?
|
26
|
+
include Merb::Authentication::Mixins::SaltedUser
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
|
31
|
+
before(:each) do
|
32
|
+
@user_class = SequelSaltedUser
|
33
|
+
@user_class.create(valid_user_params)
|
34
|
+
@new_user = @user_class.new(valid_user_params)
|
35
|
+
end
|
36
|
+
|
37
|
+
after(:each) do
|
38
|
+
SequelSaltedUser.delete
|
39
|
+
end
|
40
|
+
|
41
|
+
it_should_behave_like 'every encrypted user'
|
42
|
+
it_should_behave_like 'every salted user'
|
43
|
+
|
44
|
+
end
|
@@ -0,0 +1,117 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module UserHelper
|
4
|
+
|
5
|
+
def valid_login
|
6
|
+
'fred'
|
7
|
+
end
|
8
|
+
|
9
|
+
def valid_email
|
10
|
+
'fred@example.com'
|
11
|
+
end
|
12
|
+
|
13
|
+
def valid_password
|
14
|
+
'sekrit'
|
15
|
+
end
|
16
|
+
|
17
|
+
def valid_user_params
|
18
|
+
{
|
19
|
+
:login => valid_login,
|
20
|
+
:email => valid_email,
|
21
|
+
:password => valid_password,
|
22
|
+
:password_confirmation => valid_password
|
23
|
+
}
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
|
28
|
+
describe "every encrypted user", :shared => true do
|
29
|
+
|
30
|
+
describe "class" do
|
31
|
+
|
32
|
+
it "should authenticate valid credentials" do
|
33
|
+
@user_class.authenticate(valid_login, valid_password).should_not be_nil
|
34
|
+
end
|
35
|
+
|
36
|
+
it "should not authenticate an invalid login and an existing password" do
|
37
|
+
@user_class.authenticate("not_the_login", valid_password).should be_nil
|
38
|
+
end
|
39
|
+
|
40
|
+
it "should not authenticate a valid login and an invalid password" do
|
41
|
+
@user_class.authenticate(valid_login, "not_the_password").should be_nil
|
42
|
+
end
|
43
|
+
|
44
|
+
it "should not authenticate an invalid login and an unknown password" do
|
45
|
+
@user_class.authenticate("i_dont_exist", "not_the_password").should be_nil
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
49
|
+
|
50
|
+
describe "instance" do
|
51
|
+
|
52
|
+
it { @new_user.should respond_to(:password) }
|
53
|
+
it { @new_user.should respond_to(:password_confirmation) }
|
54
|
+
it { @new_user.should respond_to(:crypted_password) }
|
55
|
+
|
56
|
+
it "should require a password if a #password_required? returns true" do
|
57
|
+
@new_user.password = nil
|
58
|
+
@new_user.password_required?.should be_true
|
59
|
+
@new_user.should_not be_valid
|
60
|
+
end
|
61
|
+
|
62
|
+
it "should require a password_confirmation if #password_required? returns true" do
|
63
|
+
@new_user.password_confirmation = nil
|
64
|
+
@new_user.password_required?.should be_true
|
65
|
+
@new_user.should_not be_valid
|
66
|
+
end
|
67
|
+
|
68
|
+
it "should not require a password when saving an existing user" do
|
69
|
+
user = @user_class.first(:login => valid_login)
|
70
|
+
user.password.should be_nil
|
71
|
+
user.password_confirmation.should be_nil
|
72
|
+
user.login = "some_different_login_to_allow_saving"
|
73
|
+
user.save
|
74
|
+
end
|
75
|
+
|
76
|
+
it "should authenticate a user instance against a valid password" do
|
77
|
+
@user_class.first(:login => valid_login).should be_authenticated(valid_password)
|
78
|
+
end
|
79
|
+
|
80
|
+
end
|
81
|
+
|
82
|
+
end
|
83
|
+
|
84
|
+
describe 'every salted user', :shared => true do
|
85
|
+
|
86
|
+
it { @new_user.should respond_to(:salt) }
|
87
|
+
|
88
|
+
it "should set the salt" do
|
89
|
+
@new_user.salt.should be_nil
|
90
|
+
@new_user.send(:encrypt_password)
|
91
|
+
@new_user.salt.should_not be_nil
|
92
|
+
end
|
93
|
+
|
94
|
+
it "should set the salt even when user is not new record but salt is blank" do
|
95
|
+
@new_user.save
|
96
|
+
@new_user.salt = nil
|
97
|
+
@new_user.send(:encrypt_password)
|
98
|
+
@new_user.salt.should_not be_nil
|
99
|
+
end
|
100
|
+
|
101
|
+
end
|
102
|
+
|
103
|
+
describe 'every bcrypt user', :shared => true do
|
104
|
+
|
105
|
+
it "should create a valid Bcrypt password" do
|
106
|
+
lambda { @new_user.bcrypt_password }.should raise_error(BCrypt::Errors::InvalidHash)
|
107
|
+
@new_user.send(:encrypt_password)
|
108
|
+
lambda { @new_user.bcrypt_password }.should_not raise_error(BCrypt::Errors::InvalidHash)
|
109
|
+
end
|
110
|
+
|
111
|
+
it "should use the cost set in Merb::Plugins.config[:'merb-auth'][:bcrypt_cost]" do
|
112
|
+
Merb::Plugins.config[:'merb-auth'][:bcrypt_cost] = 6
|
113
|
+
@new_user.send(:encrypt_password)
|
114
|
+
@new_user.bcrypt_password.cost.should == 6
|
115
|
+
end
|
116
|
+
|
117
|
+
end
|
data/spec/spec.opts
ADDED
data/spec/spec_helper.rb
CHANGED
@@ -1,17 +1,38 @@
|
|
1
|
-
|
2
|
-
$:.push File.join(File.dirname(__FILE__), '..', 'lib')
|
1
|
+
require "rubygems"
|
3
2
|
|
4
|
-
|
3
|
+
# Use current merb-core sources if running from a typical dev checkout.
|
4
|
+
lib = File.expand_path('../../../../merb/merb-core/lib', __FILE__)
|
5
|
+
$LOAD_PATH.unshift(lib) if File.directory?(lib)
|
5
6
|
require 'merb-core'
|
6
7
|
require 'merb-core/test'
|
7
8
|
require 'merb-core/dispatch/session'
|
8
|
-
|
9
|
+
|
10
|
+
# Use current merb-auth-core sources if running from a typical dev checkout.
|
11
|
+
lib = File.expand_path('../../../merb-auth-core/lib', __FILE__)
|
12
|
+
$LOAD_PATH.unshift(lib) if File.directory?(lib)
|
9
13
|
require 'merb-auth-core'
|
10
14
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
+
# Use current merb_sequel sources if running from a typical dev checkout.
|
16
|
+
lib = File.expand_path('../../../../merb_sequel/lib', __FILE__)
|
17
|
+
$LOAD_PATH.unshift(lib) if File.directory?(lib)
|
18
|
+
require 'merb_sequel'
|
19
|
+
|
20
|
+
# The lib under test
|
21
|
+
require "merb-auth-more"
|
22
|
+
|
23
|
+
# Satisfies Autotest and anyone else not using the Rake tasks
|
24
|
+
require 'spec'
|
25
|
+
|
26
|
+
require 'shared_user_spec'
|
27
|
+
|
28
|
+
$TESTING=true
|
29
|
+
|
30
|
+
Merb.start(
|
31
|
+
:environment => "test",
|
32
|
+
:adapter => "runner",
|
33
|
+
:session_store => "cookie",
|
34
|
+
:session_secret_key => "d3a6e6f99a25004da82b71af8b9ed0ab71d3ea21"
|
35
|
+
)
|
15
36
|
|
16
37
|
module StrategyHelper
|
17
38
|
def clear_strategies!
|
metadata
CHANGED
@@ -1,7 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: merb-auth-more
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
|
4
|
+
prerelease: true
|
5
|
+
segments:
|
6
|
+
- 1
|
7
|
+
- 1
|
8
|
+
- 0
|
9
|
+
- pre
|
10
|
+
version: 1.1.0.pre
|
5
11
|
platform: ruby
|
6
12
|
authors:
|
7
13
|
- Daniel Neighman
|
@@ -9,75 +15,104 @@ autorequire:
|
|
9
15
|
bindir: bin
|
10
16
|
cert_chain: []
|
11
17
|
|
12
|
-
date:
|
18
|
+
date: 2010-02-21 00:00:00 +00:00
|
13
19
|
default_executable:
|
14
20
|
dependencies:
|
15
21
|
- !ruby/object:Gem::Dependency
|
16
22
|
name: merb-auth-core
|
23
|
+
prerelease: false
|
24
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
25
|
+
requirements:
|
26
|
+
- - ~>
|
27
|
+
- !ruby/object:Gem::Version
|
28
|
+
segments:
|
29
|
+
- 1
|
30
|
+
- 1
|
31
|
+
- 0
|
32
|
+
- pre
|
33
|
+
version: 1.1.0.pre
|
17
34
|
type: :runtime
|
18
|
-
|
19
|
-
|
35
|
+
version_requirements: *id001
|
36
|
+
- !ruby/object:Gem::Dependency
|
37
|
+
name: rspec
|
38
|
+
prerelease: false
|
39
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
20
40
|
requirements:
|
21
41
|
- - ">="
|
22
42
|
- !ruby/object:Gem::Version
|
23
|
-
|
24
|
-
|
25
|
-
|
43
|
+
segments:
|
44
|
+
- 1
|
45
|
+
- 2
|
46
|
+
- 9
|
47
|
+
version: 1.2.9
|
48
|
+
type: :development
|
49
|
+
version_requirements: *id002
|
50
|
+
description: Addons for merb-auth-core
|
26
51
|
email: has.sox@gmail.com
|
27
52
|
executables: []
|
28
53
|
|
29
54
|
extensions: []
|
30
55
|
|
31
56
|
extra_rdoc_files:
|
32
|
-
- README.textile
|
33
57
|
- LICENSE
|
58
|
+
- README.textile
|
34
59
|
- TODO
|
35
60
|
files:
|
36
61
|
- LICENSE
|
37
62
|
- README.textile
|
38
63
|
- Rakefile
|
39
64
|
- TODO
|
65
|
+
- lib/merb-auth-more.rb
|
40
66
|
- lib/merb-auth-more/merbtasks.rb
|
67
|
+
- lib/merb-auth-more/mixins/bcrypt_user.rb
|
41
68
|
- lib/merb-auth-more/mixins/redirect_back.rb
|
69
|
+
- lib/merb-auth-more/mixins/salted_user.rb
|
42
70
|
- lib/merb-auth-more/mixins/salted_user/ar_salted_user.rb
|
43
71
|
- lib/merb-auth-more/mixins/salted_user/dm_salted_user.rb
|
44
72
|
- lib/merb-auth-more/mixins/salted_user/relaxdb_salted_user.rb
|
45
73
|
- lib/merb-auth-more/mixins/salted_user/sq_salted_user.rb
|
46
|
-
- lib/merb-auth-more/mixins/salted_user.rb
|
47
74
|
- lib/merb-auth-more/strategies/abstract_password.rb
|
48
75
|
- lib/merb-auth-more/strategies/basic/basic_auth.rb
|
49
76
|
- lib/merb-auth-more/strategies/basic/openid.rb
|
50
77
|
- lib/merb-auth-more/strategies/basic/password_form.rb
|
51
|
-
- lib/merb-auth-more.rb
|
52
|
-
- spec/
|
78
|
+
- lib/merb-auth-more/version.rb
|
79
|
+
- spec/mixins/dm_bcrypt_user_spec.rb
|
80
|
+
- spec/mixins/dm_salted_user_spec.rb
|
53
81
|
- spec/mixins/redirect_back_spec.rb
|
54
|
-
- spec/mixins/
|
82
|
+
- spec/mixins/sq_bcrypt_user_spec.rb
|
83
|
+
- spec/mixins/sq_salted_user_spec.rb
|
84
|
+
- spec/shared_user_spec.rb
|
85
|
+
- spec/spec.opts
|
55
86
|
- spec/spec_helper.rb
|
56
87
|
has_rdoc: true
|
57
88
|
homepage: http://merbivore.com/
|
58
89
|
licenses: []
|
59
90
|
|
60
91
|
post_install_message:
|
61
|
-
rdoc_options:
|
62
|
-
|
92
|
+
rdoc_options:
|
93
|
+
- --charset=UTF-8
|
63
94
|
require_paths:
|
64
95
|
- lib
|
65
96
|
required_ruby_version: !ruby/object:Gem::Requirement
|
66
97
|
requirements:
|
67
98
|
- - ">="
|
68
99
|
- !ruby/object:Gem::Version
|
100
|
+
segments:
|
101
|
+
- 0
|
69
102
|
version: "0"
|
70
|
-
version:
|
71
103
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
72
104
|
requirements:
|
73
|
-
- - "
|
105
|
+
- - ">"
|
74
106
|
- !ruby/object:Gem::Version
|
75
|
-
|
76
|
-
|
107
|
+
segments:
|
108
|
+
- 1
|
109
|
+
- 3
|
110
|
+
- 1
|
111
|
+
version: 1.3.1
|
77
112
|
requirements: []
|
78
113
|
|
79
|
-
rubyforge_project:
|
80
|
-
rubygems_version: 1.3.
|
114
|
+
rubyforge_project:
|
115
|
+
rubygems_version: 1.3.6
|
81
116
|
signing_key:
|
82
117
|
specification_version: 3
|
83
118
|
summary: Additional resources for use with the merb-auth-core authentication framework.
|
data/spec/merb-auth-more_spec.rb
DELETED
@@ -1,105 +0,0 @@
|
|
1
|
-
require File.join(File.dirname(__FILE__), "..", 'spec_helper.rb')
|
2
|
-
require 'dm-core'
|
3
|
-
require 'dm-validations'
|
4
|
-
require File.join(File.expand_path(File.dirname(__FILE__)), "..", ".." ,"lib", "merb-auth-more", "strategies", "abstract_password")
|
5
|
-
require File.join(File.expand_path(File.dirname(__FILE__)), "..", ".." ,"lib", "merb-auth-more", "mixins", "salted_user")
|
6
|
-
|
7
|
-
describe "A Salted User" do
|
8
|
-
|
9
|
-
before(:all) do
|
10
|
-
DataMapper.setup(:default, "sqlite3::memory:")
|
11
|
-
|
12
|
-
class Utilisateur
|
13
|
-
include DataMapper::Resource
|
14
|
-
include Merb::Authentication::Mixins::SaltedUser
|
15
|
-
|
16
|
-
property :id, Serial
|
17
|
-
property :email, String
|
18
|
-
property :login, String
|
19
|
-
end
|
20
|
-
Utilisateur.auto_migrate!
|
21
|
-
end
|
22
|
-
|
23
|
-
after(:each) do
|
24
|
-
Utilisateur.all.destroy!
|
25
|
-
end
|
26
|
-
|
27
|
-
def default_user_params
|
28
|
-
{:login => "fred", :email => "fred@example.com", :password => "sekrit", :password_confirmation => "sekrit"}
|
29
|
-
end
|
30
|
-
|
31
|
-
it "should authenticate a user using a class method" do
|
32
|
-
user = Utilisateur.new(default_user_params)
|
33
|
-
user.save
|
34
|
-
user.should_not be_new_record
|
35
|
-
Utilisateur.authenticate("fred", "sekrit").should_not be_nil
|
36
|
-
end
|
37
|
-
|
38
|
-
it "should not authenticate a user using the wrong password" do
|
39
|
-
user = Utilisateur.new(default_user_params)
|
40
|
-
user.save
|
41
|
-
Utilisateur.authenticate("fred", "not_the_password").should be_nil
|
42
|
-
end
|
43
|
-
|
44
|
-
it "should not authenticate a user using the wrong login" do
|
45
|
-
user = Utilisateur.create(default_user_params)
|
46
|
-
Utilisateur.authenticate("not_the_login@blah.com", "sekrit").should be_nil
|
47
|
-
end
|
48
|
-
|
49
|
-
it "should not authenticate a user that does not exist" do
|
50
|
-
Utilisateur.authenticate("i_dont_exist", "password").should be_nil
|
51
|
-
end
|
52
|
-
|
53
|
-
describe "passwords" do
|
54
|
-
before(:each) do
|
55
|
-
@user = Utilisateur.new(default_user_params)
|
56
|
-
end
|
57
|
-
|
58
|
-
it{@user.should respond_to(:password)}
|
59
|
-
it{@user.should respond_to(:password_confirmation)}
|
60
|
-
it{@user.should respond_to(:crypted_password)}
|
61
|
-
|
62
|
-
it "should require password if password is required" do
|
63
|
-
user = Utilisateur.new(:login => "fred", :email => "fred@example.com")
|
64
|
-
user.stub!(:password_required?).and_return(true)
|
65
|
-
user.valid?
|
66
|
-
user.errors.on(:password).should_not be_nil
|
67
|
-
user.errors.on(:password).should_not be_empty
|
68
|
-
end
|
69
|
-
|
70
|
-
it "should set the salt" do
|
71
|
-
@user.salt.should be_nil
|
72
|
-
@user.send(:encrypt_password)
|
73
|
-
@user.salt.should_not be_nil
|
74
|
-
end
|
75
|
-
|
76
|
-
it "should require the password on create" do
|
77
|
-
user = Utilisateur.new(:login => "fred", :email => "fred@example.com")
|
78
|
-
user.save
|
79
|
-
user.errors.on(:password).should_not be_nil
|
80
|
-
user.errors.on(:password).should_not be_empty
|
81
|
-
end
|
82
|
-
|
83
|
-
it "should require password_confirmation if the password_required?" do
|
84
|
-
user = Utilisateur.new(:login => "fred", :email => "fred@example.com", :password => "sekrit")
|
85
|
-
user.save
|
86
|
-
(user.errors.on(:password) || user.errors.on(:password_confirmation)).should_not be_nil
|
87
|
-
end
|
88
|
-
|
89
|
-
it "should autenticate against a password" do
|
90
|
-
@user.save
|
91
|
-
@user.should be_authenticated("sekrit")
|
92
|
-
end
|
93
|
-
|
94
|
-
it "should not require a password when saving an existing user" do
|
95
|
-
@user.save
|
96
|
-
@user.should_not be_a_new_record
|
97
|
-
@user = Utilisateur.first(:login => "fred")
|
98
|
-
@user.password.should be_nil
|
99
|
-
@user.password_confirmation.should be_nil
|
100
|
-
@user.login = "some_different_login_to_allow_saving"
|
101
|
-
(@user.save).should be_true
|
102
|
-
end
|
103
|
-
|
104
|
-
end
|
105
|
-
end
|