Пример #1
0
    def __init__(self,
                 assertion,
                 credential_path='~/.aws',
                 profile='default',
                 region='us-east-1'):
        cred_dir = expanduser(credential_path)
        cred_file = os.path.join(cred_dir, 'credentials')

        boto_logger = logging.getLogger('botocore')
        boto_logger.setLevel(logging.WARNING)

        if not os.path.exists(cred_dir):
            log.info('Creating missing AWS Credentials dir {dir}'.format(
                dir=cred_dir))
            os.makedirs(cred_dir)

        self.sts = boto3.client('sts')

        self.profile = profile
        self.region = region

        self.assertion = SamlAssertion(assertion)
        self.writer = Credentials(cred_file)

        # Populated by self.assume_role()
        self.aws_access_key_id = None
        self.aws_secret_access_key = None
        self.aws_session_token = None
        self.expiration = None
        self.session_token = None
        self.role = None
Пример #2
0
    def test_principle_can_be_first(self):
        assertion = saml_assertion(["{},{}".format(idp_arn, dev_arn)])

        assert SamlAssertion(assertion).roles() == [{
            "role": dev_arn,
            "principle": idp_arn
        }]
Пример #3
0
    def test_white_space_is_removed(self):
        assertion = saml_assertion([" {},{} ".format(idp_arn, dev_arn)])

        assert SamlAssertion(assertion).roles() == [{
            "role": dev_arn,
            "principle": idp_arn
        }]
Пример #4
0
    def test_roles_are_extracted(self):
        assertion = saml_assertion(["{},{}".format(dev_arn, idp_arn)])

        assert SamlAssertion(assertion).roles() == [{
            "role": dev_arn,
            "principle": idp_arn
        }]
Пример #5
0
    def test_white_space_is_removed(self):
        assertion = saml_assertion([' {},{} '.format(idp_arn, dev_arn)])

        assert SamlAssertion(assertion).roles() == [{
            'role': dev_arn,
            'principle': idp_arn
        }]
Пример #6
0
    def test_principle_can_be_first(self):
        assertion = saml_assertion(['{},{}'.format(idp_arn, dev_arn)])

        assert SamlAssertion(assertion).roles() == [{
            'role': dev_arn,
            'principle': idp_arn
        }]
Пример #7
0
    def test_roles_are_extracted(self):
        assertion = saml_assertion(['{},{}'.format(dev_arn, idp_arn)])

        assert SamlAssertion(assertion).roles() == [{
            'role': dev_arn,
            'principle': idp_arn
        }]
Пример #8
0
    def test_multiple_roles_are_returned(self):
        assertion = saml_assertion([
            '{},{}'.format(dev_arn, idp_arn), '{},{}'.format(qa_arn, idp2_arn)
        ])

        assert SamlAssertion(assertion).roles() == [{
            'role': dev_arn,
            'principle': idp_arn
        }, {
            'role': qa_arn,
            'principle': idp2_arn
        }]
Пример #9
0
    def test_multiple_roles_are_returned(self):
        assertion = saml_assertion([
            "{},{}".format(dev_arn, idp_arn), "{},{}".format(qa_arn, idp2_arn)
        ])

        assert SamlAssertion(assertion).roles() == [
            {
                "role": dev_arn,
                "principle": idp_arn
            },
            {
                "role": qa_arn,
                "principle": idp2_arn
            },
        ]
Пример #10
0
class Session(object):
    '''Amazon Federated Session Generator.

    This class is used to contact Amazon with a specific SAML Assertion and
    get back a set of temporary Federated credentials. These credentials are
    written to disk (using the Credentials object above).

    This object is meant to be used once -- as SAML Assertions are one-time-use
    objects.
    '''
    def __init__(self,
                 assertion,
                 credential_path='~/.aws',
                 profile='default',
                 region='us-east-1'):
        cred_dir = expanduser(credential_path)
        cred_file = os.path.join(cred_dir, 'credentials')

        boto_logger = logging.getLogger('botocore')
        boto_logger.setLevel(logging.WARNING)

        if not os.path.exists(cred_dir):
            log.info('Creating missing AWS Credentials dir {dir}'.format(
                dir=cred_dir))
            os.makedirs(cred_dir)

        self.sts = boto3.client('sts')

        self.profile = profile
        self.region = region

        self.assertion = SamlAssertion(assertion)
        self.writer = Credentials(cred_file)

        # Populated by self.assume_role()
        self.aws_access_key_id = None
        self.aws_secret_access_key = None
        self.aws_session_token = None
        self.expiration = None
        self.session_token = None
        self.role = None

    @property
    def is_valid(self):
        '''Returns True if the Session is still valid.

        Takes the current time (in UTC) and compares it to the Expiration time
        returned by Amazon. Adds a 10 minute buffer to make sure that we start
        working to renew the creds far before they really expire and break.

        Args:
            now: A datetime.datetime() object (likely
            datetime.datetime.utcnow())
            buffer: Number of seconds before the actual expiration before we
            start returning false.

        Returns:
            Bool
        '''
        # Consider the tokens expired when they have 10m left
        try:
            buffer = datetime.timedelta(seconds=600)
            now = datetime.datetime.utcnow()
            expir = datetime.datetime.strptime(str(self.expiration),
                                               '%Y-%m-%d %H:%M:%S+00:00')

            return (now + buffer) < expir
        except ValueError:
            return False

    def set_role(self, role_index):
        '''Sets the role based on the supplied index value'''
        self.role = self.assertion.roles()[int(role_index)]

    def available_roles(self):
        '''Returns the roles availble from AWS'''
        return self.assertion.roles()

    def assume_role(self):
        '''Use the SAML Assertion to actually get the credentials.

        Uses the supplied (one time use!) SAML Assertion to go out to Amazon
        and get back a set of temporary credentials. These are written out to
        disk and can be used for an hour before they need to be replaced.
        '''
        if self.role is None:
            try:
                if len(self.assertion.roles()) > 1:
                    raise MultipleRoles
                self.role = self.assertion.roles()[0]
            except xml.etree.ElementTree.ParseError:
                log.error('Could not find any Role in the SAML assertion')
                log.error(self.assertion.__dict__)
                raise InvalidSaml()

        log.info('Assuming role: {}'.format(self.role['role']))

        session = self.sts.assume_role_with_saml(
            RoleArn=self.role['role'],
            PrincipalArn=self.role['principle'],
            SAMLAssertion=self.assertion.encode())
        creds = session['Credentials']

        self.aws_access_key_id = creds['AccessKeyId']
        self.aws_secret_access_key = creds['SecretAccessKey']
        self.session_token = creds['SessionToken']
        self.expiration = creds['Expiration']

        self._write()

    def _write(self):
        '''Writes out our secrets to the Credentials object'''
        self.writer.add_profile(name=self.profile,
                                region=self.region,
                                access_key=self.aws_access_key_id,
                                secret_key=self.aws_secret_access_key,
                                session_token=self.session_token)
        log.info('Session expires at {time}'.format(time=self.expiration))
Пример #11
0
 def test_assertion_is_encoded(self):
     test_str = str.encode("test encoding")
     assert SamlAssertion(test_str).encode() == "dGVzdCBlbmNvZGluZw=="