def __initialize_configuration(self): """ Load config file, both the desired section and the default section :return: the parameter list :rtype: dict """ clokta_cfg_file = configparser.ConfigParser() clokta_cfg_file.read(self.clokta_config_file) # Make sure we have the bare minimum in the config file. The DEFAULT section and the app URL. if not clokta_cfg_file['DEFAULT']: clokta_cfg_file['DEFAULT'] = {'okta_org': ''} if not clokta_cfg_file.has_section(self.profile_name): msg = 'No profile "{}" in clokta.cfg, but enter the information and clokta will create a profile.\n' + \ 'Copy the link from the Okta App' app_url = click.prompt(text=msg.format(self.profile_name), type=str, err=Common.to_std_error()).strip() if not app_url.startswith("https://") or not app_url.endswith( "?fromHome=true"): Common.dump_err( "Invalid App URL. URL usually of the form https://xxxxxxxx.okta.com/.../272?fromHome=true", 6) raise ValueError("Invalid URL") else: app_url = app_url[:-len("?fromHome=true")] clokta_cfg_file.add_section(self.profile_name) clokta_cfg_file.set(self.profile_name, 'okta_aws_app_url', app_url) config_section = clokta_cfg_file[self.profile_name] self.__load_parameters(config_section) if self.get('save_password_in_keychain') == 'True': self.parameters[ 'okta_password'].save_to = ConfigParameter.SaveTo.KEYRING
def __initialize_configuration(self): """ Load config file, both the desired section and the default section :return: the parameter list :rtype: dict """ clokta_cfg_file = configparser.ConfigParser() clokta_cfg_file.read(self.clokta_config_file) # Make sure we have the bare minimum in the config file. The DEFAULT section and the app URL. if not clokta_cfg_file['DEFAULT']: clokta_cfg_file['DEFAULT'] = {} if not clokta_cfg_file.has_section(self.profile_name): msg = 'No profile "{}" in clokta.cfg, but enter the information and clokta will create a profile.\n' + \ 'Copy the link from the Okta App' app_url = click.prompt(text=msg.format(self.profile_name), type=str, err=Common.to_std_error()).strip() app_url = self.__check_url(app_url) clokta_cfg_file.add_section(self.profile_name) clokta_cfg_file.set(self.profile_name, 'okta_aws_app_url', app_url) config_section = clokta_cfg_file[self.profile_name] self.__load_parameters(config_section) if self.get('save_password_in_keychain') == 'True': self.parameters[ 'okta_password'].save_to = ConfigParameter.SaveTo.KEYRING
def __prompt_for(self, param): prompt = param.prompt if param.prompt else 'Enter a value for {}'.format( param.name) if param.secret: field_value = getpass.getpass(prompt=prompt + ":") else: field_value = click.prompt(text=prompt, type=param.param_type, err=Common.to_std_error(), default=param.default_value, show_default=not param.prompt) return field_value if param.param_type == str else str(field_value)
def __prompt_for_role(self, with_set_default_option): """ Give the user a choice from the intersection of configured and supported factors :param with_set_default_option: if True will add an option for setting a default role :type with_set_default_option: bool :return: a tuple of what role was chosen and whether it is the new default :rtype: AwsRole, bool """ index = 1 for role in self.possible_roles: msg = '{index} - {prompt}'.format(index=index, prompt=role.role_name) Common.echo(message=msg, bold=True) index += 1 if with_set_default_option: Common.echo('{index} - set a default role'.format(index=index)) raw_choice = None try: raw_choice = click.prompt(text='Choose a Role ARN to use', type=int, err=Common.to_std_error()) choice = raw_choice - 1 except ValueError: Common.echo(message='Please select a valid option: you chose: {}'. format(raw_choice)) return self.__prompt_for_role() if choice == len(self.possible_roles): # They want to set a default. Prompt again (just without the set-default option) # and return that chosen role and that it's the new default chosen_option, _ = self.__prompt_for_role( with_set_default_option=False) return chosen_option, True if len(self.possible_roles) > choice >= 0: pass else: Common.echo(message='Please select a valid option: you chose: {}'. format(raw_choice)) return self.__prompt_for_role( with_set_default_option=with_set_default_option) chosen_option = self.possible_roles[choice] if Common.is_debug(): Common.dump_out( message='Using chosen Role {role} & IDP {idp}'.format( role=chosen_option.role_arn, idp=chosen_option.idp_arn)) return chosen_option, False
def choose_supported_factor(self): """ Give the user a choice from the intersection of configured and supported factors """ index = 1 for opt in self.option_factors: msg = '{index} - {prompt}'.format(index=index, prompt=opt['prompt']) Common.echo(message=msg, bold=True) index += 1 raw_choice = None try: raw_choice = click.prompt('Choose a MFA type to use', type=int, err=Common.to_std_error()) choice = raw_choice - 1 except ValueError: Common.echo(message='Please select a valid option: you chose: {}'. format(raw_choice)) return self.choose_supported_factor() if len(self.option_factors) > choice >= 0: pass else: Common.echo(message='Please select a valid option: you chose: {}'. format(raw_choice)) return self.choose_supported_factor() chosen_option = self.option_factors[choice] matching_okta_factor = [ fact for fact in self.okta_factors if fact['provider'] == chosen_option['provider'] and fact['factorType'] == chosen_option['factor_type'] ] if Common.is_debug(): Common.dump_out(message='Using chosen factor: {}'.format( chosen_option['prompt'])) return matching_okta_factor[0]
def determine_okta_onetimepassword(self, factor, first_time): """ Get the one time password, which may be in one password or may need to be prompted for :param factor: the mfa mechanism being used. Holds a user friendly label for identifying which mechanism. :type factor: dict :param first_time: whether this is the first time this run determining one time password on subsequent attempts we don't try to get it with an otp secret because that obviously didn't work the first time :return: the Okta one time password :rtype: string """ otp_value = None if self.get('okta_onetimepassword_secret'): if not first_time: Common.dump_err("OTP generator created incorrect OTP") else: try: # noinspection PyUnresolvedReferences import onetimepass as otp except ImportError: msg = 'okta_onetimepassword_secret provided in config but "onetimepass" is not installed. ' + \ 'run: pip install onetimepass' Common.dump_err(message=msg) raise ValueError("Illegal configuration") otp_value = otp.get_totp( self.get('okta_onetimepassword_secret')) if not otp_value: otp_value = click.prompt( text='Enter your {} one time password'.format( factor['clokta_id']), type=str, err=Common.to_std_error(), default='') return otp_value