scottmotte-merb-auth-remember-me 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2008 Surasit Liangpornrattana
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.
data/README ADDED
@@ -0,0 +1,43 @@
1
+ ### MerbAuthRememberMe
2
+
3
+ This plugin provides a remember me strategy for Merb Auth. The original plugin was built by Pun Neng (http://github.com/PunNeng/).
4
+
5
+ The plugin also provides some Merb::Authentication.user_class mixins to keep the models fat and the strategy code thin. The mixins are added to the user class by default. If you choose not to include these and would rather roll your own set the plugin configuration in your config/init.rb file like so:
6
+ <pre><code>
7
+ Merb::Plugins.config[:merb_auth_remember_me][:include_model_methods] = false
8
+ </code></pre>
9
+
10
+ This plugin automatically registers and activates the remember_me strategy with Merb Auth, so no additional configuration is necessary.
11
+
12
+ ### Migration Requirements
13
+
14
+ The plugin requires some fields your user authentication model. Right now there is ORM specific inclusions for Datamapper. The Sequel one needs to be built and a migration needs to be made for ActiveRecord. No migration generators are included but the plugin requires the following fields
15
+ <pre><code>
16
+ DateTime :remember_token_expires_at
17
+ String :remember_token
18
+ </code></pre>
19
+
20
+ ------------------------------------------------------------------------------
21
+
22
+ ### Instructions for installation:
23
+
24
+ # Add the plugin as a regular dependency in your dependency.rb file
25
+
26
+ dependency 'rughetto-merb-auth-remember-me', :require_as => 'merb-auth-remember-me'
27
+
28
+ # To clear the :auth\_token after log out
29
+
30
+ Unpack the merb-auth-password application code if it hasn't been done already:
31
+ <pre><code>
32
+ bin/rake slices:merb-auth-slice-password:freeze
33
+ </code></pre>
34
+
35
+ Change the #destroy method in slices/merb-auth-slice-password/app/controllers/session_override.rb to include
36
+ <pre><code>
37
+ cookies.delete :auth_token
38
+ </code></pre>
39
+
40
+ # Add the right form inputs into your unauthenticated.html.erb (login) page
41
+
42
+ <input type="checkbox" id="remember_me" name="remember_me" value="1">
43
+
data/Rakefile ADDED
@@ -0,0 +1,57 @@
1
+ require 'rubygems'
2
+ require 'rake/gempackagetask'
3
+ require 'spec/rake/spectask'
4
+
5
+ require 'merb-core'
6
+ require 'merb-core/tasks/merb'
7
+
8
+ GEM_NAME = "merb-auth-remember-me"
9
+ GEM_VERSION = "0.0.2"
10
+ AUTHOR = "Surasit Liangpornrattana"
11
+ EMAIL = "punneng@gmail.com"
12
+ HOMEPAGE = "https://github.com/PunNeng/pn-merb-auth-remember-me"
13
+ SUMMARY = "Merb plugin that provides remember me for merb-auth-slice-password"
14
+
15
+ spec = Gem::Specification.new do |s|
16
+ s.rubyforge_project = 'merb'
17
+ s.name = GEM_NAME
18
+ s.version = GEM_VERSION
19
+ s.platform = Gem::Platform::RUBY
20
+ s.has_rdoc = true
21
+ s.extra_rdoc_files = ["README", "LICENSE", 'TODO']
22
+ s.summary = SUMMARY
23
+ s.description = s.summary
24
+ s.author = AUTHOR
25
+ s.email = EMAIL
26
+ s.homepage = HOMEPAGE
27
+ s.add_dependency('merb-core', '>= 1.0')
28
+ s.require_path = 'lib'
29
+ s.files = %w(LICENSE README Rakefile TODO) + Dir.glob("{lib,spec}/**/*")
30
+ end
31
+
32
+ Rake::GemPackageTask.new(spec) do |pkg|
33
+ pkg.gem_spec = spec
34
+ end
35
+
36
+ desc "install the plugin as a gem"
37
+ task :install do
38
+ Merb::RakeHelper.install(GEM_NAME, :version => GEM_VERSION)
39
+ end
40
+
41
+ desc "Uninstall the gem"
42
+ task :uninstall do
43
+ Merb::RakeHelper.uninstall(GEM_NAME, :version => GEM_VERSION)
44
+ end
45
+
46
+ desc "Create a gemspec file"
47
+ task :gemspec do
48
+ File.open("#{GEM_NAME}.gemspec", "w") do |file|
49
+ file.puts spec.to_ruby
50
+ end
51
+ end
52
+
53
+ Spec::Rake::SpecTask.new do |t|
54
+ t.warning = true
55
+ t.spec_opts = ["--format", "specdoc", "--colour"]
56
+ t.spec_files = Dir['spec/**/*_spec.rb'].sort
57
+ end
data/TODO ADDED
@@ -0,0 +1,2 @@
1
+ TODO:
2
+ make token refresh with each request ??
@@ -0,0 +1,35 @@
1
+ if defined?(Merb::Plugins)
2
+ $:.unshift File.dirname(__FILE__)
3
+
4
+ # register the authentication strategy
5
+ require(File.expand_path(File.dirname(__FILE__) / "merb-auth-remember-me" / "mixins") / "authenticated_user")
6
+ strategy_path = File.expand_path(File.dirname(__FILE__)) / "merb-auth-remember-me" / "strategies"
7
+ Merb.logger.info('Registering and activating RememberMe strategy')
8
+ Merb::Authentication.register(:remember_me, strategy_path / "remember_me.rb")
9
+ Merb::Authentication.activate!(:remember_me) # and activate it
10
+
11
+ # Plugin configurations
12
+ Merb::Plugins.config[:merb_auth_remember_me] = {:include_model_methods => true }
13
+
14
+ Merb::BootLoader.after_app_loads do
15
+ Merb::Authentication.after_authentication do |user,request,params|
16
+ if params[:remember_me] == "1"
17
+ user.remember_me
18
+ request.cookies.set_cookie(
19
+ :auth_token,
20
+ user.remember_token,
21
+ :expires => user.remember_token_expires_at.to_time
22
+ )
23
+ end
24
+ user
25
+ end # Merb::Authentication.after_authentication
26
+
27
+ Merb::Authentication.user_class.class_eval do
28
+ if Merb::Plugins.config[:merb_auth_remember_me][:include_model_methods]
29
+ Merb.logger.info("Including RememberMe Mixin in #{Merb::Authentication.user_class}.
30
+ To avoid this inclusion add 'Merb::Plugins.config[:merb_auth_remember_me][:include_model_methods] = false' in your config/init.rb before_app_loads method")
31
+ include Merb::Authentication::Mixins::AuthenticatedUser
32
+ end
33
+ end # Merb::Authentication.user_class.class_eval
34
+ end # Merb::BootLoader.after_app_loads
35
+ end # if defined?(Merb::Plugins)
@@ -0,0 +1,100 @@
1
+ require "digest/sha1"
2
+ module Merb
3
+ class Authentication
4
+ module Mixins
5
+ # This mixin provides basic user remember token.
6
+ #
7
+ # Added properties:
8
+ # :remember_token_expires_at, DateTime
9
+ # :remember_token, 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::AuthenticatedUser
15
+ #
16
+ # end
17
+ #
18
+ module AuthenticatedUser
19
+ def self.included(base)
20
+ base.class_eval do
21
+ include Merb::Authentication::Mixins::AuthenticatedUser::InstanceMethods
22
+ extend Merb::Authentication::Mixins::AuthenticatedUser::ClassMethods
23
+
24
+ path = File.expand_path(File.dirname(__FILE__)) / "authenticated_user"
25
+ if defined?(DataMapper) && DataMapper::Resource > self
26
+ require path / "dm_authenticated_user"
27
+ extend(Merb::Authentication::Mixins::AuthenticatedUser::DMClassMethods)
28
+ elsif defined?(ActiveRecord) && ancestors.include?(ActiveRecord::Base)
29
+ require path / "ar_authenticated_user"
30
+ extend(Merb::Authentication::Mixins::AuthenticatedUser::ARClassMethods)
31
+ elsif defined?(Sequel) && ancestors.include?(Sequel::Model)
32
+ require path / "sq_authenticated_user"
33
+ extend(Merb::Authentication::Mixins::AuthenticatedUser::SQClassMethods)
34
+ elsif MongoMapper::Document > self
35
+ require path / "mm_authenticated_user"
36
+ extend(Merb::Authentication::Mixins::AuthenticatedUser::MMClassMethods)
37
+ end
38
+
39
+ end # base.class_eval
40
+ end # self.included
41
+
42
+
43
+ module ClassMethods
44
+ def secure_digest(*args)
45
+ Digest::SHA1.hexdigest(args.flatten.join('--'))
46
+ end
47
+
48
+ # Create random key.
49
+ #
50
+ # ==== Returns
51
+ # String:: The generated key
52
+ def make_token
53
+ secure_digest(Time.now, (1..10).map{ rand.to_s })
54
+ end
55
+ end # ClassMethods
56
+
57
+ module InstanceMethods
58
+ def remember_token?
59
+ (!remember_token.blank?) &&
60
+ remember_token_expires_at && (Time.now.utc < remember_token_expires_at.utc)
61
+ end
62
+
63
+ # These create and unset the fields required for remembering users between browser closes
64
+ def remember_me(time = 2.weeks)
65
+ remember_me_for time
66
+ end
67
+
68
+ def remember_me_for(time)
69
+ remember_me_until time.from_now.utc
70
+ end
71
+
72
+ def remember_me_until(time)
73
+ self.remember_token_expires_at = time
74
+ self.remember_token = self.class.make_token
75
+ save
76
+ end
77
+
78
+ # refresh token (keeping same expires_at) if it exists
79
+ def refresh_token
80
+ if remember_token?
81
+ self.remember_token = self.class.make_token
82
+ save
83
+ end
84
+ end
85
+
86
+ #
87
+ # Deletes the server-side record of the authentication token. The
88
+ # client-side (browser cookie) and server-side (this remember_token) must
89
+ # always be deleted together.
90
+ #
91
+ def forget_me
92
+ self.remember_token_expires_at = nil
93
+ self.remember_token = nil
94
+ save
95
+ end
96
+ end # InstanceMethods
97
+ end # AuthenticatedUser
98
+ end # Mixins
99
+ end # Authentication
100
+ end # Merb
@@ -0,0 +1,14 @@
1
+ module Merb
2
+ class Authentication
3
+ module Mixins
4
+ module AuthenticatedUser
5
+ module ARClassMethods
6
+ def self.extended(base)
7
+
8
+
9
+ end # self.extended
10
+ end # ARClassMethods
11
+ end # ActivatedUser
12
+ end # Mixins
13
+ end # Authentication
14
+ end # Merb
@@ -0,0 +1,17 @@
1
+ module Merb
2
+ class Authentication
3
+ module Mixins
4
+ module AuthenticatedUser
5
+ module DMClassMethods
6
+ def self.extended(base)
7
+ base.class_eval do
8
+ property :remember_token_expires_at, DateTime
9
+ property :remember_token, String
10
+ end # base.class_eval
11
+
12
+ end # self.extended
13
+ end # DMClassMethods
14
+ end # AuthenticatedUser
15
+ end # Mixins
16
+ end # Authentication
17
+ end #Merb
@@ -0,0 +1,17 @@
1
+ module Merb
2
+ class Authentication
3
+ module Mixins
4
+ module AuthenticatedUser
5
+ module MMClassMethods
6
+ def self.extended(base)
7
+ base.class_eval do
8
+ key :remember_token_expires_at, Time
9
+ key :remember_token, String
10
+ end # base.class_eval
11
+
12
+ end # self.extended
13
+ end # MMClassMethods
14
+ end # AuthenticatedUser
15
+ end # Mixins
16
+ end # Authentication
17
+ end #Merb
@@ -0,0 +1,19 @@
1
+ module Merb
2
+ class Authentication
3
+ module Mixins
4
+ module AuthenticatedUser
5
+ module SQClassMethods
6
+ def self.extended(base)
7
+ base.class_eval do
8
+
9
+ end # base.class_eval
10
+
11
+ end # self.extended
12
+ end # SQClassMethods
13
+ module SQInstanceMethods
14
+ end # SQInstanceMethods
15
+
16
+ end # AuthenticatedUser
17
+ end # Mixins
18
+ end # Authentication
19
+ end # Merb
@@ -0,0 +1,12 @@
1
+ module Merb::Authentication::Strategies
2
+ class RememberMeStrategy < Merb::Authentication::Strategy
3
+ def run!
4
+ if cookies[:auth_token]
5
+ user = Merb::Authentication.user_class.first(
6
+ :conditions => [ "remember_token = ?", cookies[:auth_token] ]
7
+ )
8
+ end
9
+ user && user.remembered? ? user : nil
10
+ end # run!
11
+ end # RememberMeStrategy
12
+ end # Merb::Authentication::Strategies
@@ -0,0 +1,2 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+
@@ -0,0 +1,34 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper'
2
+
3
+ describe "Authenticated user" do
4
+
5
+ before :all do
6
+ @user = user.new
7
+ @user.remember_token_expires_at.should be_nil
8
+ @user.remember_token.should be_nil
9
+ end
10
+
11
+ it "should add the 'remember_token_expires_at' property to the user model" do
12
+ @user.should respond_to(:remember_token_expires_at)
13
+ @user.should respond_to(:remember_token_expires_at=)
14
+ end
15
+
16
+ it "should add the 'remember_token' property to the user model" do
17
+ @user.should respond_to(:remember_token)
18
+ @user.should respond_to(:remember_token=)
19
+ end
20
+
21
+ it "should save token and expires_at" do
22
+ @user.remember_me
23
+ @user.remember_token_expires_at.should_not be_nil
24
+ @user.remember_token.should_not be_nil
25
+ end
26
+
27
+ it "should save expires_at as 2 weeks later" do
28
+ @user.remember_me
29
+ @user.remember_token_expires_at.should eql((Time.now+2.weeks).to_datetime)
30
+ end
31
+
32
+ end
33
+
34
+
@@ -0,0 +1,101 @@
1
+ $:.push File.join(File.dirname(__FILE__), '..', 'lib')
2
+
3
+ require 'rubygems'
4
+ require 'activesupport'
5
+ require 'merb-core'
6
+ require 'dm-core'
7
+ require 'do_sqlite3'
8
+ require 'merb-auth-core'
9
+ require 'merb-auth-more'
10
+ require 'merb-auth-more/mixins/redirect_back'
11
+ require 'spec'
12
+ require 'merb-auth-remember-me'
13
+
14
+ Merb.start_environment(
15
+ :testing => true,
16
+ :adapter => 'runner',
17
+ :environment => ENV['MERB_ENV'] || 'test',
18
+ # :merb_root => Merb.root,
19
+ :session_store => :cookie,
20
+ :exception_details => true,
21
+ :session_secret_key => "d3a6d6f99a25004dd82b71af8bded0ab71d3ea21"
22
+
23
+ )
24
+
25
+ DataMapper.setup(:default, "sqlite3::memory:")
26
+
27
+ class User
28
+ include DataMapper::Resource
29
+ include Merb::Authentication::Mixins::AuthenticatedUser
30
+
31
+ property :id, Serial
32
+ property :email, String
33
+ property :login, String
34
+ end
35
+
36
+ Merb::Authentication.user_class = User
37
+ def user
38
+ Merb::Authentication.user_class
39
+ end
40
+
41
+
42
+ # for strategy
43
+ Merb::Config[:exception_details] = true
44
+ Merb::Router.reset!
45
+ Merb::Router.prepare do
46
+ match("/login", :method => :get).to(:controller => "exceptions", :action => "unauthenticated").name(:login)
47
+ match("/login", :method => :put).to(:controller => "sessions", :action => "update")
48
+
49
+ authenticate do
50
+ match("/").to(:controller => "my_controller")
51
+ end
52
+ match("/logout", :method => :delete).to(:controller => "sessions", :action => "destroy")
53
+ end
54
+
55
+ class Merb::Authentication
56
+ def store_user(user); user; end
57
+ def fetch_user(session_info); session_info; end
58
+ end
59
+
60
+ Merb::Authentication.activate!(:remember_me)
61
+ Merb::Authentication.activate!(:default_password_form)
62
+
63
+ class MockUserStrategy < Merb::Authentication::Strategy
64
+ def run!
65
+ params[:pass_auth] = if params[:pass_auth] == "false"
66
+ false
67
+ else
68
+ Merb::Authentication.user_class.first
69
+ end
70
+ params[:pass_auth]
71
+ end
72
+ end
73
+
74
+ class Application < Merb::Controller; end
75
+
76
+ class Sessions < Merb::Controller
77
+ before :ensure_authenticated
78
+ def update
79
+ redirect "/"
80
+ end
81
+
82
+ def destroy
83
+ cookies.delete :auth_token
84
+ session.abandon!
85
+ end
86
+ end
87
+
88
+ class MyController < Application
89
+ def index
90
+ "IN MY CONTROLLER"
91
+ end
92
+ end
93
+
94
+ Spec::Runner.configure do |config|
95
+ config.include(Merb::Test::ViewHelper)
96
+ config.include(Merb::Test::RouteHelper)
97
+ config.include(Merb::Test::ControllerHelper)
98
+ config.before(:all){ User.auto_migrate! }
99
+ config.after(:all){ User.all.destroy! }
100
+ end
101
+
@@ -0,0 +1,63 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper'
2
+
3
+ describe "Remember me strategy" do
4
+ def do_valid_login
5
+ put("/login", {:remember_me => "1", :pass_auth => true})
6
+ end
7
+
8
+ def do_valid_login_without_remember_me
9
+ put("/login", {:pass_auth => true})
10
+ end
11
+
12
+ def do_invalid_login
13
+ put("/login", { :pass_auth => false})
14
+ end
15
+
16
+ def do_home_with_auth_token
17
+ get("/", { :pass_auth => true} ) do |controller|
18
+ controller.request.cookies[:auth_token] = "auth_token_string"
19
+ end
20
+ end
21
+
22
+ before :each do
23
+ @user = mock(Merb::Authentication.user_class, :remember_me => true)
24
+ user.stub!(:first).and_return(@user)
25
+ @user.stub!(:remember_token?).and_return(true)
26
+ @user.stub!(:remember_token).and_return(Time.now + 1.week)
27
+ @user.stub!(:remember_token_expires_at).and_return(Time.now)
28
+ @user.stub!(:forget_me).and_return(true)
29
+ end
30
+
31
+ it "should save remember_token and remember_token_expires_at if remember_me == '1'" do
32
+ Merb::Authentication.user_class.should_receive(:first).and_return(@user)
33
+ @user.should_receive(:remember_me)
34
+ @user.remember_token.should_not be_nil
35
+ @user.remember_token_expires_at.should_not be_nil
36
+ do_valid_login.should redirect_to('/')
37
+ end
38
+
39
+ it "should not remember me unless remember_me == '1'" do
40
+ Merb::Authentication.user_class.should_receive(:first).and_return(true)
41
+ @user.should_not_receive(:remember_me)
42
+ do_valid_login_without_remember_me.should redirect_to('/')
43
+ end
44
+
45
+ it "should log in automatically if auth_token exists" do
46
+ Merb::Authentication.user_class.should_receive(:first).and_return(@user)
47
+ do_home_with_auth_token.should be_successful
48
+ end
49
+
50
+ it "should raise unauthenticated if auth_token doesn't exist" do
51
+ lambda do
52
+ do_invalid_login
53
+ end.should raise_error(Merb::Controller::Unauthenticated, "Could not log in")
54
+ end
55
+
56
+ it "should clear auth_token after loging out" do
57
+ delete('/logout') do |controller|
58
+ controller.cookies.should_receive(:delete).with(:auth_token)
59
+ end
60
+ end
61
+ end
62
+
63
+
metadata ADDED
@@ -0,0 +1,84 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: scottmotte-merb-auth-remember-me
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.2
5
+ platform: ruby
6
+ authors:
7
+ - Surasit Liangpornrattana
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-07-17 00:00:00 -07:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: merb-core
17
+ type: :runtime
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: "1.0"
24
+ version:
25
+ description: Merb plugin that provides remember me for merb-auth-slice-password
26
+ email: punneng@gmail.com
27
+ executables: []
28
+
29
+ extensions: []
30
+
31
+ extra_rdoc_files:
32
+ - README
33
+ - LICENSE
34
+ - TODO
35
+ files:
36
+ - LICENSE
37
+ - README
38
+ - Rakefile
39
+ - TODO
40
+ - lib/merb-auth-remember-me
41
+ - lib/merb-auth-remember-me/mixins
42
+ - lib/merb-auth-remember-me/mixins/authenticated_user
43
+ - lib/merb-auth-remember-me/mixins/authenticated_user/ar_authenticated_user.rb
44
+ - lib/merb-auth-remember-me/mixins/authenticated_user/dm_authenticated_user.rb
45
+ - lib/merb-auth-remember-me/mixins/authenticated_user/mm_authenticated_user.rb
46
+ - lib/merb-auth-remember-me/mixins/authenticated_user/sq_authenticated_user.rb
47
+ - lib/merb-auth-remember-me/mixins/authenticated_user.rb
48
+ - lib/merb-auth-remember-me/strategies
49
+ - lib/merb-auth-remember-me/strategies/remember_me.rb
50
+ - lib/merb-auth-remember-me.rb
51
+ - spec/merb-auth-remember-me_spec.rb
52
+ - spec/mixins
53
+ - spec/mixins/authenticated_user_spec.rb
54
+ - spec/spec_helper.rb
55
+ - spec/strategies
56
+ - spec/strategies/remember_me_spec.rb
57
+ has_rdoc: false
58
+ homepage: https://github.com/PunNeng/pn-merb-auth-remember-me
59
+ post_install_message:
60
+ rdoc_options: []
61
+
62
+ require_paths:
63
+ - lib
64
+ required_ruby_version: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: "0"
69
+ version:
70
+ required_rubygems_version: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - ">="
73
+ - !ruby/object:Gem::Version
74
+ version: "0"
75
+ version:
76
+ requirements: []
77
+
78
+ rubyforge_project: merb
79
+ rubygems_version: 1.2.0
80
+ signing_key:
81
+ specification_version: 3
82
+ summary: Merb plugin that provides remember me for merb-auth-slice-password
83
+ test_files: []
84
+