Skip to content

Commit

Permalink
Allow configuring custom credentials provider (#16)
Browse files Browse the repository at this point in the history
  • Loading branch information
ests authored Sep 2, 2024
1 parent a4ac2b7 commit 2c80937
Show file tree
Hide file tree
Showing 6 changed files with 58 additions and 35 deletions.
8 changes: 4 additions & 4 deletions Gemfile.lock
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
PATH
remote: .
specs:
amazon_sp_clients (1.5.2)
amazon_sp_clients (1.6.0)
aws-sdk-core
aws-sigv4
faraday (~> 1.4)
Expand All @@ -15,11 +15,11 @@ GEM
addressable (2.8.0)
public_suffix (>= 2.0.2, < 5.0)
aws-eventstream (1.3.0)
aws-partitions (1.963.0)
aws-sdk-core (3.201.4)
aws-partitions (1.970.0)
aws-sdk-core (3.202.2)
aws-eventstream (~> 1, >= 1.3.0)
aws-partitions (~> 1, >= 1.651.0)
aws-sigv4 (~> 1.8)
aws-sigv4 (~> 1.9)
jmespath (~> 1, >= 1.6.1)
aws-sigv4 (1.9.1)
aws-eventstream (~> 1, >= 1.0.2)
Expand Down
4 changes: 4 additions & 0 deletions lib/amazon_sp_clients/configuration.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ class Configuration

attr_reader :endpoint

attr_accessor :credentials_provider

# App credentials
attr_accessor :client_id
attr_accessor :client_secret
Expand Down Expand Up @@ -108,6 +110,8 @@ class Configuration
def initialize
@sandbox_env = false

@credentials_provider = nil

# ap api
@refresh_token = nil
@marketplace_id = nil
Expand Down
19 changes: 10 additions & 9 deletions lib/amazon_sp_clients/middlewares/request_signer_v4.rb
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ def call(env)
Aws::Sigv4::Signer.new(
service: 'execute-api',
region: @options[:region],
credentials_provider: @options[:session].role_credentials,
credentials_provider: @options[:session].credentials_provider,
)

signature =
Expand All @@ -32,18 +32,19 @@ def call(env)
body: env.request_body,
)

# Add signature headers
signature_headers = signature.headers
env.request_headers.merge!(
{
'authorization' => signature_headers['authorization'],
'host' => signature_headers['host'],
CRYPTO_HEADER => signature_headers[CRYPTO_HEADER],
'x-amz-date' => signature_headers['x-amz-date'],
SESSION_HEADER => signature_headers[SESSION_HEADER],
},
'authorization' => signature_headers['authorization'],
'host' => signature_headers['host'],
CRYPTO_HEADER => signature_headers[CRYPTO_HEADER],
'x-amz-date' => signature_headers['x-amz-date']
)

# Only include SESSION_HEADER if it exists in signature_headers
if signature_headers.key?(SESSION_HEADER)
env.request_headers[SESSION_HEADER] = signature_headers[SESSION_HEADER]
end

@app.call env
end
end
Expand Down
27 changes: 10 additions & 17 deletions lib/amazon_sp_clients/session.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ class Session
},
}.freeze

attr_reader :access_token, :restricted_data_token, :session_client, :role_credentials
attr_reader :access_token, :restricted_data_token, :credentials_provider

def initialize(config = Configuration.default, &block)
@config = config
Expand All @@ -29,28 +29,21 @@ def initialize(config = Configuration.default, &block)
@scope = nil

@session_client = nil
@role_credentials = nil
@credentials_provider = @config.credentials_provider || role_credentials

init_credentials_provider
@callback = block
end

def init_credentials_provider
# https://docs.aws.amazon.com/sdk-for-ruby/v3/api/Aws/AssumeRoleCredentials.html
@session_client = Aws::STS::Client.new(
credentials: Aws::Credentials.new(@config.access_key, @config.secret_key),
region: @config.region,
# NOTE: usually will make immediate web request
def role_credentials
Aws::AssumeRoleCredentials.new(
client: Aws::STS::Client.new( credentials: Aws::Credentials.new(@config.access_key, @config.secret_key), region: @config.region),
role_arn: @config.role_arn,
role_session_name: 'SPAPISession',
)

@role_credentials =
Aws::AssumeRoleCredentials.new(
client: @session_client,
role_arn: @config.role_arn,
role_session_name: 'SPAPISession',
)

rescue => e
raise Faraday::ForbiddenError.new(e.message, { service: 'sts', request: {}, response: {} })
rescue => e
raise Faraday::ForbiddenError.new(e.message, { service: 'sts', request: {}, response: {} })
end

def with_callback(&block)
Expand Down
2 changes: 1 addition & 1 deletion lib/amazon_sp_clients/version.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
module AmazonSpClients
VERSION = '1.5.2'.freeze
VERSION = '1.6.0'.freeze
end
33 changes: 29 additions & 4 deletions spec/amazon_sp_clients_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ def access_token
'oaisdhgoajsdfoahgasd'
end

def role_credentials
def credentials_provider
Aws::Credentials.new('access_key_id', 'secret_access_key', 'session_token')
end

Expand Down Expand Up @@ -226,7 +226,7 @@ def restricted_data_token
end
end

describe 'aws credentials' do
describe 'aws sdk global credentials' do
before do
Aws.config.update(credentials: Aws::Credentials.new('bogus', 'bogus'), region: 'bogus')
end
Expand All @@ -245,14 +245,39 @@ def restricted_data_token
refresh_token = ENV['AMZ_REFRESH_TOKEN'] || 'REFRESH_TOKEN'
session = AmazonSpClients.new_session(refresh_token)

expect(session.role_credentials.client.config.credentials.access_key_id)
expect(session.credentials_provider.client.config.credentials.access_key_id)
.to eq(AmazonSpClients.configure.access_key)

expect(session.role_credentials.client.config.credentials.secret_access_key)
expect(session.credentials_provider.client.config.credentials.secret_access_key)
.to eq(AmazonSpClients.configure.secret_key)
end
end

describe 'custom credentials provider config' do
let(:callback) { -> { 'initial_access_token' } }
let(:session) { AmazonSpClients.new_callback_session(&callback) }
let(:api_client) { AmazonSpClients::ApiClient.new(session) }

before do
AmazonSpClients.configure do |c|
c.access_key = nil
c.secret_key = nil
c.role_arn = nil
c.client_id = nil
c.client_secret = nil
c.sandbox_env!
c.credentials_provider = Aws::Credentials.new('foo', 'bar')
end
end

it 'uses credentials_provider from config' do
stub_request(:get, "https://sandbox.sellingpartnerapi-na.amazon.com/test/endpoint1").to_return(status: 200, body: '{}')
expect(callback).to receive(:call).and_return('initial_access_token')
api_client.call_api(:get, '/test/endpoint1')
expect(session.credentials_provider).to be_a(Aws::Credentials)
end
end

describe 'new_callback_session' do
let(:api_client) { AmazonSpClients::ApiClient.new(session) }
let(:session) { AmazonSpClients.new_callback_session(&callback) }
Expand Down

0 comments on commit 2c80937

Please sign in to comment.