Merge pull request #2494 from edekadigital/add-iam-open-id-connect-provider
Add iam open id connect provider
This commit is contained in:
commit
b433399cb5
@ -3163,7 +3163,7 @@
|
||||
- [ ] describe_events
|
||||
|
||||
## iam
|
||||
55% implemented
|
||||
57% implemented
|
||||
- [ ] add_client_id_to_open_id_connect_provider
|
||||
- [X] add_role_to_instance_profile
|
||||
- [X] add_user_to_group
|
||||
@ -3176,7 +3176,7 @@
|
||||
- [X] create_group
|
||||
- [X] create_instance_profile
|
||||
- [X] create_login_profile
|
||||
- [ ] create_open_id_connect_provider
|
||||
- [X] create_open_id_connect_provider
|
||||
- [X] create_policy
|
||||
- [X] create_policy_version
|
||||
- [X] create_role
|
||||
@ -3193,7 +3193,7 @@
|
||||
- [ ] delete_group_policy
|
||||
- [ ] delete_instance_profile
|
||||
- [X] delete_login_profile
|
||||
- [ ] delete_open_id_connect_provider
|
||||
- [X] delete_open_id_connect_provider
|
||||
- [X] delete_policy
|
||||
- [X] delete_policy_version
|
||||
- [X] delete_role
|
||||
@ -3227,7 +3227,7 @@
|
||||
- [X] get_group_policy
|
||||
- [X] get_instance_profile
|
||||
- [X] get_login_profile
|
||||
- [ ] get_open_id_connect_provider
|
||||
- [X] get_open_id_connect_provider
|
||||
- [ ] get_organizations_access_report
|
||||
- [X] get_policy
|
||||
- [X] get_policy_version
|
||||
@ -3253,7 +3253,7 @@
|
||||
- [ ] list_instance_profiles
|
||||
- [ ] list_instance_profiles_for_role
|
||||
- [X] list_mfa_devices
|
||||
- [ ] list_open_id_connect_providers
|
||||
- [X] list_open_id_connect_providers
|
||||
- [X] list_policies
|
||||
- [ ] list_policies_granting_service_access
|
||||
- [X] list_policy_versions
|
||||
|
@ -93,3 +93,27 @@ class TooManyTags(RESTError):
|
||||
super(TooManyTags, self).__init__(
|
||||
'ValidationError', "1 validation error detected: Value '{}' at '{}' failed to satisfy "
|
||||
"constraint: Member must have length less than or equal to 50.".format(tags, param))
|
||||
|
||||
|
||||
class EntityAlreadyExists(RESTError):
|
||||
code = 409
|
||||
|
||||
def __init__(self):
|
||||
super(EntityAlreadyExists, self).__init__(
|
||||
'EntityAlreadyExists', "Unknown")
|
||||
|
||||
|
||||
class ValidationError(RESTError):
|
||||
code = 400
|
||||
|
||||
def __init__(self, message):
|
||||
super(ValidationError, self).__init__(
|
||||
'ValidationError', message)
|
||||
|
||||
|
||||
class InvalidInput(RESTError):
|
||||
code = 400
|
||||
|
||||
def __init__(self, message):
|
||||
super(InvalidInput, self).__init__(
|
||||
'InvalidInput', message)
|
||||
|
@ -7,6 +7,7 @@ import re
|
||||
|
||||
from cryptography import x509
|
||||
from cryptography.hazmat.backends import default_backend
|
||||
from six.moves.urllib.parse import urlparse
|
||||
|
||||
from moto.core.exceptions import RESTError
|
||||
from moto.core import BaseBackend, BaseModel
|
||||
@ -14,8 +15,9 @@ from moto.core.utils import iso_8601_datetime_without_milliseconds, iso_8601_dat
|
||||
from moto.iam.policy_validation import IAMPolicyDocumentValidator
|
||||
|
||||
from .aws_managed_policies import aws_managed_policies_data
|
||||
from .exceptions import IAMNotFoundException, IAMConflictException, IAMReportNotPresentException, IAMLimitExceededException, \
|
||||
MalformedCertificate, DuplicateTags, TagKeyTooBig, InvalidTagCharacters, TooManyTags, TagValueTooBig
|
||||
from .exceptions import (IAMNotFoundException, IAMConflictException, IAMReportNotPresentException, IAMLimitExceededException,
|
||||
MalformedCertificate, DuplicateTags, TagKeyTooBig, InvalidTagCharacters, TooManyTags, TagValueTooBig,
|
||||
EntityAlreadyExists, ValidationError, InvalidInput)
|
||||
from .utils import random_access_key, random_alphanumeric, random_resource_id, random_policy_id
|
||||
|
||||
ACCOUNT_ID = 123456789012
|
||||
@ -93,6 +95,82 @@ class SAMLProvider(BaseModel):
|
||||
return "arn:aws:iam::{0}:saml-provider/{1}".format(ACCOUNT_ID, self.name)
|
||||
|
||||
|
||||
class OpenIDConnectProvider(BaseModel):
|
||||
def __init__(self, url, thumbprint_list, client_id_list=None):
|
||||
self._errors = []
|
||||
self._validate(url, thumbprint_list, client_id_list)
|
||||
|
||||
parsed_url = urlparse(url)
|
||||
self.url = parsed_url.netloc + parsed_url.path
|
||||
self.thumbprint_list = thumbprint_list
|
||||
self.client_id_list = client_id_list
|
||||
self.create_date = datetime.utcnow()
|
||||
|
||||
@property
|
||||
def arn(self):
|
||||
return 'arn:aws:iam::{0}:oidc-provider/{1}'.format(ACCOUNT_ID, self.url)
|
||||
|
||||
@property
|
||||
def created_iso_8601(self):
|
||||
return iso_8601_datetime_without_milliseconds(self.create_date)
|
||||
|
||||
def _validate(self, url, thumbprint_list, client_id_list):
|
||||
if any(len(client_id) > 255 for client_id in client_id_list):
|
||||
self._errors.append(self._format_error(
|
||||
key='clientIDList',
|
||||
value=client_id_list,
|
||||
constraint='Member must satisfy constraint: '
|
||||
'[Member must have length less than or equal to 255, '
|
||||
'Member must have length greater than or equal to 1]',
|
||||
))
|
||||
|
||||
if any(len(thumbprint) > 40 for thumbprint in thumbprint_list):
|
||||
self._errors.append(self._format_error(
|
||||
key='thumbprintList',
|
||||
value=thumbprint_list,
|
||||
constraint='Member must satisfy constraint: '
|
||||
'[Member must have length less than or equal to 40, '
|
||||
'Member must have length greater than or equal to 40]',
|
||||
))
|
||||
|
||||
if len(url) > 255:
|
||||
self._errors.append(self._format_error(
|
||||
key='url',
|
||||
value=url,
|
||||
constraint='Member must have length less than or equal to 255',
|
||||
))
|
||||
|
||||
self._raise_errors()
|
||||
|
||||
parsed_url = urlparse(url)
|
||||
if not parsed_url.scheme or not parsed_url.netloc:
|
||||
raise ValidationError('Invalid Open ID Connect Provider URL')
|
||||
|
||||
if len(thumbprint_list) > 5:
|
||||
raise InvalidInput('Thumbprint list must contain fewer than 5 entries.')
|
||||
|
||||
if len(client_id_list) > 100:
|
||||
raise IAMLimitExceededException('Cannot exceed quota for ClientIdsPerOpenIdConnectProvider: 100')
|
||||
|
||||
def _format_error(self, key, value, constraint):
|
||||
return 'Value "{value}" at "{key}" failed to satisfy constraint: {constraint}'.format(
|
||||
constraint=constraint,
|
||||
key=key,
|
||||
value=value,
|
||||
)
|
||||
|
||||
def _raise_errors(self):
|
||||
if self._errors:
|
||||
count = len(self._errors)
|
||||
plural = "s" if len(self._errors) > 1 else ""
|
||||
errors = "; ".join(self._errors)
|
||||
self._errors = [] # reset collected errors
|
||||
|
||||
raise ValidationError('{count} validation error{plural} detected: {errors}'.format(
|
||||
count=count, plural=plural, errors=errors,
|
||||
))
|
||||
|
||||
|
||||
class PolicyVersion(object):
|
||||
|
||||
def __init__(self,
|
||||
@ -515,6 +593,7 @@ class IAMBackend(BaseBackend):
|
||||
self.managed_policies = self._init_managed_policies()
|
||||
self.account_aliases = []
|
||||
self.saml_providers = {}
|
||||
self.open_id_providers = {}
|
||||
self.policy_arn_regex = re.compile(
|
||||
r'^arn:aws:iam::[0-9]*:policy/.*$')
|
||||
super(IAMBackend, self).__init__()
|
||||
@ -1264,5 +1343,28 @@ class IAMBackend(BaseBackend):
|
||||
return user
|
||||
return None
|
||||
|
||||
def create_open_id_connect_provider(self, url, thumbprint_list, client_id_list):
|
||||
open_id_provider = OpenIDConnectProvider(url, thumbprint_list, client_id_list)
|
||||
|
||||
if open_id_provider.arn in self.open_id_providers:
|
||||
raise EntityAlreadyExists
|
||||
|
||||
self.open_id_providers[open_id_provider.arn] = open_id_provider
|
||||
return open_id_provider
|
||||
|
||||
def delete_open_id_connect_provider(self, arn):
|
||||
self.open_id_providers.pop(arn, None)
|
||||
|
||||
def get_open_id_connect_provider(self, arn):
|
||||
open_id_provider = self.open_id_providers.get(arn)
|
||||
|
||||
if not open_id_provider:
|
||||
raise IAMNotFoundException('OpenIDConnect Provider not found for arn {}'.format(arn))
|
||||
|
||||
return open_id_provider
|
||||
|
||||
def list_open_id_connect_providers(self):
|
||||
return list(self.open_id_providers.keys())
|
||||
|
||||
|
||||
iam_backend = IAMBackend()
|
||||
|
@ -755,6 +755,38 @@ class IamResponse(BaseResponse):
|
||||
template = self.response_template(UNTAG_ROLE_TEMPLATE)
|
||||
return template.render()
|
||||
|
||||
def create_open_id_connect_provider(self):
|
||||
open_id_provider_url = self._get_param('Url')
|
||||
thumbprint_list = self._get_multi_param('ThumbprintList.member')
|
||||
client_id_list = self._get_multi_param('ClientIDList.member')
|
||||
|
||||
open_id_provider = iam_backend.create_open_id_connect_provider(open_id_provider_url, thumbprint_list, client_id_list)
|
||||
|
||||
template = self.response_template(CREATE_OPEN_ID_CONNECT_PROVIDER_TEMPLATE)
|
||||
return template.render(open_id_provider=open_id_provider)
|
||||
|
||||
def delete_open_id_connect_provider(self):
|
||||
open_id_provider_arn = self._get_param('OpenIDConnectProviderArn')
|
||||
|
||||
iam_backend.delete_open_id_connect_provider(open_id_provider_arn)
|
||||
|
||||
template = self.response_template(DELETE_OPEN_ID_CONNECT_PROVIDER_TEMPLATE)
|
||||
return template.render()
|
||||
|
||||
def get_open_id_connect_provider(self):
|
||||
open_id_provider_arn = self._get_param('OpenIDConnectProviderArn')
|
||||
|
||||
open_id_provider = iam_backend.get_open_id_connect_provider(open_id_provider_arn)
|
||||
|
||||
template = self.response_template(GET_OPEN_ID_CONNECT_PROVIDER_TEMPLATE)
|
||||
return template.render(open_id_provider=open_id_provider)
|
||||
|
||||
def list_open_id_connect_providers(self):
|
||||
open_id_provider_arns = iam_backend.list_open_id_connect_providers()
|
||||
|
||||
template = self.response_template(LIST_OPEN_ID_CONNECT_PROVIDERS_TEMPLATE)
|
||||
return template.render(open_id_provider_arns=open_id_provider_arns)
|
||||
|
||||
|
||||
LIST_ENTITIES_FOR_POLICY_TEMPLATE = """<ListEntitiesForPolicyResponse>
|
||||
<ListEntitiesForPolicyResult>
|
||||
@ -1974,3 +2006,57 @@ UNTAG_ROLE_TEMPLATE = """<UntagRoleResponse xmlns="https://iam.amazonaws.com/doc
|
||||
<RequestId>EXAMPLE8-90ab-cdef-fedc-ba987EXAMPLE</RequestId>
|
||||
</ResponseMetadata>
|
||||
</UntagRoleResponse>"""
|
||||
|
||||
|
||||
CREATE_OPEN_ID_CONNECT_PROVIDER_TEMPLATE = """<CreateOpenIDConnectProviderResponse xmlns="https://iam.amazonaws.com/doc/2010-05-08/">
|
||||
<CreateOpenIDConnectProviderResult>
|
||||
<OpenIDConnectProviderArn>{{ open_id_provider.arn }}</OpenIDConnectProviderArn>
|
||||
</CreateOpenIDConnectProviderResult>
|
||||
<ResponseMetadata>
|
||||
<RequestId>f248366a-4f64-11e4-aefa-bfd6aEXAMPLE</RequestId>
|
||||
</ResponseMetadata>
|
||||
</CreateOpenIDConnectProviderResponse>"""
|
||||
|
||||
|
||||
DELETE_OPEN_ID_CONNECT_PROVIDER_TEMPLATE = """<DeleteOpenIDConnectProviderResponse xmlns="https://iam.amazonaws.com/doc/2010-05-08/">
|
||||
<ResponseMetadata>
|
||||
<RequestId>b5e49e29-4f64-11e4-aefa-bfd6aEXAMPLE</RequestId>
|
||||
</ResponseMetadata>
|
||||
</DeleteOpenIDConnectProviderResponse>"""
|
||||
|
||||
|
||||
GET_OPEN_ID_CONNECT_PROVIDER_TEMPLATE = """<GetOpenIDConnectProviderResponse xmlns="https://iam.amazonaws.com/doc/2010-05-08/">
|
||||
<GetOpenIDConnectProviderResult>
|
||||
<ThumbprintList>
|
||||
{% for thumbprint in open_id_provider.thumbprint_list %}
|
||||
<member>{{ thumbprint }}</member>
|
||||
{% endfor %}
|
||||
</ThumbprintList>
|
||||
<CreateDate>{{ open_id_provider.created_iso_8601 }}</CreateDate>
|
||||
<ClientIDList>
|
||||
{% for client_id in open_id_provider.client_id_list %}
|
||||
<member>{{ client_id }}</member>
|
||||
{% endfor %}
|
||||
</ClientIDList>
|
||||
<Url>{{ open_id_provider.url }}</Url>
|
||||
</GetOpenIDConnectProviderResult>
|
||||
<ResponseMetadata>
|
||||
<RequestId>2c91531b-4f65-11e4-aefa-bfd6aEXAMPLE</RequestId>
|
||||
</ResponseMetadata>
|
||||
</GetOpenIDConnectProviderResponse>"""
|
||||
|
||||
|
||||
LIST_OPEN_ID_CONNECT_PROVIDERS_TEMPLATE = """<ListOpenIDConnectProvidersResponse xmlns="https://iam.amazonaws.com/doc/2010-05-08/">
|
||||
<ListOpenIDConnectProvidersResult>
|
||||
<OpenIDConnectProviderList>
|
||||
{% for open_id_provider_arn in open_id_provider_arns %}
|
||||
<member>
|
||||
<Arn>{{ open_id_provider_arn }}</Arn>
|
||||
</member>
|
||||
{% endfor %}
|
||||
</OpenIDConnectProviderList>
|
||||
</ListOpenIDConnectProvidersResult>
|
||||
<ResponseMetadata>
|
||||
<RequestId>de2c0228-4f63-11e4-aefa-bfd6aEXAMPLE</RequestId>
|
||||
</ResponseMetadata>
|
||||
</ListOpenIDConnectProvidersResponse>"""
|
||||
|
@ -9,6 +9,8 @@ import sure # noqa
|
||||
import sys
|
||||
from boto.exception import BotoServerError
|
||||
from botocore.exceptions import ClientError
|
||||
from dateutil.tz import tzutc
|
||||
|
||||
from moto import mock_iam, mock_iam_deprecated
|
||||
from moto.iam.models import aws_managed_policies
|
||||
from nose.tools import assert_raises, assert_equals
|
||||
@ -1565,3 +1567,251 @@ def test_create_role_with_permissions_boundary():
|
||||
|
||||
# Ensure the PermissionsBoundary is included in role listing as well
|
||||
conn.list_roles().get('Roles')[0].get('PermissionsBoundary').should.equal(expected)
|
||||
|
||||
|
||||
@mock_iam
|
||||
def test_create_open_id_connect_provider():
|
||||
client = boto3.client('iam', region_name='us-east-1')
|
||||
response = client.create_open_id_connect_provider(
|
||||
Url='https://example.com',
|
||||
ThumbprintList=[] # even it is required to provide at least one thumbprint, AWS accepts an empty list
|
||||
)
|
||||
|
||||
response['OpenIDConnectProviderArn'].should.equal(
|
||||
'arn:aws:iam::123456789012:oidc-provider/example.com'
|
||||
)
|
||||
|
||||
response = client.create_open_id_connect_provider(
|
||||
Url='http://example.org',
|
||||
ThumbprintList=[
|
||||
'b' * 40
|
||||
],
|
||||
ClientIDList=[
|
||||
'b'
|
||||
]
|
||||
)
|
||||
|
||||
response['OpenIDConnectProviderArn'].should.equal(
|
||||
'arn:aws:iam::123456789012:oidc-provider/example.org'
|
||||
)
|
||||
|
||||
response = client.create_open_id_connect_provider(
|
||||
Url='http://example.org/oidc',
|
||||
ThumbprintList=[]
|
||||
)
|
||||
|
||||
response['OpenIDConnectProviderArn'].should.equal(
|
||||
'arn:aws:iam::123456789012:oidc-provider/example.org/oidc'
|
||||
)
|
||||
|
||||
response = client.create_open_id_connect_provider(
|
||||
Url='http://example.org/oidc-query?test=true',
|
||||
ThumbprintList=[]
|
||||
)
|
||||
|
||||
response['OpenIDConnectProviderArn'].should.equal(
|
||||
'arn:aws:iam::123456789012:oidc-provider/example.org/oidc-query'
|
||||
)
|
||||
|
||||
|
||||
@mock_iam
|
||||
def test_create_open_id_connect_provider_errors():
|
||||
client = boto3.client('iam', region_name='us-east-1')
|
||||
client.create_open_id_connect_provider(
|
||||
Url='https://example.com',
|
||||
ThumbprintList=[]
|
||||
)
|
||||
|
||||
client.create_open_id_connect_provider.when.called_with(
|
||||
Url='https://example.com',
|
||||
ThumbprintList=[]
|
||||
).should.throw(
|
||||
ClientError,
|
||||
'Unknown'
|
||||
)
|
||||
|
||||
client.create_open_id_connect_provider.when.called_with(
|
||||
Url='example.org',
|
||||
ThumbprintList=[]
|
||||
).should.throw(
|
||||
ClientError,
|
||||
'Invalid Open ID Connect Provider URL'
|
||||
)
|
||||
|
||||
client.create_open_id_connect_provider.when.called_with(
|
||||
Url='example',
|
||||
ThumbprintList=[]
|
||||
).should.throw(
|
||||
ClientError,
|
||||
'Invalid Open ID Connect Provider URL'
|
||||
)
|
||||
|
||||
client.create_open_id_connect_provider.when.called_with(
|
||||
Url='http://example.org',
|
||||
ThumbprintList=[
|
||||
'a' * 40,
|
||||
'b' * 40,
|
||||
'c' * 40,
|
||||
'd' * 40,
|
||||
'e' * 40,
|
||||
'f' * 40,
|
||||
]
|
||||
).should.throw(
|
||||
ClientError,
|
||||
'Thumbprint list must contain fewer than 5 entries.'
|
||||
)
|
||||
|
||||
too_many_client_ids = ['{}'.format(i) for i in range(101)]
|
||||
client.create_open_id_connect_provider.when.called_with(
|
||||
Url='http://example.org',
|
||||
ThumbprintList=[],
|
||||
ClientIDList=too_many_client_ids
|
||||
).should.throw(
|
||||
ClientError,
|
||||
'Cannot exceed quota for ClientIdsPerOpenIdConnectProvider: 100'
|
||||
)
|
||||
|
||||
too_long_url = 'b' * 256
|
||||
too_long_thumbprint = 'b' * 41
|
||||
too_long_client_id = 'b' * 256
|
||||
client.create_open_id_connect_provider.when.called_with(
|
||||
Url=too_long_url,
|
||||
ThumbprintList=[
|
||||
too_long_thumbprint
|
||||
],
|
||||
ClientIDList=[
|
||||
too_long_client_id
|
||||
]
|
||||
).should.throw(
|
||||
ClientError,
|
||||
'3 validation errors detected: '
|
||||
'Value "{0}" at "clientIDList" failed to satisfy constraint: '
|
||||
'Member must satisfy constraint: '
|
||||
'[Member must have length less than or equal to 255, '
|
||||
'Member must have length greater than or equal to 1]; '
|
||||
'Value "{1}" at "thumbprintList" failed to satisfy constraint: '
|
||||
'Member must satisfy constraint: '
|
||||
'[Member must have length less than or equal to 40, '
|
||||
'Member must have length greater than or equal to 40]; '
|
||||
'Value "{2}" at "url" failed to satisfy constraint: '
|
||||
'Member must have length less than or equal to 255'.format([too_long_client_id], [too_long_thumbprint], too_long_url)
|
||||
)
|
||||
|
||||
|
||||
@mock_iam
|
||||
def test_delete_open_id_connect_provider():
|
||||
client = boto3.client('iam', region_name='us-east-1')
|
||||
response = client.create_open_id_connect_provider(
|
||||
Url='https://example.com',
|
||||
ThumbprintList=[]
|
||||
)
|
||||
open_id_arn = response['OpenIDConnectProviderArn']
|
||||
|
||||
client.delete_open_id_connect_provider(
|
||||
OpenIDConnectProviderArn=open_id_arn
|
||||
)
|
||||
|
||||
client.get_open_id_connect_provider.when.called_with(
|
||||
OpenIDConnectProviderArn=open_id_arn
|
||||
).should.throw(
|
||||
ClientError,
|
||||
'OpenIDConnect Provider not found for arn {}'.format(open_id_arn)
|
||||
)
|
||||
|
||||
# deleting a non existing provider should be successful
|
||||
client.delete_open_id_connect_provider(
|
||||
OpenIDConnectProviderArn=open_id_arn
|
||||
)
|
||||
|
||||
|
||||
@mock_iam
|
||||
def test_get_open_id_connect_provider():
|
||||
client = boto3.client('iam', region_name='us-east-1')
|
||||
response = client.create_open_id_connect_provider(
|
||||
Url='https://example.com',
|
||||
ThumbprintList=[
|
||||
'b' * 40
|
||||
],
|
||||
ClientIDList=[
|
||||
'b'
|
||||
]
|
||||
)
|
||||
open_id_arn = response['OpenIDConnectProviderArn']
|
||||
|
||||
response = client.get_open_id_connect_provider(
|
||||
OpenIDConnectProviderArn=open_id_arn
|
||||
)
|
||||
|
||||
response['Url'].should.equal('example.com')
|
||||
response['ThumbprintList'].should.equal([
|
||||
'b' * 40
|
||||
])
|
||||
response['ClientIDList'].should.equal([
|
||||
'b'
|
||||
])
|
||||
response.should.have.key('CreateDate').should.be.a(datetime)
|
||||
|
||||
|
||||
@mock_iam
|
||||
def test_get_open_id_connect_provider_errors():
|
||||
client = boto3.client('iam', region_name='us-east-1')
|
||||
response = client.create_open_id_connect_provider(
|
||||
Url='https://example.com',
|
||||
ThumbprintList=[
|
||||
'b' * 40
|
||||
],
|
||||
ClientIDList=[
|
||||
'b'
|
||||
]
|
||||
)
|
||||
open_id_arn = response['OpenIDConnectProviderArn']
|
||||
|
||||
client.get_open_id_connect_provider.when.called_with(
|
||||
OpenIDConnectProviderArn=open_id_arn + '-not-existing'
|
||||
).should.throw(
|
||||
ClientError,
|
||||
'OpenIDConnect Provider not found for arn {}'.format(open_id_arn + '-not-existing')
|
||||
)
|
||||
|
||||
|
||||
@mock_iam
|
||||
def test_list_open_id_connect_providers():
|
||||
client = boto3.client('iam', region_name='us-east-1')
|
||||
response = client.create_open_id_connect_provider(
|
||||
Url='https://example.com',
|
||||
ThumbprintList=[]
|
||||
)
|
||||
open_id_arn_1 = response['OpenIDConnectProviderArn']
|
||||
|
||||
response = client.create_open_id_connect_provider(
|
||||
Url='http://example.org',
|
||||
ThumbprintList=[
|
||||
'b' * 40
|
||||
],
|
||||
ClientIDList=[
|
||||
'b'
|
||||
]
|
||||
)
|
||||
open_id_arn_2 = response['OpenIDConnectProviderArn']
|
||||
|
||||
response = client.create_open_id_connect_provider(
|
||||
Url='http://example.org/oidc',
|
||||
ThumbprintList=[]
|
||||
)
|
||||
open_id_arn_3 = response['OpenIDConnectProviderArn']
|
||||
|
||||
response = client.list_open_id_connect_providers()
|
||||
|
||||
sorted(response['OpenIDConnectProviderList'], key=lambda i: i['Arn']).should.equal(
|
||||
[
|
||||
{
|
||||
'Arn': open_id_arn_1
|
||||
},
|
||||
{
|
||||
'Arn': open_id_arn_2
|
||||
},
|
||||
{
|
||||
'Arn': open_id_arn_3
|
||||
}
|
||||
]
|
||||
)
|
||||
|
Loading…
Reference in New Issue
Block a user