shibbolite 0.0.1 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (38) hide show
  1. checksums.yaml +7 -0
  2. data/README.rdoc +9 -11
  3. data/app/concerns/shibbolite/filters.rb +26 -8
  4. data/app/concerns/shibbolite/helpers.rb +6 -0
  5. data/app/controllers/shibbolite/shibboleth_controller.rb +11 -1
  6. data/lib/shibbolite/version.rb +1 -1
  7. data/spec/controllers/filters_test_controller_spec.rb +62 -3
  8. data/spec/controllers/helpers_test_controller_spec.rb +29 -12
  9. data/spec/dummy/app/controllers/filters_test_controller.rb +10 -0
  10. data/spec/dummy/app/controllers/helpers_test_controller.rb +5 -0
  11. data/spec/dummy/app/views/static/home.html.erb +3 -1
  12. data/spec/dummy/config/environments/test.rb +1 -1
  13. data/spec/dummy/db/test.sqlite3 +0 -0
  14. data/spec/dummy/log/development.log +727 -0
  15. data/spec/dummy/log/test.log +24242 -0
  16. data/spec/dummy/tmp/cache/assets/development/sprockets/13fe41fee1fe35b49d145bcc06610705 +0 -0
  17. data/spec/dummy/tmp/cache/assets/development/sprockets/2f5173deea6c795b8fdde723bb4b63af +0 -0
  18. data/spec/dummy/tmp/cache/assets/development/sprockets/357970feca3ac29060c1e3861e2c0953 +0 -0
  19. data/spec/dummy/tmp/cache/assets/development/sprockets/371bf96e99717688ed7313a0c53f4212 +0 -0
  20. data/spec/dummy/tmp/cache/assets/development/sprockets/510da110ae528e2d22533be39ff696c5 +0 -0
  21. data/spec/dummy/tmp/cache/assets/development/sprockets/6fc757c2c8329244ca95d6909865bbc2 +0 -0
  22. data/spec/dummy/tmp/cache/assets/development/sprockets/cffd775d018f68ce5dba1ee0d951a994 +0 -0
  23. data/spec/dummy/tmp/cache/assets/development/sprockets/d771ace226fc8215a3572e0aa35bb0d6 +0 -0
  24. data/spec/dummy/tmp/cache/assets/development/sprockets/f7cbd26ba1d28d48de824f0e94586655 +0 -0
  25. data/spec/dummy/tmp/cache/assets/test/sprockets/13fe41fee1fe35b49d145bcc06610705 +0 -0
  26. data/spec/dummy/tmp/cache/assets/test/sprockets/2f5173deea6c795b8fdde723bb4b63af +0 -0
  27. data/spec/dummy/tmp/cache/assets/test/sprockets/357970feca3ac29060c1e3861e2c0953 +0 -0
  28. data/spec/dummy/tmp/cache/assets/test/sprockets/371bf96e99717688ed7313a0c53f4212 +0 -0
  29. data/spec/dummy/tmp/cache/assets/test/sprockets/6fc757c2c8329244ca95d6909865bbc2 +0 -0
  30. data/spec/dummy/tmp/cache/assets/test/sprockets/cffd775d018f68ce5dba1ee0d951a994 +0 -0
  31. data/spec/dummy/tmp/cache/assets/test/sprockets/d771ace226fc8215a3572e0aa35bb0d6 +0 -0
  32. data/spec/dummy/tmp/cache/assets/test/sprockets/f7cbd26ba1d28d48de824f0e94586655 +0 -0
  33. data/spec/dummy/tmp/restart.txt +0 -0
  34. data/spec/spec_helper.rb +1 -0
  35. data/spec/support/controllers/shared_access_control_examples.rb +63 -0
  36. data/spec/support/controllers/shared_auth_helpers.rb +25 -0
  37. data/spec/support/features/session_helpers.rb +12 -0
  38. metadata +102 -110
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: f736be4c42d9b6feef36b94647b8fbf3bf4ce8c4
4
+ data.tar.gz: bb91bf1108e56142cf9ef106139d54c8313e579a
5
+ SHA512:
6
+ metadata.gz: 08bbe01087d289f772581b2ce7ad1bf243155c3d1291f931b72f47f446ebc57207bb2d6b55e95765df8d9e2f9c977fb40a9a604fb8bd1c09bd9eb9278a7df75c
7
+ data.tar.gz: 1ab7667eaee8c9e3200512dc379e9ecf221d26d5d2d5960f1a5701b236674d234202ca815cecca0aac7edabc542bea0853a513a2ae0263a4e86c1bbc9ba7582b
data/README.rdoc CHANGED
@@ -48,47 +48,45 @@ Shibbolite::Filters gives you a gaggle of before filters to enable access contro
48
48
  === Filters
49
49
  before_action :require_login
50
50
 
51
- In your ApplicationController will require that users have a valid Shibboleth session before they can launch any action
51
+ ...in your ApplicationController will require that users have a valid Shibboleth session before they can launch any action
52
52
 
53
53
  before_action { |c| c.require_group :admin }
54
54
 
55
- will require that the user belong to the admin group
55
+ ...will require that the user belong to the admin group
56
56
 
57
57
  before_action { |c| c.require_group :admin, :user }
58
58
 
59
- will allow anyone who has the admin or the user group
59
+ ...will allow anyone who has the admin or the user group
60
60
 
61
61
  before_action { |c| c.require_group_or_id :admin, some_user.id }
62
62
 
63
- is useful for things like profile pages that are accessible to both an owner and anyone in the admin group
63
+ ...is useful for things like profile pages that are accessible to both an owner and anyone in the admin group
64
64
 
65
65
  before_action :use_attributes_if_available, only: :public
66
66
 
67
- will attempt to load a Shibboleth session if one is available but do nothing otherwise. Use this if you have a public page but still want to make use of attributes for users that have logged in.
67
+ ...will attempt to load a Shibboleth session if one is available but do nothing otherwise. Use this if you have a public page but still want to make use of attributes for users that have logged in.
68
68
 
69
69
  === Helpers
70
70
  These helpers will be available to views of any controllers that include Shibbolite::Filters. See the source for a complete list.
71
71
 
72
72
  current_user
73
73
 
74
- will return the User object of the Shibboleth authenticated user or nil if no one is authenticated, or the user isn't registered in the database. NOTE: current_user can still return nil after the user authenticates if one of the above filters isn't used before the controller action.
74
+ ...will return the User object of the Shibboleth authenticated user or nil if no one is authenticated, or the user isn't registered in the database. NOTE: current_user can still return nil after the user authenticates if one of the above filters isn't used before the controller action.
75
75
 
76
76
  Since current_user relies on a database lookup, you'll have to register (ie persist) your users before they can interact with most of the features of Shibbolite. How you want to handle user registration is left up to you.
77
77
 
78
78
  logged_in?
79
79
 
80
- checks to see that a username is set in the session
80
+ ...checks to see that a username is set in the session
81
81
 
82
82
  user_in_group? (:admin)
83
83
 
84
- will return true if the current user has the admin group
85
-
86
-
84
+ ...will return true if the current user has the admin group
87
85
 
88
86
  === Actions
89
87
  A couple of actions are available from Shibbolite::ShibbolethController
90
88
 
91
- shibbolite.login_path #=> '/shibbolite/login'
89
+ shibbolite.login_path #=> 'shibbolite/login'
92
90
 
93
91
  will attempt to load a Shibboleth session, or redirect to the Shibbolite.session_initiator for authentication if there is none. After authentication the user is brought back to the root_path.
94
92
 
@@ -6,21 +6,21 @@ module Shibbolite
6
6
  include Shibbolite::Helpers
7
7
 
8
8
  def require_login
9
- redirect_to login_or_access_denied unless logged_in?
9
+ authenticate_request unless logged_in?
10
10
  end
11
11
 
12
12
  def require_registered
13
- redirect_to login_or_access_denied unless registered_user?
13
+ authenticate_request unless registered_user?
14
14
  end
15
15
 
16
16
  def require_group(*groups)
17
17
  in_group = false
18
18
  groups.flatten.each { |group| in_group ||= user_in_group?(group) }
19
- redirect_to login_or_access_denied unless in_group
19
+ authenticate_request unless in_group
20
20
  end
21
21
 
22
22
  def require_id(id)
23
- redirect_to login_or_access_denied unless user_has_id?(id)
23
+ authenticate_request unless user_has_id?(id)
24
24
  end
25
25
 
26
26
  def require_group_or_id(*groups, id)
@@ -29,16 +29,34 @@ module Shibbolite
29
29
  end
30
30
  end
31
31
 
32
+ def require_attribute(attr, value)
33
+ authenticate_request unless user_has_matching_attribute?(attr, value)
34
+ end
35
+
36
+ def require_group_or_attribute(*groups, attr, value)
37
+ unless user_has_matching_attribute?(attr, value)
38
+ require_group(groups)
39
+ end
40
+ end
41
+
32
42
  def use_attributes_if_available
33
43
  if request.env[Shibbolite.pid.to_s] and not logged_in?
34
- redirect_to login_or_access_denied
44
+ authenticate_request
35
45
  end
36
46
  end
37
47
 
38
- # a handy redirect target
39
- def login_or_access_denied
48
+ # redirects the user to (re)authenticate with
49
+ # the Idp or a 403 forbidden page
50
+ def authenticate_request
40
51
  session[:requested_url] = request.fullpath
41
- logged_in? ? shibbolite.access_denied_url : shibbolite.login_url
52
+
53
+ url = logged_in? ? shibbolite.access_denied_url : shibbolite.login_url
54
+
55
+ # redirect to the selected url
56
+ respond_to do |format|
57
+ format.html { redirect_to url }
58
+ format.js { render js: "window.location.assign('#{url}');"}
59
+ end
42
60
  end
43
61
  end
44
62
  end
@@ -44,5 +44,11 @@ module Shibbolite
44
44
  return false unless user
45
45
  user.id == id
46
46
  end
47
+
48
+ # this method matches against the raw environment variables
49
+ # instead of the database attributes
50
+ def user_has_matching_attribute?(attr, value)
51
+ request.env[attr.to_s] == value
52
+ end
47
53
  end
48
54
  end
@@ -9,8 +9,18 @@ module Shibbolite
9
9
 
10
10
  def login
11
11
  session[:requested_url] ||= main_app.root_path
12
+
13
+ # attempt to load existing sp session data
12
14
  load_session
13
- redirect_to logged_in? ? session.delete(:requested_url) : sp_login_url
15
+
16
+ # redirect to Idp for authentication if
17
+ # sp session data is not present
18
+ url = (logged_in? ? session.delete(:requested_url) : sp_login_url)
19
+
20
+ respond_to do |format|
21
+ format.html { redirect_to url }
22
+ format.js { render js: "window.location.assign('#{url}');"}
23
+ end
14
24
  end
15
25
 
16
26
  def logout
@@ -1,3 +1,3 @@
1
1
  module Shibbolite
2
- VERSION = "0.0.1"
2
+ VERSION = "1.1.0"
3
3
  end
@@ -4,6 +4,8 @@ require 'spec_helper'
4
4
 
5
5
  describe FiltersTestController do
6
6
 
7
+ include_context 'auth_helpers'
8
+
7
9
  # presume the session has been loaded
8
10
  before { allow(subject).to receive(:load_session) }
9
11
 
@@ -15,15 +17,21 @@ describe FiltersTestController do
15
17
  get :_require_login
16
18
  expect(response).to render_template(:dummy)
17
19
  end
18
-
19
20
  end
20
21
 
21
22
  context 'when not logged in' do
23
+ before { allow(subject).to receive(:logged_in?).and_return(false) }
24
+
22
25
  it 'redirects' do
23
- allow(subject).to receive(:logged_in?).and_return(false)
24
26
  get :_require_login
25
27
  expect(response).to redirect_to('/shibbolite/login')
26
28
  end
29
+
30
+ # see feature spec for complete test
31
+ it 'responds to ajax requests' do
32
+ xhr :get, :_require_login
33
+ expect(response.body).to include('window.location')
34
+ end
27
35
  end
28
36
  end
29
37
 
@@ -48,7 +56,7 @@ describe FiltersTestController do
48
56
 
49
57
  describe '#use_attributes_if_available' do
50
58
 
51
- context 'when the user authenticated but login isn\'t required' do
59
+ context 'when the user authenticated but login is not required' do
52
60
  it 'redirects to login to load the session' do
53
61
  allow(subject).to receive(:logged_in?).and_return(false)
54
62
  request.env[Shibbolite.pid.to_s] = 'not nil'
@@ -65,6 +73,26 @@ describe FiltersTestController do
65
73
  end
66
74
  end
67
75
 
76
+ describe '#require_attribute' do
77
+
78
+ it 'executes action when user has the attribute' do
79
+ set_env_attribute(:department, '9th Circle')
80
+ get :_require_attribute, attr: :department, value: '9th Circle'
81
+ expect(response).to render_template(:dummy)
82
+ end
83
+
84
+ it 'redirects when user does not have the attribute' do
85
+ get :_require_attribute, attr: :dragon, value: 'Smaug'
86
+ expect(response).to redirect_to('/shibbolite/login')
87
+ end
88
+
89
+ it 'redirects when user has an incorrect value for the attribute' do
90
+ set_env_attribute(:department, 'Complaints')
91
+ get :_require_attribute, attr: :department, value: '9th Circle'
92
+ expect(response).to redirect_to('/shibbolite/login')
93
+ end
94
+ end
95
+
68
96
  context 'filters that require a user object' do
69
97
 
70
98
  let!(:user_id) { 17 }
@@ -142,5 +170,36 @@ describe FiltersTestController do
142
170
  end
143
171
  end
144
172
  end
173
+
174
+ describe '#require_group_or_attribute' do
175
+ context 'happy paths' do
176
+
177
+ it 'executes action when user has the attribute' do
178
+ set_env_attribute(:department, '9th Circle')
179
+ get :_require_group_or_attribute, groups: 'admin', attr: :department, value: '9th Circle'
180
+ expect(response).to render_template(:dummy)
181
+ end
182
+
183
+ it 'allows action with matching group' do
184
+ allow(subject).to receive(:current_user).and_return(admin)
185
+ get :_require_group_or_id, groups: 'admin', attr: :department, value: '9th Circle'
186
+ expect(response).to render_template(:dummy)
187
+ end
188
+
189
+ it 'allows action with both attribute and group matching' do
190
+ set_env_attribute(:department, '9th Circle')
191
+ allow(subject).to receive(:current_user).and_return(admin)
192
+ get :_require_group_or_id, groups: 'admin', attr: :department, value: '9th Circle'
193
+ expect(response).to render_template(:dummy)
194
+ end
195
+ end
196
+
197
+ context 'with no matching criteria' do
198
+ it 'redirects' do
199
+ get :_require_attribute, attr: :wizard, value: 'Gandalf'
200
+ expect(response).to redirect_to('/shibbolite/login')
201
+ end
202
+ end
203
+ end
145
204
  end
146
205
  end
@@ -4,6 +4,8 @@ require 'spec_helper'
4
4
  # the Shibbolite::Helpers concern
5
5
  describe HelpersTestController do
6
6
 
7
+ include_context 'auth_helpers'
8
+
7
9
  # helper methods
8
10
  #
9
11
 
@@ -38,7 +40,7 @@ describe HelpersTestController do
38
40
  it 'is false' do
39
41
  session[Shibbolite.pid] = nil
40
42
  get :_logged_in?
41
- expect(assigns(:logged_in)).to be_false
43
+ expect(assigns(:logged_in)).to be_falsey
42
44
  end
43
45
  end
44
46
 
@@ -46,7 +48,7 @@ describe HelpersTestController do
46
48
  it 'is true' do
47
49
  session[Shibbolite.pid] = 'SSO authenticated'
48
50
  get :_logged_in?
49
- expect(assigns(:logged_in)).to be_true
51
+ expect(assigns(:logged_in)).to be_truthy
50
52
  end
51
53
  end
52
54
  end
@@ -57,7 +59,7 @@ describe HelpersTestController do
57
59
  it 'is true' do
58
60
  session[Shibbolite.pid] = nil
59
61
  get :_anonymous_user?
60
- expect(assigns(:anonymous)).to be_true
62
+ expect(assigns(:anonymous)).to be_truthy
61
63
  end
62
64
  end
63
65
 
@@ -65,7 +67,7 @@ describe HelpersTestController do
65
67
  it 'is false' do
66
68
  session[Shibbolite.pid] = 'SSO authenticated'
67
69
  get :_anonymous_user?
68
- expect(assigns(:anonymous)).to be_false
70
+ expect(assigns(:anonymous)).to be_falsey
69
71
  end
70
72
  end
71
73
  end
@@ -77,7 +79,7 @@ describe HelpersTestController do
77
79
  session[Shibbolite.pid] = 'SSO authenticated'
78
80
  allow(subject).to receive(:current_user).and_return(nil)
79
81
  get :_guest_user?
80
- expect(assigns(:guest)).to be_true
82
+ expect(assigns(:guest)).to be_truthy
81
83
  end
82
84
  end
83
85
 
@@ -86,7 +88,7 @@ describe HelpersTestController do
86
88
  session[Shibbolite.pid] = nil
87
89
  allow(subject).to receive(:current_user).and_return(nil)
88
90
  get :_guest_user?
89
- expect(assigns(:guest)).to be_false
91
+ expect(assigns(:guest)).to be_falsey
90
92
  end
91
93
  end
92
94
  end
@@ -97,7 +99,7 @@ describe HelpersTestController do
97
99
  it 'is true' do
98
100
  allow(subject).to receive(:current_user).and_return('A valid user')
99
101
  get :_registered_user?
100
- expect(assigns(:registered)).to be_true
102
+ expect(assigns(:registered)).to be_truthy
101
103
  end
102
104
  end
103
105
 
@@ -105,7 +107,7 @@ describe HelpersTestController do
105
107
  it 'is false' do
106
108
  allow(subject).to receive(:current_user).and_return(nil)
107
109
  get :_registered_user?
108
- expect(assigns(:registered)).to be_false
110
+ expect(assigns(:registered)).to be_falsey
109
111
  end
110
112
  end
111
113
  end
@@ -118,12 +120,12 @@ describe HelpersTestController do
118
120
 
119
121
  it 'is true when user is in group' do
120
122
  get :_user_in_group?, group: 'jedi'
121
- expect(assigns(:result)).to be_true
123
+ expect(assigns(:result)).to be_truthy
122
124
  end
123
125
 
124
126
  it 'is false when user is not in group' do
125
127
  get :_user_in_group?, group: 'sith'
126
- expect(assigns(:result)).to be_false
128
+ expect(assigns(:result)).to be_falsey
127
129
  end
128
130
  end
129
131
 
@@ -135,12 +137,27 @@ describe HelpersTestController do
135
137
 
136
138
  it 'is true when user has the id' do
137
139
  get :_user_has_id?, id: '17'
138
- expect(assigns(:result)).to be_true
140
+ expect(assigns(:result)).to be_truthy
139
141
  end
140
142
 
141
143
  it 'is false when user does not have the id' do
142
144
  get :_user_has_id?, id: '23'
143
- expect(assigns(:result)).to be_false
145
+ expect(assigns(:result)).to be_falsey
146
+ end
147
+ end
148
+
149
+ describe '#user_has_attribute?' do
150
+
151
+ before { set_env_attribute(:department, 'HR') }
152
+
153
+ it 'is true when the user has the attribute and value' do
154
+ get :_user_has_attribute?, attr: :department, value: 'HR'
155
+ expect(assigns(:result)).to be_truthy
156
+ end
157
+
158
+ it 'is false when the user doesnt have the attribute and/or value' do
159
+ get :_user_has_attribute?, attr: :department, value: 'QA'
160
+ expect(assigns(:result)).to be_falsey
144
161
  end
145
162
  end
146
163
  end
@@ -10,6 +10,8 @@ class FiltersTestController < ApplicationController
10
10
  before_action(only: :_require_id) { |c| c.require_id params[:id].to_i }
11
11
  before_action(only: :_require_group_or_id) { |c| c.require_group_or_id params[:groups], params[:id].to_i }
12
12
  before_action :use_attributes_if_available, only: :_use_attributes_if_available
13
+ before_action(only: :_require_attribute) { |c| c.require_attribute params[:attr], params[:value] }
14
+ before_action(only: :_require_group_or_attribute) { |c| c.require_group_or_attribute params[:groups], params[:attr], params[:value] }
13
15
 
14
16
  def _require_login
15
17
  render :dummy
@@ -34,4 +36,12 @@ class FiltersTestController < ApplicationController
34
36
  def _use_attributes_if_available
35
37
  render :dummy
36
38
  end
39
+
40
+ def _require_attribute
41
+ render :dummy
42
+ end
43
+
44
+ def _require_group_or_attribute
45
+ render :dummy
46
+ end
37
47
  end
@@ -41,4 +41,9 @@ class HelpersTestController < ApplicationController
41
41
  @result = user_has_id?(params[:id].to_i)
42
42
  render :dummy
43
43
  end
44
+
45
+ def _user_has_attribute?
46
+ @result = user_has_matching_attribute?(params[:attr], params[:value])
47
+ render :dummy
48
+ end
44
49
  end
@@ -32,4 +32,6 @@
32
32
  <%= link_to 'Logout', shibbolite.logout_path %>
33
33
  </p>
34
34
 
35
-
35
+ <p>
36
+ <%= link_to 'AJAX link', controller: :static, action: :admin_resource, remote: true %>
37
+ </p>
@@ -13,7 +13,7 @@ Dummy::Application.configure do
13
13
  config.eager_load = false
14
14
 
15
15
  # Configure static asset server for tests with Cache-Control for performance.
16
- config.serve_static_assets = true
16
+ config.serve_static_files = true
17
17
  config.static_cache_control = "public, max-age=3600"
18
18
 
19
19
  # Show full error reports and disable caching.
Binary file