Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Automate prompt for mfa, app, role selections #354

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ A configuration wizard will prompt you to enter the necessary configuration para
- sms - OTP via SMS message
- web - DUO uses localhost webbrowser to support push|call|passcode
- passcode - DUO uses `OKTA_MFA_CODE` or `--mfa-code` if set, or prompts user for passcode(OTP).
preffered_mfa_provider - automatically select a mfa provider when prompted for MFA

- resolve_aws_alias - y or n. If yes, gimme-aws-creds will try to resolve AWS account ids with respective alias names (default: n). This option can also be set interactively in the command line using `-r` or `--resolve` parameter
- include_path - (optional) Includes full role path to the role name in AWS credential profile name. (default: n). If `y`: `<acct>-/some/path/administrator`. If `n`: `<acct>-administrator`
Expand Down
11 changes: 10 additions & 1 deletion gimme_aws_creds/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@ def __init__(self, gac_ui, create_config=True):
self.action_output_format = False
self.output_format = 'export'
self.roles = []
self.okta_app = None
self.okta_role = None

if self.ui.environ.get("OKTA_USERNAME") is not None:
self.username = self.ui.environ.get("OKTA_USERNAME")
Expand Down Expand Up @@ -145,6 +147,8 @@ def get_args(self):
'--action-setup-fido-authenticator', action='store_true',
help='Sets up a new FIDO WebAuthn authenticator in Okta'
)
parser.add_argument('--okta-app', type=int)
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added two of new arguments; --okta-app, --okta-role are automatically select the specific app and role.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the inputs should be the app and role names, not their position in the list from Okta. Those positions will change as accounts/roles are added and removed.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

also, there are existing config options for these settings (aws_appname and aws_rolename) the parameters should match those names

parser.add_argument('--okta-role', type=int)
args = parser.parse_args(self.ui.args)

self.action_configure = args.action_configure
Expand Down Expand Up @@ -173,6 +177,11 @@ def get_args(self):
self.output_format = args.output_format
if args.roles is not None:
self.roles = [role.strip() for role in args.roles.split(',') if role.strip()]
if args.okta_app is not None:
self.okta_app = args.okta_app
if args.okta_role is not None:
self.okta_role = args.okta_role

self.conf_profile = args.profile or 'DEFAULT'

def _handle_config(self, config, profile_config, include_inherits = True):
Expand Down Expand Up @@ -578,4 +587,4 @@ def fail_if_profile_not_found(self, profile_config, conf_profile, default_sectio
"""
if not profile_config and conf_profile == default_section:
raise errors.GimmeAWSCredsError(
'DEFAULT profile is missing! This is profile is required when not using --profile')
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have no idea why there is a change on this line.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was done by your editor when you saved the file, not a big deal.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your editor added a newline character at the end of the line. GitHub indicates the absence of this with a red circle around a horizontal line. When the character exists at the end of the last line of the file, GitHub just shows the line from the file. You can see the difference locally by running tail <filename>;echo foobar and if the trailing newline is not present "foobar" will appear appended to the last line, if the trailing newline does exist, "foobar" will be on its own line. The absence of a trailing newline can cause issues with file handling, particularly with older tools (though they're likely just working as intended).

'DEFAULT profile is missing! This is profile is required when not using --profile')
11 changes: 11 additions & 0 deletions gimme_aws_creds/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -319,6 +319,10 @@ def _choose_app(self, aws_info):
if len(aws_info) == 1:
return aws_info[0] # auto select when only 1 choice

if self.config.okta_app is not None:
self.ui.info("Detected app in config: {}".format(aws_info[self.config.okta_app]['name']))
return aws_info[self.config.okta_app]

app_strs = []
for i, app in enumerate(aws_info):
app_strs.append('[{}] {}'.format(i, app["name"]))
Expand Down Expand Up @@ -415,6 +419,10 @@ def _choose_roles(self, roles):
self.ui.info("Detected single role: {}".format(single_role))
return {single_role}

if self.config.okta_role is not None:
self.ui.info("Detected role in config: {}".format(roles[self.config.okta_role].role))
return {roles[self.config.okta_role].role}

# Gather the roles available to the user.
role_strs = self.resolver._display_role(roles)

Expand Down Expand Up @@ -549,6 +557,9 @@ def okta(self):
if self.conf_dict.get('preferred_mfa_type'):
okta.set_preferred_mfa_type(self.conf_dict['preferred_mfa_type'])

if self.conf_dict.get('preffered_mfa_provider'):
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added preffered_mfa_provider option in okta_aws_login_config. This will automatically select the specific mfa provider type like GOOGLE.

okta.set_preferred_mfa_provider(self.conf_dict['preffered_mfa_provider'])
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Spelling error - preferred_mfa_provider, not preffered_mfa_provider


if self.config.mfa_code is not None:
okta.set_mfa_code(self.config.mfa_code)
elif self.conf_dict.get('okta_mfa_code'):
Expand Down
9 changes: 8 additions & 1 deletion gimme_aws_creds/okta.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ def __init__(self, gac_ui, okta_org_url, verify_ssl_certs=True, device_token=Non
self._username = None
self._password = None
self._preferred_mfa_type = None
self._preferred_mfa_provider = None
self._mfa_code = None
self._remember_device = None

Expand Down Expand Up @@ -102,6 +103,9 @@ def set_password(self, password):
def set_preferred_mfa_type(self, preferred_mfa_type):
self._preferred_mfa_type = preferred_mfa_type

def set_preferred_mfa_provider(self, preferred_mfa_provider):
self._preferred_mfa_provider = preferred_mfa_provider

def set_mfa_code(self, mfa_code):
self._mfa_code = mfa_code

Expand Down Expand Up @@ -787,6 +791,9 @@ def _choose_factor(self, factors):
factor_name = self._build_factor_name(preferred_factors[0])
self.ui.info(factor_name + ' selected')
selection = factors.index(preferred_factors[0])
elif self._preferred_mfa_provider is not None:
self.ui.info('Detected preferred provider in config: {}'.format(self._preferred_mfa_provider))
selection = factors.index([v for v in factors if v['provider'] == self._preferred_mfa_provider][0])
else:
self.ui.info("Pick a factor:")
# print out the factors and let the user select
Expand Down Expand Up @@ -1028,7 +1035,7 @@ def _introspect_factors(self, state_token):
@staticmethod
def _extract_state_token_from_http_response(http_res):
saml_soup = BeautifulSoup(http_res.text, "html.parser")

mfa_string = (
'Dodatečné ověření',
'Ekstra verificering',
Expand Down