Fix OWCA detection for compliance login (#2401)

* Add handling for OWCA login via `compliance login`

OpsWorks Chef Automate currently returns a 200 for the
`/compliance/version` endpoint and redirects to the Chef Manage page.

This adds support to `inspec compliance login` to accept this as valid
behavior and continue with the login.

Signed-off-by: Jerry Aldrich <jerryaldrichiii@gmail.com>

* Add test case for 200 response but no Chef Manage

Signed-off-by: Jerry Aldrich <jerryaldrichiii@gmail.com>

* Add debug info and split `determine_server_type`

Signed-off-by: Jerry Aldrich <jerryaldrichiii@gmail.com>

* Appease RuboCop

Signed-off-by: Jerry Aldrich <jerryaldrichiii@gmail.com>

* Remove forced returns from `determine_server_type`

Signed-off-by: Jerry Aldrich <jerryaldrichiii@gmail.com>

* Add `false` code path for non-200/non-401 response

Signed-off-by: Jerry Aldrich <jerryaldrichiii@gmail.com>

* Reword debug messages

Signed-off-by: Jerry Aldrich <jerryaldrichiii@gmail.com>
This commit is contained in:
Jerry Aldrich 2017-12-22 08:01:18 -06:00 committed by Christoph Hartmann
parent 1d0eebcadd
commit a3c993fe18
2 changed files with 127 additions and 21 deletions

View file

@ -251,11 +251,66 @@ module Compliance
end
def self.determine_server_type(url, insecure)
if Compliance::HTTP.get(url + '/compliance/version', nil, insecure).code == '401'
if target_is_automate_server?(url, insecure)
:automate
elsif Compliance::HTTP.get(url + '/api/version', nil, insecure).code == '200'
elsif target_is_compliance_server?(url, insecure)
:compliance
else
Inspec::Log.debug('Could not determine server type using known endpoints')
nil
end
end
def self.target_is_automate_server?(url, insecure)
automate_endpoint = '/compliance/version'
response = Compliance::HTTP.get(url + automate_endpoint, nil, insecure)
case response.code
when '401'
Inspec::Log.debug(
"Received 401 from #{url}#{automate_endpoint} - " \
'assuming target is a Chef Automate instance',
)
true
when '200'
# Chef Automate currently returns 401 for `/compliance/version` but some
# versions of OpsWorks Chef Automate return 200 and a Chef Manage page
# when unauthenticated requests are received.
if response.body.include?('Are You Looking For the Chef Server?')
Inspec::Log.debug(
"Received 200 from #{url}#{automate_endpoint} - " \
'assuming target is an OpsWorks Chef Automate instance',
)
true
else
Inspec::Log.debug(
"Received 200 from #{url}#{automate_endpoint} " \
'but did not receive the Chef Manage page - ' \
'assuming target is not a Chef Automate instance',
)
false
end
else
Inspec::Log.debug(
"Received unexpected status code #{response.code} " \
"from #{url}#{automate_endpoint} - " \
'assuming target is not a Chef Automate instance',
)
false
end
end
def self.target_is_compliance_server?(url, insecure)
# All versions of Chef Compliance return 200 for `/api/version`
compliance_endpoint = '/api/version'
response = Compliance::HTTP.get(url + compliance_endpoint, nil, insecure)
return false unless response.code == '200'
Inspec::Log.debug(
"Received 200 from #{url}#{compliance_endpoint} - " \
'assuming target is a Compliance server',
)
true
end
end
end

View file

@ -247,32 +247,83 @@ describe Compliance::API do
end
describe '.determine_server_type' do
it 'returns `automate` when a 401 is received from `https://automate.example.com/compliance/version`' do
good_response = mock
let(:url) { 'https://someserver.onthe.net/' }
let(:compliance_endpoint) { '/api/version' }
let(:automate_endpoint) { '/compliance/version' }
let(:headers) { nil }
let(:insecure) { true }
let(:good_response) { mock }
let(:bad_response) { mock }
it 'returns `:automate` when a 401 is received from `https://URL/compliance/version`' do
good_response.stubs(:code).returns('401')
url = 'https://automate.example.com'
Compliance::HTTP.expects(:get).with(url + '/compliance/version', nil, true).returns(good_response)
Compliance::API.determine_server_type(url, true).must_equal(:automate)
Compliance::HTTP.expects(:get)
.with(url + automate_endpoint, headers, insecure)
.returns(good_response)
Compliance::API.determine_server_type(url, insecure).must_equal(:automate)
end
it 'returns `compliance` when a 200 is received from `https://compliance.example.com/api/version`' do
good_response = mock
# Chef Automate currently returns 401 for `/compliance/version` but some
# versions of OpsWorks Chef Automate return 200 and a Chef Manage page when
# unauthenticated requests are received.
it 'returns `:automate` when a 200 is received from `https://URL/compliance/version`' do
good_response.stubs(:code).returns('200')
bad_response = mock
bad_response.stubs(:code).returns('404')
url = 'https://compliance.example.com'
Compliance::HTTP.expects(:get).with(url + '/compliance/version', nil, true).returns(bad_response)
Compliance::HTTP.expects(:get).with(url + '/api/version', nil, true).returns(good_response)
Compliance::API.determine_server_type(url, true).must_equal(:compliance)
good_response.stubs(:body).returns('Are You Looking For the Chef Server?')
Compliance::HTTP.expects(:get)
.with(url + automate_endpoint, headers, insecure)
.returns(good_response)
Compliance::API.determine_server_type(url, insecure).must_equal(:automate)
end
it 'returns `nil` if no response returns favorably' do
bad_response = mock
it 'returns `nil` if a 200 is received from `https://URL/compliance/version` but not redirected to Chef Manage' do
bad_response.stubs(:code).returns('200')
bad_response.stubs(:body).returns('No Chef Manage here')
Compliance::HTTP.expects(:get)
.with(url + automate_endpoint, headers, insecure)
.returns(bad_response)
mock_compliance_response = mock
mock_compliance_response.stubs(:code).returns('404')
Compliance::HTTP.expects(:get)
.with(url + compliance_endpoint, headers, insecure)
.returns(mock_compliance_response)
Compliance::API.determine_server_type(url, insecure).must_be_nil
end
it 'returns `:compliance` when a 200 is received from `https://URL/api/version`' do
good_response.stubs(:code).returns('200')
bad_response.stubs(:code).returns('404')
url = 'https://bad.example.com'
Compliance::HTTP.expects(:get).with(url + '/compliance/version', nil, true).returns(bad_response)
Compliance::HTTP.expects(:get).with(url + '/api/version', nil, true).returns(bad_response)
Compliance::API.determine_server_type(url, true).must_be_nil
Compliance::HTTP.expects(:get)
.with(url + automate_endpoint, headers, insecure)
.returns(bad_response)
Compliance::HTTP.expects(:get)
.with(url + compliance_endpoint, headers, insecure)
.returns(good_response)
Compliance::API.determine_server_type(url, insecure).must_equal(:compliance)
end
it 'returns `nil` if it cannot determine the server type' do
bad_response.stubs(:code).returns('404')
Compliance::HTTP.expects(:get)
.with(url + automate_endpoint, headers, insecure)
.returns(bad_response)
Compliance::HTTP.expects(:get)
.with(url + compliance_endpoint, headers, insecure)
.returns(bad_response)
Compliance::API.determine_server_type(url, insecure).must_be_nil
end
end
end