Skip to content

Commit

Permalink
Add --u2f-trigger-default/--no-u2f-trigger-default options to determi…
Browse files Browse the repository at this point in the history
…ne whether to trigger the default authentication method when U2F is available (only works with Duo for now)
  • Loading branch information
pdecat committed Oct 10, 2019
1 parent 4cab651 commit 69ce6ec
Show file tree
Hide file tree
Showing 6 changed files with 48 additions and 22 deletions.
33 changes: 17 additions & 16 deletions aws_adfs/_duo_authenticator.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
}


def extract(html_response, ssl_verification_enabled, session):
def extract(html_response, ssl_verification_enabled, u2f_trigger_default, session):
"""
this strategy is based on description from: https://duo.com/docs/duoweb
:param response: raw http response
Expand Down Expand Up @@ -75,22 +75,23 @@ def extract(html_response, ssl_verification_enabled, session):
t.daemon = True
t.start()

# Always trigger default authentication (call or push) concurrently to U2F
t = Thread(
target=_perform_authentication_transaction,
args=(
duo_host,
sid,
preferred_factor,
preferred_device,
False,
session,
ssl_verification_enabled,
rq,
if u2f_trigger_default or not u2f_supported:
# Trigger default authentication (call or push) concurrently to U2F
t = Thread(
target=_perform_authentication_transaction,
args=(
duo_host,
sid,
preferred_factor,
preferred_device,
False,
session,
ssl_verification_enabled,
rq,
)
)
)
t.daemon = True
t.start()
t.daemon = True
t.start()

# Wait for first response
auth_signature = rq.get()
Expand Down
5 changes: 3 additions & 2 deletions aws_adfs/authenticator.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ def authenticate(config, username=None, password=None, assertfile=None):
provider_id=config.provider_id,
username=username,
password=password,
sspi=config.sspi
sspi=config.sspi,
u2f_trigger_default=config.u2f_trigger_default
)

assertion = None
Expand Down Expand Up @@ -110,7 +111,7 @@ def extract():

def _duo_extractor():
def extract():
return duo_auth.extract(html_response, config.ssl_verification, session)
return duo_auth.extract(html_response, config.ssl_verification, config.u2f_trigger_default, session)
return extract

def _symantec_vip_extractor():
Expand Down
3 changes: 2 additions & 1 deletion aws_adfs/html_roles_fetcher.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@ def fetch_html_encoded_roles(
adfs_ca_bundle=None,
username=None,
password=None,
sspi=True
sspi=True,
u2f_trigger_default=True,
):

# Support for Kerberos SSO on Windows via requests_negotiate_sspi
Expand Down
14 changes: 12 additions & 2 deletions aws_adfs/login.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,11 @@
default=None,
help='Whether or not to use Kerberos SSO authentication via SSPI, which may not work in some environments.',
)
@click.option(
'--u2f-trigger-default/--no-u2f-trigger-default',
default=None,
help='Whether or not to also trigger the default authentication method when U2F is available (only works with Duo for now).',
)
def login(
profile,
region,
Expand All @@ -116,7 +121,8 @@ def login(
role_arn,
session_duration,
assertfile,
sspi
sspi,
u2f_trigger_default,
):
"""
Authenticates an user with active directory credentials
Expand All @@ -131,7 +137,8 @@ def login(
provider_id,
s3_signature_version,
session_duration,
sspi
sspi,
u2f_trigger_default,
)

_verification_checks(config)
Expand Down Expand Up @@ -253,6 +260,8 @@ def _emit_summary(config, session_duration):
* Provider ID : '{}'
* S3 Signature Version : '{}'
* STS Session Duration in seconds : '{}'
* SSPI: : '{}'
* U2F and default method : '{}'
""".format(
config.profile,
config.region,
Expand All @@ -265,6 +274,7 @@ def _emit_summary(config, session_duration):
config.s3_signature_version,
config.session_duration,
config.sspi,
config.u2f_trigger_default,
)
)

Expand Down
6 changes: 6 additions & 0 deletions aws_adfs/prepare.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ def get_prepared_config(
s3_signature_version,
session_duration,
sspi,
u2f_trigger_default,
):
"""
Prepares ADF configuration for login task.
Expand All @@ -38,6 +39,7 @@ def get_prepared_config(
:param s3_signature_version: s3 signature version
:param session_duration: AWS STS session duration (default 1 hour)
:param sspi: Whether SSPI is enabled
:param u2f_trigger_default: Whether to also trigger the default authentication method when U2F is available
"""
def default_if_none(value, default):
return value if value is not None else default
Expand All @@ -60,6 +62,7 @@ def default_if_none(value, default):
)
adfs_config.session_duration = default_if_none(session_duration, adfs_config.session_duration)
adfs_config.sspi = default_if_none(sspi, adfs_config.sspi)
adfs_config.u2f_trigger_default = default_if_none(u2f_trigger_default, adfs_config.u2f_trigger_default)

return adfs_config

Expand Down Expand Up @@ -116,6 +119,9 @@ def create_adfs_default_config(profile):
# Whether SSPI is enabled
config.sspi = True

# Whether to also trigger the default authentication method when U2F is available
config.u2f_trigger_default = True

return config


Expand Down
9 changes: 8 additions & 1 deletion test/test_config_preparation.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ def test_when_there_is_no_profile_use_default_values(self):
default_s3_signature_version = None
default_session_duration = 3600
default_sspi = False
default_u2f_trigger_default = False

# when configuration is prepared for not existing profile
adfs_config = prepare.get_prepared_config(
Expand All @@ -36,6 +37,7 @@ def test_when_there_is_no_profile_use_default_values(self):
default_s3_signature_version,
default_session_duration,
default_sspi,
default_u2f_trigger_default,
)

# then resolved config contains defaults values
Expand All @@ -45,6 +47,8 @@ def test_when_there_is_no_profile_use_default_values(self):
assert default_adfs_host == adfs_config.adfs_host
assert default_output_format == adfs_config.output_format
assert default_session_duration == adfs_config.session_duration
assert default_sspi == adfs_config.sspi
assert default_u2f_trigger_default == adfs_config.u2f_trigger_default

def test_when_the_profile_exists_but_lacks_ssl_verification_use_default_value(self):
# given profile to read the configuration exists
Expand All @@ -61,6 +65,7 @@ def test_when_the_profile_exists_but_lacks_ssl_verification_use_default_value(se
default_ssl_config = True
default_adfs_ca_bundle = None
default_sspi = True
default_u2f_trigger_default = True
irrelevant_region = 'irrelevant_region'
irrelevant_adfs_host = 'irrelevant_adfs_host'
irrelevant_output_format = 'irrelevant_output_format'
Expand All @@ -79,10 +84,12 @@ def test_when_the_profile_exists_but_lacks_ssl_verification_use_default_value(se
irrelevant_provider_id,
irrelevant_s3_signature_version,
irrelevant_session_duration,
default_sspi,
default_sspi,
default_u2f_trigger_default,
)

# then resolved ssl verification holds the default value
assert default_ssl_config == adfs_config.ssl_verification
assert default_adfs_ca_bundle == adfs_config.adfs_ca_bundle
assert default_sspi == adfs_config.sspi
assert default_u2f_trigger_default == adfs_config.u2f_trigger_default

0 comments on commit 69ce6ec

Please sign in to comment.