aerospike 2.20.0 → 2.21.1
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 +21 -1
- data/lib/aerospike/client.rb +46 -2
- data/lib/aerospike/cluster/create_connection.rb +1 -1
- data/lib/aerospike/cluster.rb +14 -1
- data/lib/aerospike/command/admin_command.rb +367 -51
- data/lib/aerospike/command/login_command.rb +162 -0
- data/lib/aerospike/connection/authenticate.rb +36 -3
- data/lib/aerospike/policy/auth_mode.rb +36 -0
- data/lib/aerospike/policy/client_policy.rb +4 -1
- data/lib/aerospike/privilege.rb +133 -0
- data/lib/aerospike/result_code.rb +4 -4
- data/lib/aerospike/role.rb +55 -0
- data/lib/aerospike/user_role.rb +25 -0
- data/lib/aerospike/utils/buffer.rb +15 -0
- data/lib/aerospike/version.rb +1 -1
- data/lib/aerospike.rb +4 -0
- metadata +9 -6
- data/lib/aerospike/command/roles.rb +0 -39
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f0685f64b5853e918eca12c6ad4a64a1c7ac5c1d0370627c252e598f4686be68
|
4
|
+
data.tar.gz: a342e374dc180201176018cf1e13c7764a64963fe78e505d55d93b5f2ed83b70
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4151a866e0ff1c36e924aa1a6123411499f7c1bcf48b01177028db5d7a7a72ac2cfde2febb398a42774c4b490c5e0f78839a14a52d5d0c19c9850f5e34dd7141
|
7
|
+
data.tar.gz: babd62c5d0307153073c51bfa879e0700a9ad56875da37eb711965da82ddc09b765cbbd770ec60c6973d818318200708ba27a4c4ee4a7b598076324ef9093176
|
data/CHANGELOG.md
CHANGED
@@ -2,7 +2,27 @@
|
|
2
2
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
4
4
|
|
5
|
-
## [2.
|
5
|
+
## [2.21.1] - 2022-06-21
|
6
|
+
|
7
|
+
This s hotfix release. It is recommended to upgrade your client if you use authentication.
|
8
|
+
|
9
|
+
* **Bug Fixes**
|
10
|
+
* Fix called function name in Authenticate.
|
11
|
+
|
12
|
+
## [2.21.0] - 2022-06-07
|
13
|
+
|
14
|
+
* **New Features**
|
15
|
+
* Add support for new user management features. Adds `Client#query_role`, `Client#query_roles`, `Client#create_role`, `Client#drop_role`, `Client#grant_privileges`, `Client#revoke_privileges`. Adds the 'Role' class. Adds `UserRoles#read_info`, `UserRoles#write_info`, `UserRoles#conns_in_use` to the `UserRoles` class.
|
16
|
+
|
17
|
+
* **Improvements**
|
18
|
+
* Do not run PredExp tests for server v6+.
|
19
|
+
|
20
|
+
## [2.20.1] - 2022-05-11
|
21
|
+
|
22
|
+
* **Improvements**
|
23
|
+
* Add basic support for the new authentication protocol.
|
24
|
+
|
25
|
+
## [2.20.0] - 2021-11-08
|
6
26
|
|
7
27
|
Notice: This version of the client only supports Aerospike Server v4.9 and later. Some features will work for the older server versions, but they are not tested, nor officially supported.
|
8
28
|
|
data/lib/aerospike/client.rb
CHANGED
@@ -764,7 +764,7 @@ module Aerospike
|
|
764
764
|
# before sending to server.
|
765
765
|
def create_user(user, password, roles, options = nil)
|
766
766
|
policy = create_policy(options, AdminPolicy, default_admin_policy)
|
767
|
-
hash =
|
767
|
+
hash = LoginCommand.hash_password(password)
|
768
768
|
command = AdminCommand.new
|
769
769
|
command.create_user(@cluster, policy, user, hash, roles)
|
770
770
|
end
|
@@ -781,7 +781,7 @@ module Aerospike
|
|
781
781
|
raise Aerospike::Exceptions::Aerospike.new(INVALID_USER) unless @cluster.user && @cluster.user != ""
|
782
782
|
policy = create_policy(options, AdminPolicy, default_admin_policy)
|
783
783
|
|
784
|
-
hash =
|
784
|
+
hash = LoginCommand.hash_password(password)
|
785
785
|
command = AdminCommand.new
|
786
786
|
|
787
787
|
if user == @cluster.user
|
@@ -823,6 +823,50 @@ module Aerospike
|
|
823
823
|
command.query_users(@cluster, policy)
|
824
824
|
end
|
825
825
|
|
826
|
+
# Retrieve privileges for a given role.
|
827
|
+
def query_role(role, options = nil)
|
828
|
+
policy = create_policy(options, AdminPolicy, default_admin_policy)
|
829
|
+
command = AdminCommand.new
|
830
|
+
command.query_role(@cluster, policy, role)
|
831
|
+
end
|
832
|
+
|
833
|
+
# Retrieve all roles and their privileges.
|
834
|
+
def query_roles(options = nil)
|
835
|
+
policy = create_policy(options, AdminPolicy, default_admin_policy)
|
836
|
+
command = AdminCommand.new
|
837
|
+
command.query_roles(@cluster, policy)
|
838
|
+
end
|
839
|
+
|
840
|
+
# Create a user-defined role.
|
841
|
+
# Quotas require server security configuration "enable-quotas" to be set to true.
|
842
|
+
# Pass 0 for quota values for no limit.
|
843
|
+
def create_role(role_name, privileges = [], allowlist = [], read_quota = 0, write_quota = 0, options = nil)
|
844
|
+
policy = create_policy(options, AdminPolicy, default_admin_policy)
|
845
|
+
command = AdminCommand.new
|
846
|
+
command.create_role(@cluster, policy, role_name, privileges, allowlist, read_quota, write_quota)
|
847
|
+
end
|
848
|
+
|
849
|
+
# Remove a user-defined role.
|
850
|
+
def drop_role(role_name, options = nil)
|
851
|
+
policy = create_policy(options, AdminPolicy, default_admin_policy)
|
852
|
+
command = AdminCommand.new
|
853
|
+
command.drop_role(@cluster, policy, role_name)
|
854
|
+
end
|
855
|
+
|
856
|
+
# Grant privileges to a user-defined role.
|
857
|
+
def grant_privileges(role_name, privileges, options = nil)
|
858
|
+
policy = create_policy(options, AdminPolicy, default_admin_policy)
|
859
|
+
command = AdminCommand.new
|
860
|
+
command.grant_privileges(@cluster, policy, role_name, privileges)
|
861
|
+
end
|
862
|
+
|
863
|
+
# Revoke privileges from a user-defined role.
|
864
|
+
def revoke_privileges(role_name, privileges, options = nil)
|
865
|
+
policy = create_policy(options, AdminPolicy, default_admin_policy)
|
866
|
+
command = AdminCommand.new
|
867
|
+
command.revoke_privileges(@cluster, policy, role_name, privileges)
|
868
|
+
end
|
869
|
+
|
826
870
|
private
|
827
871
|
|
828
872
|
def set_default_policies(policies)
|
@@ -32,7 +32,7 @@ module Aerospike
|
|
32
32
|
).tap do |conn|
|
33
33
|
if cluster.credentials_given?
|
34
34
|
# Authenticate will raise and close connection if invalid credentials
|
35
|
-
Connection::
|
35
|
+
Connection::AuthenticateNew.(conn, cluster)
|
36
36
|
end
|
37
37
|
end
|
38
38
|
end
|
data/lib/aerospike/cluster.rb
CHANGED
@@ -27,9 +27,12 @@ module Aerospike
|
|
27
27
|
attr_reader :features, :tls_options
|
28
28
|
attr_reader :cluster_id, :aliases
|
29
29
|
attr_reader :cluster_name
|
30
|
+
attr_reader :client_policy
|
30
31
|
attr_accessor :rack_aware, :rack_id
|
32
|
+
attr_accessor :session_token, :session_expiration
|
31
33
|
|
32
34
|
def initialize(policy, hosts)
|
35
|
+
@client_policy = policy
|
33
36
|
@cluster_seeds = hosts
|
34
37
|
@fail_if_not_connected = policy.fail_if_not_connected
|
35
38
|
@connection_queue_size = policy.connection_queue_size
|
@@ -56,7 +59,7 @@ module Aerospike
|
|
56
59
|
# setup auth info for cluster
|
57
60
|
if policy.requires_authentication
|
58
61
|
@user = policy.user
|
59
|
-
@password =
|
62
|
+
@password = LoginCommand.hash_password(policy.password)
|
60
63
|
end
|
61
64
|
|
62
65
|
initialize_tls_host_names(hosts) if tls_enabled?
|
@@ -78,6 +81,15 @@ module Aerospike
|
|
78
81
|
!(@user.nil? || @user.empty?)
|
79
82
|
end
|
80
83
|
|
84
|
+
def session_valid?
|
85
|
+
@session_token && @session_expiration && @session_expiration.to_i < Time.now.to_i
|
86
|
+
end
|
87
|
+
|
88
|
+
def reset_session_info
|
89
|
+
@session_token = nil
|
90
|
+
@session_expiration = nil
|
91
|
+
end
|
92
|
+
|
81
93
|
def tls_enabled?
|
82
94
|
!tls_options.nil? && tls_options[:enable] != false
|
83
95
|
end
|
@@ -436,6 +448,7 @@ module Aerospike
|
|
436
448
|
cluster_config_changed = true
|
437
449
|
end
|
438
450
|
|
451
|
+
|
439
452
|
cluster_config_changed
|
440
453
|
end
|
441
454
|
|
@@ -18,24 +18,40 @@ module Aerospike
|
|
18
18
|
|
19
19
|
private
|
20
20
|
# Commands
|
21
|
-
AUTHENTICATE
|
22
|
-
CREATE_USER
|
23
|
-
DROP_USER
|
24
|
-
SET_PASSWORD
|
25
|
-
CHANGE_PASSWORD
|
26
|
-
GRANT_ROLES
|
27
|
-
REVOKE_ROLES
|
28
|
-
|
29
|
-
|
30
|
-
|
21
|
+
AUTHENTICATE = 0
|
22
|
+
CREATE_USER = 1
|
23
|
+
DROP_USER = 2
|
24
|
+
SET_PASSWORD = 3
|
25
|
+
CHANGE_PASSWORD = 4
|
26
|
+
GRANT_ROLES = 5
|
27
|
+
REVOKE_ROLES = 6
|
28
|
+
QUERY_USERS = 9
|
29
|
+
CREATE_ROLE = 10
|
30
|
+
DROP_ROLE = 11
|
31
|
+
GRANT_PRIVILEGES = 12
|
32
|
+
REVOKE_PRIVILEGES = 13
|
33
|
+
SET_WHITELIST = 14
|
34
|
+
SET_QUOTAS = 15
|
35
|
+
QUERY_ROLES = 16
|
36
|
+
LOGIN = 20
|
31
37
|
|
32
38
|
# Field IDs
|
33
|
-
USER
|
34
|
-
PASSWORD
|
35
|
-
OLD_PASSWORD
|
36
|
-
CREDENTIAL
|
37
|
-
|
38
|
-
|
39
|
+
USER = 0
|
40
|
+
PASSWORD = 1
|
41
|
+
OLD_PASSWORD = 2
|
42
|
+
CREDENTIAL = 3
|
43
|
+
CLEAR_PASSWORD = 4
|
44
|
+
SESSION_TOKEN = 5
|
45
|
+
SESSION_TTL = 6
|
46
|
+
ROLES = 10
|
47
|
+
ROLE = 11
|
48
|
+
PRIVILEGES = 12
|
49
|
+
ALLOWLIST = 13
|
50
|
+
READ_QUOTA = 14
|
51
|
+
WRITE_QUOTA = 15
|
52
|
+
READ_INFO = 16
|
53
|
+
WRITE_INFO = 17
|
54
|
+
CONNECTIONS = 18
|
39
55
|
|
40
56
|
# Misc
|
41
57
|
MSG_VERSION = 2
|
@@ -53,28 +69,6 @@ module Aerospike
|
|
53
69
|
@data_offset = 8
|
54
70
|
end
|
55
71
|
|
56
|
-
def authenticate(conn, user, password)
|
57
|
-
begin
|
58
|
-
set_authenticate(user, password)
|
59
|
-
conn.write(@data_buffer, @data_offset)
|
60
|
-
conn.read(@data_buffer, HEADER_SIZE)
|
61
|
-
|
62
|
-
result = @data_buffer.read(RESULT_CODE)
|
63
|
-
raise Exceptions::Aerospike.new(result, "Authentication failed") if result != 0
|
64
|
-
ensure
|
65
|
-
Buffer.put(@data_buffer)
|
66
|
-
end
|
67
|
-
end
|
68
|
-
|
69
|
-
def set_authenticate(user, password)
|
70
|
-
write_header(AUTHENTICATE, 2)
|
71
|
-
write_field_str(USER, user)
|
72
|
-
write_field_bytes(CREDENTIAL, password)
|
73
|
-
write_size
|
74
|
-
|
75
|
-
return @data_offset
|
76
|
-
end
|
77
|
-
|
78
72
|
def create_user(cluster, policy, user, password, roles)
|
79
73
|
write_header(CREATE_USER, 3)
|
80
74
|
write_field_str(USER, user)
|
@@ -118,6 +112,61 @@ module Aerospike
|
|
118
112
|
execute_command(cluster, policy)
|
119
113
|
end
|
120
114
|
|
115
|
+
def create_role(cluster, policy, role_name, privileges = [], allowlist = [], read_quota = 0, write_quota = 0)
|
116
|
+
field_count = 1
|
117
|
+
field_count += 1 if privileges.size > 0
|
118
|
+
field_count += 1 if allowlist.size > 0
|
119
|
+
field_count += 1 if read_quota > 0
|
120
|
+
field_count += 1 if write_quota > 0
|
121
|
+
|
122
|
+
write_header(CREATE_ROLE, field_count)
|
123
|
+
write_field_str(ROLE, role_name)
|
124
|
+
|
125
|
+
write_privileges(privileges) if privileges.size > 0
|
126
|
+
write_allowlist(allowlist) if allowlist.size > 0
|
127
|
+
|
128
|
+
write_field_uint32(READ_QUOTA, read_quota) if read_quota > 0
|
129
|
+
write_field_uint32(WRITE_QUOTA, write_quota) if write_quota > 0
|
130
|
+
|
131
|
+
execute_command(cluster, policy)
|
132
|
+
end
|
133
|
+
|
134
|
+
def drop_role(cluster, policy, role)
|
135
|
+
write_header(DROP_ROLE, 1)
|
136
|
+
write_field_str(ROLE, role)
|
137
|
+
execute_command(cluster, policy)
|
138
|
+
end
|
139
|
+
|
140
|
+
def grant_privileges(cluster, policy, role, privileges)
|
141
|
+
write_header(GRANT_PRIVILEGES, 2)
|
142
|
+
write_field_str(ROLE, role)
|
143
|
+
write_privileges(privileges)
|
144
|
+
execute_command(cluster, policy)
|
145
|
+
end
|
146
|
+
|
147
|
+
def revoke_privileges(cluster, policy, role, privileges)
|
148
|
+
write_header(REVOKE_PRIVILEGES, 2)
|
149
|
+
write_field_str(ROLE, role)
|
150
|
+
write_privileges(privileges)
|
151
|
+
execute_command(cluster, policy)
|
152
|
+
end
|
153
|
+
|
154
|
+
def set_allowlist(cluster, policy, role, allowlist = [])
|
155
|
+
field_count = 1
|
156
|
+
field_count += 1 if allowlist.size > 0
|
157
|
+
write_header(SET_WHITELIST, field_count)
|
158
|
+
write_allowlist(allowlist) if allowlist.size > 0
|
159
|
+
execute_command(cluster, policy)
|
160
|
+
end
|
161
|
+
|
162
|
+
def set_quotas(cluster, policy, role, read_quota, write_quota)
|
163
|
+
write_header(SET_QUOTAS, 3)
|
164
|
+
write_field_str(ROLE, role)
|
165
|
+
write_field_uint32(READ_QUOTA, read_quota)
|
166
|
+
write_field_uint32(WRITE_QUOTA, write_quota)
|
167
|
+
execute_command(cluster, policy)
|
168
|
+
end
|
169
|
+
|
121
170
|
def query_user(cluster, policy, user)
|
122
171
|
# TODO: Remove the workaround in the future
|
123
172
|
sleep(0.010)
|
@@ -144,6 +193,32 @@ module Aerospike
|
|
144
193
|
end
|
145
194
|
end
|
146
195
|
|
196
|
+
def query_role(cluster, policy, role)
|
197
|
+
# TODO: Remove the workaround in the future
|
198
|
+
sleep(0.010)
|
199
|
+
|
200
|
+
list = []
|
201
|
+
begin
|
202
|
+
write_header(QUERY_ROLES, 1)
|
203
|
+
write_field_str(ROLE, role)
|
204
|
+
list = read_roles(cluster, policy)
|
205
|
+
return (list.is_a?(Array) && list.length > 0 ? list.first : nil)
|
206
|
+
ensure
|
207
|
+
Buffer.put(@data_buffer)
|
208
|
+
end
|
209
|
+
end
|
210
|
+
|
211
|
+
def query_roles(cluster, policy)
|
212
|
+
# TODO: Remove the workaround in the future
|
213
|
+
sleep(0.010)
|
214
|
+
begin
|
215
|
+
write_header(QUERY_ROLES, 0)
|
216
|
+
return read_roles(cluster, policy)
|
217
|
+
ensure
|
218
|
+
Buffer.put(@data_buffer)
|
219
|
+
end
|
220
|
+
end
|
221
|
+
|
147
222
|
def write_roles(roles)
|
148
223
|
offset = @data_offset + FIELD_HEADER_SIZE
|
149
224
|
@data_buffer.write_byte(roles.length.ord, offset)
|
@@ -166,6 +241,54 @@ module Aerospike
|
|
166
241
|
@data_buffer.write_int64(size, 0)
|
167
242
|
end
|
168
243
|
|
244
|
+
def write_privileges(privileges)
|
245
|
+
offset = @data_offset
|
246
|
+
@data_offset += FIELD_HEADER_SIZE
|
247
|
+
write_byte(privileges.size)
|
248
|
+
|
249
|
+
for privilege in privileges
|
250
|
+
write_byte(privilege.to_code)
|
251
|
+
if privilege.can_scope?
|
252
|
+
if privilege.set_name.to_s.size > 0 && privilege.namespace.to_s.size == 0
|
253
|
+
raise Aerospike::Exceptions::Aerospike.new(Aerospike::ResultCode::INVALID_PRIVILEGE, "Admin privilege #{privilege.namespace} has a set scope with an empty namespace")
|
254
|
+
end
|
255
|
+
|
256
|
+
write_str(privilege.namespace.to_s)
|
257
|
+
write_str(privilege.set_name.to_s)
|
258
|
+
else
|
259
|
+
if privilege.set_name.to_s.bytesize > 0 || privilege.namespace.to_s.bytesize > 0
|
260
|
+
raise Aerospike::Exceptions::Aerospike.new(Aerospike::ResultCode::INVALID_PRIVILEGE, "Admin global privilege #{privilege} can't have a namespace or set")
|
261
|
+
end
|
262
|
+
end
|
263
|
+
end
|
264
|
+
|
265
|
+
size = @data_offset - offset - FIELD_HEADER_SIZE
|
266
|
+
@data_offset = offset
|
267
|
+
write_field_header(PRIVILEGES, size)
|
268
|
+
@data_offset += size
|
269
|
+
end
|
270
|
+
|
271
|
+
def write_allowlist(allowlist)
|
272
|
+
offset = @data_offset
|
273
|
+
@data_offset += FIELD_HEADER_SIZE
|
274
|
+
|
275
|
+
comma = false
|
276
|
+
for addr in allowlist
|
277
|
+
if comma
|
278
|
+
write_byte(",")
|
279
|
+
else
|
280
|
+
comma = true
|
281
|
+
end
|
282
|
+
|
283
|
+
@data_offset += @data_buffer.write_binary(addr, @data_offset)
|
284
|
+
end
|
285
|
+
|
286
|
+
size = @data_offset - offset - FIELD_HEADER_SIZE
|
287
|
+
@data_offset = offset
|
288
|
+
write_field_header(ALLOWLIST, size)
|
289
|
+
@data_offset += size
|
290
|
+
end
|
291
|
+
|
169
292
|
def write_header(command, field_count)
|
170
293
|
# Authenticate header is almost all zeros
|
171
294
|
i = @data_offset
|
@@ -178,12 +301,27 @@ module Aerospike
|
|
178
301
|
@data_offset += 16
|
179
302
|
end
|
180
303
|
|
304
|
+
def write_byte(b)
|
305
|
+
@data_offset += @data_buffer.write_byte(b, @data_offset)
|
306
|
+
end
|
307
|
+
|
308
|
+
def write_str(str)
|
309
|
+
@data_offset += @data_buffer.write_byte(str.bytesize, @data_offset)
|
310
|
+
@data_offset += @data_buffer.write_binary(str, @data_offset)
|
311
|
+
end
|
312
|
+
|
181
313
|
def write_field_str(id, str)
|
182
314
|
len = @data_buffer.write_binary(str, @data_offset+FIELD_HEADER_SIZE)
|
183
315
|
write_field_header(id, len)
|
184
316
|
@data_offset += len
|
185
317
|
end
|
186
318
|
|
319
|
+
def write_field_uint32(id, val)
|
320
|
+
len = @data_buffer.write_uint32(val, @data_offset+FIELD_HEADER_SIZE)
|
321
|
+
write_field_header(id, len)
|
322
|
+
@data_offset += len
|
323
|
+
end
|
324
|
+
|
187
325
|
def write_field_bytes(id, bytes)
|
188
326
|
@data_buffer.write_binary(bytes, @data_offset+FIELD_HEADER_SIZE)
|
189
327
|
write_field_header(id, bytes.bytesize)
|
@@ -284,7 +422,7 @@ module Aerospike
|
|
284
422
|
return (result_code == QUERY_END ? -1 : result_code)
|
285
423
|
end
|
286
424
|
|
287
|
-
|
425
|
+
user_roles = UserRoles.new
|
288
426
|
field_count = @data_buffer.read(@data_offset+3)
|
289
427
|
@data_offset += HEADER_REMAINING
|
290
428
|
|
@@ -298,10 +436,17 @@ module Aerospike
|
|
298
436
|
|
299
437
|
case id
|
300
438
|
when USER
|
301
|
-
|
439
|
+
user_roles.user = @data_buffer.read(@data_offset, len)
|
302
440
|
@data_offset += len
|
303
441
|
when ROLES
|
304
|
-
parse_roles(
|
442
|
+
parse_roles(user_roles)
|
443
|
+
when READ_INFO
|
444
|
+
user_roles.read_info = parse_info
|
445
|
+
when WRITE_INFO
|
446
|
+
user_roles.write_info = parse_info
|
447
|
+
when CONNECTIONS
|
448
|
+
user_roles.conns_in_use = @data_buffer.read_int32(@data_offset)
|
449
|
+
@data_offset += len
|
305
450
|
else
|
306
451
|
@data_offset += len
|
307
452
|
end
|
@@ -309,19 +454,19 @@ module Aerospike
|
|
309
454
|
i = i.succ
|
310
455
|
end
|
311
456
|
|
312
|
-
next if
|
457
|
+
next if user_roles.user == "" && user_roles.roles == nil
|
313
458
|
|
314
|
-
|
315
|
-
list <<
|
459
|
+
user_roles.roles = [] if user_roles.roles == nil
|
460
|
+
list << user_roles
|
316
461
|
end
|
317
462
|
|
318
463
|
return 0, list
|
319
464
|
end
|
320
465
|
|
321
|
-
def parse_roles(
|
466
|
+
def parse_roles(user_roles)
|
322
467
|
size = @data_buffer.read(@data_offset)
|
323
468
|
@data_offset += 1
|
324
|
-
|
469
|
+
user_roles.roles = []
|
325
470
|
|
326
471
|
i = 0
|
327
472
|
while i < size
|
@@ -329,17 +474,188 @@ module Aerospike
|
|
329
474
|
@data_offset += 1
|
330
475
|
role = @data_buffer.read(@data_offset, len)
|
331
476
|
@data_offset += len
|
332
|
-
|
477
|
+
user_roles.roles << role
|
333
478
|
|
334
479
|
i = i.succ
|
335
480
|
end
|
336
481
|
end
|
337
482
|
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
483
|
+
def parse_info
|
484
|
+
size = @data_buffer.read(@data_offset)
|
485
|
+
@data_offset += 1
|
486
|
+
list = []
|
487
|
+
|
488
|
+
i = 0
|
489
|
+
while i < size
|
490
|
+
val = @data_buffer.read_int32(@data_offset)
|
491
|
+
@data_offset += 4
|
492
|
+
list << val
|
493
|
+
|
494
|
+
i = i.succ
|
495
|
+
end
|
496
|
+
|
497
|
+
list
|
342
498
|
end
|
499
|
+
|
500
|
+
def read_roles(cluster, policy)
|
501
|
+
write_size
|
502
|
+
node = cluster.random_node
|
503
|
+
|
504
|
+
timeout = 1
|
505
|
+
timeout = policy.timeout if policy != nil && policy.timeout > 0
|
506
|
+
|
507
|
+
status = -1
|
508
|
+
list = []
|
509
|
+
begin
|
510
|
+
conn = node.get_connection(timeout)
|
511
|
+
conn.write(@data_buffer, @data_offset)
|
512
|
+
status, list = read_role_blocks(conn)
|
513
|
+
node.put_connection(conn)
|
514
|
+
rescue => e
|
515
|
+
conn.close if conn
|
516
|
+
raise e
|
517
|
+
end
|
518
|
+
|
519
|
+
raise Exceptions::Aerospike.new(status) if status > 0
|
520
|
+
|
521
|
+
return list
|
522
|
+
end
|
523
|
+
|
524
|
+
def read_role_blocks(conn)
|
525
|
+
rlist = []
|
526
|
+
status = 0
|
527
|
+
begin
|
528
|
+
while status == 0
|
529
|
+
conn.read(@data_buffer, 8)
|
530
|
+
size = @data_buffer.read_int64(0)
|
531
|
+
receive_size = (size & 0xFFFFFFFFFFFF)
|
532
|
+
|
533
|
+
if receive_size > 0
|
534
|
+
@data_buffer.resize(receive_size) if receive_size > @data_buffer.size
|
535
|
+
|
536
|
+
conn.read(@data_buffer, receive_size)
|
537
|
+
status, list = parse_roles_full(receive_size)
|
538
|
+
rlist.concat(list.to_a)
|
539
|
+
else
|
540
|
+
break
|
541
|
+
end
|
542
|
+
end
|
543
|
+
return status, rlist
|
544
|
+
rescue => e
|
545
|
+
return -1, []
|
546
|
+
end
|
547
|
+
end
|
548
|
+
|
549
|
+
def parse_roles_full(receive_size)
|
550
|
+
@data_offset = 0
|
551
|
+
list = []
|
552
|
+
|
553
|
+
while @data_offset < receive_size
|
554
|
+
result_code = @data_buffer.read(@data_offset+1)
|
555
|
+
|
556
|
+
if result_code != 0
|
557
|
+
return (result_code == QUERY_END ? -1 : result_code)
|
558
|
+
end
|
559
|
+
|
560
|
+
role = Role.new
|
561
|
+
field_count = @data_buffer.read(@data_offset+3)
|
562
|
+
@data_offset += HEADER_REMAINING
|
563
|
+
|
564
|
+
i = 0
|
565
|
+
while i < field_count
|
566
|
+
len = @data_buffer.read_int32(@data_offset)
|
567
|
+
@data_offset += 4
|
568
|
+
id = @data_buffer.read(@data_offset)
|
569
|
+
@data_offset += 1
|
570
|
+
len -= 1
|
571
|
+
|
572
|
+
case id
|
573
|
+
when ROLE
|
574
|
+
role.name = @data_buffer.read(@data_offset, len).to_s
|
575
|
+
@data_offset += len
|
576
|
+
when PRIVILEGES
|
577
|
+
parse_privileges(role)
|
578
|
+
when ALLOWLIST
|
579
|
+
role.allowlist = parse_allowlist(len)
|
580
|
+
when READ_QUOTA
|
581
|
+
role.read_quota = @data_buffer.read_uint32(@data_offset)
|
582
|
+
@data_offset += len
|
583
|
+
when WRITE_QUOTA
|
584
|
+
role.write_quota = @data_buffer.read_uint32(@data_offset)
|
585
|
+
@data_offset += len
|
586
|
+
else
|
587
|
+
@data_offset += len
|
588
|
+
end
|
589
|
+
|
590
|
+
i = i.succ
|
591
|
+
end
|
592
|
+
|
593
|
+
next if role.name == "" && role.privileges == nil
|
594
|
+
|
595
|
+
role.privileges ||= []
|
596
|
+
list << role
|
597
|
+
end
|
598
|
+
|
599
|
+
return 0, list
|
600
|
+
end
|
601
|
+
|
602
|
+
def parse_privileges(role)
|
603
|
+
size = @data_buffer.read(@data_offset)
|
604
|
+
@data_offset += 1
|
605
|
+
role.privileges = []
|
606
|
+
|
607
|
+
i = 0
|
608
|
+
while i < size
|
609
|
+
priv = Privilege.new
|
610
|
+
priv.code = Privilege.from(@data_buffer.read(@data_offset))
|
611
|
+
@data_offset += 1
|
612
|
+
|
613
|
+
if priv.can_scope?
|
614
|
+
len = @data_buffer.read(@data_offset)
|
615
|
+
@data_offset += 1
|
616
|
+
priv.namespace = @data_buffer.read(@data_offset, len)
|
617
|
+
@data_offset += len
|
618
|
+
|
619
|
+
len = @data_buffer.read(@data_offset)
|
620
|
+
@data_offset += 1
|
621
|
+
priv.set_name = @data_buffer.read(@data_offset, len)
|
622
|
+
@data_offset += len
|
623
|
+
end
|
624
|
+
|
625
|
+
role.privileges << priv
|
626
|
+
|
627
|
+
i = i.succ
|
628
|
+
end
|
629
|
+
end
|
630
|
+
|
631
|
+
def parse_allowlist(len)
|
632
|
+
list = []
|
633
|
+
begn = @data_offset
|
634
|
+
max = begn + len
|
635
|
+
|
636
|
+
while @data_offset < max
|
637
|
+
if @data_buffer.read(@data_offset) == ','
|
638
|
+
l = @data_offset - begn
|
639
|
+
if l > 0
|
640
|
+
s = @data_buffer.read(begn, l)
|
641
|
+
list << s
|
642
|
+
end
|
643
|
+
@data_offset += 1
|
644
|
+
begn = @data_offset
|
645
|
+
else
|
646
|
+
@data_offset += 1
|
647
|
+
end
|
648
|
+
end
|
649
|
+
|
650
|
+
l = @data_offset - begn
|
651
|
+
if l > 0
|
652
|
+
s = @data_buffer.read(begn, l)
|
653
|
+
list << s
|
654
|
+
end
|
655
|
+
|
656
|
+
list
|
657
|
+
end
|
658
|
+
|
343
659
|
end
|
344
660
|
end
|
345
661
|
|
@@ -0,0 +1,162 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# Copyright 2014-2020 Aerospike, Inc.
|
3
|
+
#
|
4
|
+
# Portions may be licensed to Aerospike, Inc. under one or more contributor
|
5
|
+
# license agreements.
|
6
|
+
#
|
7
|
+
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
8
|
+
# use this file except in compliance with the License. You may obtain a copy of
|
9
|
+
# the License at http:#www.apache.org/licenses/LICENSE-2.0
|
10
|
+
#
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
13
|
+
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
14
|
+
# License for the specific language governing permissions and limitations under
|
15
|
+
# the License.
|
16
|
+
|
17
|
+
require 'aerospike/command/admin_command'
|
18
|
+
|
19
|
+
module Aerospike
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
attr_reader :session_token, :session_expiration
|
24
|
+
|
25
|
+
class LoginCommand < AdminCommand #:nodoc:
|
26
|
+
|
27
|
+
def login(conn, policy)
|
28
|
+
hashed_pass = LoginCommand.hash_password(policy.password)
|
29
|
+
authenticate(conn, policy, hashed_pass)
|
30
|
+
end
|
31
|
+
|
32
|
+
def authenticate(conn, user, hashed_pass)
|
33
|
+
write_header(LOGIN, 2)
|
34
|
+
write_field_str(USER, policy.user)
|
35
|
+
write_field_bytes(CREDENTIAL, hashed_pass)
|
36
|
+
|
37
|
+
parse_tokens(conn)
|
38
|
+
end
|
39
|
+
|
40
|
+
def authenticate_new(conn, cluster)
|
41
|
+
policy = cluster.client_policy
|
42
|
+
case policy.auth_mode
|
43
|
+
when Aerospike::AuthMode::EXTERNAL
|
44
|
+
write_header(LOGIN, 3)
|
45
|
+
write_field_str(USER, policy.user)
|
46
|
+
write_field_bytes(CREDENTIAL, cluster.password)
|
47
|
+
write_field_str(CLEAR_PASSWORD, policy.password)
|
48
|
+
when Aerospike::AuthMode::INTERNAL
|
49
|
+
write_header(LOGIN, 2)
|
50
|
+
write_field_str(USER, policy.user)
|
51
|
+
write_field_bytes(CREDENTIAL, cluster.password)
|
52
|
+
when Aerospike::AuthMode::PKI
|
53
|
+
write_header(LOGIN, 0)
|
54
|
+
else
|
55
|
+
raise Exceptions::Aerospike.new(Aerospike::ResultCode::COMMAND_REJECTED, "Invalid client_policy#auth_mode.")
|
56
|
+
end
|
57
|
+
|
58
|
+
parse_tokens(conn)
|
59
|
+
cluster.session_token = @session_token
|
60
|
+
cluster.session_expiration = @session_expiration
|
61
|
+
end
|
62
|
+
|
63
|
+
def parse_tokens(conn)
|
64
|
+
begin
|
65
|
+
write_size
|
66
|
+
conn.write(@data_buffer, @data_offset)
|
67
|
+
conn.read(@data_buffer, HEADER_SIZE)
|
68
|
+
|
69
|
+
result = @data_buffer.read(RESULT_CODE)
|
70
|
+
|
71
|
+
if result != 0
|
72
|
+
return if result == Aerospike::ResultCode::SECURITY_NOT_ENABLED
|
73
|
+
raise Exceptions::Aerospike.new(result, "Authentication failed")
|
74
|
+
end
|
75
|
+
|
76
|
+
# read the rest of the buffer
|
77
|
+
size = @data_buffer.read_int64(0)
|
78
|
+
receive_size = (size & 0xFFFFFFFFFFFF) - HEADER_REMAINING
|
79
|
+
field_count = @data_buffer.read(11) & 0xFF
|
80
|
+
|
81
|
+
if receive_size <= 0 || receive_size > @data_buffer.size || field_count <= 0
|
82
|
+
raise Exceptions::Aerospike.new(result, "Node failed to retrieve session token")
|
83
|
+
end
|
84
|
+
|
85
|
+
if @data_buffer.size < receive_size
|
86
|
+
@data_buffer.resize(receive_size)
|
87
|
+
end
|
88
|
+
|
89
|
+
conn.read(@data_buffer, receive_size)
|
90
|
+
|
91
|
+
@data_offset = 0
|
92
|
+
for i in 0...field_count
|
93
|
+
mlen = @data_buffer.read_int32(@data_offset)
|
94
|
+
@data_offset += 4
|
95
|
+
id = @data_buffer.read(@data_offset)
|
96
|
+
@data_offset += 1
|
97
|
+
mlen -= 1
|
98
|
+
|
99
|
+
case id
|
100
|
+
when SESSION_TOKEN
|
101
|
+
# copy the contents of the buffer into a new byte slice
|
102
|
+
@session_token = @data_buffer.read(@data_offset, mlen)
|
103
|
+
|
104
|
+
when SESSION_TTL
|
105
|
+
# Subtract 60 seconds from TTL so client session expires before server session.
|
106
|
+
seconds = @data_buffer.read_int32(@data_offset) - 60
|
107
|
+
|
108
|
+
if seconds > 0
|
109
|
+
@session_expiration = Time.now + (seconds/86400)
|
110
|
+
else
|
111
|
+
Aerospike.logger.warn("Invalid session TTL: #{seconds}")
|
112
|
+
raise Exceptions::Aerospike.new(result, "Node failed to retrieve session token")
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
@data_offset += mlen
|
117
|
+
end
|
118
|
+
|
119
|
+
if !@session_token
|
120
|
+
raise Exceptions::Aerospike.new(result, "Node failed to retrieve session token")
|
121
|
+
end
|
122
|
+
ensure
|
123
|
+
Buffer.put(@data_buffer)
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
def authenticate_via_token(conn, cluster)
|
128
|
+
policy = cluster.client_policy
|
129
|
+
if policy.auth_mode != Aerospike::AuthMode::PKI
|
130
|
+
write_header(AUTHENTICATE, 2)
|
131
|
+
write_field_str(USER, policy.user)
|
132
|
+
else
|
133
|
+
write_header(AUTHENTICATE, 1)
|
134
|
+
end
|
135
|
+
|
136
|
+
write_field_bytes(SESSION_TOKEN, cluster.session_token) if cluster.session_token
|
137
|
+
write_size
|
138
|
+
|
139
|
+
conn.write(@data_buffer, @data_offset)
|
140
|
+
conn.read(@data_buffer, HEADER_SIZE)
|
141
|
+
|
142
|
+
result = @data_buffer.read(RESULT_CODE)
|
143
|
+
size = @data_buffer.read_int64(0)
|
144
|
+
receive_size = (size & 0xFFFFFFFFFFFF) - HEADER_REMAINING
|
145
|
+
conn.read(@data_buffer, receive_size)
|
146
|
+
|
147
|
+
if result != 0
|
148
|
+
return if result == Aerospike::ResultCode::SECURITY_NOT_ENABLED
|
149
|
+
raise Exceptions::Aerospike.new(result, "Authentication failed")
|
150
|
+
end
|
151
|
+
|
152
|
+
nil
|
153
|
+
end
|
154
|
+
|
155
|
+
SALT = '$2a$10$7EqJtq98hPqEX7fNZaFWoO'
|
156
|
+
def self.hash_password(password)
|
157
|
+
# Hashing the password with the cost of 10, with a static salt
|
158
|
+
return BCrypt::Engine.hash_secret(password, SALT, :cost => 10)
|
159
|
+
end
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
@@ -21,9 +21,41 @@ module Aerospike
|
|
21
21
|
module Connection # :nodoc:
|
22
22
|
module Authenticate
|
23
23
|
class << self
|
24
|
-
def call(conn, user,
|
25
|
-
command =
|
26
|
-
command.authenticate(conn, user,
|
24
|
+
def call(conn, user, hashed_pass)
|
25
|
+
command = LoginCommand.new
|
26
|
+
command.authenticate(conn, user, hashed_pass)
|
27
|
+
true
|
28
|
+
rescue ::Aerospike::Exceptions::Aerospike
|
29
|
+
conn.close if conn
|
30
|
+
raise ::Aerospike::Exceptions::InvalidCredentials
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
module AuthenticateNew
|
35
|
+
class << self
|
36
|
+
INVALID_SESSION_ERR = [ResultCode::INVALID_CREDENTIAL,
|
37
|
+
ResultCode::EXPIRED_SESSION]
|
38
|
+
|
39
|
+
def call(conn, cluster)
|
40
|
+
command = LoginCommand.new
|
41
|
+
if !cluster.session_valid?
|
42
|
+
command.authenticate_new(conn, cluster)
|
43
|
+
else
|
44
|
+
begin
|
45
|
+
command.authenticate_via_token(conn, cluster)
|
46
|
+
rescue => ae
|
47
|
+
# always reset session info on errors to be on the safe side
|
48
|
+
cluster.reset_session_info
|
49
|
+
if ae.is_a?(Exceptions::Aerospike)
|
50
|
+
if INVALID_SESSION_ERR.include?(ae.result_code)
|
51
|
+
command.authenticate_new(conn, cluster)
|
52
|
+
return
|
53
|
+
end
|
54
|
+
end
|
55
|
+
raise ae
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
27
59
|
true
|
28
60
|
rescue ::Aerospike::Exceptions::Aerospike
|
29
61
|
conn.close if conn
|
@@ -33,3 +65,4 @@ module Aerospike
|
|
33
65
|
end
|
34
66
|
end
|
35
67
|
end
|
68
|
+
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# Copyright 2014-2020 Aerospike, Inc.
|
3
|
+
#
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
5
|
+
# you may not use this file except in compliance with the License.
|
6
|
+
# You may obtain a copy of the License at
|
7
|
+
#
|
8
|
+
# http:#www.apache.org/licenses/LICENSE-2.0
|
9
|
+
#
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
+
# See the License for the specific language governing permissions and
|
14
|
+
# limitations under the License.
|
15
|
+
|
16
|
+
module Aerospike
|
17
|
+
|
18
|
+
module AuthMode
|
19
|
+
|
20
|
+
# INTERNAL uses internal authentication only when user/password defined. Hashed password is stored
|
21
|
+
# on the server. Do not send clear password. This is the default.
|
22
|
+
INTERNAL = 0
|
23
|
+
|
24
|
+
# EXTERNAL uses external authentication (like LDAP) when user/password defined. Specific external authentication is
|
25
|
+
# configured on server. If TLS is defined, sends clear password on node login via TLS.
|
26
|
+
# Will raise exception if TLS is not defined.
|
27
|
+
EXTERNAL = 1
|
28
|
+
|
29
|
+
# PKI allows authentication and authorization based on a certificate. No user name or
|
30
|
+
# password needs to be configured. Requires TLS and a client certificate.
|
31
|
+
# Requires server version 5.7.0+
|
32
|
+
PKI = 2
|
33
|
+
|
34
|
+
end # module
|
35
|
+
|
36
|
+
end # module
|
@@ -22,7 +22,7 @@ module Aerospike
|
|
22
22
|
# Container object for client policy command.
|
23
23
|
class ClientPolicy
|
24
24
|
|
25
|
-
attr_accessor :user, :password
|
25
|
+
attr_accessor :user, :password, :auth_mode
|
26
26
|
attr_accessor :timeout, :connection_queue_size, :fail_if_not_connected, :tend_interval
|
27
27
|
attr_accessor :cluster_name
|
28
28
|
attr_accessor :tls
|
@@ -44,6 +44,9 @@ module Aerospike
|
|
44
44
|
# which the client checks for cluster state changes. Minimum interval is 10ms.
|
45
45
|
self.tend_interval = opt[:tend_interval] || 1000 # 1 second
|
46
46
|
|
47
|
+
# Authentication mode
|
48
|
+
@auth_mode = opt[:auth_mode] || AuthMode::INTERNAL
|
49
|
+
|
47
50
|
# user name
|
48
51
|
@user = opt[:user]
|
49
52
|
|
@@ -0,0 +1,133 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# Copyright 2014-2022 Aerospike, Inc.
|
3
|
+
#
|
4
|
+
# Portions may be licensed to Aerospike, Inc. under one or more contributor
|
5
|
+
# license agreements.
|
6
|
+
#
|
7
|
+
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
8
|
+
# use this file except in compliance with the License. You may obtain a copy of
|
9
|
+
# the License at http:#www.apache.org/licenses/LICENSE-2.0
|
10
|
+
#
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
13
|
+
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
14
|
+
# License for the specific language governing permissions and limitations under
|
15
|
+
# the License.
|
16
|
+
|
17
|
+
module Aerospike
|
18
|
+
|
19
|
+
# Determines user access granularity.
|
20
|
+
class Privilege
|
21
|
+
|
22
|
+
# Role
|
23
|
+
attr_accessor :code
|
24
|
+
|
25
|
+
# Namespace determines namespace scope. Apply permission to this namespace only.
|
26
|
+
# If namespace is zero value, the privilege applies to all namespaces.
|
27
|
+
attr_accessor :namespace
|
28
|
+
|
29
|
+
# Set name scope. Apply permission to this set within namespace only.
|
30
|
+
# If set is zero value, the privilege applies to all sets within namespace.
|
31
|
+
attr_accessor :set_name
|
32
|
+
|
33
|
+
# Manage users and their roles.
|
34
|
+
USER_ADMIN = 'user-admin'
|
35
|
+
|
36
|
+
# Manage indicies, user-defined functions and server configuration.
|
37
|
+
SYS_ADMIN = 'sys-admin'
|
38
|
+
|
39
|
+
# Manage indicies and user defined functions.
|
40
|
+
DATA_ADMIN = 'data-admin'
|
41
|
+
|
42
|
+
# Manage user defined functions.
|
43
|
+
UDF_ADMIN = 'udf-admin'
|
44
|
+
|
45
|
+
# Manage indicies.
|
46
|
+
SINDEX_ADMIN = 'sindex-admin'
|
47
|
+
|
48
|
+
# Allow read, write and UDF transactions with the database.
|
49
|
+
READ_WRITE_UDF = "read-write-udf"
|
50
|
+
|
51
|
+
# Allow read and write transactions with the database.
|
52
|
+
READ_WRITE = 'read-write'
|
53
|
+
|
54
|
+
# Allow read transactions with the database.
|
55
|
+
READ = 'read'
|
56
|
+
|
57
|
+
# Write allows write transactions with the database.
|
58
|
+
WRITE = 'write'
|
59
|
+
|
60
|
+
# Truncate allow issuing truncate commands.
|
61
|
+
TRUNCATE = 'truncate'
|
62
|
+
|
63
|
+
def initialize(opt={})
|
64
|
+
@code = opt[:code]
|
65
|
+
@namespace = opt[:namespace]
|
66
|
+
@set_name = opt[:set_name]
|
67
|
+
end
|
68
|
+
|
69
|
+
def to_s
|
70
|
+
"code: #{@code}, namespace: #{@namespace}, set_name: #{@set_name}"
|
71
|
+
end
|
72
|
+
|
73
|
+
def to_code
|
74
|
+
case @code
|
75
|
+
when USER_ADMIN
|
76
|
+
0
|
77
|
+
when SYS_ADMIN
|
78
|
+
1
|
79
|
+
when DATA_ADMIN
|
80
|
+
2
|
81
|
+
when UDF_ADMIN
|
82
|
+
3
|
83
|
+
when SINDEX_ADMIN
|
84
|
+
4
|
85
|
+
when READ
|
86
|
+
10
|
87
|
+
when READ_WRITE
|
88
|
+
11
|
89
|
+
when READ_WRITE_UDF
|
90
|
+
12
|
91
|
+
when WRITE
|
92
|
+
13
|
93
|
+
when TRUNCATE
|
94
|
+
14
|
95
|
+
else
|
96
|
+
raise Exceptions::Aerospike.new(Aerospike::ResultCode::INVALID_PRIVILEGE, "Invalid role #{@code}")
|
97
|
+
end # case
|
98
|
+
end # def
|
99
|
+
|
100
|
+
def self.from(code)
|
101
|
+
case code
|
102
|
+
when 0
|
103
|
+
USER_ADMIN
|
104
|
+
when 1
|
105
|
+
SYS_ADMIN
|
106
|
+
when 2
|
107
|
+
DATA_ADMIN
|
108
|
+
when 3
|
109
|
+
UDF_ADMIN
|
110
|
+
when 4
|
111
|
+
SINDEX_ADMIN
|
112
|
+
when 10
|
113
|
+
READ
|
114
|
+
when 11
|
115
|
+
READ_WRITE
|
116
|
+
when 12
|
117
|
+
READ_WRITE_UDF
|
118
|
+
when 13
|
119
|
+
WRITE
|
120
|
+
when 14
|
121
|
+
TRUNCATE
|
122
|
+
else
|
123
|
+
raise Exceptions::Aerospike.new(Aerospike::ResultCode::INVALID_PRIVILEGE, "Invalid code #{code}")
|
124
|
+
end # case
|
125
|
+
end # def
|
126
|
+
|
127
|
+
def can_scope?
|
128
|
+
to_code >= 10
|
129
|
+
end
|
130
|
+
|
131
|
+
end # class
|
132
|
+
|
133
|
+
end
|
@@ -182,7 +182,7 @@ module Aerospike
|
|
182
182
|
# Privilege is invalid.
|
183
183
|
INVALID_PRIVILEGE = 72
|
184
184
|
|
185
|
-
# Specified IP
|
185
|
+
# Specified IP allowlist is invalid.
|
186
186
|
INVALID_WHITELIST = 73
|
187
187
|
|
188
188
|
# User must be authentication before performing database operations.
|
@@ -191,7 +191,7 @@ module Aerospike
|
|
191
191
|
# User does not posses the required role to perform the database operation.
|
192
192
|
ROLE_VIOLATION = 81
|
193
193
|
|
194
|
-
# Client IP address is not on the IP
|
194
|
+
# Client IP address is not on the IP allowlist.
|
195
195
|
NOT_WHITELISTED = 82
|
196
196
|
|
197
197
|
# LDAP feature not enabled on server.
|
@@ -422,7 +422,7 @@ module Aerospike
|
|
422
422
|
"Invalid privilege"
|
423
423
|
|
424
424
|
when INVALID_WHITELIST
|
425
|
-
"Specified IP
|
425
|
+
"Specified IP allowlist is invalid"
|
426
426
|
|
427
427
|
when NOT_AUTHENTICATED
|
428
428
|
"Not authenticated"
|
@@ -431,7 +431,7 @@ module Aerospike
|
|
431
431
|
"Role violation"
|
432
432
|
|
433
433
|
when NOT_WHITELISTED
|
434
|
-
"Client IP address is not on the IP
|
434
|
+
"Client IP address is not on the IP allowlist"
|
435
435
|
|
436
436
|
when LDAP_NOT_ENABLED
|
437
437
|
"LDAP feature not enabled on server"
|
@@ -0,0 +1,55 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# Copyright 2014-2020 Aerospike, Inc.
|
3
|
+
#
|
4
|
+
# Portions may be licensed to Aerospike, Inc. under one or more contributor
|
5
|
+
# license agreements.
|
6
|
+
#
|
7
|
+
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
8
|
+
# use this file except in compliance with the License. You may obtain a copy of
|
9
|
+
# the License at http:#www.apache.org/licenses/LICENSE-2.0
|
10
|
+
#
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
13
|
+
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
14
|
+
# License for the specific language governing permissions and limitations under
|
15
|
+
# the License.
|
16
|
+
|
17
|
+
module Aerospike
|
18
|
+
|
19
|
+
# Role provides granular access to database entities for users.
|
20
|
+
class Role
|
21
|
+
|
22
|
+
# Role name
|
23
|
+
attr_accessor :name
|
24
|
+
|
25
|
+
# List of assigned privileges
|
26
|
+
attr_accessor :privileges
|
27
|
+
|
28
|
+
# List of allowable IP addresses
|
29
|
+
attr_accessor :allowlist
|
30
|
+
|
31
|
+
# Maximum reads per second limit for the role
|
32
|
+
attr_accessor :read_quota
|
33
|
+
|
34
|
+
# Maximum writes per second limit for the role
|
35
|
+
attr_accessor :write_quota
|
36
|
+
|
37
|
+
# The following aliases are for backward compatibility reasons
|
38
|
+
USER_ADMIN = Privilege::USER_ADMIN # :nodoc:
|
39
|
+
SYS_ADMIN = Privilege::SYS_ADMIN # :nodoc:
|
40
|
+
DATA_ADMIN = Privilege::DATA_ADMIN # :nodoc:
|
41
|
+
UDF_ADMIN = Privilege::UDF_ADMIN # :nodoc:
|
42
|
+
SINDEX_ADMIN = Privilege::SINDEX_ADMIN # :nodoc:
|
43
|
+
READ_WRITE_UDF = Privilege::READ_WRITE_UDF # :nodoc:
|
44
|
+
READ_WRITE = Privilege::READ_WRITE # :nodoc:
|
45
|
+
READ = Privilege::READ # :nodoc:
|
46
|
+
WRITE = Privilege::WRITE # :nodoc:
|
47
|
+
TRUNCATE = Privilege::TRUNCATE # :nodoc:
|
48
|
+
|
49
|
+
def to_s
|
50
|
+
"Role [name=#{@name}, privileges=#{@privileges}, allowlist=#{@allowlist}, readQuota=#{@read_quota}, writeQuota=#{@write_quota}]";
|
51
|
+
end
|
52
|
+
|
53
|
+
end # class
|
54
|
+
|
55
|
+
end # module
|
data/lib/aerospike/user_role.rb
CHANGED
@@ -25,6 +25,31 @@ module Aerospike
|
|
25
25
|
# List of assigned roles.
|
26
26
|
attr_accessor :roles
|
27
27
|
|
28
|
+
# List of read statistics. List may be nil.
|
29
|
+
# Current statistics by offset are:
|
30
|
+
#
|
31
|
+
# 0: read quota in records per second
|
32
|
+
# 1: single record read transaction rate (TPS)
|
33
|
+
# 2: read scan/query record per second rate (RPS)
|
34
|
+
# 3: number of limitless read scans/queries
|
35
|
+
#
|
36
|
+
# Future server releases may add additional statistics.
|
37
|
+
attr_accessor :read_info
|
38
|
+
|
39
|
+
# List of write statistics. List may be nil.
|
40
|
+
# Current statistics by offset are:
|
41
|
+
#
|
42
|
+
# 0: write quota in records per second
|
43
|
+
# 1: single record write transaction rate (TPS)
|
44
|
+
# 2: write scan/query record per second rate (RPS)
|
45
|
+
# 3: number of limitless write scans/queries
|
46
|
+
#
|
47
|
+
# Future server releases may add additional statistics.
|
48
|
+
attr_accessor :write_info
|
49
|
+
|
50
|
+
# Number of currently open connections for the user
|
51
|
+
attr_accessor :conns_in_use
|
52
|
+
|
28
53
|
end
|
29
54
|
|
30
55
|
end
|
@@ -136,16 +136,31 @@ module Aerospike
|
|
136
136
|
vals.unpack(INT16)[0]
|
137
137
|
end
|
138
138
|
|
139
|
+
def read_uint16(offset)
|
140
|
+
vals = @buf[offset..offset+1]
|
141
|
+
vals.unpack(UINT16)[0]
|
142
|
+
end
|
143
|
+
|
139
144
|
def read_int32(offset)
|
140
145
|
vals = @buf[offset..offset+3]
|
141
146
|
vals.unpack(INT32)[0]
|
142
147
|
end
|
143
148
|
|
149
|
+
def read_uint32(offset)
|
150
|
+
vals = @buf[offset..offset+3]
|
151
|
+
vals.unpack(UINT32)[0]
|
152
|
+
end
|
153
|
+
|
144
154
|
def read_int64(offset)
|
145
155
|
vals = @buf[offset..offset+7]
|
146
156
|
vals.unpack(INT64)[0]
|
147
157
|
end
|
148
158
|
|
159
|
+
def read_uint64(offset)
|
160
|
+
vals = @buf[offset..offset+7]
|
161
|
+
vals.unpack(UINT64)[0]
|
162
|
+
end
|
163
|
+
|
149
164
|
def read_var_int64(offset, len)
|
150
165
|
val = 0
|
151
166
|
i = 0
|
data/lib/aerospike/version.rb
CHANGED
data/lib/aerospike.rb
CHANGED
@@ -62,6 +62,7 @@ require 'aerospike/command/touch_command'
|
|
62
62
|
require 'aerospike/command/read_command'
|
63
63
|
require 'aerospike/command/delete_command'
|
64
64
|
require 'aerospike/command/admin_command'
|
65
|
+
require 'aerospike/command/login_command'
|
65
66
|
require 'aerospike/command/unsupported_particle_type_validator'
|
66
67
|
require 'aerospike/key'
|
67
68
|
require 'aerospike/operation'
|
@@ -101,6 +102,7 @@ require 'aerospike/policy/query_policy'
|
|
101
102
|
require 'aerospike/policy/consistency_level'
|
102
103
|
require 'aerospike/policy/commit_level'
|
103
104
|
require 'aerospike/policy/admin_policy'
|
105
|
+
require 'aerospike/policy/auth_mode'
|
104
106
|
|
105
107
|
require 'aerospike/socket/base'
|
106
108
|
require 'aerospike/socket/ssl'
|
@@ -141,6 +143,8 @@ require 'aerospike/udf'
|
|
141
143
|
require 'aerospike/bin'
|
142
144
|
require 'aerospike/aerospike_exception'
|
143
145
|
require 'aerospike/user_role'
|
146
|
+
require 'aerospike/privilege'
|
147
|
+
require 'aerospike/role'
|
144
148
|
|
145
149
|
require 'aerospike/task/index_task'
|
146
150
|
require 'aerospike/task/execute_task'
|
metadata
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: aerospike
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.21.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Khosrow Afroozeh
|
8
8
|
- Jan Hecking
|
9
|
-
autorequire:
|
9
|
+
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2022-06-21 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: msgpack
|
@@ -97,11 +97,11 @@ files:
|
|
97
97
|
- lib/aerospike/command/execute_command.rb
|
98
98
|
- lib/aerospike/command/exists_command.rb
|
99
99
|
- lib/aerospike/command/field_type.rb
|
100
|
+
- lib/aerospike/command/login_command.rb
|
100
101
|
- lib/aerospike/command/multi_command.rb
|
101
102
|
- lib/aerospike/command/operate_command.rb
|
102
103
|
- lib/aerospike/command/read_command.rb
|
103
104
|
- lib/aerospike/command/read_header_command.rb
|
104
|
-
- lib/aerospike/command/roles.rb
|
105
105
|
- lib/aerospike/command/single_command.rb
|
106
106
|
- lib/aerospike/command/touch_command.rb
|
107
107
|
- lib/aerospike/command/unsupported_particle_type_validator.rb
|
@@ -138,6 +138,7 @@ files:
|
|
138
138
|
- lib/aerospike/peers/fetch.rb
|
139
139
|
- lib/aerospike/peers/parse.rb
|
140
140
|
- lib/aerospike/policy/admin_policy.rb
|
141
|
+
- lib/aerospike/policy/auth_mode.rb
|
141
142
|
- lib/aerospike/policy/batch_policy.rb
|
142
143
|
- lib/aerospike/policy/client_policy.rb
|
143
144
|
- lib/aerospike/policy/commit_level.rb
|
@@ -152,6 +153,7 @@ files:
|
|
152
153
|
- lib/aerospike/policy/replica.rb
|
153
154
|
- lib/aerospike/policy/scan_policy.rb
|
154
155
|
- lib/aerospike/policy/write_policy.rb
|
156
|
+
- lib/aerospike/privilege.rb
|
155
157
|
- lib/aerospike/query/filter.rb
|
156
158
|
- lib/aerospike/query/pred_exp.rb
|
157
159
|
- lib/aerospike/query/pred_exp/and_or.rb
|
@@ -168,6 +170,7 @@ files:
|
|
168
170
|
- lib/aerospike/query/stream_command.rb
|
169
171
|
- lib/aerospike/record.rb
|
170
172
|
- lib/aerospike/result_code.rb
|
173
|
+
- lib/aerospike/role.rb
|
171
174
|
- lib/aerospike/socket/base.rb
|
172
175
|
- lib/aerospike/socket/ssl.rb
|
173
176
|
- lib/aerospike/socket/tcp.rb
|
@@ -209,8 +212,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
209
212
|
- !ruby/object:Gem::Version
|
210
213
|
version: '0'
|
211
214
|
requirements: []
|
212
|
-
rubygems_version: 3.
|
213
|
-
signing_key:
|
215
|
+
rubygems_version: 3.2.15
|
216
|
+
signing_key:
|
214
217
|
specification_version: 4
|
215
218
|
summary: An Aerospike driver for Ruby.
|
216
219
|
test_files: []
|
@@ -1,39 +0,0 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
# Copyright 2014-2020 Aerospike, Inc.
|
3
|
-
#
|
4
|
-
# Portions may be licensed to Aerospike, Inc. under one or more contributor
|
5
|
-
# license agreements.
|
6
|
-
#
|
7
|
-
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
8
|
-
# use this file except in compliance with the License. You may obtain a copy of
|
9
|
-
# the License at http:#www.apache.org/licenses/LICENSE-2.0
|
10
|
-
#
|
11
|
-
# Unless required by applicable law or agreed to in writing, software
|
12
|
-
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
13
|
-
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
14
|
-
# License for the specific language governing permissions and limitations under
|
15
|
-
# the License.
|
16
|
-
|
17
|
-
module Aerospike
|
18
|
-
|
19
|
-
# Pre-defined user roles.
|
20
|
-
module Role
|
21
|
-
|
22
|
-
# Manage users and their roles.
|
23
|
-
USER_ADMIN = 'user-admin'
|
24
|
-
|
25
|
-
# Manage indicies, user-defined functions and server configuration.
|
26
|
-
SYS_ADMIN = 'sys-admin'
|
27
|
-
|
28
|
-
# Allow read, write and UDF transactions with the database.
|
29
|
-
READ_WRITE_UDF = "read-write-udf"
|
30
|
-
|
31
|
-
# Allow read and write transactions with the database.
|
32
|
-
READ_WRITE = 'read-write'
|
33
|
-
|
34
|
-
# Allow read transactions with the database.
|
35
|
-
READ = 'read'
|
36
|
-
|
37
|
-
end # module
|
38
|
-
|
39
|
-
end # module
|