-
Notifications
You must be signed in to change notification settings - Fork 5.5k
/
boto_cognitoidentity.py
422 lines (309 loc) · 14.7 KB
/
boto_cognitoidentity.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
# -*- coding: utf-8 -*-
'''
Connection module for Amazon CognitoIdentity
.. versionadded:: 2016.11.0
:configuration: This module accepts explicit CognitoIdentity credentials but can also
utilize IAM roles assigned to the instance trough Instance Profiles.
Dynamic credentials are then automatically obtained from AWS API and no
further configuration is necessary. More Information available at:
.. code-block:: text
http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/iam-roles-for-amazon-ec2.html
If IAM roles are not used you need to specify them either in a pillar or
in the minion's config file:
.. code-block:: yaml
cognitoidentity.keyid: GKTADJGHEIQSXMKKRBJ08H
cognitoidentity.key: askdjghsdfjkghWupUjasdflkdfklgjsdfjajkghs
A region may also be specified in the configuration:
.. code-block:: yaml
cognitoidentity.region: us-east-1
If a region is not specified, the default is us-east-1.
It's also possible to specify key, keyid and region via a profile, either
as a passed in dict, or as a string to pull from pillars or minion config:
.. code-block:: yaml
myprofile:
keyid: GKTADJGHEIQSXMKKRBJ08H
key: askdjghsdfjkghWupUjasdflkdfklgjsdfjajkghs
region: us-east-1
.. versionchanged:: 2015.8.0
All methods now return a dictionary. Create, delete, set, and
update methods return:
.. code-block:: yaml
created: true
or
.. code-block:: yaml
created: false
error:
message: error message
Request methods (e.g., `describe_identity_pools`) return:
.. code-block:: yaml
identity_pools:
- {...}
- {...}
or
.. code-block:: yaml
error:
message: error message
:depends: boto3
'''
# keep lint from choking on _get_conn and _cache_id
# pylint: disable=E0602
# Import Python libs
from __future__ import absolute_import, print_function, unicode_literals
import logging
# Import Salt libs
import salt.utils.compat
import salt.utils.versions
log = logging.getLogger(__name__)
# Import third party libs
# pylint: disable=import-error
try:
# pylint: disable=unused-import
import boto
import boto3
# pylint: enable=unused-import
from botocore.exceptions import ClientError
logging.getLogger('boto').setLevel(logging.CRITICAL)
logging.getLogger('boto3').setLevel(logging.CRITICAL)
HAS_BOTO = True
except ImportError:
HAS_BOTO = False
# pylint: enable=import-error
def __virtual__():
'''
Only load if boto libraries exist and if boto libraries are greater than
a given version.
'''
# the boto_cognitoidentity execution module relies on the connect_to_region() method
# which was added in boto 2.8.0
# https://github.com/boto/boto/commit/33ac26b416fbb48a60602542b4ce15dcc7029f12
return salt.utils.versions.check_boto_reqs(
boto_ver='2.8.0',
boto3_ver='1.2.1'
)
def __init__(opts):
salt.utils.compat.pack_dunder(__name__)
if HAS_BOTO:
__utils__['boto3.assign_funcs'](__name__, 'cognito-identity')
def _find_identity_pool_ids(name, pool_id, conn):
'''
Given identity pool name (or optionally a pool_id and name will be ignored),
find and return list of matching identity pool id's.
'''
ids = []
if pool_id is None:
for pools in __utils__['boto3.paged_call'](conn.list_identity_pools,
marker_flag='NextToken', marker_arg='NextToken', MaxResults=25):
for pool in pools['IdentityPools']:
if pool['IdentityPoolName'] == name:
ids.append(pool['IdentityPoolId'])
else:
ids.append(pool_id)
return ids
def describe_identity_pools(IdentityPoolName, IdentityPoolId=None,
region=None, key=None, keyid=None, profile=None):
'''
Given an identity pool name, (optionally if an identity pool id is given,
the given name will be ignored)
Returns a list of matched identity pool name's pool properties
CLI Example:
.. code-block:: bash
salt myminion boto_cognitoidentity.describe_identity_pools my_id_pool_name
salt myminion boto_cognitoidentity.describe_identity_pools '' IdentityPoolId=my_id_pool_id
'''
conn = _get_conn(region=region, key=key, keyid=keyid, profile=profile)
try:
ids = _find_identity_pool_ids(IdentityPoolName, IdentityPoolId, conn)
if ids:
results = []
for pool_id in ids:
response = conn.describe_identity_pool(IdentityPoolId=pool_id)
response.pop('ResponseMetadata', None)
results.append(response)
return {'identity_pools': results}
else:
return {'identity_pools': None}
except ClientError as e:
return {'error': __utils__['boto3.get_error'](e)}
def create_identity_pool(IdentityPoolName,
AllowUnauthenticatedIdentities=False,
SupportedLoginProviders=None,
DeveloperProviderName=None,
OpenIdConnectProviderARNs=None,
region=None, key=None, keyid=None, profile=None):
'''
Creates a new identity pool. All parameters except for IdentityPoolName is optional.
SupportedLoginProviders should be a dictionary mapping provider names to provider app
IDs. OpenIdConnectProviderARNs should be a list of OpenID Connect provider ARNs.
Returns the created identity pool if successful
CLI Example:
.. code-block:: bash
salt myminion boto_cognitoidentity.create_identity_pool my_id_pool_name \
DeveloperProviderName=custom_developer_provider
'''
SupportedLoginProviders = dict() if SupportedLoginProviders is None else SupportedLoginProviders
OpenIdConnectProviderARNs = list() if OpenIdConnectProviderARNs is None else OpenIdConnectProviderARNs
conn = _get_conn(region=region, key=key, keyid=keyid, profile=profile)
try:
request_params = dict(IdentityPoolName=IdentityPoolName,
AllowUnauthenticatedIdentities=AllowUnauthenticatedIdentities,
SupportedLoginProviders=SupportedLoginProviders,
OpenIdConnectProviderARNs=OpenIdConnectProviderARNs)
if DeveloperProviderName:
request_params['DeveloperProviderName'] = DeveloperProviderName
response = conn.create_identity_pool(**request_params)
response.pop('ResponseMetadata', None)
return {'created': True, 'identity_pool': response}
except ClientError as e:
return {'created': False, 'error': __utils__['boto3.get_error'](e)}
def delete_identity_pools(IdentityPoolName, IdentityPoolId=None,
region=None, key=None, keyid=None, profile=None):
'''
Given an identity pool name, (optionally if an identity pool id is given,
the given name will be ignored)
Deletes all identity pools matching the given name, or the specific identity pool with
the given identity pool id.
CLI Example:
.. code-block:: bash
salt myminion boto_cognitoidentity.delete_identity_pools my_id_pool_name
salt myminion boto_cognitoidentity.delete_identity_pools '' IdentityPoolId=my_id_pool_id
'''
conn = _get_conn(region=region, key=key, keyid=keyid, profile=profile)
try:
ids = _find_identity_pool_ids(IdentityPoolName, IdentityPoolId, conn)
count = 0
if ids:
for pool_id in ids:
conn.delete_identity_pool(IdentityPoolId=pool_id)
count += 1
return {'deleted': True, 'count': count}
else:
return {'deleted': False, 'count': count}
except ClientError as e:
return {'deleted': False, 'error': __utils__['boto3.get_error'](e)}
def get_identity_pool_roles(IdentityPoolName, IdentityPoolId=None,
region=None, key=None, keyid=None, profile=None):
'''
Given an identity pool name, (optionally if an identity pool id if given,
the given name will be ignored)
Returns a list of matched identity pool name's associated roles
CLI Example:
.. code-block:: bash
salt myminion boto_cognitoidentity.get_identity_pool_roles my_id_pool_name
salt myminion boto_cognitoidentity.get_identity_pool_roles '' IdentityPoolId=my_id_pool_id
'''
conn = _get_conn(region=region, key=key, keyid=keyid, profile=profile)
try:
ids = _find_identity_pool_ids(IdentityPoolName, IdentityPoolId, conn)
if ids:
results = []
for pool_id in ids:
response = conn.get_identity_pool_roles(IdentityPoolId=pool_id)
response.pop('ResponseMetadata', None)
results.append(response)
return {'identity_pool_roles': results}
else:
return {'identity_pool_roles': None}
except ClientError as e:
return {'error': __utils__['boto3.get_error'](e)}
def _get_role_arn(name, **conn_params):
'''
Helper function to turn a name into an arn string,
returns None if not able to resolve
'''
if name.startswith('arn:aws:iam'):
return name
role = __salt__['boto_iam.describe_role'](name, **conn_params)
rolearn = role.get('arn') if role else None
return rolearn
def set_identity_pool_roles(IdentityPoolId, AuthenticatedRole=None, UnauthenticatedRole=None,
region=None, key=None, keyid=None, profile=None):
'''
Given an identity pool id, set the given AuthenticatedRole and UnauthenticatedRole (the Role
can be an iam arn, or a role name) If AuthenticatedRole or UnauthenticatedRole is not given,
the authenticated and/or the unauthenticated role associated previously with the pool will be
cleared.
Returns set True if successful, set False if unsuccessful with the associated errors.
CLI Example:
.. code-block:: bash
salt myminion boto_cognitoidentity.set_identity_pool_roles my_id_pool_roles # this clears the roles
salt myminion boto_cognitoidentity.set_identity_pool_roles my_id_pool_id \
AuthenticatedRole=my_auth_role UnauthenticatedRole=my_unauth_role # this set both roles
salt myminion boto_cognitoidentity.set_identity_pool_roles my_id_pool_id \
AuthenticatedRole=my_auth_role # this will set the auth role and clear the unauth role
salt myminion boto_cognitoidentity.set_identity_pool_roles my_id_pool_id \
UnauthenticatedRole=my_unauth_role # this will set the unauth role and clear the auth role
'''
conn_params = dict(region=region, key=key, keyid=keyid, profile=profile)
conn = _get_conn(**conn_params)
try:
if AuthenticatedRole:
role_arn = _get_role_arn(AuthenticatedRole, **conn_params)
if role_arn is None:
return {'set': False, 'error': 'invalid AuthenticatedRole {0}'.format(AuthenticatedRole)}
AuthenticatedRole = role_arn
if UnauthenticatedRole:
role_arn = _get_role_arn(UnauthenticatedRole, **conn_params)
if role_arn is None:
return {'set': False, 'error': 'invalid UnauthenticatedRole {0}'.format(UnauthenticatedRole)}
UnauthenticatedRole = role_arn
Roles = dict()
if AuthenticatedRole:
Roles['authenticated'] = AuthenticatedRole
if UnauthenticatedRole:
Roles['unauthenticated'] = UnauthenticatedRole
conn.set_identity_pool_roles(IdentityPoolId=IdentityPoolId, Roles=Roles)
return {'set': True, 'roles': Roles}
except ClientError as e:
return {'set': False, 'error': __utils__['boto3.get_error'](e)}
def update_identity_pool(IdentityPoolId,
IdentityPoolName=None,
AllowUnauthenticatedIdentities=False,
SupportedLoginProviders=None,
DeveloperProviderName=None,
OpenIdConnectProviderARNs=None,
region=None, key=None, keyid=None, profile=None):
'''
Updates the given IdentityPoolId's properties. All parameters except for IdentityPoolId,
is optional. SupportedLoginProviders should be a dictionary mapping provider names to
provider app IDs. OpenIdConnectProviderARNs should be a list of OpenID Connect provider
ARNs.
To clear SupportedLoginProviders pass '{}'
To clear OpenIdConnectProviderARNs pass '[]'
boto3 api prevents DeveloperProviderName to be updated after it has been set for the first time.
Returns the updated identity pool if successful
CLI Example:
.. code-block:: bash
salt myminion boto_cognitoidentity.update_identity_pool my_id_pool_id my_id_pool_name \
DeveloperProviderName=custom_developer_provider
'''
conn_params = dict(region=region, key=key, keyid=keyid, profile=profile)
response = describe_identity_pools('', IdentityPoolId=IdentityPoolId, **conn_params)
error = response.get('error')
if error is None:
error = 'No matching pool' if response.get('identity_pools') is None else None
if error:
return {'updated': False, 'error': error}
id_pool = response.get('identity_pools')[0]
request_params = id_pool.copy()
# IdentityPoolName and AllowUnauthenticatedIdentities are required for the call to update_identity_pool
if IdentityPoolName is not None and IdentityPoolName != request_params.get('IdentityPoolName'):
request_params['IdentityPoolName'] = IdentityPoolName
if AllowUnauthenticatedIdentities != request_params.get('AllowUnauthenticatedIdentities'):
request_params['AllowUnauthenticatedIdentities'] = AllowUnauthenticatedIdentities
current_val = request_params.pop('SupportedLoginProviders', None)
if SupportedLoginProviders is not None and SupportedLoginProviders != current_val:
request_params['SupportedLoginProviders'] = SupportedLoginProviders
# we can only set DeveloperProviderName one time per AWS.
current_val = request_params.pop('DeveloperProviderName', None)
if current_val is None and DeveloperProviderName is not None:
request_params['DeveloperProviderName'] = DeveloperProviderName
current_val = request_params.pop('OpenIdConnectProviderARNs', None)
if OpenIdConnectProviderARNs is not None and OpenIdConnectProviderARNs != current_val:
request_params['OpenIdConnectProviderARNs'] = OpenIdConnectProviderARNs
conn = _get_conn(**conn_params)
try:
response = conn.update_identity_pool(**request_params)
response.pop('ResponseMetadata', None)
return {'updated': True, 'identity_pool': response}
except ClientError as e:
return {'updated': False, 'error': __utils__['boto3.get_error'](e)}