strelka 0.0.1.pre148 → 0.0.1.pre177
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/ChangeLog +1294 -0
- data/IDEAS.rdoc +6 -0
- data/Manifest.txt +20 -0
- data/README.rdoc +8 -2
- data/Rakefile +9 -7
- data/examples/auth-demo.rb +32 -0
- data/examples/auth-demo2.rb +37 -0
- data/examples/auth-form.tmpl +10 -0
- data/examples/auth-success.tmpl +3 -0
- data/examples/config.yml +12 -0
- data/examples/examples.css +4 -0
- data/examples/examples.html +31 -0
- data/examples/gen-config.rb +5 -2
- data/examples/layout.tmpl +31 -0
- data/lib/strelka/app/auth.rb +480 -0
- data/lib/strelka/app/sessions.rb +8 -6
- data/lib/strelka/app/templating.rb +78 -17
- data/lib/strelka/app.rb +13 -5
- data/lib/strelka/authprovider/basic.rb +134 -0
- data/lib/strelka/authprovider/hostaccess.rb +91 -0
- data/lib/strelka/authprovider.rb +122 -0
- data/lib/strelka/cookie.rb +1 -1
- data/lib/strelka/cookieset.rb +1 -1
- data/lib/strelka/httprequest/auth.rb +31 -0
- data/lib/strelka/logging.rb +69 -14
- data/lib/strelka/mixins.rb +35 -65
- data/lib/strelka/session/db.rb +115 -0
- data/lib/strelka/session/default.rb +38 -49
- data/lib/strelka/session.rb +1 -1
- data/lib/strelka.rb +4 -1
- data/spec/lib/helpers.rb +8 -3
- data/spec/strelka/app/auth_spec.rb +367 -0
- data/spec/strelka/authprovider/basic_spec.rb +192 -0
- data/spec/strelka/authprovider/hostaccess_spec.rb +70 -0
- data/spec/strelka/authprovider_spec.rb +99 -0
- data/spec/strelka/cookie_spec.rb +1 -1
- data/spec/strelka/httprequest/auth_spec.rb +55 -0
- data/spec/strelka/httprequest/session_spec.rb +63 -3
- data/spec/strelka/session/db_spec.rb +85 -0
- data/spec/strelka/session/default_spec.rb +5 -51
- data.tar.gz.sig +0 -0
- metadata +88 -57
- metadata.gz.sig +0 -0
@@ -0,0 +1,192 @@
|
|
1
|
+
# -*- rspec -*-
|
2
|
+
# vim: set nosta noet ts=4 sw=4:
|
3
|
+
|
4
|
+
BEGIN {
|
5
|
+
require 'pathname'
|
6
|
+
basedir = Pathname.new( __FILE__ ).dirname.parent.parent.parent
|
7
|
+
$LOAD_PATH.unshift( basedir ) unless $LOAD_PATH.include?( basedir )
|
8
|
+
}
|
9
|
+
|
10
|
+
require 'rspec'
|
11
|
+
require 'ipaddr'
|
12
|
+
|
13
|
+
require 'spec/lib/helpers'
|
14
|
+
|
15
|
+
require 'strelka'
|
16
|
+
require 'strelka/authprovider/basic'
|
17
|
+
|
18
|
+
|
19
|
+
#####################################################################
|
20
|
+
### C O N T E X T S
|
21
|
+
#####################################################################
|
22
|
+
|
23
|
+
describe Strelka::AuthProvider::Basic do
|
24
|
+
|
25
|
+
before( :all ) do
|
26
|
+
@request_factory = Mongrel2::RequestFactory.new( route: '/admin' )
|
27
|
+
setup_logging( :fatal )
|
28
|
+
end
|
29
|
+
|
30
|
+
before( :each ) do
|
31
|
+
@app = stub( "Strelka::App", :conn => stub("Connection", :app_id => 'test-app') )
|
32
|
+
@provider = Strelka::AuthProvider.create( :basic, @app )
|
33
|
+
@config = {
|
34
|
+
'realm' => 'Pern',
|
35
|
+
'users' => {
|
36
|
+
"lessa" => "8wiomemUvH/+CX8UJv3Yhu+X26k=",
|
37
|
+
"f'lar" => "NSeXAe7J5TTtJUE9epdaE6ojSYk=",
|
38
|
+
}
|
39
|
+
}
|
40
|
+
end
|
41
|
+
|
42
|
+
after( :each ) do
|
43
|
+
described_class.users = {}
|
44
|
+
described_class.realm = nil
|
45
|
+
end
|
46
|
+
|
47
|
+
after( :all ) do
|
48
|
+
reset_logging()
|
49
|
+
end
|
50
|
+
|
51
|
+
|
52
|
+
#
|
53
|
+
# Helpers
|
54
|
+
#
|
55
|
+
|
56
|
+
# Make a valid basic authorization header field
|
57
|
+
def make_authorization_header( username, password )
|
58
|
+
creds = [ username, password ].join( ':' )
|
59
|
+
return "Basic %s" % [ creds ].pack( 'm' )
|
60
|
+
end
|
61
|
+
|
62
|
+
|
63
|
+
#
|
64
|
+
# Examples
|
65
|
+
#
|
66
|
+
|
67
|
+
it "uses the app ID as the basic auth realm if none is explicitly configured" do
|
68
|
+
described_class.realm.should == @app.conn.app_id
|
69
|
+
end
|
70
|
+
|
71
|
+
it "can be configured via the Configurability API" do
|
72
|
+
described_class.configure( @config )
|
73
|
+
described_class.realm.should == @config['realm']
|
74
|
+
described_class.users.should == @config['users']
|
75
|
+
end
|
76
|
+
|
77
|
+
|
78
|
+
context "unconfigured" do
|
79
|
+
|
80
|
+
before( :each ) do
|
81
|
+
@expected_info = {
|
82
|
+
status: 401,
|
83
|
+
message: "Requires authentication.",
|
84
|
+
headers: {
|
85
|
+
www_authenticate: "Basic realm=test-app"
|
86
|
+
}
|
87
|
+
}
|
88
|
+
end
|
89
|
+
|
90
|
+
it "rejects a request with no Authorization header" do
|
91
|
+
req = @request_factory.get( '/admin/console' )
|
92
|
+
|
93
|
+
expect {
|
94
|
+
@provider.authenticate( req )
|
95
|
+
}.to throw_symbol( :finish, @expected_info )
|
96
|
+
end
|
97
|
+
|
98
|
+
it "rejects a request with credentials" do
|
99
|
+
req = @request_factory.get( '/admin/console' )
|
100
|
+
req.header.authorization = make_authorization_header( 'lessa', 'ramoth' )
|
101
|
+
|
102
|
+
expect {
|
103
|
+
@provider.authenticate( req )
|
104
|
+
}.to throw_symbol( :finish, @expected_info )
|
105
|
+
end
|
106
|
+
|
107
|
+
end
|
108
|
+
|
109
|
+
|
110
|
+
context "configured with at least one user" do
|
111
|
+
|
112
|
+
before( :each ) do
|
113
|
+
@expected_info = {
|
114
|
+
status: 401,
|
115
|
+
message: "Requires authentication.",
|
116
|
+
headers: {
|
117
|
+
www_authenticate: "Basic realm=Pern"
|
118
|
+
}
|
119
|
+
}
|
120
|
+
described_class.configure( @config )
|
121
|
+
end
|
122
|
+
|
123
|
+
it "rejects a request with no Authorization header" do
|
124
|
+
req = @request_factory.get( '/admin/console' )
|
125
|
+
expect {
|
126
|
+
@provider.authenticate( req )
|
127
|
+
}.to throw_symbol( :finish, @expected_info )
|
128
|
+
end
|
129
|
+
|
130
|
+
it "rejects a request with an authorization header for some other auth scheme" do
|
131
|
+
req = @request_factory.get( '/admin/console' )
|
132
|
+
req.header.authorization = %{Digest username="Mufasa",
|
133
|
+
realm="testrealm@host.com",
|
134
|
+
nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093",
|
135
|
+
uri="/dir/index.html",
|
136
|
+
qop=auth,
|
137
|
+
nc=00000001,
|
138
|
+
cnonce="0a4f113b",
|
139
|
+
response="6629fae49393a05397450978507c4ef1",
|
140
|
+
opaque="5ccc069c403ebaf9f0171e9517f40e41"}
|
141
|
+
|
142
|
+
expect {
|
143
|
+
@provider.authenticate( req )
|
144
|
+
}.to throw_symbol( :finish, @expected_info )
|
145
|
+
end
|
146
|
+
|
147
|
+
it "rejects a request with malformed credentials (no ':')" do
|
148
|
+
req = @request_factory.get( '/admin/console' )
|
149
|
+
req.header.authorization = "Basic %s" % ['fax'].pack('m')
|
150
|
+
|
151
|
+
expect {
|
152
|
+
@provider.authenticate( req )
|
153
|
+
}.to throw_symbol( :finish, @expected_info )
|
154
|
+
end
|
155
|
+
|
156
|
+
it "rejects a request with malformed credentials (invalid base64)" do
|
157
|
+
req = @request_factory.get( '/admin/console' )
|
158
|
+
req.header.authorization = "Basic \x06\x06\x18\x08\x36\x18\x02\x00"
|
159
|
+
|
160
|
+
expect {
|
161
|
+
@provider.authenticate( req )
|
162
|
+
}.to throw_symbol( :finish, @expected_info )
|
163
|
+
end
|
164
|
+
|
165
|
+
it "rejects a request with non-existant user credentials" do
|
166
|
+
req = @request_factory.get( '/admin/console' )
|
167
|
+
req.header.authorization = make_authorization_header( 'kendyl', 'charnoth' )
|
168
|
+
|
169
|
+
expect {
|
170
|
+
@provider.authenticate( req )
|
171
|
+
}.to throw_symbol( :finish, @expected_info )
|
172
|
+
end
|
173
|
+
|
174
|
+
it "rejects a request with a valid user, but the wrong password" do
|
175
|
+
req = @request_factory.get( '/admin/console' )
|
176
|
+
req.header.authorization = make_authorization_header( 'lessa', 'charnoth' )
|
177
|
+
|
178
|
+
expect {
|
179
|
+
@provider.authenticate( req )
|
180
|
+
}.to throw_symbol( :finish, @expected_info )
|
181
|
+
end
|
182
|
+
|
183
|
+
it "accepts a request with valid credentials" do
|
184
|
+
req = @request_factory.get( '/admin/console' )
|
185
|
+
req.header.authorization = make_authorization_header( 'lessa', 'ramoth' )
|
186
|
+
|
187
|
+
@provider.authenticate( req ).should be_true()
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
end
|
192
|
+
|
@@ -0,0 +1,70 @@
|
|
1
|
+
# -*- rspec -*-
|
2
|
+
# vim: set nosta noet ts=4 sw=4:
|
3
|
+
|
4
|
+
BEGIN {
|
5
|
+
require 'pathname'
|
6
|
+
basedir = Pathname.new( __FILE__ ).dirname.parent.parent.parent
|
7
|
+
$LOAD_PATH.unshift( basedir ) unless $LOAD_PATH.include?( basedir )
|
8
|
+
}
|
9
|
+
|
10
|
+
require 'rspec'
|
11
|
+
require 'ipaddr'
|
12
|
+
|
13
|
+
require 'spec/lib/helpers'
|
14
|
+
|
15
|
+
require 'strelka'
|
16
|
+
require 'strelka/authprovider/hostaccess'
|
17
|
+
|
18
|
+
|
19
|
+
#####################################################################
|
20
|
+
### C O N T E X T S
|
21
|
+
#####################################################################
|
22
|
+
|
23
|
+
describe Strelka::AuthProvider::HostAccess do
|
24
|
+
|
25
|
+
before( :all ) do
|
26
|
+
@request_factory = Mongrel2::RequestFactory.new( route: '/admin' )
|
27
|
+
setup_logging( :fatal )
|
28
|
+
end
|
29
|
+
|
30
|
+
before( :each ) do
|
31
|
+
@app = stub( "Strelka::App" )
|
32
|
+
@provider = Strelka::AuthProvider.create( :hostaccess, @app )
|
33
|
+
end
|
34
|
+
|
35
|
+
after( :all ) do
|
36
|
+
reset_logging()
|
37
|
+
end
|
38
|
+
|
39
|
+
|
40
|
+
it "knows what its allowed netblocks are" do
|
41
|
+
@provider.allowed_netblocks.should be_an( Array )
|
42
|
+
@provider.allowed_netblocks.should include( IPAddr.new('127.0.0.0/8') )
|
43
|
+
end
|
44
|
+
|
45
|
+
it "allows its netblocks to be set" do
|
46
|
+
@provider.allowed_netblocks = %w[10.5.2.0/22 10.6.2.0/24]
|
47
|
+
@provider.allowed_netblocks.should have( 2 ).members
|
48
|
+
@provider.allowed_netblocks.should include( IPAddr.new('10.5.2.0/22'), IPAddr.new('10.6.2.0/24') )
|
49
|
+
end
|
50
|
+
|
51
|
+
it "can be configured via the Configurability API" do
|
52
|
+
@provider.configure( 'allowed_netblocks' => %w[10.5.2.0/22 10.6.2.0/24] )
|
53
|
+
@provider.allowed_netblocks.should include( IPAddr.new('10.5.2.0/22'), IPAddr.new('10.6.2.0/24') )
|
54
|
+
end
|
55
|
+
|
56
|
+
|
57
|
+
it "allows a request that originates from one of its allowed netblocks" do
|
58
|
+
req = @request_factory.get( '/admin/console', :x_forwarded_for => '127.0.0.1' )
|
59
|
+
@provider.authorize( nil, req ).should be_true()
|
60
|
+
end
|
61
|
+
|
62
|
+
|
63
|
+
it "doesn't allow a request which is not from one of its allowed netblocks" do
|
64
|
+
req = @request_factory.get( '/admin/console', :x_forwarded_for => '8.8.8.8' )
|
65
|
+
@provider.authorize( nil, req ).should be_false()
|
66
|
+
end
|
67
|
+
|
68
|
+
|
69
|
+
end
|
70
|
+
|
@@ -0,0 +1,99 @@
|
|
1
|
+
# -*- rspec -*-
|
2
|
+
# vim: set nosta noet ts=4 sw=4:
|
3
|
+
|
4
|
+
BEGIN {
|
5
|
+
require 'pathname'
|
6
|
+
basedir = Pathname.new( __FILE__ ).dirname.parent.parent
|
7
|
+
$LOAD_PATH.unshift( basedir ) unless $LOAD_PATH.include?( basedir )
|
8
|
+
}
|
9
|
+
|
10
|
+
require 'rspec'
|
11
|
+
|
12
|
+
require 'spec/lib/helpers'
|
13
|
+
|
14
|
+
require 'strelka'
|
15
|
+
require 'strelka/authprovider'
|
16
|
+
|
17
|
+
|
18
|
+
#####################################################################
|
19
|
+
### C O N T E X T S
|
20
|
+
#####################################################################
|
21
|
+
|
22
|
+
describe Strelka::AuthProvider do
|
23
|
+
|
24
|
+
before( :all ) do
|
25
|
+
@request_factory = Mongrel2::RequestFactory.new( route: '/admin' )
|
26
|
+
setup_logging( :fatal )
|
27
|
+
end
|
28
|
+
|
29
|
+
after( :all ) do
|
30
|
+
reset_logging()
|
31
|
+
end
|
32
|
+
|
33
|
+
|
34
|
+
it "looks for plugins under strelka/authprovider" do
|
35
|
+
described_class.derivative_dirs.should include( 'strelka/authprovider' )
|
36
|
+
end
|
37
|
+
|
38
|
+
|
39
|
+
it "is abstract" do
|
40
|
+
expect {
|
41
|
+
described_class.new
|
42
|
+
}.to raise_error( /private method/i )
|
43
|
+
end
|
44
|
+
|
45
|
+
|
46
|
+
describe "a subclass" do
|
47
|
+
|
48
|
+
before( :each ) do
|
49
|
+
@subclass = Class.new( described_class )
|
50
|
+
@app = mock( "Application" )
|
51
|
+
@provider = @subclass.new( @app )
|
52
|
+
end
|
53
|
+
|
54
|
+
|
55
|
+
context "Authentication" do
|
56
|
+
|
57
|
+
it "returns 'anonymous' as credentials if asked to authenticate" do
|
58
|
+
req = @request_factory.get( '/admin/console' )
|
59
|
+
@provider.authenticate( req ).should == 'anonymous'
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
63
|
+
|
64
|
+
|
65
|
+
context "Authorization" do
|
66
|
+
|
67
|
+
it "doesn't fail if the application doesn't provide an authz callback" do
|
68
|
+
req = @request_factory.get( '/admin/console' )
|
69
|
+
expect {
|
70
|
+
@provider.authorize( 'anonymous', req )
|
71
|
+
}.to_not throw_symbol()
|
72
|
+
end
|
73
|
+
|
74
|
+
it "doesn't fail if the application's authz callback returns true" do
|
75
|
+
req = @request_factory.get( '/admin/console' )
|
76
|
+
expect {
|
77
|
+
@provider.authorize( 'anonymous', req ) { true }
|
78
|
+
}.to_not throw_symbol()
|
79
|
+
end
|
80
|
+
|
81
|
+
it "fails with a 403 (Forbidden) if the app's authz callback returns false" do
|
82
|
+
expected_info = {
|
83
|
+
status: 403,
|
84
|
+
message: "You are not authorized to access this resource.",
|
85
|
+
headers: {}
|
86
|
+
}
|
87
|
+
req = @request_factory.get( '/admin/console' )
|
88
|
+
|
89
|
+
expect {
|
90
|
+
@provider.authorize( 'anonymous', req ) { false }
|
91
|
+
}.to throw_symbol( :finish, expected_info )
|
92
|
+
end
|
93
|
+
|
94
|
+
end
|
95
|
+
|
96
|
+
end
|
97
|
+
|
98
|
+
end
|
99
|
+
|
data/spec/strelka/cookie_spec.rb
CHANGED
@@ -171,7 +171,7 @@ describe Strelka::Cookie do
|
|
171
171
|
|
172
172
|
it "stringifies with an expires date if one is set" do
|
173
173
|
@cookie.expires = Time.at( 1331761184 )
|
174
|
-
@cookie.to_s.should == 'by_rickirac=9917eb; Expires=Wed, 14
|
174
|
+
@cookie.to_s.should == 'by_rickirac=9917eb; Expires=Wed, 14 Mar 2012 21:39:44 GMT'
|
175
175
|
end
|
176
176
|
|
177
177
|
it "hashes the same as another cookie with the same name, regardless of value" do
|
@@ -0,0 +1,55 @@
|
|
1
|
+
# -*- rspec -*-
|
2
|
+
# vim: set nosta noet ts=4 sw=4:
|
3
|
+
|
4
|
+
BEGIN {
|
5
|
+
require 'pathname'
|
6
|
+
basedir = Pathname.new( __FILE__ ).dirname.parent.parent.parent
|
7
|
+
|
8
|
+
libdir = basedir + "lib"
|
9
|
+
|
10
|
+
$LOAD_PATH.unshift( basedir ) unless $LOAD_PATH.include?( basedir )
|
11
|
+
$LOAD_PATH.unshift( libdir ) unless $LOAD_PATH.include?( libdir )
|
12
|
+
}
|
13
|
+
|
14
|
+
require 'rspec'
|
15
|
+
|
16
|
+
require 'spec/lib/helpers'
|
17
|
+
|
18
|
+
require 'strelka'
|
19
|
+
require 'strelka/httprequest/auth'
|
20
|
+
|
21
|
+
|
22
|
+
#####################################################################
|
23
|
+
### C O N T E X T S
|
24
|
+
#####################################################################
|
25
|
+
|
26
|
+
describe Strelka::HTTPRequest::Auth do
|
27
|
+
|
28
|
+
before( :all ) do
|
29
|
+
setup_logging( :fatal )
|
30
|
+
@request_factory = Mongrel2::RequestFactory.new( route: '/service/user' )
|
31
|
+
end
|
32
|
+
|
33
|
+
after( :all ) do
|
34
|
+
reset_logging()
|
35
|
+
end
|
36
|
+
|
37
|
+
before( :each ) do
|
38
|
+
@req = @request_factory.get( '/service/user/estark' )
|
39
|
+
@req.extend( described_class )
|
40
|
+
end
|
41
|
+
|
42
|
+
|
43
|
+
it "adds an authenticated? predicate" do
|
44
|
+
@req.should_not be_authenticated()
|
45
|
+
@req.authenticated_user = 'anonymous'
|
46
|
+
@req.should be_authenticated()
|
47
|
+
end
|
48
|
+
|
49
|
+
it "adds an authenticated_user attribute" do
|
50
|
+
@req.authenticated_user.should be_nil()
|
51
|
+
@req.authenticated_user = 'someone'
|
52
|
+
@req.authenticated_user.should == 'someone'
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
@@ -16,7 +16,9 @@ require 'rspec'
|
|
16
16
|
require 'spec/lib/helpers'
|
17
17
|
|
18
18
|
require 'strelka'
|
19
|
+
require 'strelka/app/sessions'
|
19
20
|
require 'strelka/httprequest/session'
|
21
|
+
require 'strelka/session/default'
|
20
22
|
|
21
23
|
|
22
24
|
#####################################################################
|
@@ -28,16 +30,74 @@ describe Strelka::HTTPRequest::Session do
|
|
28
30
|
before( :all ) do
|
29
31
|
setup_logging( :fatal )
|
30
32
|
@request_factory = Mongrel2::RequestFactory.new( route: '/service/user' )
|
33
|
+
Strelka::App::Sessions.configure( session_class: 'default' )
|
34
|
+
end
|
35
|
+
|
36
|
+
before( :each ) do
|
37
|
+
@req = @request_factory.get( '/service/user/estark' )
|
38
|
+
Strelka.log.debug "Extending request %p" % [ @req ]
|
39
|
+
@req.extend( described_class )
|
40
|
+
end
|
41
|
+
|
42
|
+
after( :each ) do
|
43
|
+
Strelka::Session::Default.sessions.clear
|
31
44
|
end
|
32
45
|
|
33
46
|
after( :all ) do
|
34
47
|
reset_logging()
|
35
48
|
end
|
36
49
|
|
37
|
-
|
38
|
-
|
39
|
-
|
50
|
+
|
51
|
+
describe "an HTTPRequest with no session loaded" do
|
52
|
+
|
53
|
+
it "has a session_namespace attribute" do
|
54
|
+
@req.should respond_to( :session_namespace )
|
55
|
+
end
|
56
|
+
|
57
|
+
it "knows whether or not it has loaded a session" do
|
58
|
+
@req.session?.should be_false()
|
59
|
+
end
|
60
|
+
|
61
|
+
it "doesn't load the session when the session namespace is set" do
|
62
|
+
@req.session_namespace = 'an_appid'
|
63
|
+
@req.session?.should be_false()
|
64
|
+
end
|
65
|
+
|
66
|
+
it "loads the session as soon as it's accessed" do
|
67
|
+
@req.session.should be_a( Strelka::Session::Default )
|
68
|
+
end
|
69
|
+
|
70
|
+
it "sets the session's namespace when it's loaded" do
|
71
|
+
@req.session_namespace = 'an_appid'
|
72
|
+
@req.session.namespace.should == :an_appid
|
73
|
+
end
|
74
|
+
|
75
|
+
it "sets a session's namespace when it's set directly" do
|
76
|
+
@req.should respond_to( :session_namespace= )
|
77
|
+
@req.session_namespace = 'the_appid'
|
78
|
+
|
79
|
+
session = mock( "session object" )
|
80
|
+
session.should_receive( :namespace= ).with( 'the_appid' )
|
81
|
+
|
82
|
+
@req.session = session
|
83
|
+
end
|
84
|
+
|
40
85
|
end
|
41
86
|
|
42
87
|
|
88
|
+
describe "an HTTPRequest with a session loaded" do
|
89
|
+
|
90
|
+
before( :each ) do
|
91
|
+
@req.session_namespace = 'other_appid'
|
92
|
+
@req.session
|
93
|
+
end
|
94
|
+
|
95
|
+
it "sets its session's namespace when its session_namespace attribute is set" do
|
96
|
+
@req.session.namespace.should == :other_appid
|
97
|
+
@req.session_namespace = 'an_appid'
|
98
|
+
@req.session.namespace.should == :an_appid
|
99
|
+
end
|
100
|
+
|
101
|
+
end
|
102
|
+
|
43
103
|
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
# -*- rspec -*-
|
2
|
+
# vim: set nosta noet ts=4 sw=4:
|
3
|
+
|
4
|
+
BEGIN {
|
5
|
+
require 'pathname'
|
6
|
+
basedir = Pathname.new( __FILE__ ).dirname.parent.parent.parent
|
7
|
+
$LOAD_PATH.unshift( basedir ) unless $LOAD_PATH.include?( basedir )
|
8
|
+
}
|
9
|
+
|
10
|
+
require 'rspec'
|
11
|
+
|
12
|
+
require 'spec/lib/helpers'
|
13
|
+
|
14
|
+
require 'strelka'
|
15
|
+
require 'strelka/session/db'
|
16
|
+
|
17
|
+
|
18
|
+
#####################################################################
|
19
|
+
### C O N T E X T S
|
20
|
+
#####################################################################
|
21
|
+
|
22
|
+
describe Strelka::Session::Db do
|
23
|
+
|
24
|
+
before( :all ) do
|
25
|
+
@request_factory = Mongrel2::RequestFactory.new( route: '/frothy' )
|
26
|
+
setup_logging( :fatal )
|
27
|
+
|
28
|
+
@session_id = 'f9df9436f02f9b6d099a3dc95614fdb4'
|
29
|
+
@session_data = {
|
30
|
+
:namespace => {
|
31
|
+
:hurrrg => true
|
32
|
+
}
|
33
|
+
}
|
34
|
+
end
|
35
|
+
|
36
|
+
before( :each ) do
|
37
|
+
@cookie_name = described_class.cookie_options[:name]
|
38
|
+
described_class.configure
|
39
|
+
end
|
40
|
+
|
41
|
+
after( :each ) do
|
42
|
+
described_class.db.drop_table( :sessions ) if
|
43
|
+
described_class.db.table_exists?( :sessions )
|
44
|
+
end
|
45
|
+
|
46
|
+
after( :all ) do
|
47
|
+
reset_logging()
|
48
|
+
end
|
49
|
+
|
50
|
+
|
51
|
+
it "creates the database if needed" do
|
52
|
+
described_class.db.table_exists?( :sessions ).should be_true()
|
53
|
+
end
|
54
|
+
|
55
|
+
|
56
|
+
it "can change the default table name" do
|
57
|
+
described_class.configure( :table_name => :brothy )
|
58
|
+
described_class.db.table_exists?( :brothy ).should be_true()
|
59
|
+
described_class.db.drop_table( :brothy )
|
60
|
+
end
|
61
|
+
|
62
|
+
|
63
|
+
it "can load an existing session from the sessions table" do
|
64
|
+
described_class.dataset.insert(
|
65
|
+
:session_id => @session_id,
|
66
|
+
:session => @session_data.to_yaml )
|
67
|
+
|
68
|
+
session = described_class.load( @session_id )
|
69
|
+
session.namespaced_hash.should == @session_data
|
70
|
+
end
|
71
|
+
|
72
|
+
|
73
|
+
it "can save session data to the database" do
|
74
|
+
req = @request_factory.get( '/frothy/broth' )
|
75
|
+
response = req.response
|
76
|
+
session = described_class.new( @session_id, @session_data )
|
77
|
+
session.save( response )
|
78
|
+
|
79
|
+
row = session.class.dataset.filter( :session_id => @session_id ).first
|
80
|
+
row[ :session_id ].should == @session_id
|
81
|
+
row[ :session ].should =~ /hurrrg: true/
|
82
|
+
row[ :created ].to_s.should =~ /\d{4}-\d{2}-\d{2}/
|
83
|
+
response.header_data.should =~ /Set-Cookie: #{@cookie_name}=#{@session_id}/i
|
84
|
+
end
|
85
|
+
end
|
@@ -27,7 +27,7 @@ describe Strelka::Session::Default do
|
|
27
27
|
end
|
28
28
|
|
29
29
|
before( :each ) do
|
30
|
-
|
30
|
+
@cookie_name = described_class.cookie_options[:name]
|
31
31
|
end
|
32
32
|
|
33
33
|
after( :each ) do
|
@@ -47,8 +47,8 @@ describe Strelka::Session::Default do
|
|
47
47
|
|
48
48
|
|
49
49
|
it "can be configured to store its session ID in a different cookie" do
|
50
|
-
described_class.configure( :
|
51
|
-
described_class.
|
50
|
+
described_class.configure( :cookie => {:name => 'buh-mahlon'} )
|
51
|
+
described_class.cookie_options[:name].should == 'buh-mahlon'
|
52
52
|
end
|
53
53
|
|
54
54
|
it "can load sessions from and save sessions to its in-memory store" do
|
@@ -73,7 +73,7 @@ describe Strelka::Session::Default do
|
|
73
73
|
|
74
74
|
it "accepts and reuses an existing valid session-id" do
|
75
75
|
session_id = '3422067061a5790be374c81118d9ed3f'
|
76
|
-
session_cookie = "
|
76
|
+
session_cookie = "buh-mahlon=%s" % [ session_id ]
|
77
77
|
req = @request_factory.get( '/hungry/what-is-in-a-fruit-bowl?', :cookie => session_cookie )
|
78
78
|
described_class.get_session_id( req ).should == session_id
|
79
79
|
end
|
@@ -89,7 +89,7 @@ describe Strelka::Session::Default do
|
|
89
89
|
session.save( response )
|
90
90
|
|
91
91
|
described_class.sessions.should == { session_id => session_data }
|
92
|
-
response.header_data.should =~ /Set-Cookie: #{
|
92
|
+
response.header_data.should =~ /Set-Cookie: #{@cookie_name}=#{session_id}/i
|
93
93
|
end
|
94
94
|
|
95
95
|
describe "with no namespace set (the 'nil' namespace)" do
|
@@ -113,9 +113,6 @@ describe Strelka::Session::Default do
|
|
113
113
|
|
114
114
|
subject.namespace = nil
|
115
115
|
|
116
|
-
subject.keys.should have( 2 ).members
|
117
|
-
subject.keys.should include( :foo, :bar )
|
118
|
-
subject.values.should all_be_a( Hash )
|
119
116
|
subject[:foo][:number].should == 18
|
120
117
|
subject[:bar][:number].should == 28
|
121
118
|
end
|
@@ -131,23 +128,6 @@ describe Strelka::Session::Default do
|
|
131
128
|
subject.greet[ :testkey ].should be_true
|
132
129
|
subject.pork[ :testkey ].should be_nil
|
133
130
|
end
|
134
|
-
|
135
|
-
it "is Enumerable (over the hash of namespaces)" do
|
136
|
-
subject.namespace = :meta
|
137
|
-
subject.create_me = :yes
|
138
|
-
subject.namespace = :tetra
|
139
|
-
subject.create_me = :yes
|
140
|
-
subject.namespace = nil
|
141
|
-
|
142
|
-
subject.map {|k,v| k }.should include( :meta, :tetra )
|
143
|
-
end
|
144
|
-
|
145
|
-
it "can merge namespaces into the session" do
|
146
|
-
subject.merge!( :app1 => {:foom => 88}, :app2 => {:foom => 188} )
|
147
|
-
subject.app1[:foom].should == 88
|
148
|
-
subject.app2[:foom].should == 188
|
149
|
-
end
|
150
|
-
|
151
131
|
end
|
152
132
|
|
153
133
|
|
@@ -168,8 +148,6 @@ describe Strelka::Session::Default do
|
|
168
148
|
subject[:number] = 18
|
169
149
|
subject[:not_a_number] = 'woo'
|
170
150
|
|
171
|
-
subject.keys.should have( 2 ).members
|
172
|
-
subject.keys.should include( :number, :not_a_number )
|
173
151
|
subject[:number].should == 18
|
174
152
|
subject[:not_a_number].should == 'woo'
|
175
153
|
end
|
@@ -180,30 +158,6 @@ describe Strelka::Session::Default do
|
|
180
158
|
subject.testkey.should be_true
|
181
159
|
subject.i_do_not_exist.should be_nil
|
182
160
|
end
|
183
|
-
|
184
|
-
it "is Enumerable (over the namespaced hash)" do
|
185
|
-
subject.namespace = :meta
|
186
|
-
subject.create_me = :yes
|
187
|
-
subject.destroy_me = :yes
|
188
|
-
subject.whip_me = :definitely
|
189
|
-
subject.beat_me = :indubitably
|
190
|
-
|
191
|
-
banner = subject.each_with_object('Hey!') do |(k,v),accum|
|
192
|
-
accum << "#{k} "
|
193
|
-
end
|
194
|
-
|
195
|
-
banner.should =~ /create_me/
|
196
|
-
banner.should =~ /destroy_me/
|
197
|
-
banner.should =~ /whip_me/
|
198
|
-
banner.should =~ /beat_me/
|
199
|
-
end
|
200
|
-
|
201
|
-
it "can merge a hash into the namespace" do
|
202
|
-
subject.merge!( :app1 => {:foom => 88}, :app2 => {:foom => 188} )
|
203
|
-
subject.app1[:foom].should == 88
|
204
|
-
subject.app2[:foom].should == 188
|
205
|
-
end
|
206
|
-
|
207
161
|
end
|
208
162
|
|
209
163
|
end
|