-
Notifications
You must be signed in to change notification settings - Fork 124
/
role.rb
186 lines (152 loc) · 4.23 KB
/
role.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
# frozen_string_literal: true
class Role < Sequel::Model
extend Forwardable
include HasId
unrestrict_primary_key
one_to_many(
:memberships,
class: :RoleMembership,
extend: MembershipSearch,
search_key: :member_id
)
one_to_many(
:memberships_as_member,
class: :RoleMembership,
key: :member_id,
extend: MembershipSearch,
search_key: :role_id
)
one_to_one :credentials, reciprocal: :role
alias id role_id
def as_json options = {}
options[:exclude] ||= []
options[:exclude] << :credentials
super(options).tap do |response|
response["id"] = response.delete("role_id")
write_id_to_json response, "policy"
end
end
class << self
def that_can(permission, resource)
Role.from(
::Sequel.function(:roles_that_can, permission.to_s, resource.pk)
)
end
def make_full_id(id, account)
tokens = id.split(":", 3) rescue []
if tokens.size < 2
raise ArgumentError, "Expected at least 2 tokens in #{id}"
end
account, kind, id = (tokens.size == 2 ? [account] + tokens : tokens)
[account, kind, id].join(":")
end
def roleid_from_username(account, login)
tokens = login.split('/', 2)
tokens.unshift 'user' if tokens.length == 1
tokens.unshift account
tokens.join(":")
end
def username_from_roleid(roleid)
_, kind, id = roleid.split(":", 3)
return id if kind == 'user'
[kind, id].join('/')
end
end
dataset_module do
def member_of(role_ids)
filter_memberships = Set.new(
role_ids.map { |id| Role[id] }.compact.map(&:role_id)
)
where(role_id: filter_memberships.to_a)
end
def by_login login, account:
self[role_id: Role.roleid_from_username(account, login)]
end
end
def password=(password)
modify_credentials do |credentials|
credentials.password = password
end
end
def valid_origin?(ip_addr)
ip = IPAddr.new(ip_addr)
restricted_to.blank? || restricted_to.any? do |cidr|
cidr.include?(ip)
end
end
def restricted_to
self.credentials ||= Credentials.new(role: self)
self.credentials.restricted_to
end
def restricted_to=(restricted_to)
modify_credentials do |credentials|
credentials.restricted_to = restricted_to
end
end
def api_key
unless self.credentials
_, kind, id = self.id.split(":", 3)
allowed_kind = %w(user host deputy).member?(kind)
raise "Role #{id} has no credentials" unless allowed_kind
self.credentials = Credentials.create(role: self)
end
self.credentials.api_key
end
def login
self.class.username_from_roleid(role_id)
end
def resource?
Resource[id].present?
end
def resource
Resource[id] or raise "Resource not found for #{id}"
end
# All Roles of kind "layer" which this role is a direct member of.
def layers
memberships_as_member.select do |membership|
membership.role.kind == "layer"
end.map(&:role)
end
def direct_memberships_dataset(search_options = {})
memberships_as_member_dataset.search(search_options)
.select(:role_memberships.*)
end
def members_dataset(search_options = {})
memberships_dataset.search(search_options)
.select(:role_memberships.*)
end
# Role grants are performed by the policy loader, but not exposed through the
# API.
def grant_to(member, options = {})
options[:admin_option] ||= false
options[:member] = member
add_membership options
rescue Sequel::UniqueConstraintViolation
# Membership grant already exists
end
def allowed_to?(privilege, resource)
Role.from(
Sequel.function(:is_role_allowed_to, id, privilege.to_s, resource.id)
).first[:is_role_allowed_to]
end
def all_roles
Role.from(Sequel.function(:all_roles, id))
end
def ancestor_of?(role)
Role.from(
Sequel.function(:is_role_ancestor_of, id, role.id)
).first[:is_role_ancestor_of]
end
def graph
Role.from(Sequel.function(:role_graph, id))
.order(:parent, :child)
.all
.map(&:values)
end
private
def modify_credentials
credentials = self.credentials ||= Credentials.new(role: self)
yield credentials
credentials.save(raise_on_save_failure: true)
end
end