shield 0.0.4 → 0.1.0.rc1

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