Skip to content

Add basic Credentials wrapper + ManagedNative mixin #20

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 18 commits into from
Oct 12, 2020
Merged
Show file tree
Hide file tree
Changes from 16 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
4 changes: 2 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ jobs:
strategy:
fail-fast: false
matrix:
ruby: [2.5, 2.6, 2.7, jruby, truffleruby]
ruby: [2.5, 2.6, 2.7, jruby]
runs-on: ubuntu-latest
steps:
- uses: ruby/setup-ruby@v1
Expand Down Expand Up @@ -72,7 +72,7 @@ jobs:
fail-fast: false
matrix:
os: [macos]
ruby: [2.5, 2.6, 2.7, jruby, truffleruby]
ruby: [2.5, 2.6, 2.7, jruby]
runs-on: macos-latest
steps:
- uses: ruby/setup-ruby@v1
Expand Down
3 changes: 2 additions & 1 deletion .rubocop.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,10 @@ Metrics/BlockLength:
Exclude:
- 'gems/aws-crt/Rakefile'
- '**/*.rake'
- 'gems/aws-crt/spec/**/*.rb'
- 'gems/**/spec/**/*.rb'

Metrics/MethodLength:
Max: 25
Exclude:
- 'gems/aws-crt/ext/compile.rb'

Expand Down
2 changes: 1 addition & 1 deletion format-check.sh
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ if NOT type $CLANG_FORMAT 2> /dev/null ; then
fi

FAIL=0
SOURCE_FILES=`find aws-crt/native/src -type f \( -name '*.h' -o -name '*.c' \)`
SOURCE_FILES=`find gems/aws-crt/native/src -type f \( -name '*.h' -o -name '*.c' \)`
for i in $SOURCE_FILES
do
$CLANG_FORMAT -output-replacements-xml $i | grep -c "<replacement " > /dev/null
Expand Down
2 changes: 2 additions & 0 deletions gems/aws-crt-auth/lib/aws-crt-auth.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
# frozen_string_literal: true

require 'aws-crt'
require_relative 'aws-crt-auth/credentials'
require_relative 'aws-crt-auth/signer'

module Aws
module Crt
Expand Down
71 changes: 71 additions & 0 deletions gems/aws-crt-auth/lib/aws-crt-auth/credentials.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
# frozen_string_literal: true

module Aws
module Crt
module Auth
# Utility class for Credentials.
class Credentials
include Aws::Crt::ManagedNative
native_destroy Aws::Crt::Native.method(:credentials_release)

UINT64_MAX = 18_446_744_073_709_551_615

# @param [String] access_key_id
# @param [String] secret_access_key
# @param [String] session_token (nil)
# @param [Time|int] expiration (nil) - Either a Time or an int
# seconds since unix epoch
def initialize(access_key_id, secret_access_key,
session_token = nil, expiration = nil)
if !access_key_id || access_key_id.empty?
raise ArgumentError, 'access_key_id must be set'
end

if !secret_access_key || secret_access_key.empty?
raise ArgumentError, 'secret_access_key must be set'
end

manage_native do
Aws::Crt::Native.credentials_new(
access_key_id,
secret_access_key,
session_token,
expiration&.to_i || UINT64_MAX
)
end
end

# @return [String]
def access_key_id
Aws::Crt::Native.credentials_get_access_key_id(native).to_s
end

# @return [String]
def secret_access_key
Aws::Crt::Native.credentials_get_secret_access_key(native).to_s
end

# @return [String, nil]
def session_token
Aws::Crt::Native.credentials_get_session_token(native).to_s
end

# @return [Time,nil]
def expiration
exp = Aws::Crt::Native.credentials_get_expiration_timepoint_seconds!(
native
)
return if exp == UINT64_MAX

Time.at(exp)
end

# Removing the secret access key from the default inspect string.
# @api private
def inspect
"#<#{self.class.name} access_key_id=#{access_key_id.inspect}>"
end
end
end
end
end
37 changes: 37 additions & 0 deletions gems/aws-crt-auth/lib/aws-crt-auth/signer.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# frozen_string_literal: true

module Aws
module Crt
module Auth
# Utility class for creating AWS signature version 4 signature.
class Signer
def initialize(options = {})
@service = extract_service(options)
@region = extract_region(options)
@credentials_provider = extract_credentials_provider(options)
@unsigned_headers = Set.new((options.fetch(:unsigned_headers, []))
.map(&:downcase))
@unsigned_headers << 'authorization'
@unsigned_headers << 'x-amzn-trace-id'
@unsigned_headers << 'expect'
%i[uri_escape_path apply_checksum_header].each do |opt|
instance_variable_set("@#{opt}",
options.key?(opt) ? options[:opt] : true)
end
end

def sign_request(request)
# TODO
end

def sign_event(prior_signature, payload, encoder)
# TODO
end

def presign_url(options)
# TODO
end
end
end
end
end
98 changes: 98 additions & 0 deletions gems/aws-crt-auth/spec/credentials_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
# frozen_string_literal: true

require_relative 'spec_helper'
require 'weakref'

module Aws
module Crt
module Auth #:nodoc:
describe Credentials do
describe '#initilize' do
it 'raises an ArgumentError when missing access_key_id' do
expect { Credentials.new(nil, 'secret') }
.to raise_error(ArgumentError)
end

it 'raises an ArgumentError when missing secret_access_key' do
expect { Credentials.new('akid', nil) }
.to raise_error(ArgumentError)
end

it 'defaults the session token to nil' do
expect(Credentials.new('akid', 'secret').session_token).to be nil
end

it 'defaults the expiration to nil' do
expect(Credentials.new('akid', 'secret').expiration)
.to be_nil
end

it 'accepts a Time for expiration' do
exp = Time.now
creds = Credentials.new('akid', 'secret', 'token', exp)
expect(creds.expiration.to_i).to eq exp.to_i
end

it 'accepts an epoch (integer) for expiration' do
exp = Time.now
creds = Credentials.new('akid', 'secret', 'token', exp.to_i)
expect(creds.expiration.to_i).to eq exp.to_i
end
end

describe 'accessors' do
let(:exp) { Time.now }
let(:creds) { Credentials.new('akid', 'secret', 'token', exp) }

it 'provides access to the access key id' do
expect(creds.access_key_id).to eq('akid')
end

it 'provides access to the secret access key' do
expect(creds.secret_access_key).to eq('secret')
end

it 'provides access to the session token' do
expect(creds.session_token).to eq('token')
end

it 'provides access to the expiration' do
expect(creds.expiration.to_i).to eq exp.to_i
end
end

describe '#inspect' do
let(:creds) { Credentials.new('akid', 'secret', 'token') }

it 'does not include the secret_access_key' do
expect(creds.inspect).not_to include 'secret'
end
end

describe '.on_release' do
it 'cleans up with release' do
creds = Credentials.new('akid', 'secret')
expect(creds).to_not be_nil

creds.release
check_for_clean_shutdown
end

if garbage_collect_is_immediate?
it 'cleans up with GC' do
creds = Credentials.new('akid', 'secret', 'session')
weakref = WeakRef.new(creds)
expect(weakref.weakref_alive?).to be true

# force cleanup via GC
creds = nil # rubocop:disable Lint/UselessAssignment
ObjectSpace.garbage_collect
expect(weakref.weakref_alive?).to be_falsey
check_for_clean_shutdown
end
end
end
end
end
end
end
9 changes: 9 additions & 0 deletions gems/aws-crt-auth/spec/signer_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# frozen_string_literal: true

require_relative 'spec_helper'

require 'tempfile'
require 'base64'

describe Aws::Crt::Auth::Signer do
end
1 change: 1 addition & 0 deletions gems/aws-crt-auth/spec/spec_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@
# use the local version of aws-crt
$LOAD_PATH.unshift File.expand_path('../../aws-crt/lib', __dir__)

require_relative '../../aws-crt/spec/spec_helper'
require 'aws-crt-auth'
15 changes: 1 addition & 14 deletions gems/aws-crt/lib/aws-crt.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
require_relative 'aws-crt/platforms'
require_relative 'aws-crt/native'
require_relative 'aws-crt/errors'
require_relative 'aws-crt/managed_native'
require_relative 'aws-crt/io'

# Top level Amazon Web Services (AWS) namespace
Expand All @@ -11,19 +12,5 @@ module Aws
module Crt
# Ensure native init() is called when gem loads
Aws::Crt::Native.init

# Invoke native call, and raise exception if it failed
def self.call
res = yield
# functions that return void cannot fail
return unless res

# for functions that return int, non-zero indicates failure
Errors.raise_last_error if res.is_a?(Integer) && res != 0

# for functions that return pointer, NULL indicates failure
Errors.raise_last_error if res.is_a?(FFI::Pointer) && res.null?
res
end
end
end
22 changes: 4 additions & 18 deletions gems/aws-crt/lib/aws-crt/io.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ module IO
# Classes that need to do async work will ask the EventLoopGroup
# for an event-loop to use.
class EventLoopGroup
include Aws::Crt::ManagedNative
native_destroy Aws::Crt::Native.method(:event_loop_group_release)

def initialize(max_threads = nil)
unless max_threads.nil? ||
(max_threads.is_a?(Integer) && max_threads.positive?)
Expand All @@ -18,26 +21,9 @@ def initialize(max_threads = nil)
# Ruby uses nil to request default values, native code uses 0
max_threads = 0 if max_threads.nil?

native = Aws::Crt.call do
manage_native do
Aws::Crt::Native.event_loop_group_new(max_threads)
end

@native = FFI::AutoPointer.new(native, self.class.method(:on_release))
end

# Immediately release this instance's attachment to the underlying
# resources, without waiting for the garbage collector.
# Note that underlying resources will remain alive until nothing
# else is using them.
def release
return unless @native

@native.free
@native = nil
end

def self.on_release(native)
Aws::Crt::Native.event_loop_group_release(native)
end
end
end
Expand Down
Loading