rughetto-merb-auth-remember-me 0.0.1

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/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
+