def setUp(self): """Set up for the unit tests""" self.config = Config(gac_ui=ui.cli, create_config=False)
class TestConfig(unittest.TestCase): """Class to test Config Class. Mock is used to mock external calls""" def setUp(self): """Set up for the unit tests""" self.config = Config(gac_ui=ui.cli, create_config=False) def tearDown(self): """Run Clean Up""" self.config.clean_up() @patch( "argparse.ArgumentParser.parse_args", return_value=argparse.Namespace( username="******", profile=None, insecure=False, resolve=None, mfa_code=None, remember_device=False, output_format=None, roles=None, action_register_device=False, action_configure=False, action_list_profiles=False, action_list_roles=False, action_store_json_creds=False, ), ) def test_get_args_username(self, mock_arg): """Test to make sure username gets returned""" self.config.get_args() assert_equals(self.config.username, "ann") def test_read_config(self): """Test to make sure getting config works""" test_ui = MockUserInterface(argv=[ "--profile", "myprofile", ]) with open(test_ui.HOME + "/.okta_aws_login_config", "w") as config_file: config_file.write(""" [myprofile] client_id = foo """) config = Config(gac_ui=test_ui, create_config=False) config.conf_profile = "myprofile" profile_config = config.get_config_dict() self.assertEqual(profile_config, {"client_id": "foo"}) def test_read_config_inherited(self): """Test to make sure getting config works when inherited""" test_ui = MockUserInterface(argv=[ "--profile", "myprofile", ]) with open(test_ui.HOME + "/.okta_aws_login_config", "w") as config_file: config_file.write(""" [mybase] client_id = bar aws_appname = baz [myprofile] inherits = mybase client_id = foo aws_rolename = myrole """) config = Config(gac_ui=test_ui, create_config=False) config.conf_profile = "myprofile" profile_config = config.get_config_dict() self.assertEqual(profile_config, { "client_id": "foo", "aws_appname": "baz", "aws_rolename": "myrole", })
def run(self): """ Pulling it all together to make the CLI """ config = Config() config.get_args() # Create/Update config when configure arg set if config.configure is True: config.update_config_file() exit() # get the config dict conf_dict = config.get_config_dict() if not conf_dict.get('okta_org_url'): print( 'No Okta organization URL in configuration. Try running --config again.', file=sys.stderr) exit(1) if not conf_dict.get('gimme_creds_server'): print( 'No Gimme-Creds server URL in configuration. Try running --config again.', file=sys.stderr) exit(1) if config.register_device is True: conf_dict['device_token'] = None else: if not conf_dict.get('device_token'): print( 'No device token in configuration. Try running --register_device again.', file=sys.stderr) exit(1) okta = OktaClient(conf_dict['okta_org_url'], config.verify_ssl_certs, conf_dict['device_token']) if config.resolve == True: self.resolver = AwsResolver(config.verify_ssl_certs) else: if conf_dict.get('resolve_aws_alias') and str( conf_dict['resolve_aws_alias']) == 'True': self.resolver = AwsResolver(config.verify_ssl_certs) if config.username is not None: okta.set_username(config.username) else: if conf_dict.get('okta_username'): okta.set_username(conf_dict['okta_username']) if conf_dict.get('preferred_mfa_type'): okta.set_preferred_mfa_type(conf_dict['preferred_mfa_type']) if config.mfa_code is not None: okta.set_mfa_code(config.mfa_code) # AWS Default session duration .... if conf_dict.get('aws_default_duration'): config.aws_default_duration = int( conf_dict['aws_default_duration']) else: config.aws_default_duration = 3600 # Capture the Device Token and write it to the config file if config.register_device is True: auth_result = okta.auth_session() conf_dict['device_token'] = auth_result['device_token'] config.write_config_file(conf_dict) print('Device token saved!', file=sys.stderr) sys.exit() else: # Call the Okta APIs and proces data locally if conf_dict.get('gimme_creds_server') == 'internal': # Okta API key is required when calling Okta APIs internally if config.api_key is None: print('OKTA_API_KEY environment variable not found!', file=sys.stderr) exit(1) auth_result = okta.auth_session() aws_results = self._get_aws_account_info( conf_dict['okta_org_url'], config.api_key, auth_result['username']) elif conf_dict.get('gimme_creds_server') == 'appurl': auth_result = okta.auth_session() # bypass lambda & API call # Apps url is required when calling with appurl if conf_dict.get('app_url'): config.app_url = conf_dict['app_url'] if config.app_url is None: print('app_url is not defined in your config !', file=sys.stderr) exit(1) # build app list aws_results = [] newAppEntry = {} newAppEntry['id'] = "fakeid" # not used anyway newAppEntry['name'] = "fakelabel" #not used anyway newAppEntry['links'] = {} newAppEntry['links']['appLink'] = config.app_url aws_results.append(newAppEntry) # Use the gimme_creds_lambda service else: if not conf_dict.get('client_id'): print( 'No OAuth Client ID in configuration. Try running --config again.', file=sys.stderr) if not conf_dict.get('okta_auth_server'): print( 'No OAuth Authorization server in configuration. Try running --config again.', file=sys.stderr) # Authenticate with Okta and get an OAuth access token okta.auth_oauth( conf_dict['client_id'], authorization_server=conf_dict['okta_auth_server'], access_token=True, id_token=False, scopes=['openid']) # Add Access Tokens to Okta-protected requests okta.use_oauth_access_token(True) print("Authentication Success! Calling Gimme-Creds Server...", file=sys.stderr) aws_results = self._call_gimme_creds_server( okta, conf_dict['gimme_creds_server']) aws_app = self._get_selected_app(conf_dict.get('aws_appname'), aws_results) saml_data = okta.get_saml_response(aws_app['links']['appLink']) roles = self.resolver._enumerate_saml_roles( saml_data['SAMLResponse'], saml_data['TargetUrl']) aws_role = self._get_selected_role(conf_dict.get('aws_rolename'), roles) aws_partition = self._get_partition_from_saml_acs( saml_data['TargetUrl']) for _, role in enumerate(roles): # Skip irrelevant roles if aws_role != 'all' and aws_role not in role.role: continue try: aws_creds = self._get_sts_creds(aws_partition, saml_data['SAMLResponse'], role.idp, role.role, config.aws_default_duration) except ClientError as ex: if ex.response['Error'][ 'Message'] == 'The requested DurationSeconds exceeds the MaxSessionDuration set for this role.': print( "The requested session duration was too long for this role. Falling back to 1 hour.", file=sys.stderr) aws_creds = self._get_sts_creds(aws_partition, saml_data['SAMLResponse'], role.idp, role.role, 3600) #TODO: Make this regex work for GovCloud ARNs too deriv_profname = re.sub('arn:(aws|aws-cn):iam:.*/', '', role.role) # check if write_aws_creds is true if so # get the profile name and write out the file if str(conf_dict['write_aws_creds']) == 'True': # set the profile name # Note if there are multiple roles, and 'default' is # selected it will be overwritten multiple times and last role # wins. if conf_dict['cred_profile'].lower() == 'default': profile_name = 'default' elif conf_dict['cred_profile'].lower() == 'role': profile_name = deriv_profname else: profile_name = conf_dict['cred_profile'] # Write out the AWS Config file print('writing role {} to {}'.format(role.role, self.AWS_CONFIG), file=sys.stderr) self._write_aws_creds(profile_name, aws_creds['AccessKeyId'], aws_creds['SecretAccessKey'], aws_creds['SessionToken']) else: #Print out temporary AWS credentials. Credentials are printed to stderr to simplify #redirection for use in automated scripts print("export AWS_ACCESS_KEY_ID=" + aws_creds['AccessKeyId']) print("export AWS_SECRET_ACCESS_KEY=" + aws_creds['SecretAccessKey']) print("export AWS_SESSION_TOKEN=" + aws_creds['SessionToken']) print("export AWS_SECURITY_TOKEN=" + aws_creds['SessionToken']) config.clean_up()
def setUp(self): """Set up for the unit tests""" self.config = Config()
class TestConfig(unittest.TestCase): """Class to test Config Class. Mock is used to mock external calls""" def setUp(self): """Set up for the unit tests""" self.config = Config(gac_ui=ui.cli, create_config=False) def tearDown(self): """Run Clean Up""" self.config.clean_up() @patch( "argparse.ArgumentParser.parse_args", return_value=argparse.Namespace( username="******", profile=None, insecure=False, resolve=None, mfa_code=None, remember_device=False, output_format=None, roles=None, action_register_device=False, action_configure=False, action_list_profiles=False, action_list_roles=False, action_store_json_creds=False, action_setup_fido_authenticator=False, ), ) def test_get_args_username(self, mock_arg): """Test to make sure username gets returned""" self.config.get_args() self.assertEqual(self.config.username, "ann") def test_read_config(self): """Test to make sure getting config works""" test_ui = MockUserInterface(argv=[ "--profile", "myprofile", ]) with open(test_ui.HOME + "/.okta_aws_login_config", "w") as config_file: config_file.write(""" [myprofile] client_id = foo """) config = Config(gac_ui=test_ui, create_config=False) config.conf_profile = "myprofile" profile_config = config.get_config_dict() self.assertEqual(profile_config, {"client_id": "foo"}) def test_read_config_inherited(self): """Test to make sure getting config works when inherited""" test_ui = MockUserInterface(argv=[ "--profile", "myprofile", ]) with open(test_ui.HOME + "/.okta_aws_login_config", "w") as config_file: config_file.write(""" [mybase] client_id = bar aws_appname = baz [myprofile] inherits = mybase client_id = foo aws_rolename = myrole """) config = Config(gac_ui=test_ui, create_config=False) config.conf_profile = "myprofile" profile_config = config.get_config_dict() self.assertEqual(profile_config, { "client_id": "foo", "aws_appname": "baz", "aws_rolename": "myrole", }) def test_read_nested_config_inherited(self): """Test to make sure getting config works when inherited""" test_ui = MockUserInterface(argv=[ "--profile", "myprofile", ]) with open(test_ui.HOME + "/.okta_aws_login_config", "w") as config_file: config_file.write(""" [mybase-level1] client_id = bar [mybase-level2] inherits = mybase-level1 aws_appname = baz [myprofile] inherits = mybase-level2 client_id = foo aws_rolename = myrole """) config = Config(gac_ui=test_ui, create_config=False) config.conf_profile = "myprofile" profile_config = config.get_config_dict() self.assertEqual(profile_config, { "client_id": "foo", "aws_appname": "baz", "aws_rolename": "myrole", }) def test_fail_if_profile_not_found(self): """Test to make sure missing Default fails properly""" test_ui = MockUserInterface(argv=[]) with open(test_ui.HOME + "/.okta_aws_login_config", "w") as config_file: config_file.write(""" [myprofile] client_id = foo """) config = Config(gac_ui=test_ui, create_config=False) config.conf_profile = "DEFAULT" with self.assertRaises(errors.GimmeAWSCredsError) as context: config.get_config_dict() self.assertTrue( 'DEFAULT profile is missing! This is profile is required when not using --profile' == context.exception.message)
def run(self): """ Pulling it all together to make the CLI """ config = Config() config.get_args() # Create/Update config when configure arg set if config.configure is True: config.update_config_file() exit() # get the config dict conf_dict = config.get_config_dict() if not conf_dict.get('okta_org_url'): print( 'No Okta organization URL in configuration. Try running --config again.' ) exit(1) if not conf_dict.get('gimme_creds_server'): print( 'No Gimme-Creds server URL in configuration. Try running --config again.' ) exit(1) okta = OktaClient(conf_dict['okta_org_url'], config.verify_ssl_certs) if config.username is not None: okta.set_username(config.username) # Call the Okta APIs and proces data locally if conf_dict.get('gimme_creds_server') == 'internal': # Okta API key is required when calling Okta APIs internally if config.api_key is None: print('OKTA_API_KEY environment variable not found!') exit(1) # Authenticate with Okta auth_result = okta.auth_session() print("Authentication Success! Getting AWS Accounts") aws_results = self._get_aws_account_info(conf_dict['okta_org_url'], config.api_key, auth_result['username']) # Use the gimme_creds_lambda service else: if not conf_dict.get('client_id'): print( 'No OAuth Client ID in configuration. Try running --config again.' ) if not conf_dict.get('okta_auth_server'): print( 'No OAuth Authorization server in configuration. Try running --config again.' ) # Authenticate with Okta and get an OAuth access token okta.auth_oauth(conf_dict['client_id'], authorization_server=conf_dict['okta_auth_server'], access_token=True, id_token=False, scopes=['openid']) # Add Access Tokens to Okta-protected requests okta.use_oauth_access_token(True) print("Authentication Success! Calling Gimme-Creds Server...") aws_results = self._call_gimme_creds_server( okta, conf_dict['gimme_creds_server']) aws_app = self._get_selected_app(conf_dict.get('aws_appname'), aws_results) saml_data = okta.get_saml_response(aws_app['links']['appLink']) roles = self._enumerate_saml_roles(saml_data['SAMLResponse']) aws_role = self._get_selected_role(conf_dict.get('aws_rolename'), roles) aws_partition = self._get_partition_from_saml_acs( saml_data['TargetUrl']) for _, role in enumerate(roles): # Skip irrelevant roles if aws_role != 'all' and aws_role not in role.role: continue aws_creds = self._get_sts_creds(aws_partition, saml_data['SAMLResponse'], role.idp, role.role) deriv_profname = re.sub('arn:aws:iam:.*/', '', role.role) # check if write_aws_creds is true if so # get the profile name and write out the file if str(conf_dict['write_aws_creds']) == 'True': # set the profile name # Note if there are multiple roles, and 'default' is # selected it will be overwritten multiple times and last role # wins. if conf_dict['cred_profile'].lower() == 'default': profile_name = 'default' elif conf_dict['cred_profile'].lower() == 'role': profile_name = deriv_profname else: profile_name = conf_dict['cred_profile'] # Write out the AWS Config file print('writing role {} to {}'.format(role.role, self.AWS_CONFIG)) self._write_aws_creds(profile_name, aws_creds['AccessKeyId'], aws_creds['SecretAccessKey'], aws_creds['SessionToken']) else: #Print out temporary AWS credentials. Credentials are printed to stderr to simplify #redirection for use in automated scripts print("\nexport AWS_PROFILE=" + deriv_profname, file=sys.stderr) print("export AWS_ACCESS_KEY_ID=" + aws_creds['AccessKeyId'], file=sys.stderr) print("export AWS_SECRET_ACCESS_KEY=" + aws_creds['SecretAccessKey'], file=sys.stderr) print("export AWS_SESSION_TOKEN=" + aws_creds['SessionToken'], file=sys.stderr) config.clean_up()