g5_authenticatable 0.4.2 → 0.5.0
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.
- checksums.yaml +4 -4
- data/.travis.yml +12 -0
- data/CHANGELOG.md +11 -0
- data/Gemfile +2 -2
- data/README.md +186 -1
- data/app/controllers/concerns/g5_authenticatable/authorization.rb +21 -0
- data/app/models/g5_authenticatable/role.rb +8 -0
- data/app/models/g5_authenticatable/user.rb +41 -0
- data/app/policies/g5_authenticatable/base_policy.rb +73 -0
- data/config/initializers/rolify.rb +8 -0
- data/g5_authenticatable.gemspec +3 -0
- data/lib/g5_authenticatable/engine.rb +3 -0
- data/lib/g5_authenticatable/rspec.rb +1 -0
- data/lib/g5_authenticatable/test/factory.rb +51 -1
- data/lib/g5_authenticatable/test/feature_helpers.rb +15 -2
- data/lib/g5_authenticatable/version.rb +1 -1
- data/lib/generators/g5_authenticatable/install/USAGE +7 -1
- data/lib/generators/g5_authenticatable/install/install_generator.rb +33 -6
- data/lib/generators/g5_authenticatable/install/templates/403.html +26 -0
- data/lib/generators/g5_authenticatable/install/templates/application_policy.rb +4 -0
- data/lib/generators/g5_authenticatable/install/templates/{g5_authenticatable.rb → initializer.rb} +0 -0
- data/lib/generators/g5_authenticatable/install/templates/migrate/add_g5_authenticatable_users_contact_info.rb +11 -0
- data/lib/generators/g5_authenticatable/install/templates/migrate/create_g5_authenticatable_roles.rb +20 -0
- data/lib/generators/g5_authenticatable/install/templates/{create_g5_authenticatable_users.rb → migrate/create_g5_authenticatable_users.rb} +0 -0
- data/spec/controllers/application_controller_spec.rb +12 -0
- data/spec/controllers/concerns/g5_authenticatable/authorization.rb +50 -0
- data/spec/dummy/app/assets/javascripts/posts.js +2 -0
- data/spec/dummy/app/assets/stylesheets/posts.css +4 -0
- data/spec/dummy/app/assets/stylesheets/scaffold.css +56 -0
- data/spec/dummy/app/controllers/application_controller.rb +1 -0
- data/spec/dummy/app/controllers/posts_controller.rb +74 -0
- data/spec/dummy/app/helpers/posts_helper.rb +2 -0
- data/spec/dummy/app/models/post.rb +3 -0
- data/spec/dummy/app/policies/application_policy.rb +4 -0
- data/spec/dummy/app/policies/post_policy.rb +4 -0
- data/spec/dummy/app/views/home/index.html.erb +40 -0
- data/spec/dummy/app/views/posts/_form.html.erb +21 -0
- data/spec/dummy/app/views/posts/edit.html.erb +6 -0
- data/spec/dummy/app/views/posts/index.html.erb +30 -0
- data/spec/dummy/app/views/posts/new.html.erb +5 -0
- data/spec/dummy/app/views/posts/show.html.erb +17 -0
- data/spec/dummy/config/database.yml.ci +1 -2
- data/spec/dummy/config/initializers/g5_authenticatable.rb +8 -0
- data/spec/dummy/config/routes.rb +2 -0
- data/spec/dummy/db/migrate/20150428182339_add_g5_authenticatable_users_contact_info.rb +11 -0
- data/spec/dummy/db/migrate/20150429212919_create_g5_authenticatable_roles.rb +20 -0
- data/spec/dummy/db/migrate/20150509061150_create_posts.rb +9 -0
- data/spec/dummy/db/schema.rb +37 -4
- data/spec/dummy/public/403.html +26 -0
- data/spec/factories/post.rb +6 -0
- data/spec/features/default_role_authorization_spec.rb +254 -0
- data/spec/features/sign_in_spec.rb +144 -8
- data/spec/lib/generators/g5_authenticatable/install_generator_spec.rb +72 -1
- data/spec/models/g5_authenticatable/role_spec.rb +81 -0
- data/spec/models/g5_authenticatable/user_spec.rb +340 -3
- data/spec/models/post_spec.rb +12 -0
- data/spec/policies/application_policy_spec.rb +171 -0
- data/spec/policies/post_policy_spec.rb +35 -0
- data/spec/requests/default_role_authorization_spec.rb +169 -0
- data/spec/spec_helper.rb +0 -3
- data/spec/support/shared_examples/super_admin_authorizer.rb +33 -0
- metadata +109 -5
- data/circle.yml +0 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 636e93c7a2f6114bba1839103deb438f1d713098
|
4
|
+
data.tar.gz: b5d0f845a01f7a80521650e1604254940ca35992
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d934f79a4045ecc1b3ca42a81e36582ef0ede8d1c23250783d7c128683c4da1b4c76aab81c19ef890b78d4a321326d0cfba1735dbd86243f32e62b05a3f78ad0
|
7
|
+
data.tar.gz: 465efb38e1da5eb37bec731666840d1b36245dd168f63299a1f297024a6a4cab6d88c367f2e7966b9096eed6c48f07dcacf5c66d0558428036161c590cf825b0
|
data/.travis.yml
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
language: ruby
|
2
|
+
rvm:
|
3
|
+
- 2.1.2
|
4
|
+
script:
|
5
|
+
- RAILS_ENV=test bundle exec rake app:db:setup
|
6
|
+
- bundle exec rspec spec
|
7
|
+
before_script:
|
8
|
+
- cp spec/dummy/config/database.yml.ci spec/dummy/config/database.yml
|
9
|
+
- psql -c 'create database g5_authenticatable_test;' -U postgres
|
10
|
+
env:
|
11
|
+
global:
|
12
|
+
- DEVISE_SECRET_KEY=foo
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,14 @@
|
|
1
|
+
## v0.5.0 (2015-05-21)
|
2
|
+
|
3
|
+
* Added user roles. Requires running `rails g5 g5_authenticatable:install` and
|
4
|
+
`rake db:migrate`
|
5
|
+
([#33](https://github.com/G5/g5_authenticatable/pull/33))
|
6
|
+
* Added user attributes. Requires running `rails g g5_authenticatable:install`
|
7
|
+
and `rake db:migrate`
|
8
|
+
([#32](https://github.com/G5/g5_authenticatable/pull/32))
|
9
|
+
* Updated documentation around test helper dependencies and incompatibilities
|
10
|
+
([#30](https://github.com/G5/g5_authenticatable/pull/30))
|
11
|
+
|
1
12
|
## v0.4.2 (2015-02-10)
|
2
13
|
|
3
14
|
* Override `Devise::FailureApp` with fix for compatibility with Rails 4.2
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -18,7 +18,7 @@ library in isolation.
|
|
18
18
|
|
19
19
|
## Current Version
|
20
20
|
|
21
|
-
0.
|
21
|
+
0.5.0
|
22
22
|
|
23
23
|
## Requirements
|
24
24
|
|
@@ -258,12 +258,197 @@ Authorization header, or in a request parameter named `access_token`.
|
|
258
258
|
For more details, see the documentation for
|
259
259
|
[g5_authenticatable_api](https://github.com/G5/g5_authenticatable_api).
|
260
260
|
|
261
|
+
### Authorization ###
|
262
|
+
|
263
|
+
#### User Roles ####
|
264
|
+
|
265
|
+
User roles are defined on the auth server and automatically populated in the local
|
266
|
+
model layer when a user logs in:
|
267
|
+
|
268
|
+
```ruby
|
269
|
+
current_user.roles
|
270
|
+
# => #<ActiveRecord::Associations::CollectionProxy [#<G5Authenticatable::Role id: 1, name: "viewer", ...>]>
|
271
|
+
```
|
272
|
+
|
273
|
+
We use [rolify](https://github.com/RolifyCommunity/rolify) for role management,
|
274
|
+
which provides an interface for querying role assignments:
|
275
|
+
|
276
|
+
```ruby
|
277
|
+
current_user.has_role?(:editor)
|
278
|
+
```
|
279
|
+
|
280
|
+
G5 currently supports four different roles: `:super_admin`, `:admin`,
|
281
|
+
`:editor`, and `:viewer` (the default role).
|
282
|
+
|
283
|
+
#### Policies and Scopes ####
|
284
|
+
|
285
|
+
G5 Authenticatable uses [pundit](https://github.com/elabs/pundit) to encapsulate
|
286
|
+
the authorization logic in policy objects. The pundit documentation contains a much
|
287
|
+
more thorough explanation of how to define and use policies, but a quick overview
|
288
|
+
is provided here.
|
289
|
+
|
290
|
+
The G5 Authenticatable generator created an `app/policies/application_policy.rb`
|
291
|
+
file in your project:
|
292
|
+
|
293
|
+
```ruby
|
294
|
+
class ApplicationPolicy < G5Authenticatable::BasePolicy
|
295
|
+
class Scope < BaseScope
|
296
|
+
end
|
297
|
+
end
|
298
|
+
```
|
299
|
+
|
300
|
+
The `G5Authenticatable::BasePolicy` and `G5Authenticatable::BasePolicy::BaseScope`
|
301
|
+
implement a set of default authorization rules that essentially forbids access
|
302
|
+
to all actions on all model instances unless the user has the `:super_admin`
|
303
|
+
role. It also provides a set of helper methods for checking user roles:
|
304
|
+
`super_admin?`, `admin?`, `editor?`, or `viewer?`.
|
305
|
+
|
306
|
+
In order to implement a custom policy for one of your application's models, you
|
307
|
+
can create a new policy in the `app/policies` directory. For instance, if you
|
308
|
+
have a `Widget` model, and you want to also grant permissions to update that
|
309
|
+
model to users with `:admin` or `:editor` roles:
|
310
|
+
|
311
|
+
```ruby
|
312
|
+
# app/policies/widget_policy.rb
|
313
|
+
|
314
|
+
class WidgetPolicy < ApplicationPolicy
|
315
|
+
def update?
|
316
|
+
super_admin? || admin? || editor?
|
317
|
+
end
|
318
|
+
end
|
319
|
+
```
|
320
|
+
|
321
|
+
You also have access to the record being authorized, and can define rules based
|
322
|
+
on that. For instance, if you want to restrict `Widget` deletion based on both
|
323
|
+
user role and some flag on the `Widget` instance to be deleted:
|
324
|
+
|
325
|
+
```ruby
|
326
|
+
# app/policies/widget_policy.rb
|
327
|
+
|
328
|
+
class WidgetPolicy < ApplicationPolicy
|
329
|
+
def destroy?
|
330
|
+
(super_admin? || admin?) && !record.published?
|
331
|
+
end
|
332
|
+
end
|
333
|
+
```
|
334
|
+
|
335
|
+
In order to implement data-level authorization, you can define a custom scope
|
336
|
+
within your policy. The scope `resolve` method should only return the records
|
337
|
+
to which the current user has access. You have access to the current `user` and
|
338
|
+
also the `scope` object (defaults to the record class). For instance, if a user
|
339
|
+
must be the owner of a widget in order to access it, but super admins are allowed
|
340
|
+
to access all widgets:
|
341
|
+
|
342
|
+
```ruby
|
343
|
+
# app/policies/widget_policy.rb
|
344
|
+
|
345
|
+
class WidgetPolicy < ApplicationPolicy
|
346
|
+
class Scope < Scope
|
347
|
+
def resolve
|
348
|
+
if user.has_role?(:super_admin?)
|
349
|
+
scope.all
|
350
|
+
else
|
351
|
+
scope.where(owner_id: user.id)
|
352
|
+
end
|
353
|
+
end
|
354
|
+
end
|
355
|
+
end
|
356
|
+
```
|
357
|
+
|
358
|
+
If you want to apply the same authorization logic across all models in your
|
359
|
+
application, you can define them in `ApplicationPolicy` or
|
360
|
+
`ApplicationPolicy::Scope`.
|
361
|
+
|
362
|
+
#### Using Policies in Controllers ####
|
363
|
+
|
364
|
+
You can use the `authorize` method in your controller to ensure that the
|
365
|
+
current user has access to the current action on a particular model instance.
|
366
|
+
For instance, in your controller:
|
367
|
+
|
368
|
+
```ruby
|
369
|
+
class WidgetsController < ApplicationController
|
370
|
+
# ...
|
371
|
+
|
372
|
+
def update
|
373
|
+
@widget = Widget.find(params[:id])
|
374
|
+
authorize(@widget)
|
375
|
+
|
376
|
+
if @widget.update_attributes(widget_params)
|
377
|
+
flash[:notice] = "Widget successfully updated."
|
378
|
+
end
|
379
|
+
|
380
|
+
respond_with(@widget)
|
381
|
+
end
|
382
|
+
end
|
383
|
+
```
|
384
|
+
|
385
|
+
In this example, the `authorize` method will automatically lookup the correct policy
|
386
|
+
and populate it with the `current_user` and the model argument, and then call the
|
387
|
+
`update?` method on it, based on the current action name.
|
388
|
+
|
389
|
+
You can directly access the policy scope to look up the records to which the
|
390
|
+
current user has access by using the `policy_scope` method:
|
391
|
+
|
392
|
+
```ruby
|
393
|
+
class WidgetsController < ApplicationController
|
394
|
+
# ...
|
395
|
+
|
396
|
+
def index
|
397
|
+
@widgets = policy_scope(Widget)
|
398
|
+
end
|
399
|
+
```
|
400
|
+
|
401
|
+
In this example, the `policy_scope` method will automatically look up the
|
402
|
+
`WidgetPolicy::Scope`, populate it with the current user and `Widget` record
|
403
|
+
class, and call the scope `resolve` method to retrieve the results.
|
404
|
+
|
405
|
+
#### Using Policies in Views ####
|
406
|
+
|
407
|
+
Sometimes, you want to be able to access authorization logic inside Rails views.
|
408
|
+
For instance, you may want to hide the link to edit a record if the user does
|
409
|
+
not have access to update that record. In these cases, you can use the `policy`
|
410
|
+
method to lookup the instance of the policy directly:
|
411
|
+
|
412
|
+
```erb
|
413
|
+
<% if policy(@widget).update? %>
|
414
|
+
<%= link_to 'Edit', edit_widget_path(@widget) %>
|
415
|
+
<% end %>
|
416
|
+
```
|
417
|
+
|
418
|
+
You can also call the `policy_scope` method inside views.
|
419
|
+
|
420
|
+
If you are not rendering your views within your Rails application (for
|
421
|
+
instance, if you are using an Ember front-end), then you will have to build
|
422
|
+
your own API for querying policy information in order to access this
|
423
|
+
functionality directly in your view.
|
424
|
+
|
261
425
|
### Test Helpers ###
|
262
426
|
|
263
427
|
G5 Authenticatable currently only supports [rspec-rails](https://github.com/rspec/rspec-rails).
|
264
428
|
Helpers and shared contexts are provided for integration testing secure pages
|
265
429
|
and API methods.
|
266
430
|
|
431
|
+
#### Prerequisites ####
|
432
|
+
|
433
|
+
Because the test helpers are optional, bundler will not automatically install
|
434
|
+
these dependencies. You will have to add the following gems to your own Gemfile:
|
435
|
+
|
436
|
+
* [rspec-rails](https://github.com/rspec/rspec-rails)
|
437
|
+
* [factory_girl_rails](https://github.com/thoughtbot/factory_girl_rails)
|
438
|
+
* [webmock](https://github.com/bblimke/webmock)
|
439
|
+
|
440
|
+
#### Incompatibilities ####
|
441
|
+
|
442
|
+
There are [known issues](https://github.com/G5/g5_authenticatable/issues/27) using the
|
443
|
+
auth test helpers with [selenium-webdriver](http://docs.seleniumhq.org/projects/webdriver/)
|
444
|
+
and the Firefox browser. As such, selenium-webdriver is not officially supported by
|
445
|
+
the G5 Authenticatable library.
|
446
|
+
|
447
|
+
If you are using [capybara](https://github.com/jnicklas/capybara) to run your
|
448
|
+
integration tests, we highly recommend using
|
449
|
+
[poltergeist](https://github.com/teampoltergeist/poltergeist) for PhantomJS as
|
450
|
+
your javascript driver instead.
|
451
|
+
|
267
452
|
#### Installation ####
|
268
453
|
|
269
454
|
To automatically mix in helpers to your feature and request specs, include the
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module G5Authenticatable
|
2
|
+
module Authorization
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
included do
|
6
|
+
include Pundit
|
7
|
+
rescue_from Pundit::NotAuthorizedError, with: :user_not_authorized
|
8
|
+
end
|
9
|
+
|
10
|
+
def user_not_authorized
|
11
|
+
respond_to do |format|
|
12
|
+
format.json do
|
13
|
+
render status: :forbidden, json: {error: 'Access forbidden'}
|
14
|
+
end
|
15
|
+
format.html do
|
16
|
+
render status: :forbidden, file: "#{Rails.root}/public/403"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -1,8 +1,49 @@
|
|
1
1
|
module G5Authenticatable
|
2
2
|
class User < ActiveRecord::Base
|
3
3
|
devise :g5_authenticatable, :trackable, :timeoutable
|
4
|
+
rolify role_cname: 'G5Authenticatable::Role',
|
5
|
+
role_join_table_name: :g5_authenticatable_users_roles
|
4
6
|
|
5
7
|
validates :email, presence: true, uniqueness: true
|
6
8
|
validates_uniqueness_of :uid, scope: :provider
|
9
|
+
|
10
|
+
def self.new_with_session(params, session)
|
11
|
+
user = super(params, session)
|
12
|
+
auth_data = session['omniauth.auth']
|
13
|
+
|
14
|
+
if auth_data
|
15
|
+
user.assign_attributes(extended_auth_attributes(auth_data))
|
16
|
+
user.update_roles_from_auth(auth_data)
|
17
|
+
end
|
18
|
+
|
19
|
+
user
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.find_and_update_for_g5_oauth(auth_data)
|
23
|
+
user = super(auth_data)
|
24
|
+
|
25
|
+
if user
|
26
|
+
user.update_attributes(extended_auth_attributes(auth_data))
|
27
|
+
user.update_roles_from_auth(auth_data)
|
28
|
+
end
|
29
|
+
|
30
|
+
user
|
31
|
+
end
|
32
|
+
|
33
|
+
def update_roles_from_auth(auth_data)
|
34
|
+
roles.clear
|
35
|
+
auth_data.extra.roles.each { |role| add_role(role.name) }
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
def self.extended_auth_attributes(auth_data)
|
40
|
+
{
|
41
|
+
first_name: auth_data.info.first_name,
|
42
|
+
last_name: auth_data.info.last_name,
|
43
|
+
phone_number: auth_data.info.phone,
|
44
|
+
title: auth_data.extra.title,
|
45
|
+
organization_name: auth_data.extra.organization_name
|
46
|
+
}
|
47
|
+
end
|
7
48
|
end
|
8
49
|
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
class G5Authenticatable::BasePolicy
|
2
|
+
attr_reader :user, :record
|
3
|
+
|
4
|
+
def initialize(user, record)
|
5
|
+
@user = user
|
6
|
+
@record = record
|
7
|
+
end
|
8
|
+
|
9
|
+
def index?
|
10
|
+
super_admin?
|
11
|
+
end
|
12
|
+
|
13
|
+
def show?
|
14
|
+
scope.where(:id => record.id).exists?
|
15
|
+
end
|
16
|
+
|
17
|
+
def create?
|
18
|
+
super_admin?
|
19
|
+
end
|
20
|
+
|
21
|
+
def new?
|
22
|
+
create?
|
23
|
+
end
|
24
|
+
|
25
|
+
def update?
|
26
|
+
super_admin?
|
27
|
+
end
|
28
|
+
|
29
|
+
def edit?
|
30
|
+
update?
|
31
|
+
end
|
32
|
+
|
33
|
+
def destroy?
|
34
|
+
super_admin?
|
35
|
+
end
|
36
|
+
|
37
|
+
def scope
|
38
|
+
Pundit.policy_scope!(user, record.class)
|
39
|
+
end
|
40
|
+
|
41
|
+
class BaseScope
|
42
|
+
attr_reader :user, :scope
|
43
|
+
|
44
|
+
def initialize(user, scope)
|
45
|
+
@user = user
|
46
|
+
@scope = scope
|
47
|
+
end
|
48
|
+
|
49
|
+
def resolve
|
50
|
+
if user.has_role?(:super_admin)
|
51
|
+
scope.all
|
52
|
+
else
|
53
|
+
scope.none
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def super_admin?
|
59
|
+
user.present? && user.has_role?(:super_admin)
|
60
|
+
end
|
61
|
+
|
62
|
+
def admin?
|
63
|
+
user.present? && user.has_role?(:admin)
|
64
|
+
end
|
65
|
+
|
66
|
+
def editor?
|
67
|
+
user.present? && user.has_role?(:editor)
|
68
|
+
end
|
69
|
+
|
70
|
+
def viewer?
|
71
|
+
user.present? && user.has_role?(:viewer)
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,8 @@
|
|
1
|
+
Rolify.configure('G5Authenticatable::Role') do |config|
|
2
|
+
# By default ORM adapter is ActiveRecord. uncomment to use mongoid
|
3
|
+
# config.use_mongoid
|
4
|
+
|
5
|
+
# Dynamic shortcuts for User class (user.is_admin? like methods). Default is: false
|
6
|
+
# Enable this feature _after_ running rake db:migrate as it relies on the roles table
|
7
|
+
# config.use_dynamic_shortcuts
|
8
|
+
end
|
data/g5_authenticatable.gemspec
CHANGED
@@ -21,5 +21,8 @@ Gem::Specification.new do |spec|
|
|
21
21
|
spec.require_paths = ['lib']
|
22
22
|
|
23
23
|
spec.add_dependency 'devise_g5_authenticatable', '~> 0.2'
|
24
|
+
spec.add_dependency 'omniauth-g5', '~> 0.2'
|
24
25
|
spec.add_dependency 'g5_authenticatable_api', '~> 0.3.1'
|
26
|
+
spec.add_dependency 'rolify', '~> 4.0'
|
27
|
+
spec.add_dependency 'pundit', '~> 1.0'
|
25
28
|
end
|
@@ -1,10 +1,60 @@
|
|
1
1
|
require 'factory_girl_rails'
|
2
2
|
|
3
3
|
FactoryGirl.define do
|
4
|
-
factory :g5_authenticatable_user, :
|
4
|
+
factory :g5_authenticatable_user, class: 'G5Authenticatable::User' do
|
5
5
|
sequence(:email) { |n| "test.user#{n}@test.host" }
|
6
6
|
provider 'g5'
|
7
7
|
sequence(:uid) { |n| "abc123-#{n}" }
|
8
8
|
sequence(:g5_access_token) { |n| "secret_token_#{n}" }
|
9
|
+
first_name 'Jane'
|
10
|
+
last_name 'Doe'
|
11
|
+
phone_number '(555) 867-5309'
|
12
|
+
title 'Minister of Funny Walks'
|
13
|
+
organization_name 'Department of Redundancy Department'
|
14
|
+
|
15
|
+
after(:build) do |user|
|
16
|
+
user.roles << FactoryGirl.build(:g5_authenticatable_viewer_role)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
factory :g5_authenticatable_super_admin, parent: :g5_authenticatable_user do
|
21
|
+
after(:build) do |user|
|
22
|
+
user.roles.clear
|
23
|
+
user.roles << FactoryGirl.build(:g5_authenticatable_super_admin_role)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
factory :g5_authenticatable_admin, parent: :g5_authenticatable_user do
|
28
|
+
after(:build) do |user|
|
29
|
+
user.roles.clear
|
30
|
+
user.roles << FactoryGirl.build(:g5_authenticatable_admin_role)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
factory :g5_authenticatable_editor, parent: :g5_authenticatable_user do
|
35
|
+
after(:build) do |user|
|
36
|
+
user.roles.clear
|
37
|
+
user.roles << FactoryGirl.build(:g5_authenticatable_editor_role)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
factory :g5_authenticatable_role, class: 'G5Authenticatable::Role' do
|
42
|
+
sequence(:name) { |n| "role_#{n}" }
|
43
|
+
end
|
44
|
+
|
45
|
+
factory :g5_authenticatable_super_admin_role, parent: :g5_authenticatable_role do
|
46
|
+
name 'super_admin'
|
47
|
+
end
|
48
|
+
|
49
|
+
factory :g5_authenticatable_admin_role, parent: :g5_authenticatable_role do
|
50
|
+
name 'admin'
|
51
|
+
end
|
52
|
+
|
53
|
+
factory :g5_authenticatable_editor_role, parent: :g5_authenticatable_role do
|
54
|
+
name 'editor'
|
55
|
+
end
|
56
|
+
|
57
|
+
factory :g5_authenticatable_viewer_role, parent: :g5_authenticatable_role do
|
58
|
+
name 'viewer'
|
9
59
|
end
|
10
60
|
end
|
@@ -5,8 +5,21 @@ module G5Authenticatable
|
|
5
5
|
OmniAuth.config.mock_auth[:g5] = OmniAuth::AuthHash.new({
|
6
6
|
uid: user.uid,
|
7
7
|
provider: 'g5',
|
8
|
-
info: {
|
9
|
-
|
8
|
+
info: {
|
9
|
+
email: user.email,
|
10
|
+
first_name: user.first_name,
|
11
|
+
last_name: user.last_name,
|
12
|
+
phone: user.phone_number
|
13
|
+
},
|
14
|
+
credentials: {token: user.g5_access_token},
|
15
|
+
extra: {
|
16
|
+
title: user.title,
|
17
|
+
organization_name: user.organization_name,
|
18
|
+
roles: user.roles.collect do |role|
|
19
|
+
{name: role.name}
|
20
|
+
end,
|
21
|
+
raw_info: {}
|
22
|
+
}
|
10
23
|
}.merge(options))
|
11
24
|
end
|
12
25
|
|
@@ -1,11 +1,17 @@
|
|
1
1
|
Description:
|
2
|
-
Installs the g5_authenticatable engine
|
2
|
+
Installs/updates the g5_authenticatable engine
|
3
3
|
|
4
4
|
Example:
|
5
5
|
rails generate g5_authenticatable:install
|
6
6
|
|
7
7
|
This will create:
|
8
|
+
app/policies/application_policy.rb
|
9
|
+
config/initializers/g5_authenticatable.rb
|
8
10
|
db/migrate/create_g5_authenticatable_users.rb
|
11
|
+
db/migrate/add_g5_authenticatable_users_contact_info.rb
|
12
|
+
db/migrate/create_g5_authenticatable_roles.rb
|
13
|
+
public/403.html
|
9
14
|
|
10
15
|
This will modify:
|
16
|
+
app/controllers/application_controller.rb
|
11
17
|
config/routes.rb
|
@@ -9,16 +9,43 @@ class G5Authenticatable::InstallGenerator < Rails::Generators::Base
|
|
9
9
|
ActiveRecord::Migration.next_migration_number(next_migration_number)
|
10
10
|
end
|
11
11
|
|
12
|
-
def create_users_migration
|
13
|
-
filename = 'create_g5_authenticatable_users.rb'
|
14
|
-
migration_template filename, "db/migrate/#{filename}"
|
15
|
-
end
|
16
|
-
|
17
12
|
def mount_engine
|
18
13
|
route "mount G5Authenticatable::Engine => '/g5_auth'"
|
19
14
|
end
|
20
15
|
|
21
16
|
def create_initializer
|
22
|
-
template '
|
17
|
+
template 'initializer.rb', 'config/initializers/g5_authenticatable.rb'
|
18
|
+
end
|
19
|
+
|
20
|
+
def create_users_migration
|
21
|
+
copy_migration('create_g5_authenticatable_users')
|
22
|
+
end
|
23
|
+
|
24
|
+
def users_contact_info_migration
|
25
|
+
copy_migration('add_g5_authenticatable_users_contact_info')
|
26
|
+
end
|
27
|
+
|
28
|
+
def create_roles_migration
|
29
|
+
copy_migration('create_g5_authenticatable_roles')
|
30
|
+
end
|
31
|
+
|
32
|
+
def include_authorization
|
33
|
+
inject_into_file 'app/controllers/application_controller.rb',
|
34
|
+
after: "class ApplicationController < ActionController::Base\n" do
|
35
|
+
" include G5Authenticatable::Authorization\n"
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def create_application_policy
|
40
|
+
template 'application_policy.rb', 'app/policies/application_policy.rb'
|
41
|
+
end
|
42
|
+
|
43
|
+
def create_403_error_page
|
44
|
+
template '403.html', 'public/403.html'
|
45
|
+
end
|
46
|
+
|
47
|
+
private
|
48
|
+
def copy_migration(name)
|
49
|
+
migration_template "migrate/#{name}.rb", "db/migrate/#{name}.rb"
|
23
50
|
end
|
24
51
|
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<title>Access forbidden (403)</title>
|
5
|
+
<style type="text/css">
|
6
|
+
body { background-color: #fff; color: #666; text-align: center; font-family: arial, sans-serif; }
|
7
|
+
div.dialog {
|
8
|
+
width: 25em;
|
9
|
+
padding: 0 4em;
|
10
|
+
margin: 4em auto 0 auto;
|
11
|
+
border: 1px solid #ccc;
|
12
|
+
border-right-color: #999;
|
13
|
+
border-bottom-color: #999;
|
14
|
+
}
|
15
|
+
h1 { font-size: 100%; color: #f00; line-height: 1.5em; }
|
16
|
+
</style>
|
17
|
+
</head>
|
18
|
+
|
19
|
+
<body>
|
20
|
+
<!-- This file lives in public/403.html -->
|
21
|
+
<div class="dialog">
|
22
|
+
<h1>Access forbidden</h1>
|
23
|
+
<p>You do not have permission to access this page.</p>
|
24
|
+
</div>
|
25
|
+
</body>
|
26
|
+
</html>
|
data/lib/generators/g5_authenticatable/install/templates/{g5_authenticatable.rb → initializer.rb}
RENAMED
File without changes
|
@@ -0,0 +1,11 @@
|
|
1
|
+
class AddG5AuthenticatableUsersContactInfo < ActiveRecord::Migration
|
2
|
+
def change
|
3
|
+
change_table(:g5_authenticatable_users) do |t|
|
4
|
+
t.string :first_name
|
5
|
+
t.string :last_name
|
6
|
+
t.string :phone_number
|
7
|
+
t.string :title
|
8
|
+
t.string :organization_name
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
data/lib/generators/g5_authenticatable/install/templates/migrate/create_g5_authenticatable_roles.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
class CreateG5AuthenticatableRoles < ActiveRecord::Migration
|
2
|
+
def change
|
3
|
+
create_table(:g5_authenticatable_roles) do |t|
|
4
|
+
t.string :name
|
5
|
+
t.references :resource, :polymorphic => true
|
6
|
+
|
7
|
+
t.timestamps
|
8
|
+
end
|
9
|
+
|
10
|
+
create_table(:g5_authenticatable_users_roles, :id => false) do |t|
|
11
|
+
t.references :user
|
12
|
+
t.references :role
|
13
|
+
end
|
14
|
+
|
15
|
+
add_index(:g5_authenticatable_roles, :name)
|
16
|
+
add_index(:g5_authenticatable_roles, [ :name, :resource_type, :resource_id ],
|
17
|
+
name: 'index_g5_authenticatable_roles_on_name_and_resource')
|
18
|
+
add_index(:g5_authenticatable_users_roles, [ :user_id, :role_id ])
|
19
|
+
end
|
20
|
+
end
|