merb-auth-more 0.9.9

Sign up to get free protection for your applications and to get access to all the features.
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
+