rack-cerberus 1.0.3 → 1.0.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile +0 -2
- data/MIT_LICENSE +1 -1
- data/README.md +7 -8
- data/example/config.ru +4 -5
- data/lib/rack/cerberus/version.rb +1 -1
- data/lib/rack/cerberus.rb +105 -51
- data/rack_cerberus.gemspec +20 -11
- data/test/test_rack_cerberus.rb +155 -0
- metadata +52 -10
- data/spec/rack_cerberus_spec.rb +0 -149
- data/spec/spec_helper.rb +0 -24
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f646a686e4b181584972006a33b8637f44ddaef7
|
4
|
+
data.tar.gz: 152f0132226b3dd7803bf2507fb57b6d4c6523d4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c2dfda81ee63b2de2a1fb52be5e4511493f62d9d3c7256e98796f7c5fd68cec598ded528c1e0a59bd76178b662945a0ce3c823939422cbc12a72823cb77d0a37
|
7
|
+
data.tar.gz: 189a19fff0b2bbb33e5202806244b035d693d04214f19631d95fbf9b6d88cb523e86b6560d790675f9dd50022bff023906e1ae14e042ca1247f689c11b15e07e
|
data/Gemfile
CHANGED
data/MIT_LICENSE
CHANGED
data/README.md
CHANGED
@@ -8,18 +8,18 @@ options in order to style the authentication page.
|
|
8
8
|
Install with:
|
9
9
|
|
10
10
|
```
|
11
|
-
#
|
11
|
+
# gem install rack-cerberus
|
12
12
|
```
|
13
13
|
|
14
14
|
Or in your `Gemfile`:
|
15
15
|
|
16
|
-
```
|
16
|
+
```ruby
|
17
17
|
gem 'rack-cerberus'
|
18
18
|
```
|
19
19
|
|
20
20
|
You can use it almost the same way you use `Rack::Auth::Basic`:
|
21
21
|
|
22
|
-
```
|
22
|
+
```ruby
|
23
23
|
require 'rack/cerberus'
|
24
24
|
use Rack::Session::Cookie, secret: 'change_me'
|
25
25
|
use Rack::Cerberus do |login, pass|
|
@@ -45,7 +45,7 @@ There is an optional hash you can add for customisation it. Options are:
|
|
45
45
|
|
46
46
|
Which is used that way:
|
47
47
|
|
48
|
-
```
|
48
|
+
```ruby
|
49
49
|
use Rack::Cerberus, {company_name: 'Nintendo'} do |login, pass|
|
50
50
|
pass=='secret'
|
51
51
|
end
|
@@ -66,15 +66,14 @@ return `true` or `false`.
|
|
66
66
|
|
67
67
|
You can also use the 3rd argument which is the request object:
|
68
68
|
|
69
|
-
```
|
69
|
+
```ruby
|
70
70
|
use Rack::Cerberus, {company_name: 'Nintendo'} do |login, pass, req|
|
71
71
|
pass=='secret' && req.xhr?
|
72
72
|
end
|
73
73
|
```
|
74
74
|
|
75
75
|
This is useful if you want to check other details of the request.
|
76
|
-
Like the referer or another parameter. But bear in mind that `cerberus_login`
|
77
|
-
and `cerberus_pass` are still mandatory.
|
76
|
+
Like the referer or another parameter. But bear in mind that `cerberus_login` and `cerberus_pass` are still mandatory.
|
78
77
|
|
79
78
|
Example
|
80
79
|
-------
|
@@ -103,5 +102,5 @@ or send patches.
|
|
103
102
|
Copyright
|
104
103
|
---------
|
105
104
|
|
106
|
-
(c) 2010-
|
105
|
+
(c) 2010-2016 Mickael Riga - see `MIT_LICENSE` for details
|
107
106
|
|
data/example/config.ru
CHANGED
@@ -1,4 +1,6 @@
|
|
1
|
-
|
1
|
+
lib = File.expand_path('../../lib', __FILE__)
|
2
|
+
$:.unshift lib
|
3
|
+
require 'rack/cerberus'
|
2
4
|
|
3
5
|
use Rack::Session::Cookie, secret: 'change_me'
|
4
6
|
|
@@ -19,10 +21,7 @@ map '/' do
|
|
19
21
|
end
|
20
22
|
|
21
23
|
map '/secret' do
|
22
|
-
use Rack::Cerberus, {
|
23
|
-
company_name: 'Nintendo',
|
24
|
-
fg_color: 'red',
|
25
|
-
} do |login,pass|
|
24
|
+
use Rack::Cerberus, { company_name: 'Nintendo' } do |login,pass|
|
26
25
|
[login,pass]==['mario','bros']
|
27
26
|
end
|
28
27
|
run lambda {|env|
|
data/lib/rack/cerberus.rb
CHANGED
@@ -5,63 +5,115 @@ module Rack
|
|
5
5
|
|
6
6
|
class Cerberus
|
7
7
|
|
8
|
-
VERSION = '1.0.2'
|
9
|
-
|
10
8
|
class NoSessionError < RuntimeError; end
|
11
9
|
|
12
10
|
def self.new(*); ::Rack::MethodOverride.new(super); end
|
13
11
|
|
14
|
-
def initialize
|
12
|
+
def initialize app, options={}, &block
|
15
13
|
@app = app
|
16
14
|
defaults = {
|
17
15
|
company_name: 'Cerberus',
|
18
|
-
bg_color: '#
|
19
|
-
fg_color: '#
|
20
|
-
text_color: '#
|
21
|
-
icon_url: nil,
|
16
|
+
bg_color: '#93a1a1',
|
17
|
+
fg_color: '#002b36',
|
18
|
+
text_color: '#fdf6e3',
|
22
19
|
session_key: 'cerberus_user'
|
23
20
|
}
|
24
21
|
@options = defaults.merge(options)
|
25
|
-
@options[:icon] = @options[:icon_url].nil? ?
|
26
|
-
|
22
|
+
@options[:icon] = @options[:icon_url].nil? ?
|
23
|
+
'' :
|
24
|
+
"<img src='#{@options[:icon_url]}' /><br />"
|
25
|
+
@options[:css] = @options[:css_location].nil? ?
|
26
|
+
'' :
|
27
|
+
"<link href='#{@options[:css_location]}' rel='stylesheet' type='text/css'>"
|
27
28
|
@block = block
|
28
29
|
end
|
29
30
|
|
30
|
-
def call
|
31
|
+
def call env
|
31
32
|
dup._call(env)
|
32
33
|
end
|
33
34
|
|
34
|
-
def _call
|
35
|
-
|
36
|
-
req = Rack::Request.new
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
if env['PATH_INFO']=='/logout'
|
42
|
-
res = Rack::Response.new(env)
|
43
|
-
res.redirect(env['SCRIPT_NAME']=='' ? '/' : env['SCRIPT_NAME'])
|
44
|
-
res.finish
|
35
|
+
def _call env
|
36
|
+
ensure_session env
|
37
|
+
req = Rack::Request.new env
|
38
|
+
if (logged?(req) and !logging_out?(req)) or authorized?(req)
|
39
|
+
ensure_logged! req
|
40
|
+
if logging_out? req
|
41
|
+
logout_response req
|
45
42
|
else
|
46
|
-
@app.call
|
43
|
+
@app.call env
|
47
44
|
end
|
48
45
|
else
|
49
|
-
|
50
|
-
error = "<p class='err'>Wrong login or password</p>"
|
51
|
-
end
|
52
|
-
env['rack.session'].delete(@options[:session_key])
|
53
|
-
[
|
54
|
-
401, {'Content-Type' => 'text/html'},
|
55
|
-
[AUTH_PAGE % @options.merge({
|
56
|
-
error: error, submit_path: env['REQUEST_URI'],
|
57
|
-
request_method: req.request_method,
|
58
|
-
login: Rack::Utils.escape_html(login),
|
59
|
-
pass: Rack::Utils.escape_html(pass)
|
60
|
-
})]
|
61
|
-
]
|
46
|
+
form_response req
|
62
47
|
end
|
63
48
|
end
|
64
|
-
|
49
|
+
|
50
|
+
private
|
51
|
+
|
52
|
+
def ensure_session env
|
53
|
+
if env['rack.session'].nil?
|
54
|
+
raise(NoSessionError, 'Cerberus cannot work without Session')
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def h text
|
59
|
+
Rack::Utils.escape_html text
|
60
|
+
end
|
61
|
+
|
62
|
+
def login req
|
63
|
+
req.params['cerberus_login']
|
64
|
+
end
|
65
|
+
|
66
|
+
def pass req
|
67
|
+
req.params['cerberus_pass']
|
68
|
+
end
|
69
|
+
|
70
|
+
def logged? req
|
71
|
+
req.env['rack.session'][@options[:session_key]]!=nil
|
72
|
+
end
|
73
|
+
|
74
|
+
def provided_fields? req
|
75
|
+
login(req) and pass(req)
|
76
|
+
end
|
77
|
+
|
78
|
+
def authorized? req
|
79
|
+
provided_fields?(req) and
|
80
|
+
@block.call login(req), pass(req), req
|
81
|
+
end
|
82
|
+
|
83
|
+
def ensure_logged! req
|
84
|
+
req.env['rack.session'][@options[:session_key]] ||= login(req)
|
85
|
+
end
|
86
|
+
|
87
|
+
def ensure_logged_out! req
|
88
|
+
req.env['rack.session'].delete @options[:session_key]
|
89
|
+
end
|
90
|
+
|
91
|
+
def logging_out? req
|
92
|
+
req.path_info=='/logout'
|
93
|
+
end
|
94
|
+
|
95
|
+
def logout_response req
|
96
|
+
res = Rack::Response.new
|
97
|
+
res.redirect(req.script_name=='' ? '/' : req.script_name)
|
98
|
+
res.finish
|
99
|
+
end
|
100
|
+
|
101
|
+
def form_response req
|
102
|
+
if provided_fields? req
|
103
|
+
error = "<p class='err'>Wrong login or password</p>"
|
104
|
+
end
|
105
|
+
ensure_logged_out! req
|
106
|
+
[
|
107
|
+
401, {'Content-Type' => 'text/html'},
|
108
|
+
[AUTH_PAGE % @options.merge({
|
109
|
+
error: error, submit_path: req.env['REQUEST_URI'],
|
110
|
+
request_method: req.request_method,
|
111
|
+
login: h(login(req)),
|
112
|
+
pass: h(pass(req))
|
113
|
+
})]
|
114
|
+
]
|
115
|
+
end
|
116
|
+
|
65
117
|
AUTH_PAGE = <<-PAGE
|
66
118
|
<!DOCTYPE html>
|
67
119
|
<html><head>
|
@@ -81,7 +133,7 @@ module Rack
|
|
81
133
|
-moz-border-radius: 3px;
|
82
134
|
-webkit-border-radius: 3px;
|
83
135
|
color: white;
|
84
|
-
background-color:
|
136
|
+
background-color: #dc322f;
|
85
137
|
}
|
86
138
|
div {
|
87
139
|
text-align: left;
|
@@ -101,7 +153,23 @@ module Rack
|
|
101
153
|
input[type=text], input[type=password] {
|
102
154
|
display: block; width: 100%%; padding: 0.5em;
|
103
155
|
border: 0px; font-size: 1.25em;
|
156
|
+
background-color: %{text_color};
|
157
|
+
}
|
158
|
+
input[type=submit] {
|
159
|
+
background-color: %{bg_color};
|
160
|
+
color: %{fg_color};
|
161
|
+
padding: 0.5em;
|
162
|
+
-webkit-appearance: none;
|
163
|
+
-moz-appearance: none;
|
164
|
+
appearance: none;
|
165
|
+
border: 0;
|
166
|
+
cursor: pointer;
|
104
167
|
}
|
168
|
+
input[type=submit]:hover { background-color: %{text_color}; }
|
169
|
+
::-webkit-input-placeholder { color: %{bg_color}; }
|
170
|
+
:-moz-placeholder { color: %{bg_color}; }
|
171
|
+
::-moz-placeholder { color: %{bg_color}; }
|
172
|
+
:-ms-input-placeholder { color: %{bg_color}; }
|
105
173
|
</style>
|
106
174
|
%{css}
|
107
175
|
</head><body>
|
@@ -116,20 +184,6 @@ module Rack
|
|
116
184
|
<input type="hidden" name="_method" value="%{request_method}">
|
117
185
|
<p><input type="submit" value="SIGN IN →"></p>
|
118
186
|
</form>
|
119
|
-
<script type="text/javascript" charset="utf-8">
|
120
|
-
var login = document.getElementById('login');
|
121
|
-
var pass = document.getElementById('pass');
|
122
|
-
var focus = function() {
|
123
|
-
if (this.value==this.id) this.value = '';
|
124
|
-
}
|
125
|
-
var blur = function() {
|
126
|
-
if (this.value=='') this.value = this.id;
|
127
|
-
}
|
128
|
-
login.onfocus = focus;
|
129
|
-
pass.onfocus = focus;
|
130
|
-
login.onblur = blur;
|
131
|
-
pass.onblur = blur;
|
132
|
-
</script>
|
133
187
|
</div>
|
134
188
|
</body></html>
|
135
189
|
PAGE
|
data/rack_cerberus.gemspec
CHANGED
@@ -1,22 +1,31 @@
|
|
1
|
-
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
lib = File.expand_path('../lib', __FILE__)
|
4
|
+
$:.unshift lib
|
5
|
+
require 'rack/cerberus/version'
|
2
6
|
|
3
7
|
Gem::Specification.new do |s|
|
4
8
|
|
9
|
+
s.authors = ['Mickael Riga']
|
10
|
+
s.email = ['mig@mypeplum.com']
|
11
|
+
s.homepage = 'http://github.com/mig-hub/cerberus'
|
12
|
+
s.licenses = ['MIT']
|
13
|
+
|
5
14
|
s.name = 'rack-cerberus'
|
6
15
|
s.version = Rack::Cerberus::VERSION
|
7
|
-
s.summary =
|
8
|
-
s.description =
|
9
|
-
s.licenses = ['MIT']
|
16
|
+
s.summary = 'A Rack middleware for form-based authentication'
|
17
|
+
s.description = 'A Rack middleware for form-based authentication. It works roughly like Basic HTTP Authentication except that the authentication page can be styled with the middleware options.'
|
10
18
|
|
11
|
-
s.files = `git ls-files`.split("\n").sort
|
12
|
-
s.require_path = './lib'
|
13
|
-
s.add_dependency('rack')
|
14
|
-
s.test_files = s.files.select { |p| p =~ /^spec\/.*_spec.rb/ }
|
15
19
|
s.platform = Gem::Platform::RUBY
|
20
|
+
s.files = `git ls-files`.split("\n").sort
|
21
|
+
s.test_files = s.files.select { |p| p =~ /^test\/test_.*\.rb$/ }
|
22
|
+
s.require_paths = ['lib']
|
23
|
+
|
24
|
+
s.add_dependency 'rack', '>= 1.0'
|
16
25
|
|
17
|
-
s.
|
18
|
-
s.
|
19
|
-
s.
|
26
|
+
s.add_development_dependency 'bundler', '~> 1.13'
|
27
|
+
s.add_development_dependency 'minitest', '~> 5.8'
|
28
|
+
s.add_development_dependency 'rack-test', '~> 0.6'
|
20
29
|
|
21
30
|
end
|
22
31
|
|
@@ -0,0 +1,155 @@
|
|
1
|
+
require 'minitest/autorun'
|
2
|
+
require 'rack/test'
|
3
|
+
require 'rack/cerberus'
|
4
|
+
|
5
|
+
ENV['RACK_ENV'] = 'test'
|
6
|
+
|
7
|
+
class TestRackCerberus < Minitest::Test
|
8
|
+
parallelize_me!
|
9
|
+
|
10
|
+
include Rack::Test::Methods
|
11
|
+
|
12
|
+
def secret_app
|
13
|
+
lambda {|env|
|
14
|
+
[
|
15
|
+
200,
|
16
|
+
{'Content-Type'=>'text/plain'},
|
17
|
+
"#{env['REQUEST_METHOD']} #{env['rack.session'].inspect}"
|
18
|
+
]
|
19
|
+
}
|
20
|
+
end
|
21
|
+
|
22
|
+
def cerberus_app cerberus_options={}
|
23
|
+
Rack::Cerberus.new(secret_app, cerberus_options) do |login,pass|
|
24
|
+
[login,pass]==['mario@nintendo.com','bros']
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def mounted_app mount_path='/', cerberus_options={}
|
29
|
+
Rack::URLMap.new({
|
30
|
+
mount_path => Rack::Session::Cookie.new(cerberus_app(cerberus_options), {secret: '42'})
|
31
|
+
})
|
32
|
+
end
|
33
|
+
|
34
|
+
def app; @app; end
|
35
|
+
|
36
|
+
def body
|
37
|
+
last_response.body
|
38
|
+
end
|
39
|
+
|
40
|
+
def correct_logins
|
41
|
+
{
|
42
|
+
'cerberus_login' => 'mario@nintendo.com',
|
43
|
+
'cerberus_pass' => 'bros'
|
44
|
+
}
|
45
|
+
end
|
46
|
+
|
47
|
+
def wrong_logins
|
48
|
+
{
|
49
|
+
'cerberus_login' => 'fake_login',
|
50
|
+
'cerberus_pass' => 'fake_pass'
|
51
|
+
}
|
52
|
+
end
|
53
|
+
|
54
|
+
def setup
|
55
|
+
@app = mounted_app
|
56
|
+
end
|
57
|
+
|
58
|
+
def teardown
|
59
|
+
clear_cookies
|
60
|
+
end
|
61
|
+
|
62
|
+
def test_no_session_raises
|
63
|
+
@app = cerberus_app
|
64
|
+
assert_raises(Rack::Cerberus::NoSessionError) do
|
65
|
+
get '/'
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def test_unauthorized_when_not_logged_in
|
70
|
+
get '/'
|
71
|
+
assert_equal 401, last_response.status
|
72
|
+
assert_equal String, body.class
|
73
|
+
assert_match 'name="cerberus_login" value=""', body
|
74
|
+
assert_match 'name="cerberus_pass" value=""', body
|
75
|
+
end
|
76
|
+
|
77
|
+
def test_unauthorized_when_logins_are_incorrect
|
78
|
+
get '/', wrong_logins
|
79
|
+
assert_equal 401, last_response.status
|
80
|
+
assert_match 'Wrong login or password', body
|
81
|
+
end
|
82
|
+
|
83
|
+
def test_fields_filled_with_previous_info
|
84
|
+
post '/', wrong_logins
|
85
|
+
assert_match 'name="cerberus_login" value="fake_login"', body
|
86
|
+
assert_match 'name="cerberus_pass" value="fake_pass"', body
|
87
|
+
end
|
88
|
+
|
89
|
+
def test_submitted_info_is_html_escaped
|
90
|
+
post('/', {
|
91
|
+
'cerberus_login' => '<script>bad</script>',
|
92
|
+
'cerberus_pass' => '<script>bad</script>'
|
93
|
+
})
|
94
|
+
assert_match 'bad', body
|
95
|
+
refute_match '<script>bad</script>', body
|
96
|
+
end
|
97
|
+
|
98
|
+
def test_authorized_when_logins_are_correct
|
99
|
+
get '/', correct_logins
|
100
|
+
assert_equal 200, last_response.status
|
101
|
+
end
|
102
|
+
|
103
|
+
def test_calls_final_page_with_original_method
|
104
|
+
get '/'
|
105
|
+
assert_match 'name="_method" value="GET"', body
|
106
|
+
post '/', correct_logins.merge({'_method'=>'GET'})
|
107
|
+
assert_match /^GET/, body
|
108
|
+
end
|
109
|
+
|
110
|
+
def test_stay_authorized_once_logged
|
111
|
+
get '/', correct_logins
|
112
|
+
get '/'
|
113
|
+
assert_equal 200, last_response.status
|
114
|
+
assert_match '"cerberus_user"=>"mario@nintendo.com"', body
|
115
|
+
end
|
116
|
+
|
117
|
+
def test_logout_with_logout_path
|
118
|
+
@app = mounted_app '/admin'
|
119
|
+
get '/admin/', correct_logins
|
120
|
+
assert_equal 200, last_response.status
|
121
|
+
get '/admin/logout'
|
122
|
+
assert_equal 401, last_response.status
|
123
|
+
end
|
124
|
+
|
125
|
+
def test_never_redirects_to_logout_path
|
126
|
+
@app = mounted_app '/admin'
|
127
|
+
get '/admin/logout', correct_logins
|
128
|
+
assert_equal 302, last_response.status
|
129
|
+
assert_equal '/admin', last_response['Location']
|
130
|
+
end
|
131
|
+
|
132
|
+
# Options
|
133
|
+
|
134
|
+
def test_no_css_location
|
135
|
+
get '/'
|
136
|
+
refute_match '<link', body
|
137
|
+
end
|
138
|
+
|
139
|
+
def test_css_location
|
140
|
+
@app = mounted_app '/', css_location: '/main.css'
|
141
|
+
get '/'
|
142
|
+
assert_match '<link', body
|
143
|
+
assert_match '/main.css', body
|
144
|
+
end
|
145
|
+
|
146
|
+
def test_can_change_session_key
|
147
|
+
@app = mounted_app '/', session_key: 'different_user'
|
148
|
+
get '/', correct_logins
|
149
|
+
get '/'
|
150
|
+
assert_equal 200, last_response.status
|
151
|
+
assert_match '"different_user"=>"mario@nintendo.com"', body
|
152
|
+
end
|
153
|
+
|
154
|
+
end
|
155
|
+
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rack-cerberus
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Mickael Riga
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2016-11-01 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rack
|
@@ -16,18 +16,61 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '0'
|
19
|
+
version: '1.0'
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: '0'
|
26
|
+
version: '1.0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: bundler
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '1.13'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '1.13'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: minitest
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '5.8'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '5.8'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rack-test
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0.6'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0.6'
|
27
69
|
description: A Rack middleware for form-based authentication. It works roughly like
|
28
70
|
Basic HTTP Authentication except that the authentication page can be styled with
|
29
71
|
the middleware options.
|
30
|
-
email:
|
72
|
+
email:
|
73
|
+
- mig@mypeplum.com
|
31
74
|
executables: []
|
32
75
|
extensions: []
|
33
76
|
extra_rdoc_files: []
|
@@ -42,8 +85,7 @@ files:
|
|
42
85
|
- lib/rack/cerberus.rb
|
43
86
|
- lib/rack/cerberus/version.rb
|
44
87
|
- rack_cerberus.gemspec
|
45
|
-
-
|
46
|
-
- spec/spec_helper.rb
|
88
|
+
- test/test_rack_cerberus.rb
|
47
89
|
homepage: http://github.com/mig-hub/cerberus
|
48
90
|
licenses:
|
49
91
|
- MIT
|
@@ -51,7 +93,7 @@ metadata: {}
|
|
51
93
|
post_install_message:
|
52
94
|
rdoc_options: []
|
53
95
|
require_paths:
|
54
|
-
-
|
96
|
+
- lib
|
55
97
|
required_ruby_version: !ruby/object:Gem::Requirement
|
56
98
|
requirements:
|
57
99
|
- - ">="
|
@@ -64,9 +106,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
64
106
|
version: '0'
|
65
107
|
requirements: []
|
66
108
|
rubyforge_project:
|
67
|
-
rubygems_version: 2.
|
109
|
+
rubygems_version: 2.5.1
|
68
110
|
signing_key:
|
69
111
|
specification_version: 4
|
70
112
|
summary: A Rack middleware for form-based authentication
|
71
113
|
test_files:
|
72
|
-
-
|
114
|
+
- test/test_rack_cerberus.rb
|
data/spec/rack_cerberus_spec.rb
DELETED
@@ -1,149 +0,0 @@
|
|
1
|
-
require 'rack/cerberus'
|
2
|
-
|
3
|
-
RSpec.describe Rack::Cerberus do
|
4
|
-
|
5
|
-
let(:secret_app) {
|
6
|
-
lambda {|env|
|
7
|
-
[200, {'Content-Type'=>'text/plain'}, env['rack.session'].inspect]
|
8
|
-
}
|
9
|
-
}
|
10
|
-
|
11
|
-
let(:cerberus_app) {
|
12
|
-
Rack::Cerberus.new(secret_app, cerberus_options) do |login,pass|
|
13
|
-
[login,pass]==['mario@nintendo.com','bros']
|
14
|
-
end
|
15
|
-
}
|
16
|
-
|
17
|
-
let(:app) {
|
18
|
-
Rack::URLMap.new({
|
19
|
-
mount_path => Rack::Session::Cookie.new(cerberus_app, {secret: '42'})
|
20
|
-
})
|
21
|
-
}
|
22
|
-
|
23
|
-
let(:cerberus_options) { {} }
|
24
|
-
let(:mount_path) { '/' }
|
25
|
-
|
26
|
-
before :each do
|
27
|
-
clear_cookies
|
28
|
-
end
|
29
|
-
|
30
|
-
context 'No session is set' do
|
31
|
-
let(:app) { cerberus_app }
|
32
|
-
it 'Raises' do
|
33
|
-
expect{ get('/') }.to raise_error(Rack::Cerberus::NoSessionError)
|
34
|
-
end
|
35
|
-
end
|
36
|
-
|
37
|
-
context 'Not logged in' do
|
38
|
-
it 'Stops requests' do
|
39
|
-
get '/'
|
40
|
-
expect(last_response.status).to eq 401
|
41
|
-
body = last_response.body
|
42
|
-
expect(body.class).to eq String
|
43
|
-
expect(body).to include('name="cerberus_login" value=""')
|
44
|
-
expect(body).to include('name="cerberus_pass" value=""')
|
45
|
-
end
|
46
|
-
end
|
47
|
-
|
48
|
-
describe 'Logging in' do
|
49
|
-
|
50
|
-
context 'Login details are incorrect' do
|
51
|
-
it 'Stops requests' do
|
52
|
-
get('/', {'cerberus_login' => 'fake_login', 'cerberus_pass' => 'fake_pass'})
|
53
|
-
expect(last_response.status).to eq 401
|
54
|
-
expect(last_response.body).to include('Wrong login or password')
|
55
|
-
end
|
56
|
-
it 'Keeps what was entered in the fields' do
|
57
|
-
post('/', {'cerberus_login' => 'fake_login', 'cerberus_pass' => 'fake_pass'})
|
58
|
-
expect(last_response.body).to include('name="cerberus_login" value="fake_login"')
|
59
|
-
expect(last_response.body).to include('name="cerberus_pass" value="fake_pass"')
|
60
|
-
end
|
61
|
-
it 'Escapes HTML on submitted info' do
|
62
|
-
expect(Rack::Utils).to receive(:escape_html).with('<script>bad</script>').twice
|
63
|
-
post('/', {'cerberus_login' => '<script>bad</script>', 'cerberus_pass' => '<script>bad</script>'})
|
64
|
-
end
|
65
|
-
end
|
66
|
-
|
67
|
-
context 'Login details are correct' do
|
68
|
-
let(:secret_app) {
|
69
|
-
lambda {|env|
|
70
|
-
[200, {'Content-Type'=>'text/plain'}, env['REQUEST_METHOD']]
|
71
|
-
}
|
72
|
-
}
|
73
|
-
it 'Gives access' do
|
74
|
-
get('/', {'cerberus_login' => 'mario@nintendo.com', 'cerberus_pass' => 'bros'})
|
75
|
-
expect(last_response.status).to eq 200
|
76
|
-
end
|
77
|
-
it 'Calls the final page with the original method' do
|
78
|
-
get('/')
|
79
|
-
expect(last_response.body).to include('name="_method" value="GET"')
|
80
|
-
post('/', {
|
81
|
-
'cerberus_login' => 'mario@nintendo.com',
|
82
|
-
'cerberus_pass' => 'bros',
|
83
|
-
'_method' => 'GET'
|
84
|
-
})
|
85
|
-
expect(last_response.body).to eq 'GET'
|
86
|
-
end
|
87
|
-
end
|
88
|
-
|
89
|
-
end
|
90
|
-
|
91
|
-
describe 'Already logged in' do
|
92
|
-
|
93
|
-
it 'Uses session for persistent login' do
|
94
|
-
get('/', {'cerberus_login' => 'mario@nintendo.com', 'cerberus_pass' => 'bros'})
|
95
|
-
get('/')
|
96
|
-
expect(last_response.status).to eq 200
|
97
|
-
expect(last_response.body).to include('"cerberus_user"=>"mario@nintendo.com"}')
|
98
|
-
end
|
99
|
-
|
100
|
-
end
|
101
|
-
|
102
|
-
describe 'Logout' do
|
103
|
-
|
104
|
-
let(:mount_path) { '/admin' }
|
105
|
-
|
106
|
-
it 'Happens via /logout path' do
|
107
|
-
get('/admin/', {'cerberus_login' => 'mario@nintendo.com', 'cerberus_pass' => 'bros'})
|
108
|
-
expect(last_response.status).to eq 200
|
109
|
-
get('/admin/logout')
|
110
|
-
expect(last_response.status).to eq 401
|
111
|
-
end
|
112
|
-
|
113
|
-
it 'Never redirects to the logout path' do
|
114
|
-
get('/admin/logout', {'cerberus_login' => 'mario@nintendo.com', 'cerberus_pass' => 'bros'})
|
115
|
-
expect(last_response.status).to eq 302
|
116
|
-
expect(last_response['Location']).to eq '/admin'
|
117
|
-
end
|
118
|
-
|
119
|
-
end
|
120
|
-
|
121
|
-
describe 'Options' do
|
122
|
-
|
123
|
-
it 'Does not link CSS by default' do
|
124
|
-
get('/')
|
125
|
-
expect(last_response.body).not_to match(/<link/)
|
126
|
-
end
|
127
|
-
|
128
|
-
context 'CSS option is used' do
|
129
|
-
let(:cerberus_options) { {:css_location=>'/main.css'} }
|
130
|
-
it 'Links the CSS file' do
|
131
|
-
get('/')
|
132
|
-
expect(last_response.body).to match(/<link/)
|
133
|
-
end
|
134
|
-
end
|
135
|
-
|
136
|
-
context 'Session key is different' do
|
137
|
-
let(:cerberus_options) { {session_key: 'different_user'} }
|
138
|
-
it 'Uses the session key of the options' do
|
139
|
-
get('/', {'cerberus_login' => 'mario@nintendo.com', 'cerberus_pass' => 'bros'})
|
140
|
-
get('/')
|
141
|
-
expect(last_response.status).to eq 200
|
142
|
-
expect(last_response.body).to include('"different_user"=>"mario@nintendo.com"}')
|
143
|
-
end
|
144
|
-
end
|
145
|
-
|
146
|
-
end
|
147
|
-
|
148
|
-
end
|
149
|
-
|
data/spec/spec_helper.rb
DELETED
@@ -1,24 +0,0 @@
|
|
1
|
-
ENV['RACK_ENV'] = 'test'
|
2
|
-
|
3
|
-
RSpec.configure do |config|
|
4
|
-
|
5
|
-
config.include Rack::Test::Methods
|
6
|
-
config.expect_with :rspec do |expectations|
|
7
|
-
expectations.include_chain_clauses_in_custom_matcher_descriptions = true
|
8
|
-
end
|
9
|
-
config.mock_with :rspec do |mocks|
|
10
|
-
mocks.verify_partial_doubles = true
|
11
|
-
end
|
12
|
-
config.filter_run :focus
|
13
|
-
config.run_all_when_everything_filtered = true
|
14
|
-
config.disable_monkey_patching!
|
15
|
-
config.warnings = true
|
16
|
-
if config.files_to_run.one?
|
17
|
-
config.default_formatter = 'doc'
|
18
|
-
end
|
19
|
-
config.profile_examples = 10
|
20
|
-
config.order = :random
|
21
|
-
Kernel.srand config.seed
|
22
|
-
|
23
|
-
end
|
24
|
-
|