strelka 0.0.1.pre148 → 0.0.1.pre177
Sign up to get free protection for your applications and to get access to all the features.
- 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
|