strongdm 15.41.0 → 15.43.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/.git/ORIG_HEAD +1 -1
- data/.git/index +0 -0
- data/.git/logs/HEAD +3 -3
- data/.git/logs/refs/heads/master +2 -2
- data/.git/logs/refs/remotes/origin/HEAD +1 -1
- data/.git/objects/pack/{pack-72042e33d36ca85cdfa5c79a6b28c7e6d0bf83d7.idx → pack-4d13e40791f92a784a9a6a0f8729932092f3c50f.idx} +0 -0
- data/.git/objects/pack/{pack-72042e33d36ca85cdfa5c79a6b28c7e6d0bf83d7.pack → pack-4d13e40791f92a784a9a6a0f8729932092f3c50f.pack} +0 -0
- data/.git/packed-refs +3 -2
- data/.git/refs/heads/master +1 -1
- data/lib/constants.rb +1 -0
- data/lib/interceptors.rb +200 -0
- data/lib/strongdm.rb +8 -1
- data/lib/svc.rb +577 -0
- data/lib/version +1 -1
- data/lib/version.rb +1 -1
- metadata +5 -4
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 07b05d002ea762434e9a42b6da278425d8bb2adf661df165169151ead7aedbda
|
|
4
|
+
data.tar.gz: fff4b6adece624583f2ccc960359612db92edde0a6af9ada9468013740cc5f16
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 63a76d68d110c41c6c7838a4927186c8606a0c61c4eacfa2d47a729e4e0754561331e70d80a5e1f2916caae212619296c42bf38a15f0c07bc8d641d122fbebb4
|
|
7
|
+
data.tar.gz: 22e7bb7ce4c40f7935ef05feb46d1dbc2e41a9d2ccb2fa6526743dec30e55c5fe6819f9502e4c0d790b88478162ba10588372fde8691d6f2183db6ed60eb49f0
|
data/.git/ORIG_HEAD
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
b23f0912dbe900e5bd24222f9971c7820ddf128d
|
data/.git/index
CHANGED
|
Binary file
|
data/.git/logs/HEAD
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
0000000000000000000000000000000000000000
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
0000000000000000000000000000000000000000 b23f0912dbe900e5bd24222f9971c7820ddf128d root <root@cbe5b8a77e04.(none)> 1766504191 +0000 clone: from github.com:strongdm/strongdm-sdk-ruby.git
|
|
2
|
+
b23f0912dbe900e5bd24222f9971c7820ddf128d b23f0912dbe900e5bd24222f9971c7820ddf128d root <root@cbe5b8a77e04.(none)> 1766504191 +0000 checkout: moving from master to master
|
|
3
|
+
b23f0912dbe900e5bd24222f9971c7820ddf128d 1170439941e521c29339b4d2314cae0e1526759e root <root@cbe5b8a77e04.(none)> 1766504191 +0000 merge origin/development: Fast-forward
|
data/.git/logs/refs/heads/master
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
0000000000000000000000000000000000000000
|
|
2
|
-
|
|
1
|
+
0000000000000000000000000000000000000000 b23f0912dbe900e5bd24222f9971c7820ddf128d root <root@cbe5b8a77e04.(none)> 1766504191 +0000 clone: from github.com:strongdm/strongdm-sdk-ruby.git
|
|
2
|
+
b23f0912dbe900e5bd24222f9971c7820ddf128d 1170439941e521c29339b4d2314cae0e1526759e root <root@cbe5b8a77e04.(none)> 1766504191 +0000 merge origin/development: Fast-forward
|
|
@@ -1 +1 @@
|
|
|
1
|
-
0000000000000000000000000000000000000000
|
|
1
|
+
0000000000000000000000000000000000000000 b23f0912dbe900e5bd24222f9971c7820ddf128d root <root@cbe5b8a77e04.(none)> 1766504191 +0000 clone: from github.com:strongdm/strongdm-sdk-ruby.git
|
|
Binary file
|
|
Binary file
|
data/.git/packed-refs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# pack-refs with: peeled fully-peeled sorted
|
|
2
|
-
|
|
3
|
-
|
|
2
|
+
1170439941e521c29339b4d2314cae0e1526759e refs/remotes/origin/development
|
|
3
|
+
b23f0912dbe900e5bd24222f9971c7820ddf128d refs/remotes/origin/master
|
|
4
4
|
2e4fe8087177ddea9b3991ca499f758384839c89 refs/tags/untagged-84fd83a4484c785cce63
|
|
5
5
|
04f604866214fab4d5663b5171a3e596331577bd refs/tags/v0.9.4
|
|
6
6
|
6f9a7b75b345c65fb554884907b7060680c807b7 refs/tags/v0.9.5
|
|
@@ -128,6 +128,7 @@ e2a4215bd3bbfb822423e11e81b9ad47bef03840 refs/tags/v15.36.0
|
|
|
128
128
|
740f705c286a25c2abae5a44b52fe330cc4e3e71 refs/tags/v15.39.0
|
|
129
129
|
cf3b15b82cb0c4229609c07c870c6cb4fd38ef75 refs/tags/v15.4.0
|
|
130
130
|
b20e3c16d138fc17c80e82311c7613a915bc3569 refs/tags/v15.40.0
|
|
131
|
+
b23f0912dbe900e5bd24222f9971c7820ddf128d refs/tags/v15.41.0
|
|
131
132
|
0be2c5e7f7a90c49077548cb3a9bce234219b9f0 refs/tags/v15.5.0
|
|
132
133
|
4b9cd43c5dda3f369b82b6a56132a5470ff9ff53 refs/tags/v15.6.0
|
|
133
134
|
6e8e9210b26f02ebe925b8e81909ba42985cfde7 refs/tags/v15.7.0
|
data/.git/refs/heads/master
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
1170439941e521c29339b4d2314cae0e1526759e
|
data/lib/constants.rb
CHANGED
|
@@ -333,6 +333,7 @@ module SDM
|
|
|
333
333
|
RESOURCE_LOCKED = "user locked a resource"
|
|
334
334
|
RESOURCE_UNLOCKED = "user unlocked a resource"
|
|
335
335
|
RESOURCE_FORCE_UNLOCKED = "admin force-unlocked a resource"
|
|
336
|
+
RESOURCE_LOCK_REJECTED = "user lock rejected for a resource"
|
|
336
337
|
CONCURRENT_AUTHENTICATION_REVOKED_PER_ORG_SETTING = "concurrent authentications revoked per organization settings"
|
|
337
338
|
PEERING_GROUP_TOGGLED = "peering group toggled"
|
|
338
339
|
PEERING_GROUP_CREATED = "peering group created"
|
data/lib/interceptors.rb
ADDED
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
# Copyright 2020 StrongDM Inc
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
#
|
|
15
|
+
|
|
16
|
+
# @internal Code generated by protogen. DO NOT EDIT.
|
|
17
|
+
|
|
18
|
+
require "openssl"
|
|
19
|
+
require_relative "./grpc/plumbing"
|
|
20
|
+
|
|
21
|
+
module SDM
|
|
22
|
+
# MethodInterceptor provides a generic hook system for modifying
|
|
23
|
+
# requests and responses before/after gRPC calls
|
|
24
|
+
class MethodInterceptor
|
|
25
|
+
def initialize(client)
|
|
26
|
+
@client = client
|
|
27
|
+
@before_hooks = {}
|
|
28
|
+
@after_hooks = {}
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# Register a hook to run before a method call
|
|
32
|
+
# method_name: "ServiceName.MethodName" (e.g., "ManagedSecrets.Create")
|
|
33
|
+
# block: receives (service_instance, request) and should return modified request
|
|
34
|
+
def before(method_name, &block)
|
|
35
|
+
@before_hooks[method_name] = block
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# Register a hook to run after a method call
|
|
39
|
+
# method_name: "ServiceName.MethodName"
|
|
40
|
+
# block: receives (service_instance, request, response) and should return modified response
|
|
41
|
+
def after(method_name, &block)
|
|
42
|
+
@after_hooks[method_name] = block
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# Execute before hooks for a method
|
|
46
|
+
def execute_before(method_name, service_instance, request)
|
|
47
|
+
hook = @before_hooks[method_name]
|
|
48
|
+
return request unless hook
|
|
49
|
+
hook.call(service_instance, request)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# Execute after hooks for a method
|
|
53
|
+
def execute_after(method_name, service_instance, request, response)
|
|
54
|
+
hook = @after_hooks[method_name]
|
|
55
|
+
return response unless hook
|
|
56
|
+
hook.call(service_instance, request, response)
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# SecretEncryptionInterceptor implements encryption for managed secrets
|
|
61
|
+
class SecretEncryptionInterceptor
|
|
62
|
+
def initialize(client)
|
|
63
|
+
@client = client
|
|
64
|
+
@public_key_cache = {}
|
|
65
|
+
@private_key = nil
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
# Lazy-load private key for retrievals
|
|
69
|
+
def private_key
|
|
70
|
+
@private_key ||= OpenSSL::PKey::RSA.new(4096)
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
# Cache a secret engine's public key
|
|
74
|
+
def cache_public_key(engine_id, public_key_pem)
|
|
75
|
+
return if public_key_pem.nil? || public_key_pem.empty?
|
|
76
|
+
@public_key_cache[engine_id] = OpenSSL::PKey::RSA.new(public_key_pem)
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
# Get cached public key
|
|
80
|
+
def get_public_key(engine_id)
|
|
81
|
+
@public_key_cache[engine_id]
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
# Encrypt data using RSA-OAEP with SHA256
|
|
85
|
+
def encrypt(public_key, plaintext)
|
|
86
|
+
return plaintext if plaintext.nil? || plaintext.empty?
|
|
87
|
+
public_key.encrypt(plaintext, rsa_padding_mode: "oaep", rsa_oaep_md: "sha256", rsa_mgf1_md: "sha256")
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
# Decrypt data using RSA-OAEP with SHA256
|
|
91
|
+
def decrypt(ciphertext)
|
|
92
|
+
return ciphertext if ciphertext.nil? || ciphertext.empty?
|
|
93
|
+
private_key.decrypt(ciphertext, rsa_padding_mode: "oaep", rsa_oaep_md: "sha256", rsa_mgf1_md: "sha256")
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
# Export public key in PEM format
|
|
97
|
+
def export_public_key
|
|
98
|
+
private_key.public_key.to_pem
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
# Setup hooks on the interceptor
|
|
102
|
+
def setup(interceptor)
|
|
103
|
+
setup_managed_secrets_hooks(interceptor)
|
|
104
|
+
setup_secret_engines_hooks(interceptor)
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
private
|
|
108
|
+
|
|
109
|
+
def setup_managed_secrets_hooks(interceptor)
|
|
110
|
+
# Hook for ManagedSecrets.Create - encrypt before sending
|
|
111
|
+
interceptor.before("ManagedSecrets.Create") do |service, req|
|
|
112
|
+
secret = req.managed_secret
|
|
113
|
+
if secret && !secret.value.nil? && !secret.value.empty? && !secret.secret_engine_id.nil?
|
|
114
|
+
# Try to get public key from cache or fetch it
|
|
115
|
+
pub_key = get_public_key(secret.secret_engine_id)
|
|
116
|
+
if pub_key.nil?
|
|
117
|
+
begin
|
|
118
|
+
@client.secret_engines.get(secret.secret_engine_id)
|
|
119
|
+
pub_key = get_public_key(secret.secret_engine_id)
|
|
120
|
+
rescue
|
|
121
|
+
# If fetch fails, let server handle it
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
# Encrypt if we have the key
|
|
126
|
+
if pub_key
|
|
127
|
+
secret.value = encrypt(pub_key, secret.value)
|
|
128
|
+
end
|
|
129
|
+
end
|
|
130
|
+
req
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
# Hook for ManagedSecrets.Update - encrypt before sending
|
|
134
|
+
interceptor.before("ManagedSecrets.Update") do |service, req|
|
|
135
|
+
secret = req.managed_secret
|
|
136
|
+
if secret && !secret.value.nil? && !secret.value.empty? && !secret.secret_engine_id.nil?
|
|
137
|
+
pub_key = get_public_key(secret.secret_engine_id)
|
|
138
|
+
if pub_key.nil?
|
|
139
|
+
begin
|
|
140
|
+
@client.secret_engines.get(secret.secret_engine_id)
|
|
141
|
+
pub_key = get_public_key(secret.secret_engine_id)
|
|
142
|
+
rescue
|
|
143
|
+
# If fetch fails, let server handle it
|
|
144
|
+
end
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
if pub_key
|
|
148
|
+
secret.value = encrypt(pub_key, secret.value)
|
|
149
|
+
end
|
|
150
|
+
end
|
|
151
|
+
req
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
# Hook for ManagedSecrets.Retrieve - add public key and decrypt response
|
|
155
|
+
interceptor.before("ManagedSecrets.Retrieve") do |service, req|
|
|
156
|
+
if req.public_key.nil? || req.public_key.empty?
|
|
157
|
+
req.public_key = export_public_key
|
|
158
|
+
end
|
|
159
|
+
req
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
interceptor.after("ManagedSecrets.Retrieve") do |service, req, resp|
|
|
163
|
+
# Only decrypt if we provided the public key
|
|
164
|
+
if req.public_key == export_public_key
|
|
165
|
+
secret = resp.managed_secret
|
|
166
|
+
if secret && !secret.value.nil? && !secret.value.empty?
|
|
167
|
+
secret.value = decrypt(secret.value)
|
|
168
|
+
end
|
|
169
|
+
end
|
|
170
|
+
resp
|
|
171
|
+
end
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
def setup_secret_engines_hooks(interceptor)
|
|
175
|
+
# Hook for SecretEngines.Get - cache public key after response
|
|
176
|
+
interceptor.after("SecretEngines.Get") do |service, req, resp|
|
|
177
|
+
engine = Plumbing::convert_secret_engine_to_porcelain(resp.secret_engine)
|
|
178
|
+
if engine && !engine.id.nil? && !engine.public_key.nil?
|
|
179
|
+
cache_public_key(engine.id, engine.public_key)
|
|
180
|
+
end
|
|
181
|
+
resp
|
|
182
|
+
end
|
|
183
|
+
end
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
# EnumeratorInterceptor provides utilities for wrapping enumerators with hooks
|
|
187
|
+
module EnumeratorInterceptor
|
|
188
|
+
# Wraps an enumerator to cache secret engine public keys
|
|
189
|
+
def self.wrap_secret_engine_list(enumerator, encryption_interceptor)
|
|
190
|
+
Enumerator.new do |yielder|
|
|
191
|
+
enumerator.each do |engine|
|
|
192
|
+
if engine && !engine.id.nil? && !engine.public_key.nil?
|
|
193
|
+
encryption_interceptor.cache_public_key(engine.id, engine.public_key)
|
|
194
|
+
end
|
|
195
|
+
yielder << engine
|
|
196
|
+
end
|
|
197
|
+
end
|
|
198
|
+
end
|
|
199
|
+
end
|
|
200
|
+
end
|
data/lib/strongdm.rb
CHANGED
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
# @internal Code generated by protogen. DO NOT EDIT.
|
|
17
17
|
|
|
18
18
|
require_relative "./svc"
|
|
19
|
+
require_relative "./interceptors"
|
|
19
20
|
require "base64"
|
|
20
21
|
require "grpc"
|
|
21
22
|
require "openssl"
|
|
@@ -30,7 +31,7 @@ module SDM #:nodoc:
|
|
|
30
31
|
DEFAULT_RETRY_FACTOR = 1.6
|
|
31
32
|
DEFAULT_RETRY_JITTER = 0.2
|
|
32
33
|
API_VERSION = "2025-04-14"
|
|
33
|
-
USER_AGENT = "strongdm-sdk-ruby/15.
|
|
34
|
+
USER_AGENT = "strongdm-sdk-ruby/15.43.0"
|
|
34
35
|
private_constant :DEFAULT_BASE_RETRY_DELAY, :DEFAULT_MAX_RETRY_DELAY, :DEFAULT_RETRY_FACTOR, :DEFAULT_RETRY_JITTER, :API_VERSION, :USER_AGENT
|
|
35
36
|
|
|
36
37
|
# Creates a new strongDM API client.
|
|
@@ -47,6 +48,10 @@ module SDM #:nodoc:
|
|
|
47
48
|
@page_limit = page_limit
|
|
48
49
|
@retry_rate_limit_errors = retry_rate_limit_errors
|
|
49
50
|
@snapshot_time = nil
|
|
51
|
+
# Initialize method interceptor for request/response hooks
|
|
52
|
+
@interceptor = MethodInterceptor.new(self)
|
|
53
|
+
@encryption_interceptor = SecretEncryptionInterceptor.new(self)
|
|
54
|
+
@encryption_interceptor.setup(@interceptor)
|
|
50
55
|
begin
|
|
51
56
|
if insecure
|
|
52
57
|
@channel = GRPC::Core::Channel.new(host, {}, :this_channel_is_insecure)
|
|
@@ -234,6 +239,8 @@ module SDM #:nodoc:
|
|
|
234
239
|
attr_reader :api_access_key
|
|
235
240
|
# Optional timestamp at which to provide historical data
|
|
236
241
|
attr_reader :snapshot_time
|
|
242
|
+
# Method interceptor for request/response hooks (read-only).
|
|
243
|
+
attr_reader :interceptor
|
|
237
244
|
# AccessRequests are requests for access to a resource that may match a Workflow.
|
|
238
245
|
#
|
|
239
246
|
# See {AccessRequests}.
|