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/edge.rb
CHANGED
|
@@ -8,6 +8,11 @@ class SuperAuth::Edge < Sequel::Model(:super_auth_edges)
|
|
|
8
8
|
many_to_one :resource
|
|
9
9
|
|
|
10
10
|
class << self
|
|
11
|
+
# The five strategies are UNIONed positionally. A column that is a real
|
|
12
|
+
# text column in one strategy and CAST(NULL AS ...) in another must be cast
|
|
13
|
+
# in every strategy: on MySQL the table collation and the connection
|
|
14
|
+
# collation can differ, and a column meeting a NULL cast at the same
|
|
15
|
+
# coercibility raises "Illegal mix of collations for operation 'UNION'".
|
|
11
16
|
def string_cast_type
|
|
12
17
|
case SuperAuth.db.database_type
|
|
13
18
|
when :mysql, :mysql2
|
|
@@ -36,44 +41,24 @@ class SuperAuth::Edge < Sequel::Model(:super_auth_edges)
|
|
|
36
41
|
|
|
37
42
|
def users_groups_roles_permissions_resources
|
|
38
43
|
cast_type = string_cast_type
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
Sequel[:
|
|
46
|
-
Sequel[:
|
|
47
|
-
Sequel[:
|
|
48
|
-
Sequel[:
|
|
49
|
-
Sequel[:
|
|
50
|
-
Sequel[:
|
|
51
|
-
Sequel[:
|
|
52
|
-
Sequel[:super_auth_edges]
|
|
53
|
-
Sequel[:
|
|
54
|
-
Sequel[:super_auth_edges]
|
|
55
|
-
Sequel[:
|
|
56
|
-
|
|
57
|
-
Sequel[:groups][:group_name_path],
|
|
58
|
-
Sequel[:groups][:parent_id],
|
|
59
|
-
Sequel[:groups][:created_at].cast(cast_type).as(:group_created_at),
|
|
60
|
-
Sequel[:groups][:updated_at].cast(cast_type).as(:group_updated_at),
|
|
61
|
-
).join(Sequel[:super_auth_edges].as(:group_role_edges), Sequel[:group_role_edges][:group_id] => Sequel[:groups][:id]).select_append(
|
|
62
|
-
Sequel[:group_role_edges][:id].as(:group_role_edge_id),
|
|
63
|
-
Sequel[:group_role_edges][:permission_id].as(:group_role_edge_permission_id),
|
|
64
|
-
Sequel[:group_role_edges][:group_id].as(:group_role_edge_group_id),
|
|
65
|
-
Sequel[:group_role_edges][:user_id].as(:group_role_edge_user_id),
|
|
66
|
-
Sequel[:group_role_edges][:role_id].as(:group_role_edge_role_id),
|
|
67
|
-
).join(:super_auth_roles, id: Sequel[:group_role_edges][:role_id])
|
|
68
|
-
|
|
69
|
-
SuperAuth::Edge.from(
|
|
70
|
-
SuperAuth::Edge.from(
|
|
71
|
-
SuperAuth::Group.cte(SuperAuth::Group.where(id: users_groups_roles_ds.select(Sequel[:groups][:id])).select(:id)).select { [id.as(:group_id), name.as(:group_name), parent_id.as(:group_parent_id), group_path, group_name_path, created_at.cast(cast_type).as(:group_created_at), updated_at.as(:group_updated_at)] },
|
|
72
|
-
SuperAuth::Role.cte(users_groups_roles_ds.select(Sequel[:group_role_edges][:role_id])).select { [id.as(:role_id), name.as(:role_name), parent_id.as(:role_parent_id), role_path, role_name_path, created_at.as(:role_created_at), updated_at.as(:role_updated_at) ] }
|
|
73
|
-
).as(:users_groups_roles_permissions_resources)
|
|
74
|
-
).join(Sequel[:super_auth_edges].as(:user_edges), Sequel[:user_edges][:group_id] => Sequel[:users_groups_roles_permissions_resources][:group_id])
|
|
75
|
-
.join(Sequel[:super_auth_users], id: Sequel[:user_edges][:user_id])
|
|
76
|
-
.select(
|
|
44
|
+
# Join users to their group via edges. group_ancestors pairs that group with itself and
|
|
45
|
+
# every ancestor, so a group -> role edge on any of them applies. role_descendants then
|
|
46
|
+
# expands the granted role to its whole subtree. Each step is correlated to the previous
|
|
47
|
+
# one, so a role held by one group never reaches members of an unrelated group. The tree
|
|
48
|
+
# CTEs (user_groups, granted_roles) are joined by id only to supply the path columns.
|
|
49
|
+
SuperAuth::User.db[:super_auth_users].
|
|
50
|
+
join(Sequel[:super_auth_edges].as(:user_edges), user_id: :id).
|
|
51
|
+
join(SuperAuth::Group.ancestor_pairs.as(:group_ancestors), descendant_id: Sequel[:user_edges][:group_id]).
|
|
52
|
+
join(Sequel[:super_auth_edges].as(:group_role_edges), group_id: Sequel[:group_ancestors][:ancestor_id]).
|
|
53
|
+
where(Sequel.~(Sequel[:group_role_edges][:role_id] => nil)).
|
|
54
|
+
join(SuperAuth::Role.descendant_pairs.as(:role_descendants), ancestor_id: Sequel[:group_role_edges][:role_id]).
|
|
55
|
+
join(SuperAuth::Group.from(SuperAuth::Group.trees).as(:user_groups), Sequel[:user_groups][:id] => Sequel[:user_edges][:group_id]).
|
|
56
|
+
join(SuperAuth::Role.from(SuperAuth::Role.trees).as(:granted_roles), Sequel[:granted_roles][:id] => Sequel[:role_descendants][:descendant_id]).
|
|
57
|
+
join(Sequel[:super_auth_edges].as(:permission_edges), Sequel[:permission_edges][:role_id] => Sequel[:granted_roles][:id]).
|
|
58
|
+
join(Sequel[:super_auth_permissions], id: Sequel[:permission_edges][:permission_id]).
|
|
59
|
+
join(Sequel[:super_auth_edges].as(:resource_edges), Sequel[:resource_edges][:permission_id] => Sequel[:super_auth_permissions][:id]).
|
|
60
|
+
join(Sequel[:super_auth_resources], id: Sequel[:resource_edges][:resource_id]).
|
|
61
|
+
select(
|
|
77
62
|
Sequel[:super_auth_users][:id].as(:user_id),
|
|
78
63
|
Sequel[:super_auth_users][:name].as(:user_name),
|
|
79
64
|
Sequel[:super_auth_users][:external_id].as(:user_external_id),
|
|
@@ -81,24 +66,24 @@ class SuperAuth::Edge < Sequel::Model(:super_auth_edges)
|
|
|
81
66
|
Sequel[:super_auth_users][:created_at].cast(cast_type).as(:user_created_at),
|
|
82
67
|
Sequel[:super_auth_users][:updated_at].cast(cast_type).as(:user_updated_at),
|
|
83
68
|
|
|
84
|
-
Sequel[:
|
|
85
|
-
Sequel[:
|
|
86
|
-
Sequel[:
|
|
87
|
-
Sequel[:
|
|
88
|
-
Sequel[:
|
|
89
|
-
Sequel[:
|
|
90
|
-
Sequel[:
|
|
69
|
+
Sequel[:user_groups][:id].as(:group_id),
|
|
70
|
+
Sequel[:user_groups][:name].cast(cast_type).as(:group_name),
|
|
71
|
+
Sequel[:user_groups][:group_path],
|
|
72
|
+
Sequel[:user_groups][:group_name_path].cast(cast_type).as(:group_name_path),
|
|
73
|
+
Sequel[:user_groups][:parent_id].as(:group_parent_id),
|
|
74
|
+
Sequel[:user_groups][:created_at].cast(cast_type).as(:group_created_at),
|
|
75
|
+
Sequel[:user_groups][:updated_at].cast(cast_type).as(:group_updated_at),
|
|
91
76
|
|
|
92
|
-
Sequel[:
|
|
93
|
-
Sequel[:
|
|
94
|
-
Sequel[:
|
|
95
|
-
Sequel[:
|
|
96
|
-
Sequel[:
|
|
97
|
-
Sequel[:
|
|
98
|
-
Sequel[:
|
|
77
|
+
Sequel[:granted_roles][:id].as(:role_id),
|
|
78
|
+
Sequel[:granted_roles][:name].cast(cast_type).as(:role_name),
|
|
79
|
+
Sequel[:granted_roles][:role_path],
|
|
80
|
+
Sequel[:granted_roles][:role_name_path].cast(cast_type).as(:role_name_path),
|
|
81
|
+
Sequel[:granted_roles][:parent_id].as(:role_parent_id),
|
|
82
|
+
Sequel[:granted_roles][:created_at].cast(cast_type).as(:role_created_at),
|
|
83
|
+
Sequel[:granted_roles][:updated_at].cast(cast_type).as(:role_updated_at),
|
|
99
84
|
|
|
100
85
|
Sequel[:super_auth_permissions][:id].as(:permission_id),
|
|
101
|
-
Sequel[:super_auth_permissions][:name].as(:permission_name),
|
|
86
|
+
Sequel[:super_auth_permissions][:name].cast(cast_type).as(:permission_name),
|
|
102
87
|
Sequel[:super_auth_permissions][:created_at].cast(cast_type).as(:permission_created_at),
|
|
103
88
|
Sequel[:super_auth_permissions][:updated_at].cast(cast_type).as(:permission_updated_at),
|
|
104
89
|
|
|
@@ -106,27 +91,20 @@ class SuperAuth::Edge < Sequel::Model(:super_auth_edges)
|
|
|
106
91
|
Sequel[:super_auth_resources][:name].as(:resource_name),
|
|
107
92
|
Sequel[:super_auth_resources][:external_id].as(:resource_external_id),
|
|
108
93
|
Sequel[:super_auth_resources][:external_type].as(:resource_external_type)
|
|
109
|
-
)
|
|
110
|
-
|
|
111
|
-
.join(Sequel[:super_auth_permissions], id: Sequel[:permission_edges][:permission_id])
|
|
112
|
-
.join(Sequel[:super_auth_edges].as(:resource_edges), Sequel[:resource_edges][:permission_id] => Sequel[:permission_edges][:permission_id])
|
|
113
|
-
.join(Sequel[:super_auth_resources], id: Sequel[:resource_edges][:resource_id])
|
|
114
|
-
.distinct
|
|
94
|
+
).
|
|
95
|
+
distinct
|
|
115
96
|
end
|
|
116
97
|
|
|
117
98
|
def users_groups_permissions_resources
|
|
118
99
|
cast_type = string_cast_type
|
|
119
|
-
# Join users to their group via edges
|
|
120
|
-
#
|
|
121
|
-
#
|
|
100
|
+
# Join users to their group via edges. group_ancestors pairs that group with itself and
|
|
101
|
+
# every ancestor, so a group -> permission edge on any of them applies. user_groups (the
|
|
102
|
+
# tree) is joined by id only to supply the path columns.
|
|
122
103
|
SuperAuth::User.db[:super_auth_users].
|
|
123
104
|
join(Sequel[:super_auth_edges].as(:user_edges), user_id: :id).
|
|
105
|
+
join(SuperAuth::Group.ancestor_pairs.as(:group_ancestors), descendant_id: Sequel[:user_edges][:group_id]).
|
|
106
|
+
join(Sequel[:super_auth_edges].as(:group_edges), group_id: Sequel[:group_ancestors][:ancestor_id]).
|
|
124
107
|
join(SuperAuth::Group.from(SuperAuth::Group.trees).as(:user_groups), Sequel[:user_groups][:id] => Sequel[:user_edges][:group_id]).
|
|
125
|
-
join(Sequel[:super_auth_edges].as(:group_edges),
|
|
126
|
-
Sequel.function(:concat, ',', Sequel[:user_groups][:group_path], ',').like(
|
|
127
|
-
Sequel.function(:concat, '%,', Sequel[:group_edges][:group_id].cast(cast_type), ',%')
|
|
128
|
-
)
|
|
129
|
-
).
|
|
130
108
|
join(Sequel[:super_auth_permissions], id: Sequel[:group_edges][:permission_id]).
|
|
131
109
|
join(Sequel[:super_auth_edges].as(:permission_edges), Sequel[:permission_edges][:permission_id] => Sequel[:super_auth_permissions][:id]).
|
|
132
110
|
join(Sequel[:super_auth_resources], id: Sequel[:permission_edges][:resource_id]).
|
|
@@ -139,9 +117,9 @@ class SuperAuth::Edge < Sequel::Model(:super_auth_edges)
|
|
|
139
117
|
Sequel[:super_auth_users][:updated_at].cast(cast_type).as(:user_updated_at),
|
|
140
118
|
|
|
141
119
|
Sequel[:user_groups][:id].as(:group_id),
|
|
142
|
-
Sequel[:user_groups][:name].as(:group_name),
|
|
120
|
+
Sequel[:user_groups][:name].cast(cast_type).as(:group_name),
|
|
143
121
|
Sequel[:user_groups][:group_path],
|
|
144
|
-
Sequel[:user_groups][:group_name_path],
|
|
122
|
+
Sequel[:user_groups][:group_name_path].cast(cast_type).as(:group_name_path),
|
|
145
123
|
Sequel[:user_groups][:parent_id].as(:group_parent_id),
|
|
146
124
|
Sequel[:user_groups][:created_at].cast(cast_type).as(:group_created_at),
|
|
147
125
|
Sequel[:user_groups][:updated_at].cast(cast_type).as(:group_updated_at),
|
|
@@ -155,7 +133,7 @@ class SuperAuth::Edge < Sequel::Model(:super_auth_edges)
|
|
|
155
133
|
Sequel.cast(nil, string_cast_type).as(:role_updated_at),
|
|
156
134
|
|
|
157
135
|
Sequel[:super_auth_permissions][:id].as(:permission_id),
|
|
158
|
-
Sequel[:super_auth_permissions][:name].as(:permission_name),
|
|
136
|
+
Sequel[:super_auth_permissions][:name].cast(cast_type).as(:permission_name),
|
|
159
137
|
Sequel[:super_auth_permissions][:created_at].cast(cast_type).as(:permission_created_at),
|
|
160
138
|
Sequel[:super_auth_permissions][:updated_at].cast(cast_type).as(:permission_updated_at),
|
|
161
139
|
|
|
@@ -170,26 +148,13 @@ class SuperAuth::Edge < Sequel::Model(:super_auth_edges)
|
|
|
170
148
|
def users_roles_permissions_resources
|
|
171
149
|
cast_type = string_cast_type
|
|
172
150
|
|
|
173
|
-
#
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
# Step 3: Build the query from the expanded role tree
|
|
182
|
-
SuperAuth::Edge.from(role_cte.as(:users_roles_permissions_resources)).
|
|
183
|
-
# Join user_edges — match users who link to any role in the expanded CTE
|
|
184
|
-
# The user's edge links to an ancestor role, but the CTE path contains that ancestor
|
|
185
|
-
# We use the role_path to check: the role_path of the CTE row starts with the user's linked role
|
|
186
|
-
join(Sequel[:super_auth_edges].as(:user_edges),
|
|
187
|
-
Sequel.function(:concat, ',', Sequel[:users_roles_permissions_resources][:role_path], ',').like(
|
|
188
|
-
Sequel.function(:concat, '%,', Sequel[:user_edges][:role_id].cast(cast_type), ',%')
|
|
189
|
-
)
|
|
190
|
-
).
|
|
191
|
-
where(Sequel.~(Sequel[:user_edges][:user_id] => nil) & Sequel.~(Sequel[:user_edges][:role_id] => nil)).
|
|
192
|
-
join(Sequel[:super_auth_users], id: Sequel[:user_edges][:user_id]).
|
|
151
|
+
# Join users to the roles they hold directly. role_descendants expands each held role to
|
|
152
|
+
# its whole subtree; granted_roles (the tree) is joined by id only to supply the path columns.
|
|
153
|
+
SuperAuth::User.db[:super_auth_users].
|
|
154
|
+
join(Sequel[:super_auth_edges].as(:user_edges), user_id: :id).
|
|
155
|
+
where(Sequel.~(Sequel[:user_edges][:role_id] => nil)).
|
|
156
|
+
join(SuperAuth::Role.descendant_pairs.as(:role_descendants), ancestor_id: Sequel[:user_edges][:role_id]).
|
|
157
|
+
join(SuperAuth::Role.from(SuperAuth::Role.trees).as(:granted_roles), Sequel[:granted_roles][:id] => Sequel[:role_descendants][:descendant_id]).
|
|
193
158
|
select(
|
|
194
159
|
Sequel[:super_auth_users][:id].as(:user_id),
|
|
195
160
|
Sequel[:super_auth_users][:name].as(:user_name),
|
|
@@ -206,16 +171,16 @@ class SuperAuth::Edge < Sequel::Model(:super_auth_edges)
|
|
|
206
171
|
Sequel.cast(nil, string_cast_type).as(:group_created_at),
|
|
207
172
|
Sequel.cast(nil, string_cast_type).as(:group_updated_at),
|
|
208
173
|
|
|
209
|
-
Sequel[:
|
|
210
|
-
Sequel[:
|
|
211
|
-
Sequel[:
|
|
212
|
-
Sequel[:
|
|
213
|
-
Sequel[:
|
|
214
|
-
Sequel[:
|
|
215
|
-
Sequel[:
|
|
174
|
+
Sequel[:granted_roles][:id].as(:role_id),
|
|
175
|
+
Sequel[:granted_roles][:name].cast(cast_type).as(:role_name),
|
|
176
|
+
Sequel[:granted_roles][:role_path],
|
|
177
|
+
Sequel[:granted_roles][:role_name_path].cast(cast_type).as(:role_name_path),
|
|
178
|
+
Sequel[:granted_roles][:parent_id].as(:role_parent_id),
|
|
179
|
+
Sequel[:granted_roles][:created_at].cast(cast_type).as(:role_created_at),
|
|
180
|
+
Sequel[:granted_roles][:updated_at].cast(cast_type).as(:role_updated_at),
|
|
216
181
|
|
|
217
182
|
Sequel[:super_auth_permissions][:id].as(:permission_id),
|
|
218
|
-
Sequel[:super_auth_permissions][:name].as(:permission_name),
|
|
183
|
+
Sequel[:super_auth_permissions][:name].cast(cast_type).as(:permission_name),
|
|
219
184
|
Sequel[:super_auth_permissions][:created_at].cast(cast_type).as(:permission_created_at),
|
|
220
185
|
Sequel[:super_auth_permissions][:updated_at].cast(cast_type).as(:permission_updated_at),
|
|
221
186
|
|
|
@@ -225,7 +190,7 @@ class SuperAuth::Edge < Sequel::Model(:super_auth_edges)
|
|
|
225
190
|
Sequel[:super_auth_resources][:external_type].as(:resource_external_type),
|
|
226
191
|
).
|
|
227
192
|
# Join permission and resource edges on the expanded role
|
|
228
|
-
join(Sequel[:super_auth_edges].as(:permission_edges), Sequel[:permission_edges][:role_id] => Sequel[:
|
|
193
|
+
join(Sequel[:super_auth_edges].as(:permission_edges), Sequel[:permission_edges][:role_id] => Sequel[:granted_roles][:id]).
|
|
229
194
|
join(Sequel[:super_auth_permissions], id: Sequel[:permission_edges][:permission_id]).
|
|
230
195
|
join(Sequel[:super_auth_edges].as(:resource_edges), Sequel[:resource_edges][:permission_id] => Sequel[:super_auth_permissions][:id]).
|
|
231
196
|
join(Sequel[:super_auth_resources], id: Sequel[:resource_edges][:resource_id]).
|
|
@@ -261,7 +226,7 @@ class SuperAuth::Edge < Sequel::Model(:super_auth_edges)
|
|
|
261
226
|
Sequel.cast(nil, string_cast_type).as(:role_updated_at),
|
|
262
227
|
|
|
263
228
|
Sequel[:super_auth_permissions][:id].as(:permission_id),
|
|
264
|
-
Sequel[:super_auth_permissions][:name].as(:permission_name),
|
|
229
|
+
Sequel[:super_auth_permissions][:name].cast(cast_type).as(:permission_name),
|
|
265
230
|
Sequel[:super_auth_permissions][:created_at].cast(cast_type).as(:permission_created_at),
|
|
266
231
|
Sequel[:super_auth_permissions][:updated_at].cast(cast_type).as(:permission_updated_at),
|
|
267
232
|
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
require "optparse"
|
|
2
|
+
require "super_auth/editor"
|
|
3
|
+
|
|
4
|
+
module SuperAuth
|
|
5
|
+
class Editor
|
|
6
|
+
# Boots the editor from the command line: connect, optionally migrate and
|
|
7
|
+
# seed, then serve on loopback. See exe/super_auth-editor.
|
|
8
|
+
module CLI
|
|
9
|
+
DEFAULTS = { host: "127.0.0.1", port: 4666, migrate: false, seed: false }.freeze
|
|
10
|
+
LOOPBACK_BINDS = %w[127.0.0.1 localhost ::1].freeze
|
|
11
|
+
# Host headers accepted when bound to loopback (DNS-rebinding defence).
|
|
12
|
+
LOOPBACK_HOSTS = %w[localhost 127.0.0.1 [::1]].freeze
|
|
13
|
+
WARNING = "WARNING: the editor has no authentication. " \
|
|
14
|
+
"Anyone who can reach this port can rewrite the authorization graph.".freeze
|
|
15
|
+
|
|
16
|
+
module_function
|
|
17
|
+
|
|
18
|
+
def parse(argv, out: $stdout)
|
|
19
|
+
options = DEFAULTS.dup
|
|
20
|
+
parser = OptionParser.new do |o|
|
|
21
|
+
o.banner = "Usage: super_auth-editor [options]"
|
|
22
|
+
o.on("-H", "--host HOST", "bind address (default #{DEFAULTS[:host]})") { |v| options[:host] = v }
|
|
23
|
+
o.on("-p", "--port PORT", Integer, "port (default #{DEFAULTS[:port]})") { |v| options[:port] = v }
|
|
24
|
+
o.on("--migrate", "run the super_auth Sequel migrations before starting") { options[:migrate] = true }
|
|
25
|
+
o.on("--seed", "replace the whole graph with the Acme Cloud sample (destructive)") { options[:seed] = true }
|
|
26
|
+
o.on("-v", "--version", "print the version") do
|
|
27
|
+
out.puts SuperAuth::VERSION
|
|
28
|
+
exit
|
|
29
|
+
end
|
|
30
|
+
o.on("-h", "--help", "show this help") do
|
|
31
|
+
out.puts o
|
|
32
|
+
out.puts "Reads SUPER_AUTH_DATABASE_URL (required)."
|
|
33
|
+
out.puts WARNING
|
|
34
|
+
exit
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
parser.parse!(argv.dup)
|
|
38
|
+
options
|
|
39
|
+
rescue OptionParser::ParseError => e
|
|
40
|
+
raise SuperAuth::Error, "#{e.message}\n#{parser}"
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def run(argv, env: ENV, err: $stderr)
|
|
44
|
+
options = parse(argv)
|
|
45
|
+
url = env["SUPER_AUTH_DATABASE_URL"].to_s.strip
|
|
46
|
+
if url.empty?
|
|
47
|
+
raise SuperAuth::Error, "SUPER_AUTH_DATABASE_URL is not set. Point it at the database that holds " \
|
|
48
|
+
"the super_auth tables, e.g. postgres://user:password@localhost/app_development"
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# First Sequel::Database in the process: the models bind to it.
|
|
52
|
+
begin
|
|
53
|
+
SuperAuth.db = Sequel.connect(url)
|
|
54
|
+
rescue Sequel::AdapterNotFound => e
|
|
55
|
+
raise SuperAuth::Error, "#{e.message}. Install the adapter gem for this URL (pg, mysql2 or sqlite3)."
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
SuperAuth.install_migrations if options[:migrate]
|
|
59
|
+
begin
|
|
60
|
+
SuperAuth.load
|
|
61
|
+
rescue Sequel::DatabaseError => e
|
|
62
|
+
raise SuperAuth::Error, "super_auth tables not found at #{redact(url)} (#{e.message.lines.first.to_s.strip}). " \
|
|
63
|
+
"Run with --migrate to create them, or run your application's migrations."
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
if options[:seed]
|
|
67
|
+
require "super_auth/editor/seed"
|
|
68
|
+
counts = SuperAuth::Editor::Seed.run!
|
|
69
|
+
err.puts "Seeded the Acme Cloud sample graph: #{counts.map { |k, v| "#{v} #{k}" }.join(', ')}."
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
begin
|
|
73
|
+
require "rackup"
|
|
74
|
+
rescue LoadError
|
|
75
|
+
raise SuperAuth::Error, "The editor needs a Rack server: gem install rackup webrick (puma also works)."
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
loopback = LOOPBACK_BINDS.include?(options[:host])
|
|
79
|
+
err.puts WARNING
|
|
80
|
+
err.puts "Bound to #{options[:host]}, which other machines can reach." unless loopback
|
|
81
|
+
err.puts "Editor at http://#{options[:host]}:#{options[:port]}"
|
|
82
|
+
app = SuperAuth::Editor.new(hosts: loopback ? LOOPBACK_HOSTS : nil)
|
|
83
|
+
Rackup::Server.start(app: app, Host: options[:host], Port: options[:port], environment: "deployment")
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def redact(url)
|
|
87
|
+
url.sub(%r{//([^:/@]+):[^@]*@}, '//\1:***@')
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
end
|