rughetto-merb-auth-remember-me 0.0.1

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,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/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.1"
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,5 @@
1
+ TODO:
2
+ Fix LICENSE with your name
3
+ Fix Rakefile with your name and contact info
4
+ Add your code to lib/pn-remember-me.rb
5
+ Add your Merb rake tasks to lib/pn-remember-me/merbtasks.rb
@@ -0,0 +1,27 @@
1
+ # make sure we're running inside Merb
2
+ if defined?(Merb::Plugins)
3
+
4
+ $:.unshift File.dirname(__FILE__)
5
+
6
+ # register the authentication strategy
7
+ require(File.expand_path(File.dirname(__FILE__) / "merb-auth-remember-me" / "mixins") / "authenticated_user")
8
+ strategy_path = File.expand_path(File.dirname(__FILE__)) / "merb-auth-remember-me" / "strategies"
9
+ Merb::Authentication.register(:remember_me, strategy_path / "remember_me.rb")
10
+
11
+ # Plugin configurations
12
+ Merb::Plugins.config[:merb_auth_remember_me] = { }
13
+
14
+ Merb::BootLoader.before_app_loads do
15
+ end
16
+
17
+ Merb::BootLoader.after_app_loads do
18
+ Merb::Authentication.after_authentication do |user,request,params|
19
+ if params[:remember_me] == "1"
20
+ user.remember_me
21
+ request.cookies.set_cookie(:auth_token, user.remember_token, :expires => user.remember_token_expires_at.to_time)
22
+ end
23
+ true if user
24
+ end
25
+ end
26
+
27
+ end
@@ -0,0 +1,97 @@
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
+ end
35
+
36
+ end # base.class_eval
37
+ end # self.included
38
+
39
+
40
+ module ClassMethods
41
+ def secure_digest(*args)
42
+ Digest::SHA1.hexdigest(args.flatten.join('--'))
43
+ end
44
+
45
+ # Create random key.
46
+ #
47
+ # ==== Returns
48
+ # String:: The generated key
49
+ def make_token
50
+ secure_digest(Time.now, (1..10).map{ rand.to_s })
51
+ end
52
+ end # ClassMethods
53
+
54
+ module InstanceMethods
55
+ def remember_token?
56
+ (!remember_token.blank?) &&
57
+ remember_token_expires_at && (Time.now.utc < remember_token_expires_at.utc)
58
+ end
59
+
60
+ # These create and unset the fields required for remembering users between browser closes
61
+ def remember_me(time = 2.weeks)
62
+ remember_me_for time
63
+ end
64
+
65
+ def remember_me_for(time)
66
+ remember_me_until time.from_now.utc
67
+ end
68
+
69
+ def remember_me_until(time)
70
+ self.remember_token_expires_at = time
71
+ self.remember_token = self.class.make_token
72
+ save
73
+ end
74
+
75
+ # refresh token (keeping same expires_at) if it exists
76
+ def refresh_token
77
+ if remember_token?
78
+ self.remember_token = self.class.make_token
79
+ save
80
+ end
81
+ end
82
+
83
+ #
84
+ # Deletes the server-side record of the authentication token. The
85
+ # client-side (browser cookie) and server-side (this remember_token) must
86
+ # always be deleted together.
87
+ #
88
+ def forget_me
89
+ self.remember_token_expires_at = nil
90
+ self.remember_token = nil
91
+ save
92
+ end
93
+ end # InstanceMethods
94
+ end # AuthenticatedUser
95
+ end # Mixins
96
+ end # Authentication
97
+ 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,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,56 @@
1
+ class RememberMe < Merb::Authentication::Strategy
2
+ def run!
3
+ login_from_cookie
4
+ end
5
+
6
+ def current_user
7
+ @current_user
8
+ end
9
+
10
+ def current_user=(new_user)
11
+ @current_user = new_user
12
+ end
13
+
14
+ # Called from #current_user. Finaly, attempt to login by an expiring token in the cookie.
15
+ # for the paranoid: we _should_ be storing user_token = hash(cookie_token, request IP)
16
+ def login_from_cookie
17
+ current_user = cookies[:auth_token] && Merb::Authentication.user_class.first(:conditions => ["remember_token = ?", cookies[:auth_token]])
18
+ if current_user && current_user.remember_token?
19
+ handle_remember_cookie! false # freshen cookie token (keeping date)
20
+ current_user
21
+ end
22
+ end
23
+
24
+ #
25
+ # Remember_me Tokens
26
+ #
27
+ # Cookies shouldn't be allowed to persist past their freshness date,
28
+ # and they should be changed at each login
29
+
30
+ # Cookies shouldn't be allowed to persist past their freshness date,
31
+ # and they should be changed at each login
32
+
33
+ def valid_remember_cookie?
34
+ return nil unless current_user
35
+ (current_user.remember_token?) &&
36
+ (cookies[:auth_token] == current_user.remember_token)
37
+ end
38
+
39
+ # Refresh the cookie auth token if it exists, create it otherwise
40
+ def handle_remember_cookie! new_cookie_flag
41
+ return unless current_user
42
+ case
43
+ when valid_remember_cookie? then current_user.refresh_token # keeping same expiry date
44
+ when new_cookie_flag then current_user.remember_me
45
+ else current_user.forget_me
46
+ end
47
+ send_remember_cookie!
48
+ end
49
+
50
+ def send_remember_cookie!
51
+ cookies.set_cookie(:auth_token, current_user.remember_token, :expires => current_user.remember_token_expires_at.to_time)
52
+ end
53
+
54
+
55
+ end
56
+
@@ -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: rughetto-merb-auth-remember-me
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Surasit Liangpornrattana
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-02-27 00:00:00 -08: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/merbtasks.rb
42
+ - lib/merb-auth-remember-me/mixins
43
+ - lib/merb-auth-remember-me/mixins/authenticated_user
44
+ - lib/merb-auth-remember-me/mixins/authenticated_user/ar_authenticated_user.rb
45
+ - lib/merb-auth-remember-me/mixins/authenticated_user/dm_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: true
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: 2
82
+ summary: Merb plugin that provides remember me for merb-auth-slice-password
83
+ test_files: []
84
+