arrow 1.0.7
Sign up to get free protection for your applications and to get access to all the features.
- data/ChangeLog +1590 -0
- data/LICENSE +28 -0
- data/README +75 -0
- data/Rakefile +366 -0
- data/Rakefile.local +63 -0
- data/data/arrow/applets/TEMPLATE.rb.tpl +53 -0
- data/data/arrow/applets/args.rb +50 -0
- data/data/arrow/applets/config.rb +55 -0
- data/data/arrow/applets/error.rb +63 -0
- data/data/arrow/applets/files.rb +46 -0
- data/data/arrow/applets/inspect.rb +46 -0
- data/data/arrow/applets/nosuchapplet.rb +31 -0
- data/data/arrow/applets/status.rb +92 -0
- data/data/arrow/applets/test.rb +133 -0
- data/data/arrow/applets/tutorial/counter.rb +96 -0
- data/data/arrow/applets/tutorial/dingus.rb +67 -0
- data/data/arrow/applets/tutorial/hello.rb +34 -0
- data/data/arrow/applets/tutorial/hello2.rb +73 -0
- data/data/arrow/applets/tutorial/imgtext.rb +90 -0
- data/data/arrow/applets/tutorial/imgtext2.rb +286 -0
- data/data/arrow/applets/tutorial/index.rb +36 -0
- data/data/arrow/applets/tutorial/logo.rb +98 -0
- data/data/arrow/applets/tutorial/memcache.rb +61 -0
- data/data/arrow/applets/tutorial/missing.rb +37 -0
- data/data/arrow/applets/tutorial/protected.rb +100 -0
- data/data/arrow/applets/tutorial/redirector.rb +52 -0
- data/data/arrow/applets/tutorial/rndimages.rb +159 -0
- data/data/arrow/applets/tutorial/sharenotes.rb +83 -0
- data/data/arrow/applets/tutorial/subclassed-hello.rb +32 -0
- data/data/arrow/applets/tutorial/superhello.rb +72 -0
- data/data/arrow/applets/tutorial/timeclock.rb +78 -0
- data/data/arrow/applets/view-applet.rb +123 -0
- data/data/arrow/applets/view-template.rb +85 -0
- data/data/arrow/applets/wiki.rb +274 -0
- data/data/arrow/templates/TEMPLATE.tmpl.tpl +36 -0
- data/data/arrow/templates/applet-status.tmpl +153 -0
- data/data/arrow/templates/args-display.tmpl +120 -0
- data/data/arrow/templates/config/display-table.tmpl +36 -0
- data/data/arrow/templates/config/display.tmpl +36 -0
- data/data/arrow/templates/counter-deleted.tmpl +33 -0
- data/data/arrow/templates/counter.tmpl +59 -0
- data/data/arrow/templates/dingus.tmpl +55 -0
- data/data/arrow/templates/enumtable.tmpl +8 -0
- data/data/arrow/templates/error-display.tmpl +92 -0
- data/data/arrow/templates/filemap.tmpl +89 -0
- data/data/arrow/templates/hello-world-src.tmpl +34 -0
- data/data/arrow/templates/hello-world.tmpl +60 -0
- data/data/arrow/templates/imgtext/fontlist.tmpl +46 -0
- data/data/arrow/templates/imgtext/form.tmpl +70 -0
- data/data/arrow/templates/imgtext/reload-error.tmpl +40 -0
- data/data/arrow/templates/imgtext/reload.tmpl +55 -0
- data/data/arrow/templates/inspect/display.tmpl +80 -0
- data/data/arrow/templates/loginform.tmpl +64 -0
- data/data/arrow/templates/logout.tmpl +32 -0
- data/data/arrow/templates/memcache/display.tmpl +41 -0
- data/data/arrow/templates/navbar.incl +27 -0
- data/data/arrow/templates/nosuchapplet.tmpl +32 -0
- data/data/arrow/templates/printsource.tmpl +35 -0
- data/data/arrow/templates/protected.tmpl +36 -0
- data/data/arrow/templates/rndimages.tmpl +38 -0
- data/data/arrow/templates/service-response.tmpl +13 -0
- data/data/arrow/templates/sharenotes/display.tmpl +38 -0
- data/data/arrow/templates/status.tmpl +120 -0
- data/data/arrow/templates/templateviewer.tmpl +43 -0
- data/data/arrow/templates/test/harness.tmpl +57 -0
- data/data/arrow/templates/test/list.tmpl +48 -0
- data/data/arrow/templates/test/problem.tmpl +42 -0
- data/data/arrow/templates/tutorial/index.tmpl +37 -0
- data/data/arrow/templates/tutorial/missingapplet.tmpl +29 -0
- data/data/arrow/templates/view-applet-nosuch.tmpl +32 -0
- data/data/arrow/templates/view-applet.tmpl +40 -0
- data/data/arrow/templates/view-template.tmpl +83 -0
- data/data/arrow/templates/wiki/formerror.tmpl +47 -0
- data/data/arrow/templates/wiki/markup_help.incl +6 -0
- data/data/arrow/templates/wiki/new.tmpl +56 -0
- data/data/arrow/templates/wiki/new_system.tmpl +122 -0
- data/data/arrow/templates/wiki/sectionlist.tmpl +43 -0
- data/data/arrow/templates/wiki/show.tmpl +34 -0
- data/docs/manual/layouts/default.page +43 -0
- data/docs/manual/lib/api-filter.rb +81 -0
- data/docs/manual/lib/editorial-filter.rb +64 -0
- data/docs/manual/lib/examples-filter.rb +244 -0
- data/docs/manual/lib/links-filter.rb +117 -0
- data/lib/apache/fakerequest.rb +448 -0
- data/lib/apache/logger.rb +33 -0
- data/lib/arrow.rb +51 -0
- data/lib/arrow/acceptparam.rb +207 -0
- data/lib/arrow/applet.rb +725 -0
- data/lib/arrow/appletmixins.rb +218 -0
- data/lib/arrow/appletregistry.rb +590 -0
- data/lib/arrow/applettestcase.rb +503 -0
- data/lib/arrow/broker.rb +255 -0
- data/lib/arrow/cache.rb +176 -0
- data/lib/arrow/config-loaders/yaml.rb +75 -0
- data/lib/arrow/config.rb +615 -0
- data/lib/arrow/constants.rb +24 -0
- data/lib/arrow/cookie.rb +359 -0
- data/lib/arrow/cookieset.rb +108 -0
- data/lib/arrow/dispatcher.rb +368 -0
- data/lib/arrow/dispatcherloader.rb +50 -0
- data/lib/arrow/exceptions.rb +61 -0
- data/lib/arrow/fallbackhandler.rb +48 -0
- data/lib/arrow/formvalidator.rb +631 -0
- data/lib/arrow/htmltokenizer.rb +343 -0
- data/lib/arrow/logger.rb +488 -0
- data/lib/arrow/logger/apacheoutputter.rb +69 -0
- data/lib/arrow/logger/arrayoutputter.rb +63 -0
- data/lib/arrow/logger/coloroutputter.rb +111 -0
- data/lib/arrow/logger/fileoutputter.rb +96 -0
- data/lib/arrow/logger/htmloutputter.rb +54 -0
- data/lib/arrow/logger/outputter.rb +123 -0
- data/lib/arrow/mixins.rb +425 -0
- data/lib/arrow/monkeypatches.rb +94 -0
- data/lib/arrow/object.rb +117 -0
- data/lib/arrow/path.rb +196 -0
- data/lib/arrow/service.rb +447 -0
- data/lib/arrow/session.rb +289 -0
- data/lib/arrow/session/dbstore.rb +100 -0
- data/lib/arrow/session/filelock.rb +160 -0
- data/lib/arrow/session/filestore.rb +132 -0
- data/lib/arrow/session/id.rb +98 -0
- data/lib/arrow/session/lock.rb +253 -0
- data/lib/arrow/session/md5id.rb +42 -0
- data/lib/arrow/session/nulllock.rb +42 -0
- data/lib/arrow/session/posixlock.rb +166 -0
- data/lib/arrow/session/sha1id.rb +54 -0
- data/lib/arrow/session/store.rb +366 -0
- data/lib/arrow/session/usertrackid.rb +52 -0
- data/lib/arrow/spechelpers.rb +73 -0
- data/lib/arrow/template.rb +713 -0
- data/lib/arrow/template/attr.rb +31 -0
- data/lib/arrow/template/call.rb +31 -0
- data/lib/arrow/template/comment.rb +33 -0
- data/lib/arrow/template/container.rb +118 -0
- data/lib/arrow/template/else.rb +41 -0
- data/lib/arrow/template/elsif.rb +44 -0
- data/lib/arrow/template/escape.rb +53 -0
- data/lib/arrow/template/export.rb +87 -0
- data/lib/arrow/template/for.rb +145 -0
- data/lib/arrow/template/if.rb +78 -0
- data/lib/arrow/template/import.rb +119 -0
- data/lib/arrow/template/include.rb +206 -0
- data/lib/arrow/template/iterator.rb +208 -0
- data/lib/arrow/template/nodes.rb +734 -0
- data/lib/arrow/template/parser.rb +571 -0
- data/lib/arrow/template/prettyprint.rb +53 -0
- data/lib/arrow/template/render.rb +191 -0
- data/lib/arrow/template/selectlist.rb +94 -0
- data/lib/arrow/template/set.rb +87 -0
- data/lib/arrow/template/timedelta.rb +81 -0
- data/lib/arrow/template/unless.rb +78 -0
- data/lib/arrow/template/urlencode.rb +51 -0
- data/lib/arrow/template/yield.rb +139 -0
- data/lib/arrow/templatefactory.rb +125 -0
- data/lib/arrow/testcase.rb +567 -0
- data/lib/arrow/transaction.rb +608 -0
- data/rake/191_compat.rb +26 -0
- data/rake/dependencies.rb +76 -0
- data/rake/documentation.rb +114 -0
- data/rake/helpers.rb +502 -0
- data/rake/hg.rb +282 -0
- data/rake/manual.rb +787 -0
- data/rake/packaging.rb +129 -0
- data/rake/publishing.rb +278 -0
- data/rake/style.rb +62 -0
- data/rake/svn.rb +668 -0
- data/rake/testing.rb +187 -0
- data/rake/verifytask.rb +64 -0
- data/spec/arrow/acceptparam_spec.rb +157 -0
- data/spec/arrow/applet_spec.rb +575 -0
- data/spec/arrow/appletmixins_spec.rb +409 -0
- data/spec/arrow/appletregistry_spec.rb +294 -0
- data/spec/arrow/broker_spec.rb +153 -0
- data/spec/arrow/config_spec.rb +224 -0
- data/spec/arrow/cookieset_spec.rb +164 -0
- data/spec/arrow/dispatcher_spec.rb +137 -0
- data/spec/arrow/dispatcherloader_spec.rb +65 -0
- data/spec/arrow/formvalidator_spec.rb +781 -0
- data/spec/arrow/logger_spec.rb +346 -0
- data/spec/arrow/mixins_spec.rb +120 -0
- data/spec/arrow/service_spec.rb +645 -0
- data/spec/arrow/session_spec.rb +121 -0
- data/spec/arrow/template/iterator_spec.rb +222 -0
- data/spec/arrow/templatefactory_spec.rb +185 -0
- data/spec/arrow/transaction_spec.rb +319 -0
- data/spec/arrow_spec.rb +37 -0
- data/spec/lib/appletmatchers.rb +281 -0
- data/spec/lib/constants.rb +77 -0
- data/spec/lib/helpers.rb +41 -0
- data/spec/lib/matchers.rb +44 -0
- data/tests/cookie.tests.rb +310 -0
- data/tests/path.tests.rb +157 -0
- data/tests/session.tests.rb +111 -0
- data/tests/session_id.tests.rb +82 -0
- data/tests/session_lock.tests.rb +191 -0
- data/tests/session_store.tests.rb +53 -0
- data/tests/template.tests.rb +1360 -0
- metadata +339 -0
@@ -0,0 +1,409 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
BEGIN {
|
4
|
+
require 'pathname'
|
5
|
+
basedir = Pathname.new( __FILE__ ).dirname.parent.parent
|
6
|
+
|
7
|
+
libdir = basedir + "lib"
|
8
|
+
|
9
|
+
$LOAD_PATH.unshift( libdir ) unless $LOAD_PATH.include?( libdir )
|
10
|
+
}
|
11
|
+
|
12
|
+
|
13
|
+
require 'spec'
|
14
|
+
require 'spec/lib/constants'
|
15
|
+
require 'spec/lib/helpers'
|
16
|
+
require 'spec/lib/appletmatchers'
|
17
|
+
|
18
|
+
require 'arrow'
|
19
|
+
require 'arrow/applet'
|
20
|
+
require 'arrow/appletmixins'
|
21
|
+
|
22
|
+
|
23
|
+
include Arrow::TestConstants
|
24
|
+
|
25
|
+
#####################################################################
|
26
|
+
### C O N T E X T S
|
27
|
+
#####################################################################
|
28
|
+
|
29
|
+
describe Arrow::AppletAuthentication do
|
30
|
+
include Arrow::SpecHelpers,
|
31
|
+
Arrow::AppletMatchers
|
32
|
+
|
33
|
+
before( :all ) do
|
34
|
+
setup_logging( :crit )
|
35
|
+
end
|
36
|
+
|
37
|
+
after( :all ) do
|
38
|
+
reset_logging()
|
39
|
+
end
|
40
|
+
|
41
|
+
|
42
|
+
before( :each ) do
|
43
|
+
@uri = '/testing'
|
44
|
+
@connection = stub( "apache connnection", :remote_host => 'host' )
|
45
|
+
@txn = stub( "transaction", :uri => @uri, :vargs => true, :user => nil,
|
46
|
+
:authorized => false, :the_request => 'the request',
|
47
|
+
:connection => @connection, :remote_host => '127.0.0.1' )
|
48
|
+
end
|
49
|
+
|
50
|
+
|
51
|
+
describe "included by an Applet" do
|
52
|
+
|
53
|
+
describe " that doesn't override any of the auth methods" do
|
54
|
+
before( :all ) do
|
55
|
+
@appletclass = Class.new( Arrow::Applet ) do
|
56
|
+
include Arrow::AppletAuthentication
|
57
|
+
|
58
|
+
applet_name "Hi, I'm a fixture applet!"
|
59
|
+
|
60
|
+
def initialize( *args )
|
61
|
+
@authenticated = false
|
62
|
+
@authorized = false
|
63
|
+
super
|
64
|
+
end
|
65
|
+
|
66
|
+
attr_reader :authenticated, :authorized
|
67
|
+
|
68
|
+
def authenticated_action( txn )
|
69
|
+
with_authentication( txn ) do |user|
|
70
|
+
@authenticated = true
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def authorized_action( txn )
|
75
|
+
with_authorization( txn ) do
|
76
|
+
@authorized = true
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
before( :each ) do
|
83
|
+
@applet = @appletclass.new( nil, nil, nil )
|
84
|
+
end
|
85
|
+
|
86
|
+
it "returns an UNAUTHORIZED response for an action wrapped in authentication" do
|
87
|
+
@txn.should_receive( :status= ).with( Apache::HTTP_UNAUTHORIZED )
|
88
|
+
@applet.authenticated_action( @txn ).should =~ /requires auth/i
|
89
|
+
@applet.authenticated.should be_false()
|
90
|
+
end
|
91
|
+
|
92
|
+
it "returns an UNAUTHORIZED response for an action wrapped in authorization" do
|
93
|
+
@txn.should_receive( :status= ).with( Apache::HTTP_UNAUTHORIZED )
|
94
|
+
@applet.authorized_action( @txn ).should =~ /requires auth/i
|
95
|
+
@applet.authorized.should be_false()
|
96
|
+
end
|
97
|
+
|
98
|
+
end
|
99
|
+
|
100
|
+
describe " that provides an implementation of #get_authenticated_user" do
|
101
|
+
before( :all ) do
|
102
|
+
@appletclass = Class.new( Arrow::Applet ) do
|
103
|
+
include Arrow::AppletAuthentication
|
104
|
+
|
105
|
+
applet_name "Hi, I'm a fixture applet!"
|
106
|
+
|
107
|
+
def initialize( *args )
|
108
|
+
@authenticated = false
|
109
|
+
@authorized = false
|
110
|
+
super
|
111
|
+
end
|
112
|
+
|
113
|
+
attr_reader :authenticated, :authorized
|
114
|
+
|
115
|
+
def authenticated_action( txn )
|
116
|
+
with_authentication( txn ) do |user|
|
117
|
+
@authenticated = true
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
def authorized_action( txn )
|
122
|
+
with_authorization( txn ) do
|
123
|
+
@authorized = true
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
def get_authenticated_user( txn )
|
128
|
+
return txn.user
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
before( :each ) do
|
134
|
+
@applet = @appletclass.new( nil, nil, nil )
|
135
|
+
end
|
136
|
+
|
137
|
+
it "returns an UNAUTHORIZED response for an action wrapped in authentication if " +
|
138
|
+
"the transaction doesn't contain a user" do
|
139
|
+
@txn.should_receive( :status= ).with( Apache::HTTP_UNAUTHORIZED )
|
140
|
+
@applet.authenticated_action( @txn ).should =~ /requires auth/i
|
141
|
+
@applet.authenticated.should be_false()
|
142
|
+
end
|
143
|
+
|
144
|
+
it "returns a normal response for an action wrapped in authentication if " +
|
145
|
+
"the transaction does contain a user" do
|
146
|
+
@txn.stub!( :user ).and_return( :barney_the_clown )
|
147
|
+
@applet.authenticated_action( @txn ).should == true
|
148
|
+
@applet.authenticated.should be_true()
|
149
|
+
end
|
150
|
+
|
151
|
+
it "returns an UNAUTHORIZED response for an action wrapped in authorization if " +
|
152
|
+
"the transaction doesn't contain a user" do
|
153
|
+
@txn.should_receive( :status= ).with( Apache::HTTP_UNAUTHORIZED )
|
154
|
+
@applet.authenticated_action( @txn ).should =~ /requires auth/i
|
155
|
+
@applet.authorized.should be_false()
|
156
|
+
end
|
157
|
+
|
158
|
+
it "returns a FORBIDDEN response for an action wrapped in authorization if " +
|
159
|
+
"the transaction does contain a user" do
|
160
|
+
@txn.stub!( :user ).and_return( :blinky_the_wombat )
|
161
|
+
@txn.should_receive( :status= ).with( Apache::FORBIDDEN )
|
162
|
+
@applet.authorized_action( @txn ).should =~ /access denied/i
|
163
|
+
@applet.authorized.should be_false()
|
164
|
+
end
|
165
|
+
|
166
|
+
end
|
167
|
+
|
168
|
+
describe " that also provides an implementation of #user_is_authorized" do
|
169
|
+
before( :all ) do
|
170
|
+
@appletclass = Class.new( Arrow::Applet ) do
|
171
|
+
include Arrow::AppletAuthentication
|
172
|
+
|
173
|
+
applet_name "Hi, I'm a fixture applet!"
|
174
|
+
|
175
|
+
def initialize( *args )
|
176
|
+
@authenticated = false
|
177
|
+
@authorized = false
|
178
|
+
super
|
179
|
+
end
|
180
|
+
|
181
|
+
attr_reader :authenticated, :authorized
|
182
|
+
|
183
|
+
def authenticated_action( txn )
|
184
|
+
with_authentication( txn ) do |user|
|
185
|
+
@authenticated = true
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
def authorized_action( txn )
|
190
|
+
with_authorization( txn ) do
|
191
|
+
@authorized = true
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
def get_authenticated_user( txn )
|
196
|
+
# Simplified for testing -- lets the test set whether or not authentication
|
197
|
+
# exists
|
198
|
+
return txn.user
|
199
|
+
end
|
200
|
+
|
201
|
+
def user_is_authorized( user, txn )
|
202
|
+
# Simplified for testing -- lets the test set whether or not authorization
|
203
|
+
# exists
|
204
|
+
return txn.authorized
|
205
|
+
end
|
206
|
+
end
|
207
|
+
end
|
208
|
+
|
209
|
+
before( :each ) do
|
210
|
+
@applet = @appletclass.new( nil, nil, nil )
|
211
|
+
end
|
212
|
+
|
213
|
+
it "returns an UNAUTHORIZED response for an action wrapped in authentication if " +
|
214
|
+
"the transaction doesn't contain a user" do
|
215
|
+
@txn.should_receive( :status= ).with( Apache::HTTP_UNAUTHORIZED )
|
216
|
+
@applet.authenticated_action( @txn ).should =~ /requires auth/i
|
217
|
+
@applet.authenticated.should be_false()
|
218
|
+
@applet.authorized.should be_false()
|
219
|
+
end
|
220
|
+
|
221
|
+
it "returns a FORBIDDEN response for an action wrapped in authentication if " +
|
222
|
+
"the transaction does contain a user" do
|
223
|
+
@txn.stub!( :user ).and_return( :barney_the_clown )
|
224
|
+
@applet.authenticated_action( @txn ).should == true
|
225
|
+
@applet.authenticated.should be_true()
|
226
|
+
@applet.authorized.should be_false()
|
227
|
+
end
|
228
|
+
|
229
|
+
it "returns an UNAUTHORIZED response for an action wrapped in authorization if " +
|
230
|
+
"the transaction doesn't contain a user" do
|
231
|
+
@txn.should_receive( :status= ).with( Apache::HTTP_UNAUTHORIZED )
|
232
|
+
@applet.authenticated_action( @txn ).should =~ /requires auth/i
|
233
|
+
@applet.authorized.should be_false()
|
234
|
+
end
|
235
|
+
|
236
|
+
it "returns a FORBIDDEN response for an action wrapped in authorization if " +
|
237
|
+
"the transaction does contain a user, but the user isn't authorized" do
|
238
|
+
@txn.stub!( :user ).and_return( :gurney_halleck )
|
239
|
+
@txn.should_receive( :status= ).with( Apache::FORBIDDEN )
|
240
|
+
@applet.authorized_action( @txn ).should =~ /access denied/i
|
241
|
+
@applet.authorized.should be_false()
|
242
|
+
end
|
243
|
+
|
244
|
+
it "returns a normal response for an action wrapped in authorization if " +
|
245
|
+
"the transaction does contain a user, and the user is authorized" do
|
246
|
+
@txn.stub!( :user ).and_return( :alia_atreides )
|
247
|
+
@txn.stub!( :authorized ).and_return( true )
|
248
|
+
@applet.authorized_action( @txn ).should == true
|
249
|
+
@applet.authorized.should be_true()
|
250
|
+
end
|
251
|
+
|
252
|
+
end
|
253
|
+
|
254
|
+
end
|
255
|
+
|
256
|
+
end
|
257
|
+
|
258
|
+
describe Arrow::AccessControls do
|
259
|
+
include Arrow::SpecHelpers,
|
260
|
+
Arrow::AppletMatchers
|
261
|
+
|
262
|
+
before( :all ) do
|
263
|
+
setup_logging( :crit )
|
264
|
+
end
|
265
|
+
|
266
|
+
before( :each ) do
|
267
|
+
@uri = '/testing'
|
268
|
+
end
|
269
|
+
|
270
|
+
after( :all ) do
|
271
|
+
reset_logging()
|
272
|
+
end
|
273
|
+
|
274
|
+
|
275
|
+
it "adds a declarative method to including applet classes for adding to the list" +
|
276
|
+
" of methods which can be run without authentication" do
|
277
|
+
@applet_class = Class.new( Arrow::Applet ) do
|
278
|
+
include Arrow::AccessControls
|
279
|
+
end
|
280
|
+
|
281
|
+
@applet_class.respond_to?( :unauthenticated_actions )
|
282
|
+
@applet_class.unauthenticated_actions.should have(3).members
|
283
|
+
@applet_class.unauthenticated_actions.should include( :login, :logout, :deny_access )
|
284
|
+
end
|
285
|
+
|
286
|
+
|
287
|
+
describe "included in an Applet" do
|
288
|
+
|
289
|
+
describe " that doesn't declare any other unauthenticated actions" do
|
290
|
+
before( :all ) do
|
291
|
+
@applet_class = Class.new( Arrow::Applet ) do
|
292
|
+
include Arrow::AccessControls
|
293
|
+
|
294
|
+
def action_missing_action( txn, action, *args )
|
295
|
+
return action
|
296
|
+
end
|
297
|
+
|
298
|
+
def login_action( txn, *args )
|
299
|
+
return :login
|
300
|
+
end
|
301
|
+
|
302
|
+
def logout_action( txn, *args )
|
303
|
+
return :logout
|
304
|
+
end
|
305
|
+
|
306
|
+
def deny_access_action( txn, *args )
|
307
|
+
return :deny_access
|
308
|
+
end
|
309
|
+
end
|
310
|
+
end
|
311
|
+
|
312
|
+
before( :each ) do
|
313
|
+
@applet = @applet_class.new( nil, nil, @uri )
|
314
|
+
@fakerequest = Apache::Request.new( @uri )
|
315
|
+
@txn = Arrow::Transaction.new( @fakerequest, nil, nil )
|
316
|
+
end
|
317
|
+
|
318
|
+
|
319
|
+
it "doesn't require authentication for the :login action" do
|
320
|
+
@applet.run( @txn, :login ).should == :login
|
321
|
+
end
|
322
|
+
|
323
|
+
it "doesn't require authentication for the :logout action" do
|
324
|
+
@applet.run( @txn, :logout ).should == :logout
|
325
|
+
end
|
326
|
+
|
327
|
+
it "doesn't require authentication for the :deny_access action" do
|
328
|
+
@applet.run( @txn, :deny_access ).should == :deny_access
|
329
|
+
end
|
330
|
+
|
331
|
+
it "requires authentication for any other action" do
|
332
|
+
@applet.run( @txn, :serenity ).should == :login
|
333
|
+
end
|
334
|
+
|
335
|
+
end
|
336
|
+
|
337
|
+
describe " that declares a custom unauthenticated action" do
|
338
|
+
before( :all ) do
|
339
|
+
@applet_class = Class.new( Arrow::Applet ) do
|
340
|
+
include Arrow::AccessControls
|
341
|
+
|
342
|
+
unauthenticated_actions :willy_nilly, :action_missing
|
343
|
+
|
344
|
+
def action_missing_action( txn, action, *args )
|
345
|
+
return :action_missing
|
346
|
+
end
|
347
|
+
|
348
|
+
def willy_nilly_action( txn, *args )
|
349
|
+
return :willy_nilly
|
350
|
+
end
|
351
|
+
|
352
|
+
def serenity_action( txn, *args )
|
353
|
+
return :serenity
|
354
|
+
end
|
355
|
+
|
356
|
+
def login_action( txn, *args )
|
357
|
+
return :login
|
358
|
+
end
|
359
|
+
|
360
|
+
def logout_action( txn, *args )
|
361
|
+
return :logout
|
362
|
+
end
|
363
|
+
|
364
|
+
def deny_access_action( txn, *args )
|
365
|
+
return :deny_access
|
366
|
+
end
|
367
|
+
end
|
368
|
+
end
|
369
|
+
|
370
|
+
before( :each ) do
|
371
|
+
@applet = @applet_class.new( nil, nil, @uri )
|
372
|
+
@fakerequest = Apache::Request.new( @uri )
|
373
|
+
@txn = Arrow::Transaction.new( @fakerequest, nil, nil )
|
374
|
+
end
|
375
|
+
|
376
|
+
|
377
|
+
it "doesn't require authentication for the :login action" do
|
378
|
+
@applet.run( @txn, :login ).should == :login
|
379
|
+
end
|
380
|
+
|
381
|
+
it "doesn't require authentication for the :logout action" do
|
382
|
+
@applet.run( @txn, :logout ).should == :logout
|
383
|
+
end
|
384
|
+
|
385
|
+
it "doesn't require authentication for the :deny_access action" do
|
386
|
+
@applet.run( @txn, :deny_access ).should == :deny_access
|
387
|
+
end
|
388
|
+
|
389
|
+
it "doesn't require authentication for actions declared as unauthenticated" do
|
390
|
+
@applet.run( @txn, :willy_nilly ).should == :willy_nilly
|
391
|
+
end
|
392
|
+
|
393
|
+
it "doesn't require authentication for remapped actions declared as unauthenticated" do
|
394
|
+
@applet.run( @txn, :klang_locke ).should == :action_missing
|
395
|
+
end
|
396
|
+
|
397
|
+
it "requires authentication for any other action" do
|
398
|
+
@applet.run( @txn, :serenity ).should == :login
|
399
|
+
end
|
400
|
+
|
401
|
+
end
|
402
|
+
|
403
|
+
end
|
404
|
+
|
405
|
+
|
406
|
+
end # describe "Applet mixins"
|
407
|
+
|
408
|
+
|
409
|
+
|
@@ -0,0 +1,294 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
#
|
3
|
+
# Specification for the Arrow::Applet class
|
4
|
+
# $Id$
|
5
|
+
#
|
6
|
+
# Copyright (c) 2004-2008 The FaerieMUD Consortium. Most rights reserved.
|
7
|
+
#
|
8
|
+
|
9
|
+
BEGIN {
|
10
|
+
require 'pathname'
|
11
|
+
basedir = Pathname.new( __FILE__ ).dirname.parent.parent
|
12
|
+
|
13
|
+
libdir = basedir + "lib"
|
14
|
+
|
15
|
+
$LOAD_PATH.unshift( libdir ) unless $LOAD_PATH.include?( libdir )
|
16
|
+
}
|
17
|
+
|
18
|
+
begin
|
19
|
+
require 'spec'
|
20
|
+
require 'apache/fakerequest'
|
21
|
+
require 'arrow'
|
22
|
+
require 'arrow/applet'
|
23
|
+
require 'arrow/appletregistry'
|
24
|
+
require 'arrow/config'
|
25
|
+
require 'spec/lib/helpers'
|
26
|
+
rescue LoadError
|
27
|
+
unless Object.const_defined?( :Gem )
|
28
|
+
require 'rubygems'
|
29
|
+
retry
|
30
|
+
end
|
31
|
+
raise
|
32
|
+
end
|
33
|
+
|
34
|
+
|
35
|
+
#####################################################################
|
36
|
+
### C O N T E X T S
|
37
|
+
#####################################################################
|
38
|
+
|
39
|
+
describe Arrow::AppletRegistry do
|
40
|
+
include Arrow::SpecHelpers
|
41
|
+
|
42
|
+
APPLETREGISTRY_TEST_CONFIG = {
|
43
|
+
:applets => {
|
44
|
+
:path => Arrow::Path.new( "applets:specs/data/applets" ),
|
45
|
+
:pattern => '*.rb',
|
46
|
+
:pollInterval => 5,
|
47
|
+
:missingApplet => '/missing',
|
48
|
+
:errorApplet => '/error',
|
49
|
+
|
50
|
+
:layout => {
|
51
|
+
"/" => "Setup",
|
52
|
+
"/missing" => "NoSuchAppletHandler",
|
53
|
+
"/error" => "ErrorHandler",
|
54
|
+
"/status" => "ServerStatus",
|
55
|
+
"/hello" => "Hello",
|
56
|
+
"/args" => "ArgumentTester",
|
57
|
+
"/protected" => "ProtectedDelegator",
|
58
|
+
"/protected/hello" => "Hello",
|
59
|
+
"/counted" => "AccessCounter",
|
60
|
+
"/counted/hello" => "Hello",
|
61
|
+
|
62
|
+
"/test" => "TestApplet",
|
63
|
+
"/foo" => "BargleApplet",
|
64
|
+
},
|
65
|
+
:config => {},
|
66
|
+
},
|
67
|
+
}
|
68
|
+
|
69
|
+
GEM_CONFIG = APPLETREGISTRY_TEST_CONFIG.merge({
|
70
|
+
:gems => {
|
71
|
+
:require_signed => false,
|
72
|
+
:autoinstall => false,
|
73
|
+
:path => Arrow::Path.new([ "gems", *Gem.path ]),
|
74
|
+
:applets => {
|
75
|
+
'arrow-demo-apps' => '>= 0.0.3',
|
76
|
+
'arrow-management-apps' => '= 0.9.4',
|
77
|
+
'arrow-laikapedia' => nil,
|
78
|
+
},
|
79
|
+
},
|
80
|
+
})
|
81
|
+
|
82
|
+
|
83
|
+
### Set up a stubbed applet instance that can be loaded via
|
84
|
+
### Arrow::Applet.load.
|
85
|
+
def fixture_appletclass( path, name, classname )
|
86
|
+
applet = stub( "#{classname} instance (path)" )
|
87
|
+
appletclass = stub( "#{classname} class",
|
88
|
+
:name => name,
|
89
|
+
:normalized_name => classname,
|
90
|
+
:new => applet
|
91
|
+
)
|
92
|
+
|
93
|
+
Arrow::Applet.should_receive( :load ).with( path ).once.
|
94
|
+
and_return([ appletclass ])
|
95
|
+
File.should_receive( :mtime ).with( path ).and_return( Time.now )
|
96
|
+
|
97
|
+
return applet, appletclass
|
98
|
+
end
|
99
|
+
|
100
|
+
|
101
|
+
|
102
|
+
before( :all ) do
|
103
|
+
setup_logging( :crit )
|
104
|
+
end
|
105
|
+
|
106
|
+
after( :all ) do
|
107
|
+
reset_logging()
|
108
|
+
end
|
109
|
+
|
110
|
+
|
111
|
+
before( :each ) do
|
112
|
+
Arrow::Applet.stub!( :load ).and_return( [] )
|
113
|
+
end
|
114
|
+
|
115
|
+
|
116
|
+
it "ignores the gem home if it isn't a directory" do
|
117
|
+
homepath = mock( 'Pathname object for gem home' )
|
118
|
+
|
119
|
+
Gem.should_receive( :user_home ).and_return( :user_home )
|
120
|
+
Pathname.should_receive( :new ).with( :user_home ).and_return( homepath )
|
121
|
+
homepath.should_receive( :+ ).with( 'gems' ).and_return( homepath )
|
122
|
+
homepath.should_receive( :directory? ).and_return( false )
|
123
|
+
|
124
|
+
Arrow::AppletRegistry.get_safe_gemhome.should be_nil()
|
125
|
+
end
|
126
|
+
|
127
|
+
|
128
|
+
it "ignores the gem home if it's world-writable" do
|
129
|
+
homepath = mock( 'Pathname object for gem home' )
|
130
|
+
homepath_stat = mock( 'Stat data for the gem home' )
|
131
|
+
|
132
|
+
Gem.should_receive( :user_home ).and_return( :user_home )
|
133
|
+
Pathname.should_receive( :new ).with( :user_home ).and_return( homepath )
|
134
|
+
homepath.should_receive( :+ ).with( 'gems' ).and_return( homepath )
|
135
|
+
homepath.should_receive( :directory? ).and_return( true )
|
136
|
+
homepath.should_receive( :stat ).and_return( homepath_stat )
|
137
|
+
|
138
|
+
homepath_stat.should_receive( :mode ).and_return( 0777 )
|
139
|
+
|
140
|
+
Arrow::AppletRegistry.get_safe_gemhome.should be_nil()
|
141
|
+
end
|
142
|
+
|
143
|
+
|
144
|
+
it "returns an untainted Pathname for the gem home if it's sane" do
|
145
|
+
homepath = mock( 'Pathname object for gem home' )
|
146
|
+
homepath.taint
|
147
|
+
homepath_stat = mock( 'Stat data for the gem home' )
|
148
|
+
|
149
|
+
Gem.should_receive( :user_home ).and_return( :user_home )
|
150
|
+
Pathname.should_receive( :new ).with( :user_home ).and_return( homepath )
|
151
|
+
homepath.should_receive( :+ ).with( 'gems' ).and_return( homepath )
|
152
|
+
homepath.should_receive( :directory? ).and_return( true )
|
153
|
+
homepath.should_receive( :stat ).and_return( homepath_stat )
|
154
|
+
|
155
|
+
homepath_stat.should_receive( :mode ).and_return( 0755 )
|
156
|
+
|
157
|
+
rval = Arrow::AppletRegistry.get_safe_gemhome
|
158
|
+
|
159
|
+
rval.should == homepath
|
160
|
+
rval.should_not be_tainted()
|
161
|
+
end
|
162
|
+
|
163
|
+
|
164
|
+
it "loads any configured gems when it is created, and adds their template/ and applet/ " +
|
165
|
+
"directories to the template factory and path" do
|
166
|
+
Gem.should_receive( :activate ).with( 'arrow-demo-apps', '>= 0.0.3' ).
|
167
|
+
and_return( true )
|
168
|
+
Gem.should_receive( :datadir ).with( 'arrow-demo-apps' ).
|
169
|
+
and_return( '/some/path/arrow-demo-apps/data' )
|
170
|
+
Gem.should_receive( :activate ).with( 'arrow-management-apps', '= 0.9.4' ).
|
171
|
+
and_return( true )
|
172
|
+
Gem.should_receive( :datadir ).with( 'arrow-management-apps' ).
|
173
|
+
and_return( '/some/path/arrow-management-apps/data' )
|
174
|
+
Gem.should_receive( :activate ).with( 'arrow-laikapedia', Gem::Requirement.default ).
|
175
|
+
and_return( true )
|
176
|
+
Gem.should_receive( :datadir ).with( 'arrow-laikapedia' ).
|
177
|
+
and_return( '/some/path/arrow-laikapedia/data' )
|
178
|
+
|
179
|
+
config = Arrow::Config.new( GEM_CONFIG )
|
180
|
+
registry = Arrow::AppletRegistry.new( config )
|
181
|
+
|
182
|
+
registry.template_factory.path.should have(5).members
|
183
|
+
registry.template_factory.path.dirs.should include(
|
184
|
+
'/some/path/arrow-demo-apps/data/templates',
|
185
|
+
'/some/path/arrow-management-apps/data/templates',
|
186
|
+
'/some/path/arrow-laikapedia/data/templates'
|
187
|
+
)
|
188
|
+
|
189
|
+
registry.path.should have(5).members
|
190
|
+
registry.path.dirs.should include(
|
191
|
+
'/some/path/arrow-demo-apps/data/applets',
|
192
|
+
'/some/path/arrow-management-apps/data/applets',
|
193
|
+
'/some/path/arrow-laikapedia/data/applets'
|
194
|
+
)
|
195
|
+
end
|
196
|
+
|
197
|
+
|
198
|
+
it "searches for applets in its list of paths, and loads all of them" do
|
199
|
+
test_applet, test_appletclass = fixture_appletclass( 'test.rb', 'test', 'TestApplet' )
|
200
|
+
bargle_applet, bargle_appletclass = fixture_appletclass( 'bargle.rb', 'bargle', 'BargleApplet' )
|
201
|
+
|
202
|
+
File.stub!( :exist? ).and_return( true )
|
203
|
+
|
204
|
+
Dir.should_receive( :[] ).with( 'applets/*.rb' ).and_return([ 'test.rb', 'bargle.rb' ])
|
205
|
+
|
206
|
+
applets_path = stub( 'applets path object', :dirs => ['applets'] )
|
207
|
+
applets_path.stub!( :each ).and_yield( 'applets' )
|
208
|
+
config = Arrow::Config.new( APPLETREGISTRY_TEST_CONFIG )
|
209
|
+
config.applets.path = applets_path
|
210
|
+
registry = Arrow::AppletRegistry.new( config )
|
211
|
+
|
212
|
+
registry.urispace.should have(2).members
|
213
|
+
registry.urispace.values.should include( bargle_applet, test_applet )
|
214
|
+
end
|
215
|
+
|
216
|
+
|
217
|
+
describe "instance" do
|
218
|
+
|
219
|
+
before( :all ) do
|
220
|
+
setup_logging( :crit )
|
221
|
+
end
|
222
|
+
|
223
|
+
TEST_URISPACE = {
|
224
|
+
"" => "Setup",
|
225
|
+
"hello" => "Hello",
|
226
|
+
"args" => "ArgumentTester",
|
227
|
+
"protected" => "ProtectedDelegator",
|
228
|
+
"protected/hello" => "Hello",
|
229
|
+
"counted" => "AccessCounter",
|
230
|
+
"counted/hello" => "Hello",
|
231
|
+
}
|
232
|
+
|
233
|
+
before( :each ) do
|
234
|
+
@config = Arrow::Config.new( APPLETREGISTRY_TEST_CONFIG )
|
235
|
+
@registry = Arrow::AppletRegistry.new( @config )
|
236
|
+
@registry.instance_variable_set( :@urispace, TEST_URISPACE )
|
237
|
+
end
|
238
|
+
|
239
|
+
|
240
|
+
it "can create an applet chain for a uri" do
|
241
|
+
@registry.find_applet_chain( '/protected/hello' ).should have(3).members
|
242
|
+
@registry.find_applet_chain( '/protected/hello' ).
|
243
|
+
collect {|cl| cl.path }.should == [ '', 'protected', 'protected/hello' ]
|
244
|
+
@registry.find_applet_chain( '/protected/hello' ).
|
245
|
+
collect {|cl| cl.applet }.should == [ 'Setup', 'ProtectedDelegator', 'Hello' ]
|
246
|
+
|
247
|
+
@registry.find_applet_chain( '/protected' ).should have(2).members
|
248
|
+
@registry.find_applet_chain( '/protected' ).
|
249
|
+
collect {|cl| cl.path }.should == [ '', 'protected' ]
|
250
|
+
@registry.find_applet_chain( '/protected' ).
|
251
|
+
collect {|cl| cl.applet }.should == [ 'Setup', 'ProtectedDelegator' ]
|
252
|
+
|
253
|
+
@registry.find_applet_chain( '/' ).should have(1).members
|
254
|
+
@registry.find_applet_chain( '/' ).
|
255
|
+
collect {|cl| cl.path }.should == [ '' ]
|
256
|
+
@registry.find_applet_chain( '/' ).
|
257
|
+
collect {|cl| cl.applet }.should == [ 'Setup' ]
|
258
|
+
|
259
|
+
@registry.find_applet_chain( '/args' ).should have(2).members
|
260
|
+
@registry.find_applet_chain( '/args' ).
|
261
|
+
collect {|cl| cl.path }.should == [ '', 'args' ]
|
262
|
+
@registry.find_applet_chain( '/args' ).
|
263
|
+
collect {|cl| cl.applet }.should == [ 'Setup', 'ArgumentTester' ]
|
264
|
+
end
|
265
|
+
|
266
|
+
|
267
|
+
it "reloads its applets if the configured interval has passed since applets " +
|
268
|
+
"were loaded" do
|
269
|
+
# Make sure the load time is far enough in the past
|
270
|
+
@registry.load_time = Time.now - 2000
|
271
|
+
@registry.should_receive( :reload_applets ).once
|
272
|
+
@registry.check_for_updates
|
273
|
+
end
|
274
|
+
|
275
|
+
it "doesn't reload its applets if the configured interval hasn't passed since " +
|
276
|
+
"applets were loaded" do
|
277
|
+
# Make sure the load time is far enough in the past
|
278
|
+
@registry.load_time = Time.now
|
279
|
+
@registry.should_not_receive( :reload_applets )
|
280
|
+
@registry.check_for_updates
|
281
|
+
end
|
282
|
+
|
283
|
+
it "doesn't reload its applets if reloading is turned off (interval is zero)" do
|
284
|
+
# Make sure the load time is far enough in the past
|
285
|
+
@config.applets.pollInterval = 0
|
286
|
+
@registry.load_time = Time.now - 2000
|
287
|
+
@registry.should_not_receive( :reload_applets )
|
288
|
+
@registry.check_for_updates
|
289
|
+
end
|
290
|
+
|
291
|
+
end
|
292
|
+
|
293
|
+
end
|
294
|
+
|