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
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 }]
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 }]
def test_roles_are_extracted(self): assertion = saml_assertion(["{},{}".format(dev_arn, idp_arn)]) assert SamlAssertion(assertion).roles() == [{ "role": dev_arn, "principle": idp_arn }]
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 }]
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 }]
def test_roles_are_extracted(self): assertion = saml_assertion(['{},{}'.format(dev_arn, idp_arn)]) assert SamlAssertion(assertion).roles() == [{ 'role': dev_arn, 'principle': idp_arn }]
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 }]
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 }, ]
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))
def test_assertion_is_encoded(self): test_str = str.encode("test encoding") assert SamlAssertion(test_str).encode() == "dGVzdCBlbmNvZGluZw=="