Exemplo n.º 1
0
    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)
            choice = raw_choice - 1
        except ValueError as err:
            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 self.verbose:
            Common.dump_verbose(message='Using chosen factor: {}'.format(
                chosen_option['prompt']))

        return matching_okta_factor[0]
Exemplo n.º 2
0
    def verify_preferred_factor(self):
        ''' Return the Okta MFA configuration for the matching, supported configuration '''
        preferred_factors = [
            opt for opt in self.option_factors
            if self.factor_preference == opt['prompt']
        ]
        if preferred_factors:
            if self.verbose:
                msg = 'Using preferred factor: {}'.format(
                    self.factor_preference)
                Common.dump_verbose(message=msg)

            matching_okta_factor = [
                fact for fact in self.okta_factors
                if fact['provider'] == preferred_factors[0]['provider']
                and fact['factorType'] == preferred_factors[0]['factor_type']
            ]

            return matching_okta_factor[0]

        else:
            msg = 'The MFA option ({}) in your configuration file is not available'.format(
                self.factor_preference)
            Common.dump_err(message=msg, exit_code=3, verbose=self.verbose)
Exemplo n.º 3
0
    def assume_role(self):
        ''' entry point for the cli tool '''
        profile_mgr = ProfileManager(profile_name=self.profile,
                                     verbose=self.verbose)
        configuration = profile_mgr.initialize_configuration()
        profile_mgr.update_configuration(profile_configuration=configuration)

        # Need a directory to store intermediate files.  Use the same directory that clokta configuration
        # is kept in
        self.data_dir = os.path.dirname(profile_mgr.config_location)

        saml_assertion = self.__saml_assertion_aws(session_token=None,
                                                   configuration=configuration)

        if not saml_assertion:
            if 'okta_password' not in configuration or not configuration[
                    'okta_password']:
                configuration['okta_password'] = profile_mgr.prompt_for(
                    'okta_password')

            session_token = self.__okta_session_token(
                configuration=configuration)
            if self.verbose:
                Common.dump_verbose(
                    message='Okta session token: {}'.format(session_token))

            saml_assertion = self.__saml_assertion_aws(
                session_token=session_token, configuration=configuration)

        idp_and_role_chooser = RoleChooser(
            saml_assertion=saml_assertion,
            role_preference=configuration.get('okta_aws_role_to_assume'),
            verbose=self.verbose)
        idp_role_tuple = idp_and_role_chooser.choose_idp_role_tuple()

        client = boto3.client('sts')
        # Try for a 12 hour session.  If it fails, try for shorter periods
        durations = [43200, 14400, 3600]
        for duration in durations:
            try:
                assumed_role_credentials = client.assume_role_with_saml(
                    RoleArn=idp_role_tuple[2],
                    PrincipalArn=idp_role_tuple[1],
                    SAMLAssertion=saml_assertion,
                    DurationSeconds=duration)
                if duration == 3600:
                    Common.echo(message='YOUR SESSION WILL ONLY LAST ONE HOUR')
                break
            except ClientError as e:
                # If we get a validation error and we have shorter durations to try, try a shorter duration
                if e.response['Error'][
                        'Code'] != 'ValidationError' or duration == durations[
                            -1]:
                    raise

        profile_mgr.apply_credentials(credentials=assumed_role_credentials,
                                      echo_message=True)
        bash_file = profile_mgr.write_sourceable_file(
            credentials=assumed_role_credentials)
        docker_file = profile_mgr.write_dockerenv_file(
            credentials=assumed_role_credentials)
        Common.echo(
            message=
            'AWS keys generated. To use, run "export AWS_PROFILE={prof}"\nor use files {file1} with docker compose or {file2} with shell scripts'
            .format(prof=self.profile, file1=docker_file, file2=bash_file))