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