Skip to content

Commit

Permalink
Merge pull request #425 from alencar/feature/support-safenet-trusted-…
Browse files Browse the repository at this point in the history
…access-mfa

Support SafeNet Trusted Access MFA
  • Loading branch information
pdecat committed Jan 16, 2024
2 parents 4b3c9ee + e6f3db3 commit 1c4a9f3
Show file tree
Hide file tree
Showing 3 changed files with 102 additions and 0 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ aws-adfs integrates with:
* SMS codes
* Phone call
* [Silverfort](https://www.silverfort.com/) MFA provider
* [Thales/SafeNet Trusted Access](https://cpl.thalesgroup.com/access-management/authentication) MFA provider
* OTP 6 digit codes generated by MobilePASS+ Authenticator app

## Setup Dependencies

Expand Down
84 changes: 84 additions & 0 deletions aws_adfs/_safenet_mfa.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
import click
import lxml.etree as ET

import logging
import re

from . import run_command

try:
# Python 3
from urllib.parse import urlparse, parse_qs
except ImportError:
# Python 2
from urlparse import urlparse, parse_qs

from . import roles_assertion_extractor
from .helpers import trace_http_request


def extract(html_response, ssl_verification_enabled, mfa_token_command, mfa_token, session):
"""
:param response: raw http response
:param html_response: html result of parsing http response
:return:
"""

roles_page_url = _action_url_on_validation_success(html_response)

if mfa_token_command:
data = run_command.run_command(mfa_token_command)
safenet_mfa_code = data['mfa_token']
logging.debug(f"using SafeNet MFA token from command: {safenet_mfa_code}")
elif mfa_token:
safenet_mfa_code = mfa_token
logging.debug(f"using SafeNet MFA token from env: {safenet_mfa_code}")
else:
safenet_mfa_code = click.prompt(text='Enter your SafeNet MFA token', type=str, hide_input=True)

click.echo('Going for aws roles', err=True)
return _retrieve_roles_page(
roles_page_url,
_context(html_response),
session,
ssl_verification_enabled,
safenet_mfa_code,
)

def _context(html_response):
context_query = './/input[@name="Context"]'
element = html_response.find(context_query)
return element.get('value')


def _retrieve_roles_page(roles_page_url, context, session, ssl_verification_enabled,
safenet_mfa_code):
response = session.post(
roles_page_url,
verify=ssl_verification_enabled,
allow_redirects=True,
data={
'AuthMethod': 'SafeNet-MFA',
'Context': context,
'SAFENET_PASSWORD': safenet_mfa_code,
}
)
trace_http_request(response)

if response.status_code != 200:
raise click.ClickException(
u'Issues during redirection to aws roles page. The error response {}'.format(
response
)
)

# Save session cookies to avoid having to repeat MFA on each login
session.cookies.save(ignore_discard=True)

html_response = ET.fromstring(response.text, ET.HTMLParser())
return roles_assertion_extractor.extract(html_response)

def _action_url_on_validation_success(html_response):
safenet_mfa_auth_method = './/form[@id="options"]'
element = html_response.find(safenet_mfa_auth_method)
return element.get('action')
16 changes: 16 additions & 0 deletions aws_adfs/authenticator.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
from . import _azure_mfa_authenticator as azure_mfa_auth
from . import _azure_cloud_mfa_authenticator as azure_cloud_mfa_auth
from . import _silverfort_authenticator as silverfort_mfa_auth
from . import _safenet_mfa as safenet_mfa
from . import html_roles_fetcher
from . import roles_assertion_extractor
from .helpers import trace_http_request
Expand Down Expand Up @@ -128,6 +129,11 @@ def _silverfort_extractor():
def extract():
return silverfort_mfa_auth.extract(html_response, config.ssl_verification, session)
return extract

def _safenet_extractor():
def extract():
return safenet_mfa.extract(html_response, config.ssl_verification, config.mfa_token_command, config.mfa_token, session)
return extract

if assertfile is None:
chosen_strategy = _plain_extractor
Expand All @@ -148,6 +154,8 @@ def extract():
chosen_strategy = _azure_cloud_mfa_extractor
elif _is_silverfort_mfa_authentication(html_response):
chosen_strategy = _silverfort_extractor
elif _is_safenet_mfa_authentication(html_response):
chosen_strategy = _safenet_extractor

return chosen_strategy()

Expand Down Expand Up @@ -215,3 +223,11 @@ def _is_silverfort_mfa_authentication(html_response):
element is not None
and element.get('value') == 'SilverfortAdfs'
)

def _is_safenet_mfa_authentication(html_response):
auth_method = './/input[@name="AuthMethod"]'
element = html_response.find(auth_method)
return (
element is not None
and element.get('value') == 'SafeNet-MFA'
)

0 comments on commit 1c4a9f3

Please sign in to comment.