conjur-api 6.3.1.pre.848 → 6.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +9 -25
- data/Jenkinsfile +6 -123
- data/Rakefile +1 -28
- data/VERSION +1 -1
- data/conjur-api.gemspec +0 -4
- data/docker-compose.yml +0 -15
- data/lib/conjur/api/router.rb +2 -33
- data/lib/conjur/api.rb +0 -3
- data/test.sh +0 -78
- metadata +1 -36
- data/ci/get_gcp_token.sh +0 -43
- data/features/README.md +0 -80
- data/features/authn_azure.feature +0 -15
- data/features/authn_gcp.feature +0 -19
- data/features/authn_iam.feature +0 -18
- data/features/step_definitions/cloud_authn_steps.rb +0 -182
- data/lib/conjur/api/authn_azure.rb +0 -145
- data/lib/conjur/api/authn_gcp.rb +0 -137
- data/lib/conjur/api/authn_iam.rb +0 -140
- data/secrets.yml +0 -13
- data/spec/authn_azure_spec.rb +0 -91
- data/spec/authn_gcp_spec.rb +0 -121
- data/spec/authn_iam_spec.rb +0 -103
data/lib/conjur/api/authn_iam.rb
DELETED
|
@@ -1,140 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require 'json'
|
|
4
|
-
require 'uri'
|
|
5
|
-
|
|
6
|
-
module Conjur
|
|
7
|
-
class API
|
|
8
|
-
# Authenticator that uses AWS IAM credentials to obtain Conjur access tokens.
|
|
9
|
-
# Signs an AWS STS GetCallerIdentity request with SigV4, then POSTs the
|
|
10
|
-
# resulting headers as JSON to the Conjur authn-iam endpoint.
|
|
11
|
-
#
|
|
12
|
-
# Requires the +aws-sdk-core+ gem (not bundled with conjur-api).
|
|
13
|
-
# Add `gem 'aws-sdk-core'` to your Gemfile to use this authenticator.
|
|
14
|
-
class IAMAuthenticator
|
|
15
|
-
include TokenExpiration
|
|
16
|
-
|
|
17
|
-
DEFAULT_SERVICE_ID = 'prod'.freeze
|
|
18
|
-
DEFAULT_REGION = 'us-east-1'.freeze
|
|
19
|
-
|
|
20
|
-
STS_GLOBAL_URL = 'https://sts.amazonaws.com/?Action=GetCallerIdentity&Version=2011-06-15'.freeze
|
|
21
|
-
STS_REGIONAL_URL = 'https://sts.%<region>s.amazonaws.com/?Action=GetCallerIdentity&Version=2011-06-15'.freeze
|
|
22
|
-
STS_GLOBAL_SIGNING_REGION = 'us-east-1'.freeze
|
|
23
|
-
|
|
24
|
-
attr_reader :account, :service_id, :identity, :aws_region
|
|
25
|
-
|
|
26
|
-
def initialize(account, service_id, identity, aws_region = DEFAULT_REGION)
|
|
27
|
-
@account = account
|
|
28
|
-
@service_id = service_id
|
|
29
|
-
@identity = identity
|
|
30
|
-
@aws_region = aws_region
|
|
31
|
-
update_token_born
|
|
32
|
-
end
|
|
33
|
-
|
|
34
|
-
def refresh_token
|
|
35
|
-
Conjur::API.authenticate_iam(identity, account: account,
|
|
36
|
-
service_id: service_id,
|
|
37
|
-
aws_region: aws_region).tap do
|
|
38
|
-
update_token_born
|
|
39
|
-
end
|
|
40
|
-
end
|
|
41
|
-
end
|
|
42
|
-
|
|
43
|
-
class << self
|
|
44
|
-
# Create a {Conjur::API} instance authenticated via AWS IAM (authn-iam).
|
|
45
|
-
#
|
|
46
|
-
# AWS credentials are resolved from the default chain: environment variables
|
|
47
|
-
# (AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_SESSION_TOKEN), then
|
|
48
|
-
# ~/.aws/credentials, then the EC2 instance profile.
|
|
49
|
-
#
|
|
50
|
-
# Requires the +aws-sdk-core+ gem.
|
|
51
|
-
#
|
|
52
|
-
# @param [String] identity Conjur host identity (e.g. "host/my-app/my-role")
|
|
53
|
-
# @param [String] service_id the authn-iam service ID (default: "prod")
|
|
54
|
-
# @param [String] account the Conjur organization account
|
|
55
|
-
# @param [String] aws_region AWS region for STS signing. Use "global" for the
|
|
56
|
-
# global STS endpoint (signed as us-east-1).
|
|
57
|
-
# @param [String, nil] remote_ip optional IP address recorded in the audit log
|
|
58
|
-
# @return [Conjur::API]
|
|
59
|
-
def new_from_iam(identity,
|
|
60
|
-
account: Conjur.configuration.account,
|
|
61
|
-
service_id: IAMAuthenticator::DEFAULT_SERVICE_ID,
|
|
62
|
-
aws_region: IAMAuthenticator::DEFAULT_REGION,
|
|
63
|
-
remote_ip: nil)
|
|
64
|
-
self.new.init_from_iam(identity, account: account, service_id: service_id,
|
|
65
|
-
aws_region: aws_region, remote_ip: remote_ip)
|
|
66
|
-
end
|
|
67
|
-
|
|
68
|
-
# Authenticate via authn-iam and return a parsed Conjur access token.
|
|
69
|
-
#
|
|
70
|
-
# @param [String] identity Conjur host identity
|
|
71
|
-
# @param [String] service_id the authn-iam service ID
|
|
72
|
-
# @param [String] account the Conjur organization account
|
|
73
|
-
# @param [String] aws_region AWS region for STS signing
|
|
74
|
-
# @return [Hash] parsed access token
|
|
75
|
-
def authenticate_iam(identity,
|
|
76
|
-
account: Conjur.configuration.account,
|
|
77
|
-
service_id: IAMAuthenticator::DEFAULT_SERVICE_ID,
|
|
78
|
-
aws_region: IAMAuthenticator::DEFAULT_REGION)
|
|
79
|
-
raise ArgumentError, "identity is required" if identity.nil? || identity.empty?
|
|
80
|
-
raise ArgumentError, "service_id is required" if service_id.nil? || service_id.empty?
|
|
81
|
-
|
|
82
|
-
begin
|
|
83
|
-
require 'aws-sdk-core'
|
|
84
|
-
rescue LoadError
|
|
85
|
-
raise LoadError,
|
|
86
|
-
"aws-sdk-core is required for IAM authentication. " \
|
|
87
|
-
"Add `gem 'aws-sdk-core'` to your Gemfile."
|
|
88
|
-
end
|
|
89
|
-
|
|
90
|
-
if Conjur.log
|
|
91
|
-
Conjur.log << "Authenticating #{identity} to account #{account} via authn-iam/#{service_id}\n"
|
|
92
|
-
end
|
|
93
|
-
|
|
94
|
-
signed_headers = build_iam_signed_headers(aws_region)
|
|
95
|
-
JSON.parse(url_for(:authn_iam_authenticate, account, service_id, identity)
|
|
96
|
-
.post(signed_headers.to_json, content_type: 'application/json'))
|
|
97
|
-
end
|
|
98
|
-
|
|
99
|
-
private
|
|
100
|
-
|
|
101
|
-
def build_iam_signed_headers(aws_region)
|
|
102
|
-
signing_region = aws_region == 'global' ? IAMAuthenticator::STS_GLOBAL_SIGNING_REGION : aws_region
|
|
103
|
-
sts_url = aws_region == 'global' || aws_region == IAMAuthenticator::STS_GLOBAL_SIGNING_REGION \
|
|
104
|
-
? IAMAuthenticator::STS_GLOBAL_URL
|
|
105
|
-
: format(IAMAuthenticator::STS_REGIONAL_URL, region: aws_region)
|
|
106
|
-
|
|
107
|
-
provider = Aws::CredentialProviderChain.new.resolve
|
|
108
|
-
raise ArgumentError,
|
|
109
|
-
"No AWS credentials found. Configure an instance profile, " \
|
|
110
|
-
"environment variables (AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY), " \
|
|
111
|
-
"or ~/.aws/credentials." unless provider
|
|
112
|
-
|
|
113
|
-
creds = provider.credentials
|
|
114
|
-
signer = Aws::Sigv4::Signer.new(
|
|
115
|
-
service: 'sts',
|
|
116
|
-
region: signing_region,
|
|
117
|
-
access_key_id: creds.access_key_id,
|
|
118
|
-
secret_access_key: creds.secret_access_key,
|
|
119
|
-
session_token: creds.session_token
|
|
120
|
-
)
|
|
121
|
-
|
|
122
|
-
signed = signer.sign_request(http_method: 'GET', url: sts_url, headers: {}, body: '')
|
|
123
|
-
headers = signed.headers.dup
|
|
124
|
-
# Conjur expects these specific keys
|
|
125
|
-
headers['host'] = URI.parse(sts_url).host
|
|
126
|
-
headers.compact
|
|
127
|
-
end
|
|
128
|
-
end
|
|
129
|
-
|
|
130
|
-
def init_from_iam(identity,
|
|
131
|
-
account: Conjur.configuration.account,
|
|
132
|
-
service_id: IAMAuthenticator::DEFAULT_SERVICE_ID,
|
|
133
|
-
aws_region: IAMAuthenticator::DEFAULT_REGION,
|
|
134
|
-
remote_ip: nil)
|
|
135
|
-
@remote_ip = remote_ip
|
|
136
|
-
@authenticator = IAMAuthenticator.new(account, service_id, identity, aws_region)
|
|
137
|
-
self
|
|
138
|
-
end
|
|
139
|
-
end
|
|
140
|
-
end
|
data/secrets.yml
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
# Summon secrets for CI. `summon -e <env> ./test.sh` resolves the !var
|
|
2
|
-
# references below from the CI Conjur vault and exports them into the
|
|
3
|
-
# environment for the wrapped command.
|
|
4
|
-
#
|
|
5
|
-
# The azure environment supplies the values the authn-azure integration
|
|
6
|
-
# feature needs (see features/authn_azure.feature and features/README.md).
|
|
7
|
-
# Mirrors the layout used by conjur-api-java / conjur-api-dotnet.
|
|
8
|
-
azure:
|
|
9
|
-
RUN_AZURE_TESTS: "true"
|
|
10
|
-
AZURE_SUBSCRIPTION_ID: !var ci/azure/subscription-id
|
|
11
|
-
AZURE_RESOURCE_GROUP: !var ci/azure/authn-test/resource-group
|
|
12
|
-
USER_ASSIGNED_IDENTITY: !var ci/azure/authn-test/user-assigned-id
|
|
13
|
-
USER_ASSIGNED_IDENTITY_CLIENT_ID: !var ci/azure/authn-test/user-assigned-id-client-id
|
data/spec/authn_azure_spec.rb
DELETED
|
@@ -1,91 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require 'spec_helper'
|
|
4
|
-
require 'cgi'
|
|
5
|
-
require 'conjur/api/router'
|
|
6
|
-
|
|
7
|
-
describe Conjur::API, api: :dummy do
|
|
8
|
-
let(:service_id) { 'my-azure-service' }
|
|
9
|
-
let(:identity) { 'host/my-app/azure-host' }
|
|
10
|
-
let(:azure_jwt) { 'eyJhbGciOiJSUzI1NiJ9.azure-payload.sig' }
|
|
11
|
-
let(:raw_token) { { 'protected' => 'p', 'payload' => 'pl', 'signature' => 's' } }
|
|
12
|
-
|
|
13
|
-
describe '.new_from_azure' do
|
|
14
|
-
it 'returns an API instance with an AzureAuthenticator' do
|
|
15
|
-
allow(Conjur::API).to receive(:authenticate_azure).and_return(raw_token)
|
|
16
|
-
api_instance = Conjur::API.new_from_azure(service_id, identity, account: account)
|
|
17
|
-
expect(api_instance).to be_a(Conjur::API)
|
|
18
|
-
expect(api_instance.authenticator).to be_a(Conjur::API::AzureAuthenticator)
|
|
19
|
-
end
|
|
20
|
-
end
|
|
21
|
-
|
|
22
|
-
describe '.authenticate_azure' do
|
|
23
|
-
let(:resource) { double('resource') }
|
|
24
|
-
|
|
25
|
-
before do
|
|
26
|
-
allow(Conjur::API).to receive(:url_for)
|
|
27
|
-
.with(:authn_azure_authenticate, account, service_id, identity)
|
|
28
|
-
.and_return(resource)
|
|
29
|
-
allow(resource).to receive(:post)
|
|
30
|
-
.with("jwt=#{CGI.escape(azure_jwt)}", content_type: 'application/x-www-form-urlencoded')
|
|
31
|
-
.and_return(raw_token.to_json)
|
|
32
|
-
allow(Conjur::API).to receive(:fetch_azure_jwt).and_return(azure_jwt)
|
|
33
|
-
end
|
|
34
|
-
|
|
35
|
-
it 'returns a parsed token' do
|
|
36
|
-
token = Conjur::API.authenticate_azure(service_id, identity, account: account)
|
|
37
|
-
expect(token).to eq(raw_token)
|
|
38
|
-
end
|
|
39
|
-
|
|
40
|
-
it 'raises ArgumentError when service_id is empty' do
|
|
41
|
-
expect { Conjur::API.authenticate_azure('', identity, account: account) }
|
|
42
|
-
.to raise_error(ArgumentError, /service_id is required/)
|
|
43
|
-
end
|
|
44
|
-
|
|
45
|
-
it 'raises ArgumentError when identity is empty' do
|
|
46
|
-
expect { Conjur::API.authenticate_azure(service_id, '', account: account) }
|
|
47
|
-
.to raise_error(ArgumentError, /identity is required/)
|
|
48
|
-
end
|
|
49
|
-
end
|
|
50
|
-
|
|
51
|
-
describe 'AzureAuthenticator#refresh_token' do
|
|
52
|
-
subject(:authenticator) do
|
|
53
|
-
Conjur::API::AzureAuthenticator.new(account, service_id, identity)
|
|
54
|
-
end
|
|
55
|
-
|
|
56
|
-
it 'delegates to authenticate_azure with stored credentials' do
|
|
57
|
-
expect(Conjur::API).to receive(:authenticate_azure)
|
|
58
|
-
.with(service_id, identity,
|
|
59
|
-
account: account,
|
|
60
|
-
resource_uri: Conjur::API::AzureAuthenticator::DEFAULT_RESOURCE,
|
|
61
|
-
client_id: nil,
|
|
62
|
-
imds_base_url: Conjur::API::AzureAuthenticator::DEFAULT_IMDS_BASE,
|
|
63
|
-
imds_api_version: Conjur::API::AzureAuthenticator::DEFAULT_IMDS_VER)
|
|
64
|
-
.and_return(raw_token)
|
|
65
|
-
expect(authenticator.refresh_token).to eq(raw_token)
|
|
66
|
-
end
|
|
67
|
-
end
|
|
68
|
-
end
|
|
69
|
-
|
|
70
|
-
describe Conjur::API::Router do
|
|
71
|
-
let(:account) { 'myaccount' }
|
|
72
|
-
let(:service_id) { 'my-service' }
|
|
73
|
-
let(:identity) { 'host/my-app/azure-host' }
|
|
74
|
-
|
|
75
|
-
before do
|
|
76
|
-
allow(Conjur.configuration).to receive(:core_url).and_return('https://conjur.example.com')
|
|
77
|
-
allow(Conjur.configuration).to receive(:rest_client_options).and_return({})
|
|
78
|
-
end
|
|
79
|
-
|
|
80
|
-
describe '#authn_azure_authenticate' do
|
|
81
|
-
subject { described_class.authn_azure_authenticate(account, service_id, identity) }
|
|
82
|
-
|
|
83
|
-
it 'returns a RestClient::Resource' do
|
|
84
|
-
expect(subject).to be_a(RestClient::Resource)
|
|
85
|
-
end
|
|
86
|
-
|
|
87
|
-
it 'builds the correct URL' do
|
|
88
|
-
expect(subject.url).to end_with('/authn-azure/my-service/myaccount/host%2Fmy-app%2Fazure-host/authenticate')
|
|
89
|
-
end
|
|
90
|
-
end
|
|
91
|
-
end
|
data/spec/authn_gcp_spec.rb
DELETED
|
@@ -1,121 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require 'spec_helper'
|
|
4
|
-
require 'cgi'
|
|
5
|
-
require 'conjur/api/router'
|
|
6
|
-
|
|
7
|
-
describe Conjur::API, api: :dummy do
|
|
8
|
-
let(:identity) { 'host/data/test/gcp-apps/test-app' }
|
|
9
|
-
let(:gcp_jwt) { 'eyJhbGciOiJSUzI1NiJ9.gcp-payload.sig' }
|
|
10
|
-
let(:raw_token) { { 'protected' => 'p', 'payload' => 'pl', 'signature' => 's' } }
|
|
11
|
-
|
|
12
|
-
describe '.new_from_gcp' do
|
|
13
|
-
it 'returns an API instance with a GCPAuthenticator' do
|
|
14
|
-
allow(Conjur::API).to receive(:authenticate_gcp).and_return(raw_token)
|
|
15
|
-
api_instance = Conjur::API.new_from_gcp(identity, account: account)
|
|
16
|
-
expect(api_instance).to be_a(Conjur::API)
|
|
17
|
-
expect(api_instance.authenticator).to be_a(Conjur::API::GCPAuthenticator)
|
|
18
|
-
end
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
describe '.authenticate_gcp' do
|
|
22
|
-
let(:resource) { double('resource') }
|
|
23
|
-
|
|
24
|
-
before do
|
|
25
|
-
allow(Conjur::API).to receive(:url_for)
|
|
26
|
-
.with(:authn_gcp_authenticate, account)
|
|
27
|
-
.and_return(resource)
|
|
28
|
-
allow(resource).to receive(:post)
|
|
29
|
-
.with("jwt=#{CGI.escape(gcp_jwt)}", content_type: 'application/x-www-form-urlencoded')
|
|
30
|
-
.and_return(raw_token.to_json)
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
context 'with a pre-supplied JWT' do
|
|
34
|
-
it 'returns a parsed token without calling the metadata service' do
|
|
35
|
-
expect(Conjur::API).not_to receive(:fetch_gcp_jwt)
|
|
36
|
-
token = Conjur::API.authenticate_gcp(identity, account: account, jwt: gcp_jwt)
|
|
37
|
-
expect(token).to eq(raw_token)
|
|
38
|
-
end
|
|
39
|
-
end
|
|
40
|
-
|
|
41
|
-
context 'without a pre-supplied JWT' do
|
|
42
|
-
it 'fetches from the metadata service' do
|
|
43
|
-
allow(Conjur::API).to receive(:fetch_gcp_jwt).and_return(gcp_jwt)
|
|
44
|
-
token = Conjur::API.authenticate_gcp(identity, account: account)
|
|
45
|
-
expect(token).to eq(raw_token)
|
|
46
|
-
end
|
|
47
|
-
end
|
|
48
|
-
|
|
49
|
-
it 'raises ArgumentError when identity is empty' do
|
|
50
|
-
expect { Conjur::API.authenticate_gcp('', account: account) }
|
|
51
|
-
.to raise_error(ArgumentError, /identity is required/)
|
|
52
|
-
end
|
|
53
|
-
end
|
|
54
|
-
|
|
55
|
-
describe 'GCPAuthenticator#refresh_token' do
|
|
56
|
-
context 'with a pre-supplied JWT' do
|
|
57
|
-
subject(:authenticator) do
|
|
58
|
-
Conjur::API::GCPAuthenticator.new(account, identity, jwt: gcp_jwt)
|
|
59
|
-
end
|
|
60
|
-
|
|
61
|
-
it 'passes the stored JWT to authenticate_gcp' do
|
|
62
|
-
expect(Conjur::API).to receive(:authenticate_gcp)
|
|
63
|
-
.with(identity,
|
|
64
|
-
account: account,
|
|
65
|
-
jwt: gcp_jwt,
|
|
66
|
-
gcp_identity_url: Conjur::API::GCPAuthenticator::DEFAULT_METADATA_URL)
|
|
67
|
-
.and_return(raw_token)
|
|
68
|
-
expect(authenticator.refresh_token).to eq(raw_token)
|
|
69
|
-
end
|
|
70
|
-
end
|
|
71
|
-
|
|
72
|
-
context 'without a pre-supplied JWT' do
|
|
73
|
-
subject(:authenticator) do
|
|
74
|
-
Conjur::API::GCPAuthenticator.new(account, identity)
|
|
75
|
-
end
|
|
76
|
-
|
|
77
|
-
it 'passes nil jwt to authenticate_gcp (which then calls metadata service)' do
|
|
78
|
-
expect(Conjur::API).to receive(:authenticate_gcp)
|
|
79
|
-
.with(identity,
|
|
80
|
-
account: account,
|
|
81
|
-
jwt: nil,
|
|
82
|
-
gcp_identity_url: Conjur::API::GCPAuthenticator::DEFAULT_METADATA_URL)
|
|
83
|
-
.and_return(raw_token)
|
|
84
|
-
expect(authenticator.refresh_token).to eq(raw_token)
|
|
85
|
-
end
|
|
86
|
-
end
|
|
87
|
-
end
|
|
88
|
-
|
|
89
|
-
describe '.gcp_audience' do
|
|
90
|
-
it 'strips a leading host/ and rebuilds the conjur audience' do
|
|
91
|
-
expect(Conjur::API.send(:gcp_audience, account, 'host/data/app'))
|
|
92
|
-
.to eq("conjur/#{account}/host/data/app")
|
|
93
|
-
end
|
|
94
|
-
|
|
95
|
-
it 'assumes a host identity when the host/ prefix is absent' do
|
|
96
|
-
expect(Conjur::API.send(:gcp_audience, account, 'data/app'))
|
|
97
|
-
.to eq("conjur/#{account}/host/data/app")
|
|
98
|
-
end
|
|
99
|
-
end
|
|
100
|
-
end
|
|
101
|
-
|
|
102
|
-
describe Conjur::API::Router do
|
|
103
|
-
let(:account) { 'myaccount' }
|
|
104
|
-
|
|
105
|
-
before do
|
|
106
|
-
allow(Conjur.configuration).to receive(:core_url).and_return('https://conjur.example.com')
|
|
107
|
-
allow(Conjur.configuration).to receive(:rest_client_options).and_return({})
|
|
108
|
-
end
|
|
109
|
-
|
|
110
|
-
describe '#authn_gcp_authenticate' do
|
|
111
|
-
subject { described_class.authn_gcp_authenticate(account) }
|
|
112
|
-
|
|
113
|
-
it 'returns a RestClient::Resource' do
|
|
114
|
-
expect(subject).to be_a(RestClient::Resource)
|
|
115
|
-
end
|
|
116
|
-
|
|
117
|
-
it 'builds the correct URL using the serviceless authn-gcp path' do
|
|
118
|
-
expect(subject.url).to end_with('/authn-gcp/myaccount/authenticate')
|
|
119
|
-
end
|
|
120
|
-
end
|
|
121
|
-
end
|
data/spec/authn_iam_spec.rb
DELETED
|
@@ -1,103 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require 'spec_helper'
|
|
4
|
-
require 'conjur/api/router'
|
|
5
|
-
|
|
6
|
-
describe Conjur::API, api: :dummy do
|
|
7
|
-
let(:service_id) { 'prod' }
|
|
8
|
-
let(:identity) { 'host/my-app/my-role' }
|
|
9
|
-
let(:raw_token) { { 'protected' => 'p', 'payload' => 'pl', 'signature' => 's' } }
|
|
10
|
-
let(:signed_headers) do
|
|
11
|
-
{
|
|
12
|
-
'Authorization' => 'AWS4-HMAC-SHA256 Credential=AKIAEXAMPLE/...',
|
|
13
|
-
'x-amz-date' => '20240101T000000Z',
|
|
14
|
-
'x-amz-content-sha256' => 'e3b0c44298fc1c149afbf4c8996fb924',
|
|
15
|
-
'x-amz-security-token' => 'token',
|
|
16
|
-
'host' => 'sts.amazonaws.com'
|
|
17
|
-
}
|
|
18
|
-
end
|
|
19
|
-
|
|
20
|
-
describe '.new_from_iam' do
|
|
21
|
-
it 'returns an API instance with an IAMAuthenticator' do
|
|
22
|
-
allow(Conjur::API).to receive(:authenticate_iam).and_return(raw_token)
|
|
23
|
-
api_instance = Conjur::API.new_from_iam(identity, account: account)
|
|
24
|
-
expect(api_instance).to be_a(Conjur::API)
|
|
25
|
-
expect(api_instance.authenticator).to be_a(Conjur::API::IAMAuthenticator)
|
|
26
|
-
end
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
describe '.authenticate_iam' do
|
|
30
|
-
let(:resource) { double('resource') }
|
|
31
|
-
|
|
32
|
-
before do
|
|
33
|
-
allow(Conjur::API).to receive(:require).with('aws-sdk-core')
|
|
34
|
-
allow(Conjur::API).to receive(:url_for)
|
|
35
|
-
.with(:authn_iam_authenticate, account, service_id, identity)
|
|
36
|
-
.and_return(resource)
|
|
37
|
-
allow(resource).to receive(:post)
|
|
38
|
-
.with(signed_headers.to_json, content_type: 'application/json')
|
|
39
|
-
.and_return(raw_token.to_json)
|
|
40
|
-
allow(Conjur::API).to receive(:build_iam_signed_headers).and_return(signed_headers)
|
|
41
|
-
end
|
|
42
|
-
|
|
43
|
-
it 'returns a parsed token' do
|
|
44
|
-
token = Conjur::API.authenticate_iam(identity, account: account, service_id: service_id)
|
|
45
|
-
expect(token).to eq(raw_token)
|
|
46
|
-
end
|
|
47
|
-
|
|
48
|
-
it 'raises ArgumentError when identity is empty' do
|
|
49
|
-
expect { Conjur::API.authenticate_iam('', account: account) }
|
|
50
|
-
.to raise_error(ArgumentError, /identity is required/)
|
|
51
|
-
end
|
|
52
|
-
|
|
53
|
-
it 'raises ArgumentError when service_id is empty' do
|
|
54
|
-
expect { Conjur::API.authenticate_iam(identity, account: account, service_id: '') }
|
|
55
|
-
.to raise_error(ArgumentError, /service_id is required/)
|
|
56
|
-
end
|
|
57
|
-
|
|
58
|
-
it 'raises LoadError when aws-sdk-core is unavailable' do
|
|
59
|
-
allow(Conjur::API).to receive(:require).with('aws-sdk-core').and_raise(LoadError)
|
|
60
|
-
expect { Conjur::API.authenticate_iam(identity, account: account) }
|
|
61
|
-
.to raise_error(LoadError, /aws-sdk-core/)
|
|
62
|
-
end
|
|
63
|
-
end
|
|
64
|
-
|
|
65
|
-
describe 'IAMAuthenticator#refresh_token' do
|
|
66
|
-
subject(:authenticator) do
|
|
67
|
-
Conjur::API::IAMAuthenticator.new(account, service_id, identity)
|
|
68
|
-
end
|
|
69
|
-
|
|
70
|
-
it 'delegates to authenticate_iam with stored credentials' do
|
|
71
|
-
expect(Conjur::API).to receive(:authenticate_iam)
|
|
72
|
-
.with(identity,
|
|
73
|
-
account: account,
|
|
74
|
-
service_id: service_id,
|
|
75
|
-
aws_region: Conjur::API::IAMAuthenticator::DEFAULT_REGION)
|
|
76
|
-
.and_return(raw_token)
|
|
77
|
-
expect(authenticator.refresh_token).to eq(raw_token)
|
|
78
|
-
end
|
|
79
|
-
end
|
|
80
|
-
end
|
|
81
|
-
|
|
82
|
-
describe Conjur::API::Router do
|
|
83
|
-
let(:account) { 'myaccount' }
|
|
84
|
-
let(:service_id) { 'prod' }
|
|
85
|
-
let(:identity) { 'host/my-app/my-role' }
|
|
86
|
-
|
|
87
|
-
before do
|
|
88
|
-
allow(Conjur.configuration).to receive(:core_url).and_return('https://conjur.example.com')
|
|
89
|
-
allow(Conjur.configuration).to receive(:rest_client_options).and_return({})
|
|
90
|
-
end
|
|
91
|
-
|
|
92
|
-
describe '#authn_iam_authenticate' do
|
|
93
|
-
subject { described_class.authn_iam_authenticate(account, service_id, identity) }
|
|
94
|
-
|
|
95
|
-
it 'returns a RestClient::Resource' do
|
|
96
|
-
expect(subject).to be_a(RestClient::Resource)
|
|
97
|
-
end
|
|
98
|
-
|
|
99
|
-
it 'builds the correct URL' do
|
|
100
|
-
expect(subject.url).to end_with('/authn-iam/prod/myaccount/host%2Fmy-app%2Fmy-role/authenticate')
|
|
101
|
-
end
|
|
102
|
-
end
|
|
103
|
-
end
|