shield 0.0.4 → 0.1.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
data/lib/shield.rb CHANGED
@@ -1,7 +1,5 @@
1
1
  module Shield
2
- VERSION = "0.0.3"
3
-
4
- autoload :Password, "shield/password"
5
- autoload :Helpers, "shield/helpers"
6
- autoload :Model, "shield/model"
2
+ autoload :Password, "shield/password"
3
+ autoload :Helpers, "shield/helpers"
4
+ autoload :Model, "shield/model"
7
5
  end
@@ -1,11 +1,31 @@
1
1
  module Shield
2
2
  module Helpers
3
- def ensure_authenticated(model)
3
+ class NoSessionError < StandardError; end
4
+
5
+ def session
6
+ env["rack.session"] || raise(NoSessionError)
7
+ end
8
+
9
+ def redirect(path, status = 302)
10
+ if defined?(super)
11
+ # If the application context has defined a proper redirect
12
+ # we can simply use that definition.
13
+ super
14
+ else
15
+ # We implement the Cuba redirect here, being Cuba users we
16
+ # are biased towards it of course.
17
+ halt [status, { "Location" => path, "Content-Type" => "text/html" }, []]
18
+ end
19
+ end
20
+
21
+ def ensure_authenticated(model, login_url = "/login")
4
22
  if authenticated(model)
5
23
  return true
6
24
  else
7
- session[:return_to] = request.fullpath
8
- redirect_to_login
25
+ # If you've ever used request.path, it just so happens
26
+ # to be SCRIPT_NAME + PATH_INFO.
27
+ session[:return_to] = env["SCRIPT_NAME"] + env["PATH_INFO"]
28
+ redirect login_url
9
29
  return false
10
30
  end
11
31
  end
@@ -15,20 +35,18 @@ module Shield
15
35
  @_authenticated[model] ||= session[model.to_s] && model[session[model.to_s]]
16
36
  end
17
37
 
18
- def redirect_to_login
19
- redirect "/login"
20
- end
21
-
22
- def redirect_to_stored(default = "/")
23
- redirect(session.delete(:return_to) || default)
38
+ def persist_session!
39
+ if session[:remember_for]
40
+ env["rack.session.options"][:expire_after] = session[:remember_for]
41
+ end
24
42
  end
25
43
 
26
- def login(model, username, password)
44
+ def login(model, username, password, remember = false, expire = 1209600)
27
45
  instance = model.authenticate(username, password)
28
46
 
29
47
  if instance
48
+ session[:remember_for] = expire if remember
30
49
  session[model.to_s] = instance.id
31
- return true
32
50
  else
33
51
  return false
34
52
  end
@@ -37,6 +55,7 @@ module Shield
37
55
  def logout(model)
38
56
  session.delete(model.to_s)
39
57
  session.delete(:return_to)
58
+ session.delete(:remember_for)
40
59
 
41
60
  @_authenticated.delete(model) if defined?(@_authenticated)
42
61
  end
data/test/cuba.rb ADDED
@@ -0,0 +1,110 @@
1
+ require File.expand_path("helper", File.dirname(__FILE__))
2
+
3
+ class User < Struct.new(:id)
4
+ extend Shield::Model
5
+
6
+ def self.[](id)
7
+ User.new(1) unless id.to_s.empty?
8
+ end
9
+
10
+ def self.authenticate(username, password)
11
+ User.new(1001) if username == "quentin" && password == "password"
12
+ end
13
+ end
14
+
15
+ Cuba.use Rack::Session::Cookie
16
+
17
+ Cuba.send :include, Shield::Helpers
18
+
19
+ Cuba.define do
20
+ on get, "public" do
21
+ res.write "Public"
22
+ end
23
+
24
+ on get, "private" do
25
+ ensure_authenticated(User)
26
+
27
+ res.write "Private"
28
+ end
29
+
30
+ on get, "login" do
31
+ res.write "Login"
32
+ end
33
+
34
+ on post, "login", param("login"), param("password") do |u, p|
35
+ if login(User, u, p, req[:remember_me])
36
+ res.redirect(session[:return_to] || "/")
37
+ else
38
+ res.redirect "/login"
39
+ end
40
+ end
41
+
42
+ on "logout" do
43
+ logout(User)
44
+ res.redirect "/"
45
+ end
46
+ end
47
+
48
+ scope do
49
+ def app
50
+ Cuba
51
+ end
52
+
53
+ def assert_redirected_to(path)
54
+ unless last_response.status == 302
55
+ flunk
56
+ end
57
+ assert_equal path, URI(last_response.headers["Location"]).path
58
+ end
59
+
60
+ def session
61
+ last_request.env["rack.session"]
62
+ end
63
+
64
+ setup do
65
+ clear_cookies
66
+ end
67
+
68
+ test "public" do
69
+ get "/public"
70
+ assert "Public" == last_response.body
71
+ end
72
+
73
+ test "successful logging in" do
74
+ get "/private"
75
+
76
+ assert_redirected_to "/login"
77
+ assert "/private" == session[:return_to]
78
+
79
+ post "/login", :login => "quentin", :password => "password"
80
+ assert_redirected_to "/private"
81
+
82
+ assert 1001 == session["User"]
83
+ end
84
+
85
+ test "failed login" do
86
+ post "/login", :login => "q", :password => "p"
87
+ assert_redirected_to "/login"
88
+
89
+ assert nil == session["User"]
90
+ end
91
+
92
+ test "logging out" do
93
+ post "/login", :login => "quentin", :password => "password"
94
+
95
+ get "/logout"
96
+
97
+ assert nil == session["User"]
98
+ assert nil == session[:return_to]
99
+ end
100
+
101
+ test "remember functionality" do
102
+ post "/login", :login => "quentin", :password => "password", :remember_me => "1"
103
+
104
+ assert_equal session[:remember_for], 86400 * 14
105
+
106
+ get "/logout"
107
+
108
+ assert_equal nil, session[:remember_for]
109
+ end
110
+ end
data/test/helper.rb CHANGED
@@ -3,17 +3,8 @@ $:.unshift(File.expand_path("../lib", File.dirname(__FILE__)))
3
3
  require "shield"
4
4
  require "cutest"
5
5
  require "rack/test"
6
- require "sinatra/base"
6
+ require "cuba"
7
7
 
8
8
  class Cutest::Scope
9
9
  include Rack::Test::Methods
10
-
11
- def assert_redirected_to(path)
12
- assert_equal 302, last_response.status
13
- assert_equal path, URI(last_response.headers["Location"]).path
14
- end
15
-
16
- def session
17
- last_request.env["rack.session"]
18
- end
19
10
  end
File without changes
File without changes
@@ -17,6 +17,10 @@ class Context
17
17
  @path = path
18
18
  end
19
19
 
20
+ def env
21
+ { "SCRIPT_NAME" => "", "PATH_INFO" => @path }
22
+ end
23
+
20
24
  def session
21
25
  @session ||= {}
22
26
  end
@@ -24,7 +28,7 @@ class Context
24
28
  class Request < Struct.new(:fullpath)
25
29
  end
26
30
 
27
- def request
31
+ def req
28
32
  Request.new(@path)
29
33
  end
30
34
 
@@ -73,22 +77,6 @@ test "caches authenticated in @_authenticated" do |context|
73
77
  assert User.new(1) == context.instance_variable_get(:@_authenticated)[User]
74
78
  end
75
79
 
76
- test "redirect to stored when :return_to is set" do |context|
77
- context.session[:return_to] = "/private"
78
- context.redirect_to_stored
79
-
80
- assert "/private" == context.redirect
81
- assert nil == context.session[:return_to]
82
- end
83
-
84
- test "redirect to stored when no return to" do |context|
85
- context.redirect_to_stored
86
- assert "/" == context.redirect
87
-
88
- context.redirect_to_stored("/custom")
89
- assert "/custom" == context.redirect
90
- end
91
-
92
80
  test "login success" do |context|
93
81
  assert context.login(User, "quentin", "password")
94
82
  assert 1001 == context.session["User"]
@@ -1,4 +1,5 @@
1
1
  require File.expand_path("helper", File.dirname(__FILE__))
2
+ require "sinatra/base"
2
3
 
3
4
  class User < Struct.new(:id)
4
5
  extend Shield::Model
@@ -31,10 +32,10 @@ class SinatraApp < Sinatra::Base
31
32
  end
32
33
 
33
34
  post "/login" do
34
- if login(User, params[:login], params[:password])
35
- redirect_to_stored
35
+ if login(User, params[:login], params[:password], params[:remember_me])
36
+ redirect(session[:return_to] || "/")
36
37
  else
37
- redirect_to_login
38
+ redirect "/login"
38
39
  end
39
40
  end
40
41
 
@@ -49,6 +50,23 @@ scope do
49
50
  SinatraApp.new
50
51
  end
51
52
 
53
+ def assert_redirected_to(path)
54
+ unless last_response.status == 302
55
+ flunk
56
+ end
57
+ assert_equal path, URI(last_response.headers["Location"]).path
58
+ end
59
+
60
+ def session
61
+ last_request.env["rack.session"]
62
+ end
63
+
64
+ def debug
65
+ require "open3"
66
+ out, _, _ = Open3.capture3("elinks -dump", stdin_data: last_response.body)
67
+ puts out
68
+ end
69
+
52
70
  setup do
53
71
  clear_cookies
54
72
  end
@@ -60,8 +78,9 @@ scope do
60
78
 
61
79
  test "successful logging in" do
62
80
  get "/private"
81
+
63
82
  assert_redirected_to "/login"
64
- assert "/private" == session[:return_to]
83
+ assert_equal "/private", session[:return_to]
65
84
 
66
85
  post "/login", :login => "quentin", :password => "password"
67
86
  assert_redirected_to "/private"
@@ -84,4 +103,14 @@ scope do
84
103
  assert nil == session["User"]
85
104
  assert nil == session[:return_to]
86
105
  end
106
+
107
+ test "remember functionality" do
108
+ post "/login", :login => "quentin", :password => "password", :remember_me => "1"
109
+
110
+ assert_equal session[:remember_for], 86400 * 14
111
+
112
+ get "/logout"
113
+
114
+ assert_equal nil, session[:remember_for]
115
+ end
87
116
  end
metadata CHANGED
@@ -1,8 +1,8 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: shield
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.4
5
- prerelease:
4
+ version: 0.1.0.rc1
5
+ prerelease: 6
6
6
  platform: ruby
7
7
  authors:
8
8
  - Michel Martens
@@ -11,11 +11,11 @@ authors:
11
11
  autorequire:
12
12
  bindir: bin
13
13
  cert_chain: []
14
- date: 2012-01-20 00:00:00.000000000 Z
14
+ date: 2012-01-21 00:00:00.000000000 Z
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
17
  name: cutest
18
- requirement: &2156259380 !ruby/object:Gem::Requirement
18
+ requirement: &2156273880 !ruby/object:Gem::Requirement
19
19
  none: false
20
20
  requirements:
21
21
  - - ! '>='
@@ -23,10 +23,21 @@ dependencies:
23
23
  version: '0'
24
24
  type: :development
25
25
  prerelease: false
26
- version_requirements: *2156259380
26
+ version_requirements: *2156273880
27
+ - !ruby/object:Gem::Dependency
28
+ name: cuba
29
+ requirement: &2156272920 !ruby/object:Gem::Requirement
30
+ none: false
31
+ requirements:
32
+ - - ! '>='
33
+ - !ruby/object:Gem::Version
34
+ version: '0'
35
+ type: :development
36
+ prerelease: false
37
+ version_requirements: *2156272920
27
38
  - !ruby/object:Gem::Dependency
28
39
  name: sinatra
29
- requirement: &2156274580 !ruby/object:Gem::Requirement
40
+ requirement: &2156271720 !ruby/object:Gem::Requirement
30
41
  none: false
31
42
  requirements:
32
43
  - - ! '>='
@@ -34,10 +45,10 @@ dependencies:
34
45
  version: '0'
35
46
  type: :development
36
47
  prerelease: false
37
- version_requirements: *2156274580
48
+ version_requirements: *2156271720
38
49
  - !ruby/object:Gem::Dependency
39
50
  name: rack-test
40
- requirement: &2156273800 !ruby/object:Gem::Requirement
51
+ requirement: &2156270860 !ruby/object:Gem::Requirement
41
52
  none: false
42
53
  requirements:
43
54
  - - ! '>='
@@ -45,7 +56,7 @@ dependencies:
45
56
  version: '0'
46
57
  type: :development
47
58
  prerelease: false
48
- version_requirements: *2156273800
59
+ version_requirements: *2156270860
49
60
  description: ! "\n Provides all the protocol you need in order to do authentication
50
61
  on\n your rack application. The implementation specifics can be found in\n http://github.com/cyx/shield-contrib\n
51
62
  \ "
@@ -59,15 +70,16 @@ extra_rdoc_files: []
59
70
  files:
60
71
  - lib/shield/helpers.rb
61
72
  - lib/shield/model.rb
62
- - lib/shield/password.rb
63
- - lib/shield/password/simple.rb
64
73
  - lib/shield/password/pbkdf2.rb
74
+ - lib/shield/password/simple.rb
75
+ - lib/shield/password.rb
65
76
  - lib/shield.rb
77
+ - test/cuba.rb
66
78
  - test/helper.rb
67
- - test/model_test.rb
68
- - test/password_hash_test.rb
69
- - test/shield_test.rb
70
- - test/sinatra_test.rb
79
+ - test/model.rb
80
+ - test/password.rb
81
+ - test/shield.rb
82
+ - test/sinatra.rb
71
83
  homepage: http://github.com/cyx/shield
72
84
  licenses: []
73
85
  post_install_message:
@@ -83,9 +95,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
83
95
  required_rubygems_version: !ruby/object:Gem::Requirement
84
96
  none: false
85
97
  requirements:
86
- - - ! '>='
98
+ - - ! '>'
87
99
  - !ruby/object:Gem::Version
88
- version: '0'
100
+ version: 1.3.1
89
101
  requirements: []
90
102
  rubyforge_project: shield
91
103
  rubygems_version: 1.8.11