merb-auth-more 0.9.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/LICENSE ADDED
@@ -0,0 +1,42 @@
1
+ Copyright (c) 2008 Daniel Neighman
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
+
22
+ Some of the code in this plugin is based on Restful Merb::Authentication by Rick Olsen. License File here:
23
+
24
+ Copyright (c) 2005 Rick Olson
25
+
26
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
27
+ this software and associated documentation files (the "Software"), to deal in
28
+ the Software without restriction, including without limitation the rights to
29
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
30
+ the Software, and to permit persons to whom the Software is furnished to do so,
31
+ subject to the following conditions:
32
+
33
+ The above copyright notice and this permission notice shall be included in all
34
+ copies or substantial portions of the Software.
35
+
36
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
37
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
38
+ FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
39
+ COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
40
+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
41
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
42
+ =======
@@ -0,0 +1,50 @@
1
+ merb-auth-more
2
+ ==============
3
+
4
+ merb-auth-more provides stuff that's useful, but not core to the functionality of
5
+ merb-auth. Strategies and "User" object mixins are here.
6
+
7
+ h3. What Strategies are there?
8
+
9
+ Strategies are really simple to implement, but we've made some basic ones available.
10
+
11
+ The built in ones are basic but should be enough to get you going for most things.
12
+
13
+ To specify them, simply require them. For example,in lib/auth-strategies.rb
14
+
15
+ <pre><code>
16
+ Merb::Authentication.activate!(:default_password_form)
17
+ Merb::Authentication.activate!(:default_openid)
18
+
19
+ class MyApiLogin < ::Merb::Authentication::Strategy
20
+ def run!
21
+ # check for api login
22
+ end
23
+ end
24
+ </code></pre>
25
+
26
+ So far there are:
27
+
28
+ * :default_password_form
29
+ * :default_basic_auth
30
+ * :default_openid
31
+
32
+ h3. "User" mixins
33
+
34
+ To assist with your authenticating needs, there is user mixins available to enhance your user model
35
+ for basic cases. These really are just for the basic case, so if you need something extra you should
36
+ overwrite the methods, or implement (and share ;) ;) ) your requirements.
37
+
38
+ To use these, require the specific mixin, and then include it into your "User" class.
39
+
40
+ <pre><code>
41
+ require 'merb-auth-more/mixins/salted_user'
42
+
43
+ class User
44
+ include Merb::Authentication::Mixins::SaltedUser
45
+
46
+ end
47
+ </code></pre>
48
+
49
+ The salted user mixin provides basic salted SHA1 password authentication. It implements the required User.authenticate method
50
+ for use with the default password strategies.
@@ -0,0 +1,65 @@
1
+ require 'rubygems'
2
+ require 'rake/gempackagetask'
3
+ require 'rubygems/specification'
4
+ require 'date'
5
+ require "spec/rake/spectask"
6
+ require 'merb-core/version'
7
+ require 'merb-core/tasks/merb_rake_helper'
8
+ require 'rake/testtask'
9
+
10
+ require File.join(File.dirname(__FILE__), "../../merb-core/lib/merb-core/version.rb")
11
+
12
+ GEM_NAME = "merb-auth-more"
13
+ GEM_VERSION = Merb::VERSION
14
+ AUTHOR = "Daniel Neighman"
15
+ EMAIL = "has.sox@gmail.com"
16
+ HOMEPAGE = "http://merbivore.com/"
17
+ SUMMARY = "Additional resources for use with the merb-auth-core authentication framework."
18
+
19
+ spec = Gem::Specification.new do |s|
20
+ s.rubyforge_project = 'merb'
21
+ s.name = GEM_NAME
22
+ s.version = GEM_VERSION
23
+ s.platform = Gem::Platform::RUBY
24
+ s.has_rdoc = true
25
+ s.extra_rdoc_files = ["README.textile", "LICENSE", 'TODO']
26
+ s.summary = SUMMARY
27
+ s.description = s.summary
28
+ s.author = AUTHOR
29
+ s.email = EMAIL
30
+ s.homepage = HOMEPAGE
31
+ s.add_dependency("merb-auth-core", "= #{Merb::VERSION}")
32
+ s.require_path = 'lib'
33
+ s.files = %w(LICENSE README.textile Rakefile TODO) + Dir.glob("{lib,spec}/**/*")
34
+
35
+ end
36
+
37
+ Rake::GemPackageTask.new(spec) do |pkg|
38
+ pkg.gem_spec = spec
39
+ end
40
+
41
+ desc "install the plugin as a gem"
42
+ task :install do
43
+ Merb::RakeHelper.install(GEM_NAME, :version => GEM_VERSION)
44
+ end
45
+
46
+ desc "Uninstall the gem"
47
+ task :uninstall do
48
+ Merb::RakeHelper.uninstall(GEM_NAME, :version => GEM_VERSION)
49
+ end
50
+
51
+ desc "Create a gemspec file"
52
+ task :gemspec do
53
+ File.open("#{GEM_NAME}.gemspec", "w") do |file|
54
+ file.puts spec.to_ruby
55
+ end
56
+ end
57
+
58
+ desc "Run all specs"
59
+ Spec::Rake::SpecTask.new("specs") do |t|
60
+ t.spec_opts = ["--format", "specdoc", "--colour"]
61
+ t.spec_files = Dir["spec/**/*_spec.rb"].sort
62
+ t.rcov = false
63
+ t.rcov_opts << '--sort' << 'coverage' << '--sort-reverse'
64
+ t.rcov_opts << '--only-uncovered'
65
+ end
data/TODO ADDED
File without changes
@@ -0,0 +1,24 @@
1
+ # make sure we're running inside Merb
2
+ if defined?(Merb::Plugins)
3
+ # Merb gives you a Merb::Plugins.config hash...feel free to put your stuff in your piece of it
4
+ Merb::Plugins.config[:"merb-auth_more"] = {
5
+ :chickens => false
6
+ }
7
+
8
+ # Register the strategies so that plugins and apps may utilize them
9
+ basic_path = File.expand_path(File.dirname(__FILE__)) / "merb-auth-more" / "strategies" / "basic"
10
+
11
+ Merb::Authentication.register(:default_basic_auth, basic_path / "basic_auth.rb")
12
+ Merb::Authentication.register(:default_openid, basic_path / "openid.rb")
13
+ Merb::Authentication.register(:default_password_form, basic_path / "password_form.rb")
14
+
15
+ Merb::BootLoader.before_app_loads do
16
+ # require code that must be loaded before the application
17
+ end
18
+
19
+ Merb::BootLoader.after_app_loads do
20
+ # code that can be required after the application loads
21
+ end
22
+
23
+ Merb::Plugins.add_rakefiles "merb-auth-more/merbtasks"
24
+ end
@@ -0,0 +1,6 @@
1
+ namespace :"merb-auth_more" do
2
+ desc "Do something for merb-auth-more"
3
+ task :default do
4
+ puts "merb-auth-more doesn't do anything"
5
+ end
6
+ end
@@ -0,0 +1,59 @@
1
+ # Impelments redirect_back_or. i.e. remembers where you've come from on a failed login
2
+ # and stores this inforamtion in the session. When you're finally logged in you can use
3
+ # the redirect_back_or helper to redirect them either back where they came from, or a pre-defined url.
4
+ #
5
+ # Here's some examples:
6
+ #
7
+ # 1. User visits login form and is logged in
8
+ # - redirect to the provided (default) url
9
+ #
10
+ # 2. User vists a page (/page) and gets kicked to login (raised Unauthenticated)
11
+ # - On successful login, the user may be redirect_back_or("/home") and they will
12
+ # return to the /page url. The /home url is ignored
13
+ #
14
+ #
15
+
16
+ #
17
+ module Merb::AuthenticatedHelper
18
+
19
+ # Add a helper to do the redirect_back_or for you. Also tidies up the session afterwards
20
+ # If there has been a failed login attempt on some page using this method
21
+ # you'll be redirected back to that page. Otherwise redirect to the default_url
22
+ #
23
+ # To make sure you're not redirected back to the login page after a failed then successful login,
24
+ # you can include an ignore url. Basically, if the return url == the ignore url go to the default_url
25
+ #
26
+ # set the ignore url via an :ignore option in the opts hash.
27
+ def redirect_back_or(default_url, opts = {})
28
+ if session.authentication.return_to_url && ![opts[:ignore]].flatten.include?(session.authentication.return_to_url)
29
+ redirect session.authentication.return_to_url, opts
30
+ else
31
+ redirect default_url, opts
32
+ end
33
+ session.authentication.return_to_url = nil
34
+ end
35
+
36
+ end
37
+
38
+
39
+ class Application < Merb::Controller; end
40
+
41
+ class Exceptions < Application
42
+ after :_set_return_to, :only => :unauthenticated
43
+
44
+ private
45
+ def _set_return_to
46
+ session.authentication.return_to_url ||= request.uri unless request.exceptions.blank?
47
+ end
48
+ end
49
+
50
+ class Merb::Authentication
51
+
52
+ def return_to_url
53
+ @return_to_url ||= session[:return_to]
54
+ end
55
+
56
+ def return_to_url=(return_url)
57
+ @return_to_url = session[:return_to] = return_url
58
+ end
59
+ end
@@ -0,0 +1,73 @@
1
+ require "digest/sha1"
2
+ class Merb::Authentication
3
+ module Mixins
4
+ # This mixin provides basic salted user password encryption.
5
+ #
6
+ # Added properties:
7
+ # :crypted_password, String
8
+ # :salt, String
9
+ #
10
+ # To use it simply require it and include it into your user class.
11
+ #
12
+ # class User
13
+ # include Merb::Authentication::Mixins::SaltedUser
14
+ #
15
+ # end
16
+ #
17
+ module SaltedUser
18
+
19
+ def self.included(base)
20
+ base.class_eval do
21
+ attr_accessor :password, :password_confirmation
22
+
23
+ include Merb::Authentication::Mixins::SaltedUser::InstanceMethods
24
+ extend Merb::Authentication::Mixins::SaltedUser::ClassMethods
25
+
26
+ path = File.expand_path(File.dirname(__FILE__)) / "salted_user"
27
+ if defined?(DataMapper) && DataMapper::Resource > self
28
+ require path / "dm_salted_user"
29
+ extend(Merb::Authentication::Mixins::SaltedUser::DMClassMethods)
30
+ elsif defined?(ActiveRecord) && ancestors.include?(ActiveRecord::Base)
31
+ require path / "ar_salted_user"
32
+ extend(Merb::Authentication::Mixins::SaltedUser::ARClassMethods)
33
+ elsif defined?(Sequel) && ancestors.include?(Sequel::Model)
34
+ require path / "sq_salted_user"
35
+ extend(Merb::Authentication::Mixins::SaltedUser::SQClassMethods)
36
+ end
37
+
38
+ end # base.class_eval
39
+ end # self.included
40
+
41
+
42
+ module ClassMethods
43
+ # Encrypts some data with the salt.
44
+ def encrypt(password, salt)
45
+ Digest::SHA1.hexdigest("--#{salt}--#{password}--")
46
+ end
47
+ end
48
+
49
+ module InstanceMethods
50
+ def authenticated?(password)
51
+ crypted_password == encrypt(password)
52
+ end
53
+
54
+ def encrypt(password)
55
+ self.class.encrypt(password, salt)
56
+ end
57
+
58
+ def password_required?
59
+ crypted_password.blank? || !password.blank?
60
+ end
61
+
62
+ def encrypt_password
63
+ return if password.blank?
64
+ self.salt = Digest::SHA1.hexdigest("--#{Time.now.to_s}--#{Merb::Authentication::Strategies::Basic::Base.login_param}--") if new_record?
65
+ self.crypted_password = encrypt(password)
66
+ end
67
+
68
+ end # InstanceMethods
69
+
70
+ end # SaltedUser
71
+ end # Mixins
72
+ end # Merb::Authentication
73
+
@@ -0,0 +1,25 @@
1
+ class Merb::Authentication
2
+ module Mixins
3
+ module SaltedUser
4
+ module ARClassMethods
5
+
6
+ def self.extended(base)
7
+ base.class_eval do
8
+
9
+ validates_presence_of :password, :if => :password_required?
10
+ validates_presence_of :password_confirmation, :if => :password_required?
11
+ validates_confirmation_of :password, :if => :password_required?
12
+
13
+ before_save :encrypt_password
14
+ end # base.class_eval
15
+
16
+ end # self.extended
17
+
18
+ def authenticate(login, password)
19
+ @u = find(:first, :conditions => ["#{Merb::Authentication::Strategies::Basic::Base.login_param} = ?", login])
20
+ @u && @u.authenticated?(password) ? @u : nil
21
+ end
22
+ end # ARClassMethods
23
+ end # SaltedUser
24
+ end # Mixins
25
+ end # Merb::Authentication
@@ -0,0 +1,26 @@
1
+ class Merb::Authentication
2
+ module Mixins
3
+ module SaltedUser
4
+ module DMClassMethods
5
+ def self.extended(base)
6
+ base.class_eval do
7
+
8
+ property :crypted_password, String
9
+ property :salt, String
10
+
11
+ validates_present :password, :if => proc{|m| m.password_required?}
12
+ validates_is_confirmed :password, :if => proc{|m| m.password_required?}
13
+
14
+ before :save, :encrypt_password
15
+ end # base.class_eval
16
+
17
+ end # self.extended
18
+
19
+ def authenticate(login, password)
20
+ @u = first(Merb::Authentication::Strategies::Basic::Base.login_param => login)
21
+ @u && @u.authenticated?(password) ? @u : nil
22
+ end
23
+ end # DMClassMethods
24
+ end # SaltedUser
25
+ end # Mixins
26
+ end # Merb::Authentication
@@ -0,0 +1,35 @@
1
+ class Merb::Authentication
2
+ module Mixins
3
+ module SaltedUser
4
+ module SQClassMethods
5
+
6
+ def self.extended(base)
7
+ base.class_eval do
8
+
9
+ validates_presence_of :password, :if => :password_required?
10
+ validates_presence_of :password_confirmation, :if => :password_required?
11
+ validates_confirmation_of :password, :if => :password_required?
12
+
13
+ before_save :encrypt_password
14
+
15
+ include Merb::Authentication::Mixins::SaltedUser::SQInstanceMethods
16
+
17
+ end # base.class_eval
18
+
19
+ end # self.extended
20
+
21
+ def authenticate(login, password)
22
+ @u = find(Merb::Authentication::Strategies::Basic::Base.login_param => login)
23
+ @u && @u.authenticated?(password) ? @u : nil
24
+ end
25
+ end # SQClassMethods
26
+
27
+ module SQInstanceMethods
28
+ def new_record?
29
+ new?
30
+ end
31
+ end
32
+
33
+ end # SaltedUser
34
+ end # Mixins
35
+ end # Merb::Authentication
@@ -0,0 +1,31 @@
1
+ class Merb::Authentication
2
+ module Strategies
3
+ # To use the password strategies, it is expected that you will provide
4
+ # an @authenticate@ method on your user class. This should take two parameters
5
+ # login, and password. It should return nil or the user object.
6
+ module Basic
7
+
8
+ class Base < Merb::Authentication::Strategy
9
+ abstract!
10
+
11
+ # Overwrite this method to customize the field
12
+ def self.password_param
13
+ (Merb::Plugins.config[:"merb-auth"][:password_param] || :password).to_s.to_sym
14
+ end
15
+
16
+ # Overwrite this method to customize the field
17
+ def self.login_param
18
+ (Merb::Plugins.config[:"merb-auth"][:login_param] || :login).to_s.to_sym
19
+ end
20
+
21
+ def password_param
22
+ @password_param ||= Base.password_param
23
+ end
24
+
25
+ def login_param
26
+ @login_param ||= Base.login_param
27
+ end
28
+ end # Base
29
+ end # Password
30
+ end # Strategies
31
+ end # Merb::Authentication
@@ -0,0 +1,76 @@
1
+ require 'merb-auth-more/strategies/abstract_password'
2
+ # This strategy is used with basic authentication in Merb.
3
+ #
4
+ # == Requirements
5
+ #
6
+ # == Methods
7
+ # <User>.authenticate(login_field, password_field)
8
+ #
9
+ class Merb::Authentication
10
+ module Strategies
11
+ module Basic
12
+ class BasicAuth < Base
13
+
14
+ def run!
15
+ if basic_authentication?
16
+ basic_authentication do |login, password|
17
+ user = user_class.authenticate(login, password)
18
+ unless user
19
+ request_basic_auth!
20
+ end
21
+ user
22
+ end
23
+ end
24
+ end
25
+
26
+ def self.realm
27
+ @realm ||= "Application"
28
+ end
29
+
30
+ cattr_writer :realm
31
+ def realm
32
+ @realm ||= self.class.realm
33
+ end
34
+
35
+ cattr_accessor :failure_message
36
+ @@failure_message = "Login Required"
37
+
38
+ private
39
+ def initialize(request, params)
40
+ super
41
+ @auth = Rack::Auth::Basic::Request.new(request.env)
42
+ end
43
+
44
+ def basic_authentication?
45
+ @auth.provided? and @auth.basic?
46
+ end
47
+
48
+ def username
49
+ basic_authentication? ? @auth.credentials.first : nil
50
+ end
51
+
52
+ def password
53
+ basic_authentication? ? @auth.credentials.last : nil
54
+ end
55
+
56
+ def request_basic_auth!
57
+ self.status = Merb::Controller::Unauthorized.status
58
+ self.headers['WWW-Authenticate'] = 'Basic realm="%s"' % realm
59
+ self.body = self.class.failure_message
60
+ halt!
61
+ end
62
+
63
+ def basic_authentication(realm = nil, &authenticator)
64
+ self.realm = realm if realm
65
+ if basic_authentication?
66
+ authenticator.call(*@auth.credentials)
67
+ else
68
+ false
69
+ end
70
+ end
71
+
72
+
73
+ end # BasicAuth
74
+ end # Password
75
+ end # Strategies
76
+ end # Merb::Authentication
@@ -0,0 +1,129 @@
1
+ # The openid strategy attempts to login users based on the OpenID protocol
2
+ # http://openid.net/
3
+ #
4
+ # Overwrite the on_sucess!, on_failure!, on_setup_needed!, and on_cancel! to customize events.
5
+ #
6
+ # Overwite the required_reg_fields method to require different sreg fields. Default is email and nickname
7
+ #
8
+ # Overwrite the openid_store method to customize your session store
9
+ #
10
+ # == Requirments
11
+ #
12
+ # === Routes:
13
+ # :openid - an action that is accessilbe via http GET and protected via ensure_authenticated
14
+ # :signup - a url accessed via GET that takes a user to a signup form (overwritable)
15
+ #
16
+ # === Attributes
17
+ # :identity_url - A string for holding the identity_url associated with this user (overwritable)
18
+ #
19
+ # install the ruby-openid gem
20
+ require 'openid'
21
+ require 'openid/store/filesystem'
22
+ require 'openid/extensions/sreg'
23
+
24
+ class Merb::Authentication
25
+ module Strategies
26
+ module Basic
27
+ class OpenID < Base
28
+ def run!
29
+ if request.params[:'openid.mode']
30
+ response = consumer.complete(request.send(:query_params), "#{request.protocol}://#{request.host}" + request.path)
31
+ case response.status.to_s
32
+ when 'success'
33
+ sreg_response = ::OpenID::SReg::Response.from_success_response(response)
34
+ result = on_success!(response, sreg_response)
35
+ Merb.logger.info "\n\n#{result.inspect}\n\n"
36
+ result
37
+ when 'failure'
38
+ on_failure!(response)
39
+ when 'setup_needed'
40
+ on_setup_needed!(response)
41
+ when 'cancel'
42
+ on_cancel!(response)
43
+ end
44
+ elsif identity_url = params[:openid_url]
45
+ begin
46
+ openid_request = consumer.begin(identity_url)
47
+ openid_reg = ::OpenID::SReg::Request.new
48
+ openid_reg.request_fields(required_reg_fields)
49
+ openid_request.add_extension(openid_reg)
50
+ redirect_to = "#{request.protocol}://#{request.host}#{Merb::Router.url(:openid)}"
51
+ redirect!(openid_request.redirect_url("#{request.protocol}://#{request.host}", redirect_to))
52
+ rescue ::OpenID::OpenIDError => e
53
+ request.session.authentication.errors.clear!
54
+ request.session.authentication.errors.add(:openid, 'The OpenID verification failed')
55
+ nil
56
+ end
57
+ end
58
+ end # run!
59
+
60
+
61
+ # Overwrite the on_success! method with the required behavior for successful logins
62
+ #
63
+ # @api overwritable
64
+ def on_success!(response, sreg_response)
65
+ if user = find_user_by_identity_url(response.identity_url)
66
+ user
67
+ else
68
+ request.session[:'openid.url'] = response.identity_url
69
+ required_reg_fields.each do |f|
70
+ session[:"openid.#{f}"] = sreg_response.data[f] if sreg_response.data[f]
71
+ end if sreg_response
72
+ redirect!(Merb::Router.url(:signup))
73
+ end
74
+ end
75
+
76
+ # Overwrite the on_failure! method with the required behavior for failed logins
77
+ #
78
+ # @api overwritable
79
+ def on_failure!(response)
80
+ session.authentication.errors.clear!
81
+ session.authentication.errors.add(:openid, 'OpenID verification failed, maybe the provider is down? Or the session timed out')
82
+ nil
83
+ end
84
+
85
+ #
86
+ # @api overwritable
87
+ def on_setup_needed!(response)
88
+ request.session.authentication.errors.clear!
89
+ request.session.authentication.errors.add(:openid, 'OpenID does not seem to be configured correctly')
90
+ nil
91
+ end
92
+
93
+ #
94
+ # @api overwritable
95
+ def on_cancel!(response)
96
+ request.session.authentication.errors.clear!
97
+ request.session.authentication.errors.add(:openid, 'OpenID rejected our request')
98
+ nil
99
+ end
100
+
101
+ #
102
+ # @api overwritable
103
+ def required_reg_fields
104
+ ['nickname', 'email']
105
+ end
106
+
107
+ # Overwrite this to support an ORM other than DataMapper
108
+ #
109
+ # @api overwritable
110
+ def find_user_by_identity_url(url)
111
+ user_class.first(:identity_url => url)
112
+ end
113
+
114
+ # Overwrite this method to set your store
115
+ #
116
+ # @api overwritable
117
+ def openid_store
118
+ ::OpenID::Store::Filesystem.new("#{Merb.root}/tmp/openid")
119
+ end
120
+
121
+ private
122
+ def consumer
123
+ @consumer ||= ::OpenID::Consumer.new(request.session, openid_store)
124
+ end
125
+
126
+ end # OpenID
127
+ end # Basic
128
+ end # Strategies
129
+ end # Merb::Authentication
@@ -0,0 +1,32 @@
1
+ require 'merb-auth-more/strategies/abstract_password'
2
+ # This strategy uses a login and password parameter.
3
+ #
4
+ # Overwrite the :password_param, and :login_param
5
+ # to return the name of the field (on the form) that you're using the
6
+ # login with. These can be strings or symbols
7
+ #
8
+ # == Required
9
+ #
10
+ # === Methods
11
+ # <User>.authenticate(login_param, password_param)
12
+ #
13
+ class Merb::Authentication
14
+ module Strategies
15
+ module Basic
16
+ class Form < Base
17
+
18
+ def run!
19
+ if request.params[login_param] && request.params[password_param]
20
+ user = user_class.authenticate(request.params[login_param], request.params[password_param])
21
+ if !user
22
+ request.session.authentication.errors.clear!
23
+ request.session.authentication.errors.add(login_param, "#{login_param.to_s.capitalize} or #{password_param.to_s.capitalize} were incorrect")
24
+ end
25
+ user
26
+ end
27
+ end # run!
28
+
29
+ end # Form
30
+ end # Password
31
+ end # Strategies
32
+ end # Authentication
@@ -0,0 +1,4 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+
3
+ describe "merb-auth-more" do
4
+ end
@@ -0,0 +1,84 @@
1
+ require File.join(File.dirname(__FILE__), "..", 'spec_helper.rb')
2
+ require File.join(File.expand_path(File.dirname(__FILE__)), "..", ".." ,"lib", "merb-auth-more", "mixins", "redirect_back")
3
+
4
+ describe "redirect_back" do
5
+
6
+ before(:all) do
7
+ clear_strategies!
8
+
9
+ class Merb::Authentication
10
+ def store_user(user); user; end
11
+ def fetch_user(session_info); session_info; end
12
+ end
13
+
14
+ class MyStrategy < Merb::Authentication::Strategy; def run!; request.env["USER"]; end; end
15
+
16
+ class Application < Merb::Controller; end
17
+
18
+ class Exceptions < Application
19
+ def unauthenticated; end
20
+ end
21
+
22
+ class MyController < Application
23
+ before :ensure_authenticated
24
+
25
+ def index; "HERE!" end
26
+
27
+ end
28
+ end
29
+
30
+ it "should set the return_to in the session when sent to the exceptions controller from a failed login" do
31
+ controller = dispatch_to(Exceptions, :unauthenticated, {}, {:user => "winna", :request_uri => "go_back"}) do |c|
32
+ c.request.exceptions = [Merb::Controller::Unauthenticated.new]
33
+ end
34
+ controller.session.authentication.return_to_url.should == "go_back"
35
+ end
36
+
37
+ it "should not set the return_to in the session when deliberately going to unauthenticated" do
38
+ controller = dispatch_to(Exceptions, :unauthenticated, {}, {:user => "winna", :request_uri => "don't_go_back"}) do |c|
39
+ c.request.exceptions = []
40
+ end
41
+ controller.session.authentication.return_to_url.should be_nil
42
+ end
43
+
44
+ it "should not set the return_to when loggin into a controller directly" do
45
+ controller = dispatch_to(MyController, :index, {}, :user => "winna", :request_uri => "NOOO")
46
+ controller.session.authentication.return_to_url.should be_nil
47
+ end
48
+
49
+ describe "redirect_back helper" do
50
+
51
+ before(:each) do
52
+ @with_redirect = dispatch_to(Exceptions, :unauthenticated, {}, :user => "WINNA", :request_uri => "request_uri") do |c|
53
+ c.request.exceptions = [Merb::Controller::Unauthenticated.new]
54
+ end
55
+ @no_redirect = dispatch_to(MyController, :index, {}, :user => "winna", :request_uri => "NOOO")
56
+ end
57
+
58
+ it "should provide the url stored in the session" do
59
+ @with_redirect.session.authentication.return_to_url.should == "request_uri"
60
+ @with_redirect.redirect_back_or("/some/path")
61
+ @with_redirect.headers["Location"].should == "request_uri"
62
+ end
63
+
64
+ it "should provide the url passed in by default when there is no return_to" do
65
+ @no_redirect.session.authentication.return_to_url.should be_nil
66
+ @no_redirect.redirect_back_or("/some/path")
67
+ @no_redirect.headers["Location"].should == "/some/path"
68
+ end
69
+
70
+ it "should wipe out the return_to in the session after the redirect" do
71
+ @with_redirect.session.authentication.return_to_url.should == "request_uri"
72
+ @with_redirect.redirect_back_or("somewhere")
73
+ @with_redirect.headers["Location"].should == "request_uri"
74
+ @with_redirect.session.authentication.return_to_url.should be_nil
75
+ end
76
+
77
+ it "should ignore a return_to if it's the same as the ignore url" do
78
+ @with_redirect.redirect_back_or("somewhere", :ignore => "request_uri")
79
+ @with_redirect.headers["Location"].should == "somewhere"
80
+ end
81
+
82
+ end
83
+
84
+ end
@@ -0,0 +1,105 @@
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
@@ -0,0 +1,34 @@
1
+ $TESTING=true
2
+ $:.push File.join(File.dirname(__FILE__), '..', 'lib')
3
+
4
+ require 'rubygems'
5
+ require 'merb-core'
6
+ require 'merb-core/test'
7
+ require 'merb-core/dispatch/session'
8
+ require 'spec' # Satisfies Autotest and anyone else not using the Rake tasks
9
+ require 'merb-auth-core'
10
+
11
+ Merb.start :environment => "test",
12
+ :adapter => "runner",
13
+ :session_store => "cookie",
14
+ :session_secret_key => "d3a6e6f99a25004da82b71af8b9ed0ab71d3ea21"
15
+
16
+ module StrategyHelper
17
+ def clear_strategies!
18
+ Merb::Authentication.strategies.each do |s|
19
+ begin
20
+ Object.class_eval{ remove_const(s.name) if defined?(s)}
21
+ rescue
22
+ end
23
+ end
24
+ Merb::Authentication.strategies.clear
25
+ Merb::Authentication.default_strategy_order.clear
26
+ end
27
+ end
28
+
29
+ Spec::Runner.configure do |config|
30
+ config.include(Merb::Test::ViewHelper)
31
+ config.include(Merb::Test::RouteHelper)
32
+ config.include(Merb::Test::ControllerHelper)
33
+ config.include(StrategyHelper)
34
+ end
metadata ADDED
@@ -0,0 +1,88 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: merb-auth-more
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.9.9
5
+ platform: ruby
6
+ authors:
7
+ - Daniel Neighman
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2008-10-13 00:00:00 -07:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: merb-auth-core
17
+ type: :runtime
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - "="
22
+ - !ruby/object:Gem::Version
23
+ version: 0.9.9
24
+ version:
25
+ description: Additional resources for use with the merb-auth-core authentication framework.
26
+ email: has.sox@gmail.com
27
+ executables: []
28
+
29
+ extensions: []
30
+
31
+ extra_rdoc_files:
32
+ - README.textile
33
+ - LICENSE
34
+ - TODO
35
+ files:
36
+ - LICENSE
37
+ - README.textile
38
+ - Rakefile
39
+ - TODO
40
+ - lib/merb-auth-more
41
+ - lib/merb-auth-more/merbtasks.rb
42
+ - lib/merb-auth-more/mixins
43
+ - lib/merb-auth-more/mixins/redirect_back.rb
44
+ - lib/merb-auth-more/mixins/salted_user
45
+ - lib/merb-auth-more/mixins/salted_user/ar_salted_user.rb
46
+ - lib/merb-auth-more/mixins/salted_user/dm_salted_user.rb
47
+ - lib/merb-auth-more/mixins/salted_user/sq_salted_user.rb
48
+ - lib/merb-auth-more/mixins/salted_user.rb
49
+ - lib/merb-auth-more/strategies
50
+ - lib/merb-auth-more/strategies/abstract_password.rb
51
+ - lib/merb-auth-more/strategies/basic
52
+ - lib/merb-auth-more/strategies/basic/basic_auth.rb
53
+ - lib/merb-auth-more/strategies/basic/openid.rb
54
+ - lib/merb-auth-more/strategies/basic/password_form.rb
55
+ - lib/merb-auth-more.rb
56
+ - spec/merb-auth-more_spec.rb
57
+ - spec/mixins
58
+ - spec/mixins/redirect_back_spec.rb
59
+ - spec/mixins/salted_user_spec.rb
60
+ - spec/spec_helper.rb
61
+ has_rdoc: true
62
+ homepage: http://merbivore.com/
63
+ post_install_message:
64
+ rdoc_options: []
65
+
66
+ require_paths:
67
+ - lib
68
+ required_ruby_version: !ruby/object:Gem::Requirement
69
+ requirements:
70
+ - - ">="
71
+ - !ruby/object:Gem::Version
72
+ version: "0"
73
+ version:
74
+ required_rubygems_version: !ruby/object:Gem::Requirement
75
+ requirements:
76
+ - - ">="
77
+ - !ruby/object:Gem::Version
78
+ version: "0"
79
+ version:
80
+ requirements: []
81
+
82
+ rubyforge_project: merb
83
+ rubygems_version: 1.2.0
84
+ signing_key:
85
+ specification_version: 2
86
+ summary: Additional resources for use with the merb-auth-core authentication framework.
87
+ test_files: []
88
+