Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .generator/src/generator/templates/api_client.j2
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ module {{ module_name }}
#Redact api and app key in the request header
def sanitize_request_header(request_header)
sanitized_headers= request_header.dup
keys_to_redact = ["DD-API-KEY", "DD-APPLICATION-KEY"]
keys_to_redact = ["DD-API-KEY", "DD-APPLICATION-KEY", "Authorization"]
keys_to_redact.each do |key_to_redact|
if sanitized_headers.key?(key_to_redact)
sanitized_headers[key_to_redact] = "REDACTED"
Expand Down Expand Up @@ -369,6 +369,7 @@ module {{ module_name }}
Array(auth_names).each do |auth_name|
auth_setting = @config.auth_settings[auth_name]
next unless auth_setting
next if auth_setting[:value].nil? || auth_setting[:value].to_s.empty?
case auth_setting[:in]
when 'header' then header_params[auth_setting[:key]] = auth_setting[:value]
when 'query' then query_params[auth_setting[:key]] = auth_setting[:value]
Expand Down
13 changes: 6 additions & 7 deletions .generator/src/generator/templates/configuration.j2
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,9 @@ module {{ module_name }}
{%- for name, schema in openapi.components.securitySchemes.items() if "x-env-name" in schema and schema.in == "header" and schema.type == "apiKey" %}
@api_key['{{ name }}'] = ENV['{{ schema["x-env-name"] }}'] if ENV.key? '{{ schema["x-env-name"] }}'
{%- endfor %}
{%- for name, schema in openapi.components.securitySchemes.items() if "x-env-name" in schema and schema.type == "http" and schema.scheme == "bearer" %}
@access_token = ENV['{{ schema["x-env-name"] }}'] if ENV.key? '{{ schema["x-env-name"] }}'
{%- endfor %}

yield(self) if block_given?
end
Expand Down Expand Up @@ -284,18 +287,14 @@ module {{ module_name }}
key: 'Authorization',
value: basic_auth_token
},
{# {%- elif schema.type == "http" and schema.scheme == "bearer" %}
{%- elif schema.type == "http" and schema.scheme == "bearer" %}
{{name}}:
{
type: 'bearer',
type: 'http',
in: 'header',
{% if schema.bearerFormat %}
format: '{{ schema.bearerFormat }}',
{% endif %}
key: 'Authorization',
value: "Bearer #{access_token}"
value: access_token ? "Bearer #{access_token}" : nil
},
#}
{%- elif schema.type == "oauth2" %}
{{name}}:
{
Expand Down
3 changes: 2 additions & 1 deletion lib/datadog_api_client/api_client.rb
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ def calculate_retry_interval(response, backoff_base, backoff_multiplier, attempt
#Redact api and app key in the request header
def sanitize_request_header(request_header)
sanitized_headers= request_header.dup
keys_to_redact = ["DD-API-KEY", "DD-APPLICATION-KEY"]
keys_to_redact = ["DD-API-KEY", "DD-APPLICATION-KEY", "Authorization"]
keys_to_redact.each do |key_to_redact|
if sanitized_headers.key?(key_to_redact)
sanitized_headers[key_to_redact] = "REDACTED"
Expand Down Expand Up @@ -380,6 +380,7 @@ def update_params_for_auth!(header_params, query_params, auth_names)
Array(auth_names).each do |auth_name|
auth_setting = @config.auth_settings[auth_name]
next unless auth_setting
next if auth_setting[:value].nil? || auth_setting[:value].to_s.empty?
case auth_setting[:in]
when 'header' then header_params[auth_setting[:key]] = auth_setting[:value]
when 'query' then query_params[auth_setting[:key]] = auth_setting[:value]
Expand Down
8 changes: 8 additions & 0 deletions lib/datadog_api_client/configuration.rb
Original file line number Diff line number Diff line change
Expand Up @@ -408,6 +408,7 @@ def initialize
@server_variables[:site] = ENV['DD_SITE'] if ENV.key? 'DD_SITE'
@api_key['apiKeyAuth'] = ENV['DD_API_KEY'] if ENV.key? 'DD_API_KEY'
@api_key['appKeyAuth'] = ENV['DD_APP_KEY'] if ENV.key? 'DD_APP_KEY'
@access_token = ENV['DD_BEARER_TOKEN'] if ENV.key? 'DD_BEARER_TOKEN'

yield(self) if block_given?
end
Expand Down Expand Up @@ -503,6 +504,13 @@ def auth_settings
key: 'DD-APPLICATION-KEY',
value: api_key_with_prefix('appKeyAuth')
},
bearerAuth:
{
type: 'http',
in: 'header',
key: 'Authorization',
value: access_token ? "Bearer #{access_token}" : nil
},
}
end

Expand Down
71 changes: 71 additions & 0 deletions spec/api_client_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -206,4 +206,75 @@
expect(api_client.sanitize_filename('.\sun.gif')).to eq('sun.gif')
end
end

describe '#update_params_for_auth!' do
let(:config) { DatadogAPIClient::Configuration.new }
let(:api_client) { DatadogAPIClient::APIClient.new(config) }

context 'when all auth credentials are configured' do
before do
config.api_key = 'test_api_key'
config.application_key = 'test_app_key'
config.access_token = 'ddpat_test_pat'
end

it 'sends all configured auth headers simultaneously' do
header_params = {}
query_params = {}
api_client.update_params_for_auth!(header_params, query_params, [:apiKeyAuth, :appKeyAuth, :bearerAuth])
expect(header_params['Authorization']).to eq('Bearer ddpat_test_pat')
expect(header_params['DD-API-KEY']).to eq('test_api_key')
expect(header_params['DD-APPLICATION-KEY']).to eq('test_app_key')
end
end

context 'when only bearer token is configured' do
before do
config.access_token = 'ddpat_test_pat'
end

it 'sends only Bearer header, skips empty API key and app key' do
header_params = {}
query_params = {}
api_client.update_params_for_auth!(header_params, query_params, [:apiKeyAuth, :appKeyAuth, :bearerAuth])
expect(header_params['Authorization']).to eq('Bearer ddpat_test_pat')
expect(header_params).not_to have_key('DD-API-KEY')
expect(header_params).not_to have_key('DD-APPLICATION-KEY')
end
end

context 'when only API key and app key are configured' do
before do
config.api_key = 'test_api_key'
config.application_key = 'test_app_key'
end

it 'sends API key and app key, no Bearer header' do
header_params = {}
query_params = {}
api_client.update_params_for_auth!(header_params, query_params, [:apiKeyAuth, :appKeyAuth, :bearerAuth])
expect(header_params['DD-API-KEY']).to eq('test_api_key')
expect(header_params['DD-APPLICATION-KEY']).to eq('test_app_key')
expect(header_params).not_to have_key('Authorization')
end
end
end

describe '#sanitize_request_header' do
let(:api_client) { DatadogAPIClient::APIClient.new }

it 'redacts sensitive headers including Authorization' do
headers = {
'DD-API-KEY' => 'secret_api_key',
'DD-APPLICATION-KEY' => 'secret_app_key',
'Authorization' => 'Bearer ddapp_secret_pat',
'Content-Type' => 'application/json'
}
sanitized = api_client.sanitize_request_header(headers)
expect(sanitized['DD-API-KEY']).to eq('REDACTED')
expect(sanitized['DD-APPLICATION-KEY']).to eq('REDACTED')
expect(sanitized['Authorization']).to eq('REDACTED')
expect(sanitized['Content-Type']).to eq('application/json')
end
end
end
40 changes: 40 additions & 0 deletions spec/configuration_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -58,5 +58,45 @@
end
end

describe '#access_token (bearer auth)' do
let(:config) { DatadogAPIClient::Configuration.new }

it 'defaults to nil' do
expect(config.access_token).to be_nil
end

it 'can be set directly' do
config.access_token = 'ddpat_test_token_123'
expect(config.access_token).to eq('ddpat_test_token_123')
end

it 'loads from DD_BEARER_TOKEN environment variable' do
allow(ENV).to receive(:key?).and_call_original
allow(ENV).to receive(:key?).with('DD_BEARER_TOKEN').and_return(true)
allow(ENV).to receive(:[]).and_call_original
allow(ENV).to receive(:[]).with('DD_BEARER_TOKEN').and_return('ddpat_env_token')
new_config = DatadogAPIClient::Configuration.new
expect(new_config.access_token).to eq('ddpat_env_token')
end
end

describe '#auth_settings' do
let(:config) { DatadogAPIClient::Configuration.new }

it 'includes bearerAuth with nil value when token not set' do
expect(config.auth_settings[:bearerAuth]).not_to be_nil
expect(config.auth_settings[:bearerAuth][:value]).to be_nil
end

it 'includes bearerAuth with Bearer token when access_token is set' do
config.access_token = 'ddpat_my_token'
auth = config.auth_settings[:bearerAuth]
expect(auth[:type]).to eq('http')
expect(auth[:in]).to eq('header')
expect(auth[:key]).to eq('Authorization')
expect(auth[:value]).to eq('Bearer ddpat_my_token')
end
end


end
Loading