Skip to content

Commit

Permalink
Merge pull request #2217 from cyberark/2173-authenticators
Browse files Browse the repository at this point in the history
Enabled authenticators can be configured using configuration file
  • Loading branch information
h-artzi authored May 27, 2021
2 parents 0609416 + 1a00282 commit a48be72
Show file tree
Hide file tree
Showing 12 changed files with 87 additions and 41 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.

## [Unreleased]
### Added
- Enabled authenticators can now be configured via a configuration file, or the
CONJUR_AUTHENTICATORS environment variable.
[cyberark/conjur##2173](https://github.com/cyberark/conjur/issues/#2173)
- Trusted Proxies can now be configured with a configuration file or by setting
the CONJUR_TRUSTED_PROXIES environment variable.
[cyberark/conjur#2168](https://github.com/cyberark/conjur/issues/2168)
Expand Down
5 changes: 4 additions & 1 deletion Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,10 @@ gem 'websocket'
gem 'jwt'
gem 'openid_connect'

gem "anyway_config", "~> 2.0"
# Unpin version once this Github issue,
# https://github.com/palkan/anyway_config/issues/82
# is resolved
gem "anyway_config", "2.1.0"

group :development, :test do
gem 'aruba'
Expand Down
2 changes: 1 addition & 1 deletion Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -444,7 +444,7 @@ PLATFORMS

DEPENDENCIES
activesupport
anyway_config (~> 2.0)
anyway_config (= 2.1.0)
aruba
aws-sdk-iam
base32-crockford
Expand Down
6 changes: 3 additions & 3 deletions app/controllers/authenticate_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ def index
def status
Authentication::ValidateStatus.new.(
authenticator_status_input: status_input,
enabled_authenticators: Authentication::InstalledAuthenticators.enabled_authenticators_str(ENV)
enabled_authenticators: Authentication::InstalledAuthenticators.enabled_authenticators_str
)
render(json: { status: "ok" })
rescue => e
Expand Down Expand Up @@ -70,7 +70,7 @@ def authenticate(input = authenticator_input)
authn_token = Authentication::Authenticate.new.(
authenticator_input: input,
authenticators: installed_authenticators,
enabled_authenticators: Authentication::InstalledAuthenticators.enabled_authenticators_str(ENV)
enabled_authenticators: Authentication::InstalledAuthenticators.enabled_authenticators_str
)
content_type = :json
if encoded_response?
Expand Down Expand Up @@ -237,7 +237,7 @@ def installed_authenticators
end

def enabled_authenticators
Authentication::InstalledAuthenticators.enabled_authenticators(ENV)
Authentication::InstalledAuthenticators.enabled_authenticators
end

def encoded_response?
Expand Down
2 changes: 1 addition & 1 deletion app/controllers/concerns/basic_authenticator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ def authenticator_login(username, password)
::Authentication::Login.new.(
authenticator_input: login_input(username, password),
authenticators: installed_login_authenticators,
enabled_authenticators: Authentication::InstalledAuthenticators.enabled_authenticators_str(ENV)
enabled_authenticators: Authentication::InstalledAuthenticators.enabled_authenticators_str
)
end

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ module AuthnK8s
k8s_object_lookup_class: K8sObjectLookup,
validate_webservice_is_whitelisted: Security::ValidateWebserviceIsWhitelisted.new,
validate_role_can_access_webservice: Security::ValidateRoleCanAccessWebservice.new,
enabled_authenticators: InstalledAuthenticators.enabled_authenticators_str(ENV),
enabled_authenticators: InstalledAuthenticators.enabled_authenticators_str,
validate_resource_restrictions: ResourceRestrictions::ValidateResourceRestrictions.new(
extract_resource_restrictions: ExtractK8sResourceRestrictions.new
),
Expand Down
15 changes: 6 additions & 9 deletions app/domain/authentication/installed_authenticators.rb
Original file line number Diff line number Diff line change
Expand Up @@ -33,21 +33,18 @@ def configured_authenticators
.push(::Authentication::Common.default_authenticator_name)
end

def enabled_authenticators(env)
def enabled_authenticators
# Enabling via environment overrides enabling via CLI
env_enabled_authenticators(env) || db_enabled_authenticators
authenticators =
Rails.application.config.conjur_config.authenticators
authenticators.empty? ? db_enabled_authenticators : authenticators
end

def enabled_authenticators_str(env)
enabled_authenticators(env).join(',')
def enabled_authenticators_str
enabled_authenticators.join(',')
end

private

def env_enabled_authenticators(env)
authenticators = env["CONJUR_AUTHENTICATORS"]
authenticators.present? ? authenticators.split(',') : nil
end

def db_enabled_authenticators
# Always include 'authn' when enabling authenticators via CLI so that it
Expand Down
2 changes: 1 addition & 1 deletion ci/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ services:
RAILS_ENV:
REQUIRE_SIMPLECOV: "true"
CONJUR_LOG_LEVEL: debug
CONJUR_AUTHENTICATORS: authn-ldap/test,authn-ldap/secure,authn-oidc/keycloak,authn-oidc,authn-config/env,authn-azure/prod,authn-gcp
CONJUR_AUTHENTICATORS: authn-ldap/test,authn-ldap/secure,authn-oidc/keycloak,authn-oidc,authn-k8s/test,authn-azure/prod,authn-gcp
LDAP_URI: ldap://ldap-server:389
LDAP_BASE: dc=conjur,dc=net
LDAP_FILTER: '(uid=%s)'
Expand Down
34 changes: 17 additions & 17 deletions cucumber/authenticators_config/features/authn_config.feature
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,15 @@ Feature: Authenticator configuration
And I have user "authn-updater"
And I load a policy:
"""
# authn-config/env is enabled in CONJUR_AUTHENTICATORS and used in tests to
# authn-k8s/test is enabled in CONJUR_AUTHENTICATORS and used in tests to
# ensure that the env value continues to be used even when DB config exists.
- !policy
id: conjur/authn-config/env
id: conjur/authn-k8s/test
body:
- !webservice
- !policy
id: conjur/authn-config/db
id: conjur/authn-k8s/db
body:
- !webservice
Expand All @@ -35,48 +35,48 @@ Feature: Authenticator configuration
resource: !webservice
- !grant
role: !group conjur/authn-config/db/viewers
role: !group conjur/authn-k8s/db/viewers
member: !user authn-viewer
- !grant
role: !group conjur/authn-config/db/updaters
role: !group conjur/authn-k8s/db/updaters
member: !user authn-updater
"""

Scenario: Authenticator is not configured in database
When I am the super-user
And I retrieve the list of authenticators
Then the enabled authenticators contains "authn-config/env"
Then the enabled authenticators contains "authn-k8s/test"

Scenario: Authenticator is enabled in the environment and disabled in the database
When I am the super-user
And I successfully PATCH "/authn-config/env/cucumber" with body:
And I successfully PATCH "/authn-k8s/test/cucumber" with body:
"""
enabled=false
"""
And I retrieve the list of authenticators
Then the enabled authenticators contains "authn-config/env"
Then the enabled authenticators contains "authn-k8s/test"

Scenario: Authenticator is successfully configured
When I login as "authn-updater"
And I successfully PATCH "/authn-config/db/cucumber" with body:
And I successfully PATCH "/authn-k8s/db/cucumber" with body:
"""
enabled=true
"""
Then the HTTP response status code is 204
And authenticator "cucumber:webservice:conjur/authn-config/db" is enabled
And authenticator "cucumber:webservice:conjur/authn-k8s/db" is enabled

When I successfully PATCH "/authn-config/db/cucumber" with body:
When I successfully PATCH "/authn-k8s/db/cucumber" with body:
"""
enabled=false
"""
Then the HTTP response status code is 204
And authenticator "cucumber:webservice:conjur/authn-config/db" is disabled
And authenticator "cucumber:webservice:conjur/authn-k8s/db" is disabled

Scenario: Authenticator account does not exist
When I am the super-user
And I save my place in the log file
And I PATCH "/authn-config/db/nope" with body:
And I PATCH "/authn-k8s/db/nope" with body:
"""
enabled=true
"""
Expand All @@ -89,7 +89,7 @@ Feature: Authenticator configuration
Scenario: Authenticator webservice does not exist
When I am the super-user
And I save my place in the log file
And I PATCH "/authn-config/db%2Fnope/cucumber" with body:
And I PATCH "/authn-k8s/db%2Fnope/cucumber" with body:
"""
enabled=true
"""
Expand All @@ -102,12 +102,12 @@ Feature: Authenticator configuration
Scenario: Authenticated user can not update authenticator
When I login as "authn-viewer"
And I save my place in the log file
And I PATCH "/authn-config/db/cucumber" with body:
And I PATCH "/authn-k8s/db/cucumber" with body:
"""
enabled=true
"""
Then the HTTP response status code is 403
And authenticator "cucumber:webservice:conjur/authn-config/db" is disabled
And authenticator "cucumber:webservice:conjur/authn-k8s/db" is disabled
And The following appears in the log after my savepoint:
"""
Errors::Authentication::Security::RoleNotAuthorizedOnResource
Expand All @@ -116,7 +116,7 @@ Feature: Authenticator configuration
Scenario: Nested webservice can not be configured
When I am the super-user
And I save my place in the log file
And I PATCH "/authn-config/db%2Fstatus/cucumber" with body:
And I PATCH "/authn-k8s/db%2Fstatus/cucumber" with body:
"""
enabled=true
"""
Expand Down
2 changes: 1 addition & 1 deletion dev/start
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ docker-compose exec -d conjur conjurctl server
echo 'Checking if Conjur server is ready'
conjur_isready?

default_authenticators="authn,authn-config/env"
default_authenticators="authn,authn-k8s/test"
enabled_authenticators="$default_authenticators"

env_args=
Expand Down
27 changes: 24 additions & 3 deletions lib/conjur/conjur_config.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,16 @@ class ConjurConfig < Anyway::Config

attr_config(
# Read TRUSTED_PROXIES before default to maintain backwards compatibility
trusted_proxies: (ENV['TRUSTED_PROXIES'] || [])
trusted_proxies: (ENV['TRUSTED_PROXIES'] || []),
authenticators: []
)

# Perform validations and collect errors then report results as exception
on_load do
invalid = []

invalid << "trusted_proxies" unless trusted_proxies_valid?
invalid << "authenticators" unless authenticators_valid?

unless invalid.empty?
raise Errors::Conjur::InvalidConfigValues, invalid.join(', ')
Expand All @@ -32,7 +34,7 @@ class ConjurConfig < Anyway::Config

# Get attribute sources without including attribute values
def attribute_sources
to_source_trace.map { |k,v| [ k.to_sym, v[:source][:type] ] }.to_h
to_source_trace.map { |k, v| [ k.to_sym, v[:source][:type] ] }.to_h
end

# The Anyway config gem automatically converts a comma-separated env var to
Expand All @@ -43,9 +45,15 @@ def attribute_sources
#
# To address this inconsistent behavior, we use custom setters to ensure
# list attributes are always converted to a a list type.
# We filed an issue regarding this behavior:
# https://github.com/palkan/anyway_config/issues/82

def trusted_proxies=(val)
super(str_to_list(val))
super(str_to_list(val)&.uniq)
end

def authenticators=(val)
super(str_to_list(val)&.uniq)
end

private
Expand All @@ -63,5 +71,18 @@ def trusted_proxies_valid?
rescue
false
end

def authenticators_valid?
# TODO: Ideally we would check against the enabled authenticators
# in the DB. However, we need to figure out how to use code from the
# application without introducing warnings.
authenticators_regex =
%r{^(authn|authn-(k8s|oidc|iam|ldap|gcp|azure)(/.+)?)$}
authenticators.all? do |authenticator|
authenticators_regex.match?(authenticator.strip)
end
rescue
false
end
end
end
28 changes: 25 additions & 3 deletions spec/lib/conjur/conjur_config_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -86,23 +86,45 @@
end

describe "validation" do
let(:invalid_config) {
let(:invalid_trusted_proxies_config) {
Conjur::ConjurConfig.new(trusted_proxies: "boop")
}

let(:invalid_authenticators_config) {
Conjur::ConjurConfig.new(authenticators: "invalid-authn")
}

let(:invalid_config) {
Conjur::ConjurConfig.new(
authenticators: "invalid-authn", trusted_proxies: "boop"
)
}

it "raises error when validation fails" do
expect { invalid_trusted_proxies_config }.
to raise_error(Errors::Conjur::InvalidConfigValues)
expect { invalid_authenticators_config }.
to raise_error(Errors::Conjur::InvalidConfigValues)
expect { invalid_config }.
to raise_error(Errors::Conjur::InvalidConfigValues)
end

it "includes the attribute that failed validation" do
expect { invalid_config }.
expect { invalid_trusted_proxies_config }.
to raise_error(/trusted_proxies/)
expect { invalid_authenticators_config }.
to raise_error(/authenticators/)
expect { invalid_config }.
to raise_error(/trusted_proxies, authenticators/)
end

it "does not include the value that failed validation" do
expect { invalid_config }.
expect { invalid_trusted_proxies_config }.
to_not raise_error(/boop/)
expect { invalid_authenticators_config }.
to_not raise_error(/invalid-authn/)
expect { invalid_config }.
to_not raise_error(/boop.*invalid-authn/)
end
end

Expand Down

0 comments on commit a48be72

Please sign in to comment.