Skip to content

Commit ada13fa

Browse files
authored
Fix: encode body before signing to match manticore adapter encoding. (opensearch-project#217)
Signed-off-by: dblock <dblock@dblock.org>
1 parent 1528755 commit ada13fa

File tree

2 files changed

+82
-21
lines changed

2 files changed

+82
-21
lines changed

lib/logstash/outputs/opensearch/http_client/manticore_adapter.rb

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@
1212
require 'manticore'
1313
require 'uri'
1414

15+
java_import 'org.apache.http.util.EntityUtils'
16+
java_import 'org.apache.http.entity.StringEntity'
17+
1518
module LogStash; module Outputs; class OpenSearch; class HttpClient;
1619
AWS_DEFAULT_PORT = 443
1720
AWS_DEFAULT_PROFILE = 'default'
@@ -181,8 +184,20 @@ def perform_request(url, method, path, params={}, body=nil)
181184
resp
182185
end
183186

187+
# from Manticore, https://github.com/cheald/manticore/blob/acc25cac2999f4658a77a0f39f60ddbca8fe14a4/lib/manticore/client.rb#L536
188+
ISO_8859_1 = "ISO-8859-1".freeze
189+
190+
def minimum_encoding_for(string)
191+
if string.ascii_only?
192+
ISO_8859_1
193+
else
194+
string.encoding.to_s
195+
end
196+
end
197+
184198
def sign_aws_request(request_uri, path, method, params)
185199
url = URI::HTTPS.build({:host=>URI(request_uri.to_s).host, :port=>AWS_DEFAULT_PORT.to_s, :path=>path})
200+
186201
request = Seahorse::Client::Http::Request.new(options={:endpoint=>url, :http_method => method.to_s.upcase,
187202
:headers => params[:headers],:body => params[:body]})
188203

@@ -191,7 +206,8 @@ def sign_aws_request(request_uri, path, method, params)
191206
http_method: request.http_method,
192207
url: url,
193208
headers: params[:headers],
194-
body: params[:body]
209+
# match encoding of the HTTP adapter, see https://github.com/opensearch-project/logstash-output-opensearch/issues/207
210+
body: params[:body] ? EntityUtils.toString(StringEntity.new(params[:body], minimum_encoding_for(params[:body]))) : nil
195211
)
196212
params[:headers] = params[:headers].merge(signed_key.headers)
197213
end

spec/unit/outputs/opensearch/http_client/manticore_adapter_spec.rb

Lines changed: 65 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -70,35 +70,80 @@
7070
} }
7171
subject { described_class.new(logger, options) }
7272
let(:uri) { ::LogStash::Util::SafeURI.new("http://localhost:9200") }
73-
let(:sign_aws_request) { }
7473

75-
it "should validate AWS IAM credentials initialization" do
76-
expect(subject.aws_iam_auth_initialization(options)).not_to be_nil
77-
expect(subject.get_service_name).to eq("es")
78-
end
79-
80-
it "should validate AWS IAM service_name config" do
81-
expect(subject.aws_iam_auth_initialization(options_svc)).not_to be_nil
82-
expect(subject.get_service_name).to eq("svc_test")
83-
end
74+
let(:expected_uri) {
75+
expected_uri = uri.clone
76+
expected_uri.path = "/"
77+
expected_uri
78+
}
8479

85-
it "should validate signing aws request" do
80+
let(:resp) {
8681
resp = double("response")
8782
allow(resp).to receive(:call)
8883
allow(resp).to receive(:code).and_return(200)
89-
allow(subject).to receive(:sign_aws_request).with(any_args).and_return(sign_aws_request)
84+
resp
85+
}
9086

91-
expected_uri = uri.clone
92-
expected_uri.path = "/"
87+
context 'with a signer' do
88+
let(:sign_aws_request) { }
9389

94-
expect(subject.manticore).to receive(:get).
95-
with(expected_uri.to_s, {
96-
:headers => {"content-type"=> "application/json"}
97-
}
90+
it "should validate AWS IAM credentials initialization" do
91+
expect(subject.aws_iam_auth_initialization(options)).not_to be_nil
92+
expect(subject.get_service_name).to eq("es")
93+
end
94+
95+
it "should validate AWS IAM service_name config" do
96+
expect(subject.aws_iam_auth_initialization(options_svc)).not_to be_nil
97+
expect(subject.get_service_name).to eq("svc_test")
98+
end
99+
100+
it "should validate signing aws request" do
101+
allow(subject).to receive(:sign_aws_request).with(any_args).and_return(sign_aws_request)
102+
103+
expect(subject.manticore).to receive(:get).
104+
with(expected_uri.to_s, {
105+
:headers => {"content-type"=> "application/json"}
106+
}
107+
).and_return resp
108+
109+
expect(subject).to receive(:sign_aws_request)
110+
subject.perform_request(uri, :get, "/")
111+
end
112+
end
113+
114+
context 'sign_aws_request' do
115+
it 'handles UTF-8' do
116+
encoded_body = body = "boîte de réception"
117+
expect_any_instance_of(Aws::Sigv4::Signer).to receive(:sign_request).with(hash_including({
118+
body: body,
119+
})).and_return(
120+
double(headers: {})
121+
)
122+
expect(subject.manticore).to receive(:post).
123+
with(expected_uri.to_s, {
124+
:body => encoded_body,
125+
:headers => {"content-type"=> "application/json"}
126+
}
98127
).and_return resp
128+
subject.perform_request(uri, :post, "/", { body: encoded_body })
129+
end
99130

100-
expect(subject).to receive(:sign_aws_request)
101-
subject.perform_request(uri, :get, "/")
131+
it 'encodes body before signing to match manticore adapter encoding' do
132+
body = "boîte de réception"
133+
encoded_body = body.encode("ISO-8859-1")
134+
expect_any_instance_of(Aws::Sigv4::Signer).to receive(:sign_request).with(hash_including({
135+
body: body,
136+
})).and_return(
137+
double(headers: {})
138+
)
139+
expect(subject.manticore).to receive(:post).
140+
with(expected_uri.to_s, {
141+
:body => encoded_body,
142+
:headers => {"content-type"=> "application/json"}
143+
}
144+
).and_return resp
145+
subject.perform_request(uri, :post, "/", { body: encoded_body })
146+
end
102147
end
103148
end
104149

0 commit comments

Comments
 (0)