super_auth 0.3.3 → 0.7.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/CHANGELOG.md +78 -0
- data/Gemfile +5 -0
- data/Gemfile.lock +8 -1
- data/README.md +286 -22
- data/USAGE.md +41 -16
- data/config/routes.rb +9 -71
- data/db/migrate/10_add_super_auth_label_to_resources.rb +13 -0
- data/db/migrate/1_users.rb +1 -1
- data/db/migrate/5_resources.rb +1 -1
- data/db/migrate/7_authorization.rb +2 -2
- data/db/migrate/8_add_indexes_to_edges.rb +7 -0
- data/db/migrate_activerecord/20250101000001_create_super_auth_users.rb +1 -1
- data/db/migrate_activerecord/20250101000005_create_super_auth_resources.rb +1 -1
- data/db/migrate_activerecord/20250101000007_create_super_auth_authorizations.rb +2 -2
- data/db/migrate_activerecord/20250101000010_add_super_auth_label_to_super_auth_resources.rb +5 -0
- data/exe/super_auth-editor +9 -0
- data/lib/generators/super_auth/install/templates/README +15 -10
- data/lib/generators/super_auth/install/templates/super_auth.rb +16 -5
- data/lib/generators/super_auth/rls/rls_generator.rb +22 -0
- data/lib/generators/super_auth/rls/templates/migration.rb.erb +15 -0
- data/lib/super_auth/active_record/by_current_user.rb +25 -5
- data/lib/super_auth/active_record/resource.rb +41 -0
- data/lib/super_auth/active_record/user.rb +3 -1
- data/lib/super_auth/authorization.rb +12 -0
- data/lib/super_auth/edge.rb +65 -100
- data/lib/super_auth/editor/cli.rb +91 -0
- data/lib/super_auth/editor/index.html +423 -0
- data/lib/super_auth/editor/seed.rb +170 -0
- data/lib/super_auth/editor.rb +273 -0
- data/lib/super_auth/nestable.rb +41 -3
- data/lib/super_auth/railtie.rb +0 -2
- data/lib/super_auth/rls.rb +256 -0
- data/lib/super_auth/user.rb +3 -1
- data/lib/super_auth/version.rb +1 -1
- data/lib/super_auth.rb +85 -0
- data/lib/tasks/super_auth_tasks.rake +28 -0
- metadata +15 -9
- data/VISUALIZATION.md +0 -58
- data/app/controllers/super_auth/graph_controller.rb +0 -654
- data/app/views/super_auth/graph/index.html.erb +0 -1408
- data/super_auth.gemspec +0 -35
- data/visualization.html +0 -747
data/lib/super_auth.rb
CHANGED
|
@@ -22,6 +22,43 @@ module SuperAuth
|
|
|
22
22
|
@missing_user_behavior = behavior
|
|
23
23
|
end
|
|
24
24
|
|
|
25
|
+
# Column type for the external id columns (users.external_id,
|
|
26
|
+
# resources.external_id and their copies on authorizations). Set it to your
|
|
27
|
+
# application's primary key type (:bigint, :uuid, :string, ...) BEFORE
|
|
28
|
+
# running the super_auth migrations — the columns are then created with the
|
|
29
|
+
# matching type and every comparison against your tables' pks is natively
|
|
30
|
+
# typed, with no casting anywhere. Default :string.
|
|
31
|
+
def self.external_id_type
|
|
32
|
+
@external_id_type || :string
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def self.external_id_type=(type)
|
|
36
|
+
@external_id_type = type
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# Sequel migrations take the Ruby String class for varchar; anything else
|
|
40
|
+
# passes through as the literal database type name.
|
|
41
|
+
def self.sequel_external_id_type
|
|
42
|
+
external_id_type == :string ? String : external_id_type
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# The human name of the application record behind a node, by convention
|
|
46
|
+
# rather than configuration: a model says it explicitly with
|
|
47
|
+
# `super_auth_label`, otherwise `name` then `title` are tried, and a model
|
|
48
|
+
# with none of them has no label. This is also the name of the column the
|
|
49
|
+
# derivation is stored in, since `label` is a name applications want for
|
|
50
|
+
# themselves. Deliberately never `to_s` — the label sits where the editor
|
|
51
|
+
# otherwise renders `Type#id`, and "#<Claim:0x000055…>" is worse than the id
|
|
52
|
+
# it would replace.
|
|
53
|
+
def self.label_for(record)
|
|
54
|
+
%i[super_auth_label name title].each do |method|
|
|
55
|
+
next unless record.respond_to?(method)
|
|
56
|
+
value = record.public_send(method)
|
|
57
|
+
return value.to_s unless value.nil? || value.to_s.empty?
|
|
58
|
+
end
|
|
59
|
+
nil
|
|
60
|
+
end
|
|
61
|
+
|
|
25
62
|
def self.load
|
|
26
63
|
require "super_auth/authorization"
|
|
27
64
|
require "super_auth/edge"
|
|
@@ -30,6 +67,7 @@ module SuperAuth
|
|
|
30
67
|
require "super_auth/permission"
|
|
31
68
|
require "super_auth/railtie"
|
|
32
69
|
require "super_auth/resource"
|
|
70
|
+
require "super_auth/rls"
|
|
33
71
|
require "super_auth/role"
|
|
34
72
|
require "super_auth/user"
|
|
35
73
|
require "super_auth/active_record" if defined?(ActiveRecord::Base)
|
|
@@ -40,6 +78,25 @@ module SuperAuth
|
|
|
40
78
|
require "pathname"
|
|
41
79
|
path = Pathname.new(__FILE__).parent.parent.join("db", "migrate")
|
|
42
80
|
Sequel::Migrator.run(SuperAuth.db, path)
|
|
81
|
+
refresh_model_schemas
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
# Both ORMs cache column types per model class; after (re)installing the
|
|
85
|
+
# migrations those caches can describe a previous schema (e.g. a different
|
|
86
|
+
# external_id_type) and silently miscast assigned values.
|
|
87
|
+
def self.refresh_model_schemas
|
|
88
|
+
models = %w[User Group Permission Role Resource Edge Authorization]
|
|
89
|
+
if defined?(SuperAuth::ActiveRecord::User)
|
|
90
|
+
models.each do |name|
|
|
91
|
+
SuperAuth::ActiveRecord.const_get(name).reset_column_information
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
if defined?(SuperAuth::User) && SuperAuth::User.respond_to?(:set_dataset)
|
|
95
|
+
models.each do |name|
|
|
96
|
+
model = SuperAuth.const_get(name)
|
|
97
|
+
model.set_dataset(model.dataset)
|
|
98
|
+
end
|
|
99
|
+
end
|
|
43
100
|
end
|
|
44
101
|
|
|
45
102
|
def self.uninstall_migrations
|
|
@@ -55,6 +112,33 @@ module SuperAuth
|
|
|
55
112
|
raise Error, "Failed to uninstall migrations: #{e.message}"
|
|
56
113
|
end
|
|
57
114
|
|
|
115
|
+
# Run the block as `user` in both layers: SuperAuth.current_user, which the
|
|
116
|
+
# ByCurrentUser scope reads, and the database identity the RLS policies read
|
|
117
|
+
# (see SuperAuth::RLS.as). Both are restored on the way out, whether the
|
|
118
|
+
# block returns, raises, or was nested inside another `as`. Passing nil runs
|
|
119
|
+
# the block with no user in either layer. Postgres only, since the database
|
|
120
|
+
# half is. Keyword options (auto_savepoint:, ...) go to SuperAuth::RLS.as.
|
|
121
|
+
# current_user is assigned inside the transaction, after the database
|
|
122
|
+
# identity, so an application that hooks the writer to re-assert does so on
|
|
123
|
+
# the connection that holds the transaction.
|
|
124
|
+
def self.as(user, db: SuperAuth.db, **options)
|
|
125
|
+
previous = current_user
|
|
126
|
+
SuperAuth::RLS.as(user, db: db, **options) do
|
|
127
|
+
self.current_user = user
|
|
128
|
+
yield
|
|
129
|
+
end
|
|
130
|
+
ensure
|
|
131
|
+
self.current_user = previous
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
# Both user models are internal: their id is the user_id that the policies
|
|
135
|
+
# and ByCurrentUser match on. Anything else is an application object,
|
|
136
|
+
# matched by id and class name.
|
|
137
|
+
def self.internal_user?(user)
|
|
138
|
+
(defined?(SuperAuth::ActiveRecord::User) && user.is_a?(SuperAuth::ActiveRecord::User)) ||
|
|
139
|
+
(defined?(SuperAuth::User) && user.is_a?(SuperAuth::User))
|
|
140
|
+
end
|
|
141
|
+
|
|
58
142
|
def self.current_user=(user)
|
|
59
143
|
Thread.current[:super_auth_current_user] = user
|
|
60
144
|
end
|
|
@@ -128,4 +212,5 @@ module SuperAuth
|
|
|
128
212
|
end
|
|
129
213
|
end
|
|
130
214
|
|
|
215
|
+
require "super_auth/rls"
|
|
131
216
|
require "super_auth/railtie" if defined?(Rails::Railtie)
|
|
@@ -6,6 +6,34 @@ namespace :super_auth do
|
|
|
6
6
|
puts "Done"
|
|
7
7
|
end
|
|
8
8
|
|
|
9
|
+
namespace :labels do
|
|
10
|
+
desc "Re-derive super_auth_resources.super_auth_label from the application records"
|
|
11
|
+
task backfill: :environment do
|
|
12
|
+
SuperAuth.load
|
|
13
|
+
backfill = lambda do
|
|
14
|
+
changed = 0
|
|
15
|
+
SuperAuth::ActiveRecord::Resource.where.not(external_id: nil).find_each do |resource|
|
|
16
|
+
before = resource.super_auth_label
|
|
17
|
+
resource.refresh_label!
|
|
18
|
+
changed += 1 if resource.super_auth_label != before
|
|
19
|
+
end
|
|
20
|
+
changed
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# The application tables this reads are the ones RLS protects, so a run
|
|
24
|
+
# with no identity derives nil for exactly the rows that matter most and
|
|
25
|
+
# then reports success. Assert the system identity where RLS is
|
|
26
|
+
# installed; where it is not, there is nothing to assert.
|
|
27
|
+
changed =
|
|
28
|
+
if SuperAuth::RLS.installed?
|
|
29
|
+
SuperAuth.as(SuperAuth::ActiveRecord::User.system) { backfill.call }
|
|
30
|
+
else
|
|
31
|
+
backfill.call
|
|
32
|
+
end
|
|
33
|
+
puts "Labelled #{changed} resources"
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
9
37
|
task :rollback => :environment do
|
|
10
38
|
raise "You must define SUPER_AUTH_DATABASE_URL in your environment for this to work" if ENV['SUPER_AUTH_DATABASE_URL'].nil? || ENV['SUPER_AUTH_DATABASE_URL'].empty?
|
|
11
39
|
SuperAuth.uninstall_migrations
|
metadata
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: super_auth
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.7.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Jonathan Frias
|
|
8
|
-
bindir:
|
|
8
|
+
bindir: exe
|
|
9
9
|
cert_chain: []
|
|
10
10
|
date: 1980-01-02 00:00:00.000000000 Z
|
|
11
11
|
dependencies:
|
|
@@ -40,7 +40,8 @@ dependencies:
|
|
|
40
40
|
description: Simple, yet super powerful authorization for you application
|
|
41
41
|
email:
|
|
42
42
|
- jonathan@gofrias.com
|
|
43
|
-
executables:
|
|
43
|
+
executables:
|
|
44
|
+
- super_auth-editor
|
|
44
45
|
extensions: []
|
|
45
46
|
extra_rdoc_files: []
|
|
46
47
|
files:
|
|
@@ -53,10 +54,8 @@ files:
|
|
|
53
54
|
- README.md
|
|
54
55
|
- Rakefile
|
|
55
56
|
- USAGE.md
|
|
56
|
-
- VISUALIZATION.md
|
|
57
|
-
- app/controllers/super_auth/graph_controller.rb
|
|
58
|
-
- app/views/super_auth/graph/index.html.erb
|
|
59
57
|
- config/routes.rb
|
|
58
|
+
- db/migrate/10_add_super_auth_label_to_resources.rb
|
|
60
59
|
- db/migrate/1_users.rb
|
|
61
60
|
- db/migrate/2_groups.rb
|
|
62
61
|
- db/migrate/3_permissions.rb
|
|
@@ -74,11 +73,15 @@ files:
|
|
|
74
73
|
- db/migrate_activerecord/20250101000006_create_super_auth_edges.rb
|
|
75
74
|
- db/migrate_activerecord/20250101000007_create_super_auth_authorizations.rb
|
|
76
75
|
- db/migrate_activerecord/20250101000009_add_by_current_user_index_to_super_auth_authorizations.rb
|
|
76
|
+
- db/migrate_activerecord/20250101000010_add_super_auth_label_to_super_auth_resources.rb
|
|
77
77
|
- db/seeds/sample_data.rb
|
|
78
|
+
- exe/super_auth-editor
|
|
78
79
|
- lib/basic_loader.rb
|
|
79
80
|
- lib/generators/super_auth/install/install_generator.rb
|
|
80
81
|
- lib/generators/super_auth/install/templates/README
|
|
81
82
|
- lib/generators/super_auth/install/templates/super_auth.rb
|
|
83
|
+
- lib/generators/super_auth/rls/rls_generator.rb
|
|
84
|
+
- lib/generators/super_auth/rls/templates/migration.rb.erb
|
|
82
85
|
- lib/super_auth.rb
|
|
83
86
|
- lib/super_auth/active_record.rb
|
|
84
87
|
- lib/super_auth/active_record/authorization.rb
|
|
@@ -91,20 +94,23 @@ files:
|
|
|
91
94
|
- lib/super_auth/active_record/user.rb
|
|
92
95
|
- lib/super_auth/authorization.rb
|
|
93
96
|
- lib/super_auth/edge.rb
|
|
97
|
+
- lib/super_auth/editor.rb
|
|
98
|
+
- lib/super_auth/editor/cli.rb
|
|
99
|
+
- lib/super_auth/editor/index.html
|
|
100
|
+
- lib/super_auth/editor/seed.rb
|
|
94
101
|
- lib/super_auth/group.rb
|
|
95
102
|
- lib/super_auth/nestable.rb
|
|
96
103
|
- lib/super_auth/permission.rb
|
|
97
104
|
- lib/super_auth/railtie.rb
|
|
98
105
|
- lib/super_auth/resource.rb
|
|
106
|
+
- lib/super_auth/rls.rb
|
|
99
107
|
- lib/super_auth/role.rb
|
|
100
108
|
- lib/super_auth/user.rb
|
|
101
109
|
- lib/super_auth/version.rb
|
|
102
110
|
- lib/tasks/super_auth_tasks.rake
|
|
103
|
-
- super_auth.gemspec
|
|
104
|
-
- visualization.html
|
|
105
111
|
homepage: https://github.com/JonathanFrias/super_auth
|
|
106
112
|
licenses:
|
|
107
|
-
-
|
|
113
|
+
- GPL-2.0
|
|
108
114
|
metadata:
|
|
109
115
|
homepage_uri: https://github.com/JonathanFrias/super_auth
|
|
110
116
|
source_code_uri: https://github.com/JonathanFrias/super_auth
|
data/VISUALIZATION.md
DELETED
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
# SuperAuth Graph Visualization
|
|
2
|
-
|
|
3
|
-
SuperAuth includes an interactive graph visualization tool that helps you understand and debug your authorization rules.
|
|
4
|
-
|
|
5
|
-
## Setup
|
|
6
|
-
|
|
7
|
-
### 1. Run the Installer
|
|
8
|
-
|
|
9
|
-
Generate the initializer and install migrations:
|
|
10
|
-
|
|
11
|
-
```bash
|
|
12
|
-
rails generate super_auth:install
|
|
13
|
-
```
|
|
14
|
-
|
|
15
|
-
This will:
|
|
16
|
-
- Create `config/initializers/super_auth.rb`
|
|
17
|
-
- Install SuperAuth database migrations
|
|
18
|
-
- Show you the next steps
|
|
19
|
-
|
|
20
|
-
### 2. Mount the Engine
|
|
21
|
-
|
|
22
|
-
Add the following to your `config/routes.rb`:
|
|
23
|
-
|
|
24
|
-
```ruby
|
|
25
|
-
Rails.application.routes.draw do
|
|
26
|
-
mount SuperAuth::Engine => '/super_auth'
|
|
27
|
-
|
|
28
|
-
# Your other routes...
|
|
29
|
-
end
|
|
30
|
-
```
|
|
31
|
-
|
|
32
|
-
## Features
|
|
33
|
-
|
|
34
|
-
### Interactive Graph
|
|
35
|
-
|
|
36
|
-
- **Nodes**: Color-coded by type (Users, Groups, Roles, Permissions, Resources)
|
|
37
|
-
- **Edges**: Solid lines for authorization relationships, dashed for hierarchy
|
|
38
|
-
- **Zoom & Pan**: Navigate large graphs easily
|
|
39
|
-
- **Click nodes**: View node details
|
|
40
|
-
|
|
41
|
-
### Authorization Query
|
|
42
|
-
|
|
43
|
-
1. Select a user from the dropdown
|
|
44
|
-
2. Select a resource from the dropdown
|
|
45
|
-
3. Click "Find Authorization Paths"
|
|
46
|
-
4. View all paths that grant access
|
|
47
|
-
5. See the first path highlighted on the graph
|
|
48
|
-
|
|
49
|
-
### Statistics Panel
|
|
50
|
-
|
|
51
|
-
Real-time counts of:
|
|
52
|
-
- Users
|
|
53
|
-
- Groups (with hierarchical relationships)
|
|
54
|
-
- Roles (with hierarchical relationships)
|
|
55
|
-
- Permissions
|
|
56
|
-
- Resources
|
|
57
|
-
- Authorization edges
|
|
58
|
-
|