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 +3 -5
- data/lib/shield/helpers.rb +30 -11
- data/test/cuba.rb +110 -0
- data/test/helper.rb +1 -10
- data/test/{model_test.rb → model.rb} +0 -0
- data/test/{password_hash_test.rb → password.rb} +0 -0
- data/test/{shield_test.rb → shield.rb} +5 -17
- data/test/{sinatra_test.rb → sinatra.rb} +33 -4
- metadata +29 -17
data/lib/shield.rb
CHANGED
@@ -1,7 +1,5 @@
|
|
1
1
|
module Shield
|
2
|
-
|
3
|
-
|
4
|
-
autoload :
|
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
|
data/lib/shield/helpers.rb
CHANGED
@@ -1,11 +1,31 @@
|
|
1
1
|
module Shield
|
2
2
|
module Helpers
|
3
|
-
|
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
|
-
|
8
|
-
|
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
|
19
|
-
|
20
|
-
|
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 "
|
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
|
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
|
-
|
35
|
+
if login(User, params[:login], params[:password], params[:remember_me])
|
36
|
+
redirect(session[:return_to] || "/")
|
36
37
|
else
|
37
|
-
|
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
|
-
|
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.
|
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-
|
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: &
|
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: *
|
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: &
|
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: *
|
48
|
+
version_requirements: *2156271720
|
38
49
|
- !ruby/object:Gem::Dependency
|
39
50
|
name: rack-test
|
40
|
-
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: *
|
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/
|
68
|
-
- test/
|
69
|
-
- test/
|
70
|
-
- test/
|
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:
|
100
|
+
version: 1.3.1
|
89
101
|
requirements: []
|
90
102
|
rubyforge_project: shield
|
91
103
|
rubygems_version: 1.8.11
|