Skip to content

Commit 59fa53e

Browse files
committed
[GEM] Extracts api_key from elasticsearch-transport into elasticsearch
1 parent 6405034 commit 59fa53e

File tree

8 files changed

+126
-87
lines changed

8 files changed

+126
-87
lines changed

benchmarks/actions/002_info.rb

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414
# KIND, either express or implied. See the License for the
1515
# specific language governing permissions and limitations
1616
# under the License.
17-
1817
require_relative '../lib/benchmarks'
1918

2019
Benchmarks.register \

elasticsearch-transport/lib/elasticsearch/transport/client.rb

Lines changed: 2 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -113,8 +113,6 @@ class Client
113113
# The default is false. Responses will automatically be inflated if they are compressed.
114114
# If a custom transport object is used, it must handle the request compression and response inflation.
115115
#
116-
# @option api_key [String, Hash] :api_key Use API Key Authentication, either the base64 encoding of `id` and `api_key`
117-
# joined by a colon as a String, or a hash with the `id` and `api_key` values.
118116
# @option opaque_id_prefix [String] :opaque_id_prefix set a prefix for X-Opaque-Id when initializing the client.
119117
# This will be prepended to the id you set before each request
120118
# if you're using X-Opaque-Id
@@ -124,7 +122,7 @@ class Client
124122
# @yield [faraday] Access and configure the `Faraday::Connection` instance directly with a block
125123
#
126124
def initialize(arguments = {}, &block)
127-
@options = arguments.each_with_object({}) { |(k, v), args| args[k.to_sym] = v }
125+
@options = arguments.transform_keys(&:to_sym)
128126
@arguments = @options
129127
@arguments[:logger] ||= @arguments[:log] ? DEFAULT_LOGGER.call() : nil
130128
@arguments[:tracer] ||= @arguments[:trace] ? DEFAULT_TRACER.call() : nil
@@ -134,11 +132,9 @@ def initialize(arguments = {}, &block)
134132
@arguments[:randomize_hosts] ||= false
135133
@arguments[:transport_options] ||= {}
136134
@arguments[:http] ||= {}
137-
@arguments[:enable_meta_header] = arguments.fetch(:enable_meta_header) { true }
135+
@arguments[:enable_meta_header] = arguments.fetch(:enable_meta_header, true)
138136
@options[:http] ||= {}
139137

140-
set_api_key if (@api_key = @arguments[:api_key])
141-
142138
@hosts = __extract_hosts(@arguments[:hosts] ||
143139
@arguments[:host] ||
144140
@arguments[:url] ||
@@ -184,13 +180,6 @@ def perform_request(method, path, params = {}, body = nil, headers = nil)
184180

185181
private
186182

187-
def set_api_key
188-
@api_key = __encode(@api_key) if @api_key.is_a? Hash
189-
add_header('Authorization' => "ApiKey #{@api_key}")
190-
@arguments.delete(:user)
191-
@arguments.delete(:password)
192-
end
193-
194183
def add_header(header)
195184
headers = @arguments[:transport_options]&.[](:headers) || {}
196185
headers.merge!(header)
@@ -297,13 +286,6 @@ def __auto_detect_adapter
297286
::Faraday.default_adapter
298287
end
299288
end
300-
301-
# Encode credentials for the Authorization Header
302-
# Credentials is the base64 encoding of id and api_key joined by a colon
303-
# @see https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api-create-api-key.html
304-
def __encode(api_key)
305-
Base64.strict_encode64([api_key[:id], api_key[:api_key]].join(':'))
306-
end
307289
end
308290
end
309291
end

elasticsearch-transport/spec/elasticsearch/transport/client_spec.rb

Lines changed: 0 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -70,48 +70,6 @@
7070
end
7171
end
7272

73-
context 'when an encoded api_key is provided' do
74-
let(:client) do
75-
described_class.new(api_key: 'an_api_key')
76-
end
77-
let(:authorization_header) do
78-
client.transport.connections.first.connection.headers['Authorization']
79-
end
80-
81-
it 'Adds the ApiKey header to the connection' do
82-
expect(authorization_header).to eq('ApiKey an_api_key')
83-
end
84-
end
85-
86-
context 'when an un-encoded api_key is provided' do
87-
let(:client) do
88-
described_class.new(api_key: { id: 'my_id', api_key: 'my_api_key' })
89-
end
90-
let(:authorization_header) do
91-
client.transport.connections.first.connection.headers['Authorization']
92-
end
93-
94-
it 'Adds the ApiKey header to the connection' do
95-
expect(authorization_header).to eq("ApiKey #{Base64.strict_encode64('my_id:my_api_key')}")
96-
end
97-
end
98-
99-
context 'when basic auth and api_key are provided' do
100-
let(:client) do
101-
described_class.new(
102-
api_key: { id: 'my_id', api_key: 'my_api_key' },
103-
host: 'http://elastic:password@localhost:9200'
104-
)
105-
end
106-
let(:authorization_header) do
107-
client.transport.connections.first.connection.headers['Authorization']
108-
end
109-
110-
it 'removes basic auth credentials' do
111-
expect(authorization_header).not_to match(/^Basic/)
112-
expect(authorization_header).to match(/^ApiKey/)
113-
end
114-
end
11573

11674
context 'when a user-agent header is specified as client option in lower-case' do
11775

elasticsearch-transport/spec/elasticsearch/transport/meta_header_spec.rb

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -78,22 +78,6 @@ def meta_version
7878
end
7979
end
8080

81-
context 'when using API Key' do
82-
let(:client) do
83-
described_class.new(api_key: 'an_api_key', adapter: adapter)
84-
end
85-
86-
let(:authorization_header) do
87-
client.transport.connections.first.connection.headers['Authorization']
88-
end
89-
90-
it 'adds the ApiKey header to the connection' do
91-
expect(authorization_header).to eq('ApiKey an_api_key')
92-
expect(subject['x-elastic-client-meta']).to match(regexp)
93-
expect(subject).to include('x-elastic-client-meta' => meta_header)
94-
end
95-
end
96-
9781
context 'adapters' do
9882
let(:meta_header) do
9983
if jruby?

elasticsearch/lib/elasticsearch.rb

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,10 @@ class Client
3232
# Create a client connected to an Elasticsearch cluster.
3333
#
3434
# @option arguments [String] :cloud_id - The Cloud ID to connect to Elastic Cloud
35-
#
35+
# @option api_key [String, Hash] :api_key Use API Key Authentication, either the base64 encoding of `id` and `api_key`
36+
# joined by a colon as a String, or a hash with the `id` and `api_key` values.
3637
def initialize(arguments = {}, &block)
38+
api_key(arguments) if arguments[:api_key]
3739
if arguments[:cloud_id]
3840
arguments[:hosts] = setup_cloud_host(
3941
arguments[:cloud_id],
@@ -73,11 +75,22 @@ def setup_cloud_host(cloud_id, user, password, port)
7375
[{ scheme: 'https', user: user, password: password, host: host, port: port.to_i }]
7476
end
7577

76-
def set_api_key
77-
@api_key = encode(@api_key) if @api_key.is_a? Hash
78-
add_header('Authorization' => "ApiKey #{@api_key}")
79-
@arguments.delete(:user)
80-
@arguments.delete(:password)
78+
def api_key(arguments)
79+
api_key = if arguments[:api_key].is_a? Hash
80+
encode(arguments[:api_key])
81+
else
82+
arguments[:api_key]
83+
end
84+
arguments.delete(:user)
85+
arguments.delete(:password)
86+
authorization = { 'Authorization' => "ApiKey #{api_key}" }
87+
if (headers = arguments.dig(:transport_options, :headers))
88+
headers.merge!(authorization)
89+
else
90+
arguments[:transport_options] = {
91+
headers: authorization
92+
}
93+
end
8194
end
8295

8396
# Encode credentials for the Authorization Header
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
# Licensed to Elasticsearch B.V. under one or more contributor
2+
# license agreements. See the NOTICE file distributed with
3+
# this work for additional information regarding copyright
4+
# ownership. Elasticsearch B.V. licenses this file to you under
5+
# the Apache License, Version 2.0 (the "License"); you may
6+
# not use this file except in compliance with the License.
7+
# You may obtain a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing,
12+
# software distributed under the License is distributed on an
13+
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
# KIND, either express or implied. See the License for the
15+
# specific language governing permissions and limitations
16+
# under the License.
17+
require 'spec_helper'
18+
19+
describe Elasticsearch::Client do
20+
context 'when using API Key' do
21+
let(:authorization_header) do
22+
client.transport.connections.first.connection.headers['Authorization']
23+
end
24+
25+
context 'when an encoded api_key is provided' do
26+
let(:client) do
27+
described_class.new(api_key: 'an_api_key')
28+
end
29+
30+
it 'Adds the ApiKey header to the connection' do
31+
expect(authorization_header).to eq('ApiKey an_api_key')
32+
end
33+
end
34+
35+
context 'when an un-encoded api_key is provided' do
36+
let(:client) do
37+
described_class.new(api_key: { id: 'my_id', api_key: 'my_api_key' })
38+
end
39+
40+
it 'Adds the ApiKey header to the connection' do
41+
expect(authorization_header).to eq("ApiKey #{Base64.strict_encode64('my_id:my_api_key')}")
42+
end
43+
end
44+
45+
context 'when basic auth and api_key are provided' do
46+
let(:client) do
47+
described_class.new(
48+
api_key: { id: 'my_id', api_key: 'my_api_key' },
49+
host: 'http://elastic:password@localhost:9200'
50+
)
51+
end
52+
53+
it 'removes basic auth credentials' do
54+
expect(authorization_header).not_to match(/^Basic/)
55+
expect(authorization_header).to match(/^ApiKey/)
56+
end
57+
end
58+
59+
context 'when other headers where specified' do
60+
let(:client) do
61+
described_class.new(
62+
api_key: 'elasticsearch_api_key',
63+
transport_options: { headers: { 'x-test-header' => 'test' } }
64+
)
65+
end
66+
67+
it 'Adds the ApiKey header to the connection and keeps the header' do
68+
header = client.transport.connections.first.connection.headers
69+
expect(header['Authorization']).to eq('ApiKey elasticsearch_api_key')
70+
expect(header['X-Test-Header']).to eq('test')
71+
end
72+
end
73+
74+
context 'Metaheader' do
75+
let(:adapter_code) { "nh=#{defined?(Net::HTTP::VERSION) ? Net::HTTP::VERSION : Net::HTTP::HTTPVersion}" }
76+
let(:meta_header) do
77+
if defined?(JRUBY)
78+
"es=#{meta_version},rb=#{RUBY_VERSION},t=#{Elasticsearch::Transport::VERSION},jv=#{ENV_JAVA['java.version']},jr=#{JRUBY_VERSION},fd=#{Faraday::VERSION},#{adapter_code}"
79+
else
80+
"es=#{meta_version},rb=#{RUBY_VERSION},t=#{Elasticsearch::Transport::VERSION},fd=#{Faraday::VERSION},#{adapter_code}"
81+
end
82+
end
83+
84+
def meta_version
85+
client.send(:client_meta_version, Elasticsearch::VERSION)
86+
end
87+
context 'when using API Key' do
88+
let(:client) do
89+
described_class.new(api_key: 'an_api_key')
90+
end
91+
92+
let(:headers) do
93+
client.transport.connections.first.connection.headers
94+
end
95+
96+
it 'adds the ApiKey header to the connection' do
97+
expect(authorization_header).to eq('ApiKey an_api_key')
98+
expect(headers).to include('x-elastic-client-meta' => meta_header)
99+
end
100+
end
101+
end
102+
end
103+
end

elasticsearch/spec/unit/cloud_credentials_spec.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
# KIND, either express or implied. See the License for the
1515
# specific language governing permissions and limitations
1616
# under the License.
17-
require 'elasticsearch'
17+
require 'spec_helper'
1818

1919
describe Elasticsearch::Client do
2020
context 'when cloud credentials are provided' do

elasticsearch/spec/unit/wrapper_gem_spec.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
# KIND, either express or implied. See the License for the
1515
# specific language governing permissions and limitations
1616
# under the License.
17-
require 'elasticsearch'
17+
require 'spec_helper'
1818

1919
describe 'Elasticsearch: wrapper gem' do
2020
it 'requires all neccessary subgems' do

0 commit comments

Comments
 (0)