Пример #1
0
 def setUp(self):
     """Set up for the unit tests"""
     self.config = Config(gac_ui=ui.cli, create_config=False)
Пример #2
0
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",
        })
Пример #3
0
    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()
Пример #4
0
 def setUp(self):
     """Set up for the unit tests"""
     self.config = Config()
Пример #5
0
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)
Пример #6
0
    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()