aker 3.0.0.pre
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.md +210 -0
- data/README.md +282 -0
- data/assets/aker/form/login.css +73 -0
- data/assets/aker/form/login.html.erb +44 -0
- data/lib/aker/authorities/automatic_access.rb +36 -0
- data/lib/aker/authorities/composite.rb +301 -0
- data/lib/aker/authorities/static.rb +283 -0
- data/lib/aker/authorities/support/find_sole_user.rb +24 -0
- data/lib/aker/authorities/support.rb +9 -0
- data/lib/aker/authorities.rb +46 -0
- data/lib/aker/cas/authority.rb +79 -0
- data/lib/aker/cas/configuration_helper.rb +85 -0
- data/lib/aker/cas/middleware/logout_responder.rb +49 -0
- data/lib/aker/cas/middleware/ticket_remover.rb +35 -0
- data/lib/aker/cas/middleware.rb +6 -0
- data/lib/aker/cas/proxy_mode.rb +108 -0
- data/lib/aker/cas/rack_proxy_callback.rb +188 -0
- data/lib/aker/cas/service_mode.rb +88 -0
- data/lib/aker/cas/service_url.rb +62 -0
- data/lib/aker/cas/user_ext.rb +64 -0
- data/lib/aker/cas.rb +31 -0
- data/lib/aker/central_parameters.rb +101 -0
- data/lib/aker/configuration.rb +534 -0
- data/lib/aker/deprecation.rb +105 -0
- data/lib/aker/form/custom_views_mode.rb +80 -0
- data/lib/aker/form/login_form_asset_provider.rb +56 -0
- data/lib/aker/form/middleware/custom_view_login_responder.rb +19 -0
- data/lib/aker/form/middleware/login_renderer.rb +72 -0
- data/lib/aker/form/middleware/login_responder.rb +71 -0
- data/lib/aker/form/middleware/logout_responder.rb +26 -0
- data/lib/aker/form/middleware.rb +10 -0
- data/lib/aker/form/mode.rb +118 -0
- data/lib/aker/form.rb +26 -0
- data/lib/aker/group.rb +67 -0
- data/lib/aker/group_membership.rb +162 -0
- data/lib/aker/ldap/authority.rb +392 -0
- data/lib/aker/ldap/user_ext.rb +19 -0
- data/lib/aker/ldap.rb +22 -0
- data/lib/aker/modes/base.rb +85 -0
- data/lib/aker/modes/http_basic.rb +100 -0
- data/lib/aker/modes/support/attempted_path.rb +22 -0
- data/lib/aker/modes/support/rfc_2617.rb +32 -0
- data/lib/aker/modes/support.rb +12 -0
- data/lib/aker/modes.rb +48 -0
- data/lib/aker/rack/authenticate.rb +37 -0
- data/lib/aker/rack/configuration_helper.rb +18 -0
- data/lib/aker/rack/default_logout_responder.rb +36 -0
- data/lib/aker/rack/environment_helper.rb +34 -0
- data/lib/aker/rack/facade.rb +102 -0
- data/lib/aker/rack/failure.rb +69 -0
- data/lib/aker/rack/logout.rb +63 -0
- data/lib/aker/rack/request_ext.rb +19 -0
- data/lib/aker/rack/session_timer.rb +95 -0
- data/lib/aker/rack/setup.rb +77 -0
- data/lib/aker/rack.rb +107 -0
- data/lib/aker/test/helpers.rb +22 -0
- data/lib/aker/test.rb +8 -0
- data/lib/aker/user.rb +231 -0
- data/lib/aker/version.rb +3 -0
- data/lib/aker.rb +51 -0
- data/spec/aker/aker-sample.yml +11 -0
- data/spec/aker/authorities/automatic_access_spec.rb +52 -0
- data/spec/aker/authorities/composite_spec.rb +488 -0
- data/spec/aker/authorities/nu-schema.jar +0 -0
- data/spec/aker/authorities/static_spec.rb +455 -0
- data/spec/aker/authorities/support/find_sole_user_spec.rb +33 -0
- data/spec/aker/authorities_spec.rb +16 -0
- data/spec/aker/cas/authority_spec.rb +106 -0
- data/spec/aker/cas/configuration_helper_spec.rb +92 -0
- data/spec/aker/cas/middleware/logout_responder_spec.rb +47 -0
- data/spec/aker/cas/middleware/ticket_remover_spec.rb +49 -0
- data/spec/aker/cas/proxy_mode_spec.rb +185 -0
- data/spec/aker/cas/rack_proxy_callback_spec.rb +190 -0
- data/spec/aker/cas/service_mode_spec.rb +122 -0
- data/spec/aker/cas/service_url_spec.rb +114 -0
- data/spec/aker/cas/user_ext_spec.rb +27 -0
- data/spec/aker/cas_spec.rb +19 -0
- data/spec/aker/central_parameters_spec.rb +44 -0
- data/spec/aker/configuration_spec.rb +465 -0
- data/spec/aker/deprecation_spec.rb +115 -0
- data/spec/aker/form/a_form_mode.rb +129 -0
- data/spec/aker/form/custom_views_mode_spec.rb +34 -0
- data/spec/aker/form/login_form_asset_provider_spec.rb +80 -0
- data/spec/aker/form/middleware/a_form_login_responder.rb +89 -0
- data/spec/aker/form/middleware/custom_view_login_responder_spec.rb +47 -0
- data/spec/aker/form/middleware/login_renderer_spec.rb +56 -0
- data/spec/aker/form/middleware/login_responder_spec.rb +34 -0
- data/spec/aker/form/middleware/logout_responder_spec.rb +55 -0
- data/spec/aker/form/mode_spec.rb +15 -0
- data/spec/aker/form_spec.rb +11 -0
- data/spec/aker/group_membership_spec.rb +208 -0
- data/spec/aker/group_spec.rb +66 -0
- data/spec/aker/ldap/authority_spec.rb +414 -0
- data/spec/aker/ldap/ldap-users.ldif +197 -0
- data/spec/aker/ldap_spec.rb +11 -0
- data/spec/aker/modes/a_aker_mode.rb +41 -0
- data/spec/aker/modes/http_basic_spec.rb +127 -0
- data/spec/aker/modes/support/attempted_path_spec.rb +32 -0
- data/spec/aker/modes_spec.rb +11 -0
- data/spec/aker/rack/authenticate_spec.rb +78 -0
- data/spec/aker/rack/default_logout_responder_spec.rb +67 -0
- data/spec/aker/rack/facade_spec.rb +154 -0
- data/spec/aker/rack/failure_spec.rb +151 -0
- data/spec/aker/rack/logout_spec.rb +63 -0
- data/spec/aker/rack/request_ext_spec.rb +29 -0
- data/spec/aker/rack/session_timer_spec.rb +134 -0
- data/spec/aker/rack/setup_spec.rb +87 -0
- data/spec/aker/rack_spec.rb +216 -0
- data/spec/aker/test/helpers_spec.rb +44 -0
- data/spec/aker/user_spec.rb +362 -0
- data/spec/aker_spec.rb +80 -0
- data/spec/deprecation_helper.rb +58 -0
- data/spec/java_helper.rb +5 -0
- data/spec/logger_helper.rb +17 -0
- data/spec/matchers.rb +31 -0
- data/spec/mock_builder.rb +25 -0
- data/spec/spec_helper.rb +52 -0
- metadata +265 -0
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
require File.expand_path('../../../spec_helper', __FILE__)
|
|
2
|
+
|
|
3
|
+
module Aker::Rack
|
|
4
|
+
describe Facade do
|
|
5
|
+
##
|
|
6
|
+
# @return [Object] the options passed to the warden throw
|
|
7
|
+
# @raise RuntimeError if :warden is never thrown
|
|
8
|
+
def catch_warden_throw(&block)
|
|
9
|
+
opts = catch(:warden) do
|
|
10
|
+
block.call
|
|
11
|
+
end
|
|
12
|
+
if opts
|
|
13
|
+
opts
|
|
14
|
+
else
|
|
15
|
+
fail ":warden not thrown (or thrown without options)"
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
before do
|
|
20
|
+
@user = Aker::User.new("jo")
|
|
21
|
+
@user.portals << :ENU
|
|
22
|
+
@user.default_portal = :ENU
|
|
23
|
+
@user.group_memberships << Aker::GroupMembership.new(Aker::Group.new("User"))
|
|
24
|
+
|
|
25
|
+
@config = Aker::Configuration.new {
|
|
26
|
+
portal :ENU
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
@with_user = Facade.new(@config, @user)
|
|
30
|
+
@without_user = Facade.new(@config, nil)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
describe "#authentication_required!" do
|
|
34
|
+
it "throws to warden if there's no user" do
|
|
35
|
+
catch_warden_throw {
|
|
36
|
+
@without_user.authentication_required!
|
|
37
|
+
}.should == { :login_required => true }
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
describe "with a user" do
|
|
41
|
+
it "does not throw to warden if the user is authenticated and in the proper portal" do
|
|
42
|
+
lambda { @with_user.authentication_required! }.should_not raise_error
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
it "throws to warden if the user isn't permitted to access the configured portal" do
|
|
46
|
+
@config.portal = :NOTIS
|
|
47
|
+
catch_warden_throw {
|
|
48
|
+
@with_user.authentication_required!
|
|
49
|
+
}.should == { :portal_required => :NOTIS }
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
it "does not throw to warden if there's no configured portal" do
|
|
53
|
+
@config.portal = nil
|
|
54
|
+
lambda { @with_user.authentication_required! }.should_not raise_error
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
describe "#authenticated?" do
|
|
60
|
+
it "returns false if there's not a user" do
|
|
61
|
+
@without_user.should_not be_authenticated
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
describe "with a user" do
|
|
65
|
+
it "returns true if the user is in the configured portal" do
|
|
66
|
+
@with_user.should be_authenticated
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
it "returns false if the user is not in the configured portal" do
|
|
70
|
+
@config.portal = :NOTIS
|
|
71
|
+
@with_user.should_not be_authenticated
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
it "returns true if there is no configured portal" do
|
|
75
|
+
@config.portal = nil
|
|
76
|
+
@with_user.should be_authenticated
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
describe "#permit?" do
|
|
82
|
+
describe "without a block" do
|
|
83
|
+
it "returns true if the facade user is in the group" do
|
|
84
|
+
@with_user.permit?(:User).should be_true
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
it "returns false if the user is not in the group" do
|
|
88
|
+
@with_user.permit?(:Admin).should be_false
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
it "returns false without a user" do
|
|
92
|
+
@without_user.permit?(:User).should be_false
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
describe "with a block" do
|
|
97
|
+
it "evaluates the block if the facade user is in the group" do
|
|
98
|
+
executed = false
|
|
99
|
+
@with_user.permit?(:User) do
|
|
100
|
+
executed = true
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
executed.should be_true
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
it "does not evaluate the block if the facade user is not in the group" do
|
|
107
|
+
executed = false
|
|
108
|
+
@with_user.permit?(:Admin) do
|
|
109
|
+
executed = true
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
executed.should be_false
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
it "does not evaluate the block if there is no user" do
|
|
116
|
+
executed = false
|
|
117
|
+
@without_user.permit?(:User) do
|
|
118
|
+
executed = true
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
executed.should be_false
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
it "is aliased as permit (without the question mark)" do
|
|
126
|
+
@with_user.permit(:User).should be_true
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
describe "#permit!" do
|
|
131
|
+
it "tells warden authentication is required if there's no user" do
|
|
132
|
+
catch_warden_throw {
|
|
133
|
+
@without_user.permit!(:User)
|
|
134
|
+
}.should == { :login_required => true }
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
it "tells warden that particular groups are required if the user isn't in any of them" do
|
|
138
|
+
catch_warden_throw {
|
|
139
|
+
@with_user.permit!(:Developer, :Admin)
|
|
140
|
+
}.should == { :groups_required => [:Developer, :Admin] }
|
|
141
|
+
end
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
describe "#user" do
|
|
145
|
+
it "returns the user if there's a user" do
|
|
146
|
+
@with_user.user.username.should == "jo"
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
it "returns nil if there's no user" do
|
|
150
|
+
@without_user.user.should be_nil
|
|
151
|
+
end
|
|
152
|
+
end
|
|
153
|
+
end
|
|
154
|
+
end
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
require File.expand_path('../../../spec_helper', __FILE__)
|
|
2
|
+
|
|
3
|
+
require 'rack/mock'
|
|
4
|
+
|
|
5
|
+
module Aker::Rack
|
|
6
|
+
describe Failure do
|
|
7
|
+
before do
|
|
8
|
+
@config = Aker::Configuration.new
|
|
9
|
+
@config.logger = spec_logger
|
|
10
|
+
@env = ::Rack::MockRequest.env_for("/", "aker.configuration" => @config)
|
|
11
|
+
@app = Failure.new
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
after do
|
|
15
|
+
Warden::Strategies.clear!
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def call
|
|
19
|
+
@app.call(@env)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def actual_code
|
|
23
|
+
call[0]
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def actual_headers
|
|
27
|
+
call[1]
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def actual_body
|
|
31
|
+
actual_lines = []
|
|
32
|
+
call[2].each { |l| actual_lines << l }
|
|
33
|
+
actual_lines.join
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
describe "of authorization" do
|
|
37
|
+
before do
|
|
38
|
+
@env['aker.check'] = Facade.new(@env["aker.configuration"], Aker::User.new("jo"))
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
shared_examples_for "an authorization failure" do
|
|
42
|
+
it "403s" do
|
|
43
|
+
actual_code.should == 403
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
it "returns HTML" do
|
|
47
|
+
actual_headers["Content-Type"].should == "text/html"
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
it "returns a somewhat friendly message" do
|
|
51
|
+
actual_body.should ==
|
|
52
|
+
"<html><head><title>Authorization denied</title></head><body>jo may not use this page.</body></html>"
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
describe "at the portal level" do
|
|
57
|
+
before do
|
|
58
|
+
@env['warden.options'] = { :portal_required => :ENU }
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
it_should_behave_like "an authorization failure"
|
|
62
|
+
|
|
63
|
+
it "logs the failure appropriately" do
|
|
64
|
+
call
|
|
65
|
+
actual_log.should =~ /Resource authorization failure: User "jo" is not in the :ENU portal./
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
describe "at the group level" do
|
|
70
|
+
before do
|
|
71
|
+
@env['warden.options'] = { :groups_required => [:Admin, :Developer] }
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
it_should_behave_like "an authorization failure"
|
|
75
|
+
|
|
76
|
+
it "logs the failure appropriately" do
|
|
77
|
+
call
|
|
78
|
+
actual_log.should =~ /Resource authorization failure: User "jo" is not in any of the required groups \[:Admin, :Developer\]./
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
describe "of authentication" do
|
|
84
|
+
before do
|
|
85
|
+
@env['warden.options'] = { :login_required => true }
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
describe "when interactive" do
|
|
89
|
+
before do
|
|
90
|
+
Warden::Strategies.add(:fake_ui) do
|
|
91
|
+
def authenticate!; nil; end
|
|
92
|
+
def on_ui_failure
|
|
93
|
+
::Rack::Response.new(["UI failed!"], 403, {})
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
@env['aker.interactive'] = true
|
|
98
|
+
@env['aker.configuration'].ui_mode = :fake_ui
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
it "invokes #on_ui_failure on the appropriate mode" do
|
|
102
|
+
actual_code.should == 403
|
|
103
|
+
actual_body.should == "UI failed!"
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
describe "when not interactive" do
|
|
108
|
+
before do
|
|
109
|
+
@env['aker.interactive'] = false
|
|
110
|
+
|
|
111
|
+
%w(Alpha Beta).each do |n|
|
|
112
|
+
cls = Class.new(Aker::Modes::Base)
|
|
113
|
+
cls.class_eval <<-RUBY
|
|
114
|
+
include Aker::Modes::Support::Rfc2617
|
|
115
|
+
def authenticate!; nil; end
|
|
116
|
+
def scheme; #{n.inspect}; end
|
|
117
|
+
RUBY
|
|
118
|
+
Warden::Strategies.add(n.downcase.to_sym, cls)
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
it "responds with a challenge" do
|
|
123
|
+
@env['aker.configuration'].api_mode = :beta
|
|
124
|
+
|
|
125
|
+
actual = call
|
|
126
|
+
actual[0].should == 401
|
|
127
|
+
actual[1]["WWW-Authenticate"].should == 'Beta realm="Aker"'
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
it "responds for with challenges for all modes" do
|
|
131
|
+
@env['aker.configuration'].api_mode = [:beta, :alpha]
|
|
132
|
+
|
|
133
|
+
actual_headers["WWW-Authenticate"].should == %Q{Beta realm="Aker"\nAlpha realm="Aker"}
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
it "uses the portal as the realm if it is set" do
|
|
137
|
+
@env['aker.configuration'].portal = :ENU
|
|
138
|
+
@env['aker.configuration'].api_mode = [:alpha]
|
|
139
|
+
|
|
140
|
+
actual_headers["WWW-Authenticate"].should == %Q{Alpha realm="ENU"}
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
it "gives a human-readable message in the body for debugging" do
|
|
144
|
+
@env['aker.configuration'].api_mode = :beta
|
|
145
|
+
actual_headers["Content-Type"].should == "text/plain"
|
|
146
|
+
actual_body.should == "Authentication required"
|
|
147
|
+
end
|
|
148
|
+
end
|
|
149
|
+
end
|
|
150
|
+
end
|
|
151
|
+
end
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
require File.expand_path('../../../spec_helper', __FILE__)
|
|
2
|
+
require 'rack/test'
|
|
3
|
+
|
|
4
|
+
module Aker::Rack
|
|
5
|
+
describe Logout do
|
|
6
|
+
include Rack::Test::Methods
|
|
7
|
+
|
|
8
|
+
let(:path) { '/auth/logout' }
|
|
9
|
+
|
|
10
|
+
let(:app) do
|
|
11
|
+
Rack::Builder.new do
|
|
12
|
+
use Aker::Rack::Logout
|
|
13
|
+
run lambda { |env| [200, {'Content-Type' => 'text/html'}, ['from the app']] }
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
let(:warden) { stub.as_null_object }
|
|
18
|
+
|
|
19
|
+
let(:config) do
|
|
20
|
+
p = path
|
|
21
|
+
Aker::Configuration.new {
|
|
22
|
+
rack_parameters :logout_path => p
|
|
23
|
+
}
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
let(:env) do
|
|
27
|
+
{
|
|
28
|
+
'warden' => warden,
|
|
29
|
+
'aker.configuration' => config
|
|
30
|
+
}
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
describe '#call' do
|
|
34
|
+
context 'given GET {the configured path}' do
|
|
35
|
+
it 'instructs Warden to log out' do
|
|
36
|
+
warden.should_receive(:logout)
|
|
37
|
+
|
|
38
|
+
get path, {}, env
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
it 'passes control to the rest of the app' do
|
|
42
|
+
get path, {}, env
|
|
43
|
+
|
|
44
|
+
last_response.body.should == 'from the app'
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
context 'given GET (some other path)' do
|
|
49
|
+
it 'does not instruct Warden to log out' do
|
|
50
|
+
warden.should_receive(:logout).never
|
|
51
|
+
|
|
52
|
+
get '/', {}, env
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
it 'passes control to the rest of the app' do
|
|
56
|
+
get '/', {}, env
|
|
57
|
+
|
|
58
|
+
last_response.body.should == 'from the app'
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
require File.expand_path('../../../spec_helper', __FILE__)
|
|
2
|
+
|
|
3
|
+
require 'rack'
|
|
4
|
+
|
|
5
|
+
module Aker::Rack
|
|
6
|
+
describe RequestExt do
|
|
7
|
+
let(:request_class) do
|
|
8
|
+
Class.new(Rack::Request) do
|
|
9
|
+
include RequestExt
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
let(:request) { request_class.new({}) }
|
|
14
|
+
|
|
15
|
+
describe '#interactive?' do
|
|
16
|
+
it 'returns true if the request is interactive' do
|
|
17
|
+
request.env['aker.interactive'] = true
|
|
18
|
+
|
|
19
|
+
request.should be_interactive
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
it 'returns false if the request is non-interactive' do
|
|
23
|
+
request.env['aker.interactive'] = false
|
|
24
|
+
|
|
25
|
+
request.should_not be_interactive
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
require File.expand_path('../../../spec_helper', __FILE__)
|
|
2
|
+
require 'rack/test'
|
|
3
|
+
|
|
4
|
+
module Aker::Rack
|
|
5
|
+
describe SessionTimer do
|
|
6
|
+
let(:app) { stub.as_null_object }
|
|
7
|
+
let(:configuration) { Aker::Configuration.new { rack_parameters :logout_path => '/a/logout' } }
|
|
8
|
+
let(:env) {
|
|
9
|
+
{
|
|
10
|
+
'aker.configuration' => configuration,
|
|
11
|
+
'rack.session' => session,
|
|
12
|
+
'warden' => warden
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
let(:expected_timeout) { 600 }
|
|
16
|
+
let(:session) { {} }
|
|
17
|
+
let(:timer) { SessionTimer.new(app) }
|
|
18
|
+
let(:warden) { mock }
|
|
19
|
+
|
|
20
|
+
before do
|
|
21
|
+
configuration.add_parameters_for(:policy, %s(session-timeout-seconds) => expected_timeout)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
describe "#call" do
|
|
25
|
+
let(:current_request_time) { 1234567890 }
|
|
26
|
+
|
|
27
|
+
before do
|
|
28
|
+
Time.stub!(:now => Time.at(current_request_time))
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
it "sets aker.timeout_at" do
|
|
32
|
+
timer.call(env)
|
|
33
|
+
|
|
34
|
+
env['aker.timeout_at'].should == current_request_time + expected_timeout
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
context 'if no session timeout is given' do
|
|
38
|
+
before do
|
|
39
|
+
configuration.add_parameters_for(:policy, %s(session-timeout-seconds) => nil)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
it 'passes control down the Rack stack' do
|
|
43
|
+
app.should_receive(:call)
|
|
44
|
+
|
|
45
|
+
timer.call(env)
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
context 'if no last request timestamp is present' do
|
|
50
|
+
before do
|
|
51
|
+
session['aker.last_request_at'] = nil
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
it 'sets last request time to the current request time' do
|
|
55
|
+
timer.call(env)
|
|
56
|
+
|
|
57
|
+
session['aker.last_request_at'].should == current_request_time
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
it 'passes control down the Rack stack' do
|
|
61
|
+
app.should_receive(:call)
|
|
62
|
+
|
|
63
|
+
timer.call(env)
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
context 'if a last request timestamp is present' do
|
|
68
|
+
context 'and the current request is within the timeout window' do
|
|
69
|
+
before do
|
|
70
|
+
#
|
|
71
|
+
# The below calculation places the current request time in the
|
|
72
|
+
# middle of the session timeout window:
|
|
73
|
+
#
|
|
74
|
+
# prv cur
|
|
75
|
+
# | |
|
|
76
|
+
# |------|
|
|
77
|
+
# |e.t./2|
|
|
78
|
+
# |------------
|
|
79
|
+
# | e.t.
|
|
80
|
+
#
|
|
81
|
+
session['aker.last_request_at'] = current_request_time - (expected_timeout / 2)
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
it 'sets the last request timestamp' do
|
|
85
|
+
timer.call(env)
|
|
86
|
+
|
|
87
|
+
session['aker.last_request_at'].should == current_request_time
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
it 'passes control down the Rack stack' do
|
|
91
|
+
app.should_receive(:call)
|
|
92
|
+
|
|
93
|
+
timer.call(env)
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
context 'and the current request is outside the timeout window' do
|
|
98
|
+
before do
|
|
99
|
+
#
|
|
100
|
+
# The below calculation places the current request time at the edge
|
|
101
|
+
# of the session timeout window:
|
|
102
|
+
#
|
|
103
|
+
# prv cur
|
|
104
|
+
# | |
|
|
105
|
+
# |------------|
|
|
106
|
+
# | e.t. |
|
|
107
|
+
#
|
|
108
|
+
session['aker.last_request_at'] = current_request_time - expected_timeout
|
|
109
|
+
|
|
110
|
+
warden.stub!(:logout)
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
it 'passes control down the Rack stack' do
|
|
114
|
+
app.should_receive(:call)
|
|
115
|
+
|
|
116
|
+
timer.call(env)
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
it 'resets the session' do
|
|
120
|
+
warden.should_receive(:logout)
|
|
121
|
+
|
|
122
|
+
timer.call(env)
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
it 'sets the session expired flag in the environment' do
|
|
126
|
+
timer.call(env)
|
|
127
|
+
|
|
128
|
+
env['aker.session_expired'].should == true
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
end
|
|
134
|
+
end
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
require File.expand_path('../../../spec_helper', __FILE__)
|
|
2
|
+
|
|
3
|
+
module Aker::Rack
|
|
4
|
+
describe Setup do
|
|
5
|
+
let(:app) { lambda { |x| x } }
|
|
6
|
+
let(:configuration) { Aker::Configuration.new }
|
|
7
|
+
let(:middleware) { Setup.new(app, configuration) }
|
|
8
|
+
|
|
9
|
+
def call(env = {})
|
|
10
|
+
middleware.call(env)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
describe "env['aker.configuration']" do
|
|
14
|
+
it "is the configuration provided in its constructor" do
|
|
15
|
+
env = call
|
|
16
|
+
|
|
17
|
+
env['aker.configuration'].should == configuration
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
describe "env['aker.authority']" do
|
|
22
|
+
it "is the authority from the configuration" do
|
|
23
|
+
authority = stub
|
|
24
|
+
configuration.stub!(:composite_authority => authority)
|
|
25
|
+
|
|
26
|
+
env = call
|
|
27
|
+
|
|
28
|
+
env['aker.authority'].should == authority
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
describe "env['aker.interactive']" do
|
|
33
|
+
it "is true if the Accept header includes text/html" do
|
|
34
|
+
env = call("HTTP_ACCEPT" =>
|
|
35
|
+
"application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5")
|
|
36
|
+
|
|
37
|
+
env['aker.interactive'].should be_true
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
describe "when there are any API modes" do
|
|
41
|
+
let(:configuration) do
|
|
42
|
+
Aker::Configuration.new do
|
|
43
|
+
api_mode :http_basic
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
it "is false if the Accept header does not include text/html" do
|
|
48
|
+
env = call("HTTP_ACCEPT" => "*/*")
|
|
49
|
+
|
|
50
|
+
env['aker.interactive'].should be_false
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
it "is false if there is no Accept header" do
|
|
54
|
+
env = call
|
|
55
|
+
|
|
56
|
+
env['aker.interactive'].should be_false
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
it "is true if the User-Agent header contains 'Mozilla'" do
|
|
60
|
+
env = call("HTTP_USER_AGENT" => "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1)")
|
|
61
|
+
|
|
62
|
+
env['aker.interactive'].should be_true
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
describe "when there are no API modes" do
|
|
67
|
+
it "is true if the Accept header does not include text/html" do
|
|
68
|
+
env = call("HTTP_ACCEPT" => "*/*")
|
|
69
|
+
|
|
70
|
+
env['aker.interactive'].should be_true
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
it "is true if there is no Accept header" do
|
|
74
|
+
env = call
|
|
75
|
+
|
|
76
|
+
env['aker.interactive'].should be_true
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
it "always invokes the app" do
|
|
82
|
+
app.should_receive(:call)
|
|
83
|
+
|
|
84
|
+
middleware.call({})
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
end
|