Implement some of cognito-idp
This commit is contained in:
parent
cb364eedc6
commit
e111cd1ff9
@ -2,5 +2,6 @@ include README.md LICENSE AUTHORS.md
|
|||||||
include requirements.txt requirements-dev.txt tox.ini
|
include requirements.txt requirements-dev.txt tox.ini
|
||||||
include moto/ec2/resources/instance_types.json
|
include moto/ec2/resources/instance_types.json
|
||||||
include moto/ec2/resources/amis.json
|
include moto/ec2/resources/amis.json
|
||||||
|
include moto/cognitoidp/resources/*.json
|
||||||
recursive-include moto/templates *
|
recursive-include moto/templates *
|
||||||
recursive-include tests *
|
recursive-include tests *
|
||||||
|
@ -72,6 +72,8 @@ It gets even better! Moto isn't just for Python code and it isn't just for S3. L
|
|||||||
|------------------------------------------------------------------------------|
|
|------------------------------------------------------------------------------|
|
||||||
| Cognito Identity | @mock_cognitoidentity| basic endpoints done |
|
| Cognito Identity | @mock_cognitoidentity| basic endpoints done |
|
||||||
|------------------------------------------------------------------------------|
|
|------------------------------------------------------------------------------|
|
||||||
|
| Cognito Identity Provider | @mock_cognitoidp| basic endpoints done |
|
||||||
|
|------------------------------------------------------------------------------|
|
||||||
| Data Pipeline | @mock_datapipeline| basic endpoints done |
|
| Data Pipeline | @mock_datapipeline| basic endpoints done |
|
||||||
|------------------------------------------------------------------------------|
|
|------------------------------------------------------------------------------|
|
||||||
| DynamoDB | @mock_dynamodb | core endpoints done |
|
| DynamoDB | @mock_dynamodb | core endpoints done |
|
||||||
|
@ -12,6 +12,7 @@ from .awslambda import mock_lambda, mock_lambda_deprecated # flake8: noqa
|
|||||||
from .cloudformation import mock_cloudformation, mock_cloudformation_deprecated # flake8: noqa
|
from .cloudformation import mock_cloudformation, mock_cloudformation_deprecated # flake8: noqa
|
||||||
from .cloudwatch import mock_cloudwatch, mock_cloudwatch_deprecated # flake8: noqa
|
from .cloudwatch import mock_cloudwatch, mock_cloudwatch_deprecated # flake8: noqa
|
||||||
from .cognitoidentity import mock_cognitoidentity, mock_cognitoidentity_deprecated # flake8: noqa
|
from .cognitoidentity import mock_cognitoidentity, mock_cognitoidentity_deprecated # flake8: noqa
|
||||||
|
from .cognitoidp import mock_cognitoidp, mock_cognitoidp_deprecated # flake8: noqa
|
||||||
from .datapipeline import mock_datapipeline, mock_datapipeline_deprecated # flake8: noqa
|
from .datapipeline import mock_datapipeline, mock_datapipeline_deprecated # flake8: noqa
|
||||||
from .dynamodb import mock_dynamodb, mock_dynamodb_deprecated # flake8: noqa
|
from .dynamodb import mock_dynamodb, mock_dynamodb_deprecated # flake8: noqa
|
||||||
from .dynamodb2 import mock_dynamodb2, mock_dynamodb2_deprecated # flake8: noqa
|
from .dynamodb2 import mock_dynamodb2, mock_dynamodb2_deprecated # flake8: noqa
|
||||||
|
@ -7,6 +7,7 @@ from moto.awslambda import lambda_backends
|
|||||||
from moto.cloudformation import cloudformation_backends
|
from moto.cloudformation import cloudformation_backends
|
||||||
from moto.cloudwatch import cloudwatch_backends
|
from moto.cloudwatch import cloudwatch_backends
|
||||||
from moto.cognitoidentity import cognitoidentity_backends
|
from moto.cognitoidentity import cognitoidentity_backends
|
||||||
|
from moto.cognitoidp import cognitoidp_backends
|
||||||
from moto.core import moto_api_backends
|
from moto.core import moto_api_backends
|
||||||
from moto.datapipeline import datapipeline_backends
|
from moto.datapipeline import datapipeline_backends
|
||||||
from moto.dynamodb import dynamodb_backends
|
from moto.dynamodb import dynamodb_backends
|
||||||
@ -51,6 +52,7 @@ BACKENDS = {
|
|||||||
'cloudformation': cloudformation_backends,
|
'cloudformation': cloudformation_backends,
|
||||||
'cloudwatch': cloudwatch_backends,
|
'cloudwatch': cloudwatch_backends,
|
||||||
'cognito-identity': cognitoidentity_backends,
|
'cognito-identity': cognitoidentity_backends,
|
||||||
|
'cognito-idp': cognitoidp_backends,
|
||||||
'datapipeline': datapipeline_backends,
|
'datapipeline': datapipeline_backends,
|
||||||
'dynamodb': dynamodb_backends,
|
'dynamodb': dynamodb_backends,
|
||||||
'dynamodb2': dynamodb_backends2,
|
'dynamodb2': dynamodb_backends2,
|
||||||
|
6
moto/cognitoidp/__init__.py
Normal file
6
moto/cognitoidp/__init__.py
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
from __future__ import unicode_literals
|
||||||
|
from .models import cognitoidp_backends
|
||||||
|
from ..core.models import base_decorator, deprecated_base_decorator
|
||||||
|
|
||||||
|
mock_cognitoidp = base_decorator(cognitoidp_backends)
|
||||||
|
mock_cognitoidp_deprecated = deprecated_base_decorator(cognitoidp_backends)
|
34
moto/cognitoidp/exceptions.py
Normal file
34
moto/cognitoidp/exceptions.py
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
import json
|
||||||
|
from werkzeug.exceptions import BadRequest
|
||||||
|
|
||||||
|
|
||||||
|
class ResourceNotFoundError(BadRequest):
|
||||||
|
|
||||||
|
def __init__(self, message):
|
||||||
|
super(ResourceNotFoundError, self).__init__()
|
||||||
|
self.description = json.dumps({
|
||||||
|
"message": message,
|
||||||
|
'__type': 'ResourceNotFoundException',
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
class UserNotFoundError(BadRequest):
|
||||||
|
|
||||||
|
def __init__(self, message):
|
||||||
|
super(UserNotFoundError, self).__init__()
|
||||||
|
self.description = json.dumps({
|
||||||
|
"message": message,
|
||||||
|
'__type': 'UserNotFoundException',
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
class NotAuthorizedError(BadRequest):
|
||||||
|
|
||||||
|
def __init__(self, message):
|
||||||
|
super(NotAuthorizedError, self).__init__()
|
||||||
|
self.description = json.dumps({
|
||||||
|
"message": message,
|
||||||
|
'__type': 'NotAuthorizedException',
|
||||||
|
})
|
512
moto/cognitoidp/models.py
Normal file
512
moto/cognitoidp/models.py
Normal file
@ -0,0 +1,512 @@
|
|||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
import datetime
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
import time
|
||||||
|
import uuid
|
||||||
|
|
||||||
|
import boto.cognito.identity
|
||||||
|
from jose import jws
|
||||||
|
|
||||||
|
from moto.compat import OrderedDict
|
||||||
|
from moto.core import BaseBackend, BaseModel
|
||||||
|
from .exceptions import NotAuthorizedError, ResourceNotFoundError, UserNotFoundError
|
||||||
|
|
||||||
|
|
||||||
|
UserStatus = {
|
||||||
|
"FORCE_CHANGE_PASSWORD": "FORCE_CHANGE_PASSWORD",
|
||||||
|
"CONFIRMED": "CONFIRMED",
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class CognitoIdpUserPool(BaseModel):
|
||||||
|
|
||||||
|
def __init__(self, region, name, extended_config):
|
||||||
|
self.region = region
|
||||||
|
self.id = str(uuid.uuid4())
|
||||||
|
self.name = name
|
||||||
|
self.status = None
|
||||||
|
self.extended_config = extended_config or {}
|
||||||
|
self.creation_date = datetime.datetime.utcnow()
|
||||||
|
self.last_modified_date = datetime.datetime.utcnow()
|
||||||
|
|
||||||
|
self.clients = OrderedDict()
|
||||||
|
self.identity_providers = OrderedDict()
|
||||||
|
self.users = OrderedDict()
|
||||||
|
self.refresh_tokens = {}
|
||||||
|
self.access_tokens = {}
|
||||||
|
self.id_tokens = {}
|
||||||
|
|
||||||
|
with open(os.path.join(os.path.dirname(__file__), "resources/jwks-private.json")) as f:
|
||||||
|
self.json_web_key = json.loads(f.read())
|
||||||
|
|
||||||
|
def _base_json(self):
|
||||||
|
return {
|
||||||
|
"Id": self.id,
|
||||||
|
"Name": self.name,
|
||||||
|
"Status": self.status,
|
||||||
|
"CreationDate": time.mktime(self.creation_date.timetuple()),
|
||||||
|
"LastModifiedDate": time.mktime(self.last_modified_date.timetuple()),
|
||||||
|
}
|
||||||
|
|
||||||
|
def to_json(self, extended=False):
|
||||||
|
user_pool_json = self._base_json()
|
||||||
|
if extended:
|
||||||
|
user_pool_json.update(self.extended_config)
|
||||||
|
else:
|
||||||
|
user_pool_json["LambdaConfig"] = self.extended_config.get("LambdaConfig") or {}
|
||||||
|
|
||||||
|
return user_pool_json
|
||||||
|
|
||||||
|
def create_jwt(self, client_id, username, expires_in=60 * 60, extra_data={}):
|
||||||
|
now = int(time.time())
|
||||||
|
payload = {
|
||||||
|
"iss": "https://cognito-idp.{}.amazonaws.com/{}".format(self.region, self.id),
|
||||||
|
"sub": self.users[username].id,
|
||||||
|
"aud": client_id,
|
||||||
|
"token_use": "id",
|
||||||
|
"auth_time": now,
|
||||||
|
"exp": now + expires_in,
|
||||||
|
}
|
||||||
|
payload.update(extra_data)
|
||||||
|
|
||||||
|
return jws.sign(payload, self.json_web_key, algorithm='RS256'), expires_in
|
||||||
|
|
||||||
|
def create_id_token(self, client_id, username):
|
||||||
|
id_token, expires_in = self.create_jwt(client_id, username)
|
||||||
|
self.id_tokens[id_token] = (client_id, username)
|
||||||
|
return id_token, expires_in
|
||||||
|
|
||||||
|
def create_refresh_token(self, client_id, username):
|
||||||
|
refresh_token = str(uuid.uuid4())
|
||||||
|
self.refresh_tokens[refresh_token] = (client_id, username)
|
||||||
|
return refresh_token
|
||||||
|
|
||||||
|
def create_access_token(self, client_id, username):
|
||||||
|
access_token, expires_in = self.create_jwt(client_id, username)
|
||||||
|
self.access_tokens[access_token] = (client_id, username)
|
||||||
|
return access_token, expires_in
|
||||||
|
|
||||||
|
def create_tokens_from_refresh_token(self, refresh_token):
|
||||||
|
client_id, username = self.refresh_tokens.get(refresh_token)
|
||||||
|
if not username:
|
||||||
|
raise NotAuthorizedError(refresh_token)
|
||||||
|
|
||||||
|
access_token, expires_in = self.create_access_token(client_id, username)
|
||||||
|
id_token, _ = self.create_id_token(client_id, username)
|
||||||
|
return access_token, id_token, expires_in
|
||||||
|
|
||||||
|
|
||||||
|
class CognitoIdpUserPoolDomain(BaseModel):
|
||||||
|
|
||||||
|
def __init__(self, user_pool_id, domain):
|
||||||
|
self.user_pool_id = user_pool_id
|
||||||
|
self.domain = domain
|
||||||
|
|
||||||
|
def to_json(self):
|
||||||
|
return {
|
||||||
|
"UserPoolId": self.user_pool_id,
|
||||||
|
"AWSAccountId": str(uuid.uuid4()),
|
||||||
|
"CloudFrontDistribution": None,
|
||||||
|
"Domain": self.domain,
|
||||||
|
"S3Bucket": None,
|
||||||
|
"Status": "ACTIVE",
|
||||||
|
"Version": None,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class CognitoIdpUserPoolClient(BaseModel):
|
||||||
|
|
||||||
|
def __init__(self, user_pool_id, extended_config):
|
||||||
|
self.user_pool_id = user_pool_id
|
||||||
|
self.id = str(uuid.uuid4())
|
||||||
|
self.secret = str(uuid.uuid4())
|
||||||
|
self.extended_config = extended_config or {}
|
||||||
|
|
||||||
|
def _base_json(self):
|
||||||
|
return {
|
||||||
|
"ClientId": self.id,
|
||||||
|
"ClientName": self.extended_config.get("ClientName"),
|
||||||
|
"UserPoolId": self.user_pool_id,
|
||||||
|
}
|
||||||
|
|
||||||
|
def to_json(self, extended=False):
|
||||||
|
user_pool_client_json = self._base_json()
|
||||||
|
if extended:
|
||||||
|
user_pool_client_json.update(self.extended_config)
|
||||||
|
|
||||||
|
return user_pool_client_json
|
||||||
|
|
||||||
|
|
||||||
|
class CognitoIdpIdentityProvider(BaseModel):
|
||||||
|
|
||||||
|
def __init__(self, name, extended_config):
|
||||||
|
self.name = name
|
||||||
|
self.extended_config = extended_config or {}
|
||||||
|
self.creation_date = datetime.datetime.utcnow()
|
||||||
|
self.last_modified_date = datetime.datetime.utcnow()
|
||||||
|
|
||||||
|
def _base_json(self):
|
||||||
|
return {
|
||||||
|
"ProviderName": self.name,
|
||||||
|
"ProviderType": self.extended_config.get("ProviderType"),
|
||||||
|
"CreationDate": time.mktime(self.creation_date.timetuple()),
|
||||||
|
"LastModifiedDate": time.mktime(self.last_modified_date.timetuple()),
|
||||||
|
}
|
||||||
|
|
||||||
|
def to_json(self, extended=False):
|
||||||
|
identity_provider_json = self._base_json()
|
||||||
|
if extended:
|
||||||
|
identity_provider_json.update(self.extended_config)
|
||||||
|
|
||||||
|
return identity_provider_json
|
||||||
|
|
||||||
|
|
||||||
|
class CognitoIdpUser(BaseModel):
|
||||||
|
|
||||||
|
def __init__(self, user_pool_id, username, password, status, attributes):
|
||||||
|
self.id = str(uuid.uuid4())
|
||||||
|
self.user_pool_id = user_pool_id
|
||||||
|
self.username = username
|
||||||
|
self.password = password
|
||||||
|
self.status = status
|
||||||
|
self.enabled = True
|
||||||
|
self.attributes = attributes
|
||||||
|
self.create_date = datetime.datetime.utcnow()
|
||||||
|
self.last_modified_date = datetime.datetime.utcnow()
|
||||||
|
|
||||||
|
def _base_json(self):
|
||||||
|
return {
|
||||||
|
"UserPoolId": self.user_pool_id,
|
||||||
|
"Username": self.username,
|
||||||
|
"UserStatus": self.status,
|
||||||
|
"UserCreateDate": time.mktime(self.create_date.timetuple()),
|
||||||
|
"UserLastModifiedDate": time.mktime(self.last_modified_date.timetuple()),
|
||||||
|
}
|
||||||
|
|
||||||
|
# list_users brings back "Attributes" while admin_get_user brings back "UserAttributes".
|
||||||
|
def to_json(self, extended=False, attributes_key="Attributes"):
|
||||||
|
user_json = self._base_json()
|
||||||
|
if extended:
|
||||||
|
user_json.update(
|
||||||
|
{
|
||||||
|
"Enabled": self.enabled,
|
||||||
|
attributes_key: self.attributes,
|
||||||
|
"MFAOptions": []
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
return user_json
|
||||||
|
|
||||||
|
|
||||||
|
class CognitoIdpBackend(BaseBackend):
|
||||||
|
|
||||||
|
def __init__(self, region):
|
||||||
|
super(CognitoIdpBackend, self).__init__()
|
||||||
|
self.region = region
|
||||||
|
self.user_pools = OrderedDict()
|
||||||
|
self.user_pool_domains = OrderedDict()
|
||||||
|
self.sessions = {}
|
||||||
|
|
||||||
|
def reset(self):
|
||||||
|
region = self.region
|
||||||
|
self.__dict__ = {}
|
||||||
|
self.__init__(region)
|
||||||
|
|
||||||
|
# User pool
|
||||||
|
def create_user_pool(self, name, extended_config):
|
||||||
|
user_pool = CognitoIdpUserPool(self.region, name, extended_config)
|
||||||
|
self.user_pools[user_pool.id] = user_pool
|
||||||
|
return user_pool
|
||||||
|
|
||||||
|
def list_user_pools(self):
|
||||||
|
return self.user_pools.values()
|
||||||
|
|
||||||
|
def describe_user_pool(self, user_pool_id):
|
||||||
|
user_pool = self.user_pools.get(user_pool_id)
|
||||||
|
if not user_pool:
|
||||||
|
raise ResourceNotFoundError(user_pool_id)
|
||||||
|
|
||||||
|
return user_pool
|
||||||
|
|
||||||
|
def delete_user_pool(self, user_pool_id):
|
||||||
|
if user_pool_id not in self.user_pools:
|
||||||
|
raise ResourceNotFoundError(user_pool_id)
|
||||||
|
|
||||||
|
del self.user_pools[user_pool_id]
|
||||||
|
|
||||||
|
# User pool domain
|
||||||
|
def create_user_pool_domain(self, user_pool_id, domain):
|
||||||
|
if user_pool_id not in self.user_pools:
|
||||||
|
raise ResourceNotFoundError(user_pool_id)
|
||||||
|
|
||||||
|
user_pool_domain = CognitoIdpUserPoolDomain(user_pool_id, domain)
|
||||||
|
self.user_pool_domains[domain] = user_pool_domain
|
||||||
|
return user_pool_domain
|
||||||
|
|
||||||
|
def describe_user_pool_domain(self, domain):
|
||||||
|
if domain not in self.user_pool_domains:
|
||||||
|
return None
|
||||||
|
|
||||||
|
return self.user_pool_domains[domain]
|
||||||
|
|
||||||
|
def delete_user_pool_domain(self, domain):
|
||||||
|
if domain not in self.user_pool_domains:
|
||||||
|
raise ResourceNotFoundError(domain)
|
||||||
|
|
||||||
|
del self.user_pool_domains[domain]
|
||||||
|
|
||||||
|
# User pool client
|
||||||
|
def create_user_pool_client(self, user_pool_id, extended_config):
|
||||||
|
user_pool = self.user_pools.get(user_pool_id)
|
||||||
|
if not user_pool:
|
||||||
|
raise ResourceNotFoundError(user_pool_id)
|
||||||
|
|
||||||
|
user_pool_client = CognitoIdpUserPoolClient(user_pool_id, extended_config)
|
||||||
|
user_pool.clients[user_pool_client.id] = user_pool_client
|
||||||
|
return user_pool_client
|
||||||
|
|
||||||
|
def list_user_pool_clients(self, user_pool_id):
|
||||||
|
user_pool = self.user_pools.get(user_pool_id)
|
||||||
|
if not user_pool:
|
||||||
|
raise ResourceNotFoundError(user_pool_id)
|
||||||
|
|
||||||
|
return user_pool.clients.values()
|
||||||
|
|
||||||
|
def describe_user_pool_client(self, user_pool_id, client_id):
|
||||||
|
user_pool = self.user_pools.get(user_pool_id)
|
||||||
|
if not user_pool:
|
||||||
|
raise ResourceNotFoundError(user_pool_id)
|
||||||
|
|
||||||
|
client = user_pool.clients.get(client_id)
|
||||||
|
if not client:
|
||||||
|
raise ResourceNotFoundError(client_id)
|
||||||
|
|
||||||
|
return client
|
||||||
|
|
||||||
|
def update_user_pool_client(self, user_pool_id, client_id, extended_config):
|
||||||
|
user_pool = self.user_pools.get(user_pool_id)
|
||||||
|
if not user_pool:
|
||||||
|
raise ResourceNotFoundError(user_pool_id)
|
||||||
|
|
||||||
|
client = user_pool.clients.get(client_id)
|
||||||
|
if not client:
|
||||||
|
raise ResourceNotFoundError(client_id)
|
||||||
|
|
||||||
|
client.extended_config.update(extended_config)
|
||||||
|
return client
|
||||||
|
|
||||||
|
def delete_user_pool_client(self, user_pool_id, client_id):
|
||||||
|
user_pool = self.user_pools.get(user_pool_id)
|
||||||
|
if not user_pool:
|
||||||
|
raise ResourceNotFoundError(user_pool_id)
|
||||||
|
|
||||||
|
if client_id not in user_pool.clients:
|
||||||
|
raise ResourceNotFoundError(client_id)
|
||||||
|
|
||||||
|
del user_pool.clients[client_id]
|
||||||
|
|
||||||
|
# Identity provider
|
||||||
|
def create_identity_provider(self, user_pool_id, name, extended_config):
|
||||||
|
user_pool = self.user_pools.get(user_pool_id)
|
||||||
|
if not user_pool:
|
||||||
|
raise ResourceNotFoundError(user_pool_id)
|
||||||
|
|
||||||
|
identity_provider = CognitoIdpIdentityProvider(name, extended_config)
|
||||||
|
user_pool.identity_providers[name] = identity_provider
|
||||||
|
return identity_provider
|
||||||
|
|
||||||
|
def list_identity_providers(self, user_pool_id):
|
||||||
|
user_pool = self.user_pools.get(user_pool_id)
|
||||||
|
if not user_pool:
|
||||||
|
raise ResourceNotFoundError(user_pool_id)
|
||||||
|
|
||||||
|
return user_pool.identity_providers.values()
|
||||||
|
|
||||||
|
def describe_identity_provider(self, user_pool_id, name):
|
||||||
|
user_pool = self.user_pools.get(user_pool_id)
|
||||||
|
if not user_pool:
|
||||||
|
raise ResourceNotFoundError(user_pool_id)
|
||||||
|
|
||||||
|
identity_provider = user_pool.identity_providers.get(name)
|
||||||
|
if not identity_provider:
|
||||||
|
raise ResourceNotFoundError(name)
|
||||||
|
|
||||||
|
return identity_provider
|
||||||
|
|
||||||
|
def delete_identity_provider(self, user_pool_id, name):
|
||||||
|
user_pool = self.user_pools.get(user_pool_id)
|
||||||
|
if not user_pool:
|
||||||
|
raise ResourceNotFoundError(user_pool_id)
|
||||||
|
|
||||||
|
if name not in user_pool.identity_providers:
|
||||||
|
raise ResourceNotFoundError(name)
|
||||||
|
|
||||||
|
del user_pool.identity_providers[name]
|
||||||
|
|
||||||
|
# User
|
||||||
|
def admin_create_user(self, user_pool_id, username, temporary_password, attributes):
|
||||||
|
user_pool = self.user_pools.get(user_pool_id)
|
||||||
|
if not user_pool:
|
||||||
|
raise ResourceNotFoundError(user_pool_id)
|
||||||
|
|
||||||
|
user = CognitoIdpUser(user_pool_id, username, temporary_password, UserStatus["FORCE_CHANGE_PASSWORD"], attributes)
|
||||||
|
user_pool.users[user.username] = user
|
||||||
|
return user
|
||||||
|
|
||||||
|
def admin_get_user(self, user_pool_id, username):
|
||||||
|
user_pool = self.user_pools.get(user_pool_id)
|
||||||
|
if not user_pool:
|
||||||
|
raise ResourceNotFoundError(user_pool_id)
|
||||||
|
|
||||||
|
if username not in user_pool.users:
|
||||||
|
raise ResourceNotFoundError(username)
|
||||||
|
|
||||||
|
return user_pool.users[username]
|
||||||
|
|
||||||
|
def list_users(self, user_pool_id):
|
||||||
|
user_pool = self.user_pools.get(user_pool_id)
|
||||||
|
if not user_pool:
|
||||||
|
raise ResourceNotFoundError(user_pool_id)
|
||||||
|
|
||||||
|
return user_pool.users.values()
|
||||||
|
|
||||||
|
def admin_delete_user(self, user_pool_id, username):
|
||||||
|
user_pool = self.user_pools.get(user_pool_id)
|
||||||
|
if not user_pool:
|
||||||
|
raise ResourceNotFoundError(user_pool_id)
|
||||||
|
|
||||||
|
if username not in user_pool.users:
|
||||||
|
raise ResourceNotFoundError(username)
|
||||||
|
|
||||||
|
del user_pool.users[username]
|
||||||
|
|
||||||
|
def _log_user_in(self, user_pool, client, username):
|
||||||
|
refresh_token = user_pool.create_refresh_token(client.id, username)
|
||||||
|
access_token, id_token, expires_in = user_pool.create_tokens_from_refresh_token(refresh_token)
|
||||||
|
|
||||||
|
return {
|
||||||
|
"AuthenticationResult": {
|
||||||
|
"IdToken": id_token,
|
||||||
|
"AccessToken": access_token,
|
||||||
|
"RefreshToken": refresh_token,
|
||||||
|
"ExpiresIn": expires_in,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def admin_initiate_auth(self, user_pool_id, client_id, auth_flow, auth_parameters):
|
||||||
|
user_pool = self.user_pools.get(user_pool_id)
|
||||||
|
if not user_pool:
|
||||||
|
raise ResourceNotFoundError(user_pool_id)
|
||||||
|
|
||||||
|
client = user_pool.clients.get(client_id)
|
||||||
|
if not client:
|
||||||
|
raise ResourceNotFoundError(client_id)
|
||||||
|
|
||||||
|
if auth_flow == "ADMIN_NO_SRP_AUTH":
|
||||||
|
username = auth_parameters.get("USERNAME")
|
||||||
|
password = auth_parameters.get("PASSWORD")
|
||||||
|
user = user_pool.users.get(username)
|
||||||
|
if not user:
|
||||||
|
raise UserNotFoundError(username)
|
||||||
|
|
||||||
|
if user.password != password:
|
||||||
|
raise NotAuthorizedError(username)
|
||||||
|
|
||||||
|
if user.status == UserStatus["FORCE_CHANGE_PASSWORD"]:
|
||||||
|
session = str(uuid.uuid4())
|
||||||
|
self.sessions[session] = user_pool
|
||||||
|
|
||||||
|
return {
|
||||||
|
"ChallengeName": "NEW_PASSWORD_REQUIRED",
|
||||||
|
"ChallengeParameters": {},
|
||||||
|
"Session": session,
|
||||||
|
}
|
||||||
|
|
||||||
|
return self._log_user_in(user_pool, client, username)
|
||||||
|
elif auth_flow == "REFRESH_TOKEN":
|
||||||
|
refresh_token = auth_parameters.get("REFRESH_TOKEN")
|
||||||
|
id_token, access_token, expires_in = user_pool.create_tokens_from_refresh_token(refresh_token)
|
||||||
|
|
||||||
|
return {
|
||||||
|
"AuthenticationResult": {
|
||||||
|
"IdToken": id_token,
|
||||||
|
"AccessToken": access_token,
|
||||||
|
"ExpiresIn": expires_in,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else:
|
||||||
|
return {}
|
||||||
|
|
||||||
|
def respond_to_auth_challenge(self, session, client_id, challenge_name, challenge_responses):
|
||||||
|
user_pool = self.sessions.get(session)
|
||||||
|
if not user_pool:
|
||||||
|
raise ResourceNotFoundError(session)
|
||||||
|
|
||||||
|
client = user_pool.clients.get(client_id)
|
||||||
|
if not client:
|
||||||
|
raise ResourceNotFoundError(client_id)
|
||||||
|
|
||||||
|
if challenge_name == "NEW_PASSWORD_REQUIRED":
|
||||||
|
username = challenge_responses.get("USERNAME")
|
||||||
|
new_password = challenge_responses.get("NEW_PASSWORD")
|
||||||
|
user = user_pool.users.get(username)
|
||||||
|
if not user:
|
||||||
|
raise UserNotFoundError(username)
|
||||||
|
|
||||||
|
user.password = new_password
|
||||||
|
user.status = UserStatus["CONFIRMED"]
|
||||||
|
del self.sessions[session]
|
||||||
|
|
||||||
|
return self._log_user_in(user_pool, client, username)
|
||||||
|
else:
|
||||||
|
return {}
|
||||||
|
|
||||||
|
def confirm_forgot_password(self, client_id, username, password):
|
||||||
|
for user_pool in self.user_pools.values():
|
||||||
|
if client_id in user_pool.clients and username in user_pool.users:
|
||||||
|
user_pool.users[username].password = password
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
raise ResourceNotFoundError(client_id)
|
||||||
|
|
||||||
|
def change_password(self, access_token, previous_password, proposed_password):
|
||||||
|
for user_pool in self.user_pools.values():
|
||||||
|
if access_token in user_pool.access_tokens:
|
||||||
|
_, username = user_pool.access_tokens[access_token]
|
||||||
|
user = user_pool.users.get(username)
|
||||||
|
if not user:
|
||||||
|
raise UserNotFoundError(username)
|
||||||
|
|
||||||
|
if user.password != previous_password:
|
||||||
|
raise NotAuthorizedError(username)
|
||||||
|
|
||||||
|
user.password = proposed_password
|
||||||
|
if user.status == UserStatus["FORCE_CHANGE_PASSWORD"]:
|
||||||
|
user.status = UserStatus["CONFIRMED"]
|
||||||
|
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
raise NotAuthorizedError(access_token)
|
||||||
|
|
||||||
|
|
||||||
|
cognitoidp_backends = {}
|
||||||
|
for region in boto.cognito.identity.regions():
|
||||||
|
cognitoidp_backends[region.name] = CognitoIdpBackend(region.name)
|
||||||
|
|
||||||
|
|
||||||
|
# Hack to help moto-server process requests on localhost, where the region isn't
|
||||||
|
# specified in the host header. Some endpoints (change password, confirm forgot
|
||||||
|
# password) have no authorization header from which to extract the region.
|
||||||
|
def find_region_by_value(key, value):
|
||||||
|
for region in cognitoidp_backends:
|
||||||
|
backend = cognitoidp_backends[region]
|
||||||
|
for user_pool in backend.user_pools.values():
|
||||||
|
if key == "client_id" and value in user_pool.clients:
|
||||||
|
return region
|
||||||
|
|
||||||
|
if key == "access_token" and value in user_pool.access_tokens:
|
||||||
|
return region
|
||||||
|
|
||||||
|
return cognitoidp_backends.keys()[0]
|
9
moto/cognitoidp/resources/jwks-private.json
Normal file
9
moto/cognitoidp/resources/jwks-private.json
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"alg": "RS256",
|
||||||
|
"d": "DrrLT2qMERN0Id-bNglOe6SVkUNF3MTIzrH-TVkMZhsHk8kyqiqt-8JbLQMh2gOgTIjpu93b2_UREGA0BGdWs34hv0v7Gx8uIngCY6e6XO8LDemOo-2VHZHl5Ew-lrRYhwq12c_c4mfavAdMzXHODrpXSnqLnbFK88S-3fu6Da4czc4Svo4v8MkGZk_fcTml3Y1jIFHxbbTWka37j4NLpAzdfvX--J086m-LbZ8CJL_lGMKbAKsWURMmzCFL9ZFH9JdzX79KeDOH0GrzGwS_cOsZHsCamF_CWrtG4asPt-SHyn_k0X4JJJgAWVA674VCqorMAPDVYIzKJOUMImmsEQ",
|
||||||
|
"e": "AQAB",
|
||||||
|
"kid": "dummy",
|
||||||
|
"kty": "RSA",
|
||||||
|
"n": "j1pT3xKbswmMySvCefmiD3mfDaRFpZ9Y3Jl4fF0hMaCRVAt_e0yR7BeueDfqmj_NhVSO0WB5ao5e8V-9RFQOtK8SrqKl3i01-CyWYPICwybaGKhbJJR0S_6cZ8n5kscF1MjpIlsJcCzm-yKgTc3Mxk6KtrLoNgRvMwGLeHUXPkhS9YHfDKRe864iMFOK4df69brIYEICG2VLduh0hXYa0i-J3drwm7vxNdX7pVpCDu34qJtYoWq6CXt3Tzfi3YfWp8cFjGNbaDa3WnCd2IXpp0TFsFS-cEsw5rJjSl5OllJGeZKBtLeyVTy9PYwnk7MW43WSYeYstbk9NluX4H8Iuw",
|
||||||
|
"use": "sig"
|
||||||
|
}
|
12
moto/cognitoidp/resources/jwks-public.json
Normal file
12
moto/cognitoidp/resources/jwks-public.json
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"keys": [
|
||||||
|
{
|
||||||
|
"alg": "RS256",
|
||||||
|
"e": "AQAB",
|
||||||
|
"kid": "dummy",
|
||||||
|
"kty": "RSA",
|
||||||
|
"n": "j1pT3xKbswmMySvCefmiD3mfDaRFpZ9Y3Jl4fF0hMaCRVAt_e0yR7BeueDfqmj_NhVSO0WB5ao5e8V-9RFQOtK8SrqKl3i01-CyWYPICwybaGKhbJJR0S_6cZ8n5kscF1MjpIlsJcCzm-yKgTc3Mxk6KtrLoNgRvMwGLeHUXPkhS9YHfDKRe864iMFOK4df69brIYEICG2VLduh0hXYa0i-J3drwm7vxNdX7pVpCDu34qJtYoWq6CXt3Tzfi3YfWp8cFjGNbaDa3WnCd2IXpp0TFsFS-cEsw5rJjSl5OllJGeZKBtLeyVTy9PYwnk7MW43WSYeYstbk9NluX4H8Iuw",
|
||||||
|
"use": "sig"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
235
moto/cognitoidp/responses.py
Normal file
235
moto/cognitoidp/responses.py
Normal file
@ -0,0 +1,235 @@
|
|||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
|
||||||
|
from moto.core.responses import BaseResponse
|
||||||
|
from .models import cognitoidp_backends, find_region_by_value
|
||||||
|
|
||||||
|
|
||||||
|
class CognitoIdpResponse(BaseResponse):
|
||||||
|
|
||||||
|
@property
|
||||||
|
def parameters(self):
|
||||||
|
return json.loads(self.body)
|
||||||
|
|
||||||
|
# User pool
|
||||||
|
def create_user_pool(self):
|
||||||
|
name = self.parameters.pop("PoolName")
|
||||||
|
user_pool = cognitoidp_backends[self.region].create_user_pool(name, self.parameters)
|
||||||
|
return json.dumps({
|
||||||
|
"UserPool": user_pool.to_json(extended=True)
|
||||||
|
})
|
||||||
|
|
||||||
|
def list_user_pools(self):
|
||||||
|
user_pools = cognitoidp_backends[self.region].list_user_pools()
|
||||||
|
return json.dumps({
|
||||||
|
"UserPools": [user_pool.to_json() for user_pool in user_pools]
|
||||||
|
})
|
||||||
|
|
||||||
|
def describe_user_pool(self):
|
||||||
|
user_pool_id = self._get_param("UserPoolId")
|
||||||
|
user_pool = cognitoidp_backends[self.region].describe_user_pool(user_pool_id)
|
||||||
|
return json.dumps({
|
||||||
|
"UserPool": user_pool.to_json(extended=True)
|
||||||
|
})
|
||||||
|
|
||||||
|
def delete_user_pool(self):
|
||||||
|
user_pool_id = self._get_param("UserPoolId")
|
||||||
|
cognitoidp_backends[self.region].delete_user_pool(user_pool_id)
|
||||||
|
return ""
|
||||||
|
|
||||||
|
# User pool domain
|
||||||
|
def create_user_pool_domain(self):
|
||||||
|
domain = self._get_param("Domain")
|
||||||
|
user_pool_id = self._get_param("UserPoolId")
|
||||||
|
cognitoidp_backends[self.region].create_user_pool_domain(user_pool_id, domain)
|
||||||
|
return ""
|
||||||
|
|
||||||
|
def describe_user_pool_domain(self):
|
||||||
|
domain = self._get_param("Domain")
|
||||||
|
user_pool_domain = cognitoidp_backends[self.region].describe_user_pool_domain(domain)
|
||||||
|
domain_description = {}
|
||||||
|
if user_pool_domain:
|
||||||
|
domain_description = user_pool_domain.to_json()
|
||||||
|
|
||||||
|
return json.dumps({
|
||||||
|
"DomainDescription": domain_description
|
||||||
|
})
|
||||||
|
|
||||||
|
def delete_user_pool_domain(self):
|
||||||
|
domain = self._get_param("Domain")
|
||||||
|
cognitoidp_backends[self.region].delete_user_pool_domain(domain)
|
||||||
|
return ""
|
||||||
|
|
||||||
|
# User pool client
|
||||||
|
def create_user_pool_client(self):
|
||||||
|
user_pool_id = self.parameters.pop("UserPoolId")
|
||||||
|
user_pool_client = cognitoidp_backends[self.region].create_user_pool_client(user_pool_id, self.parameters)
|
||||||
|
return json.dumps({
|
||||||
|
"UserPoolClient": user_pool_client.to_json(extended=True)
|
||||||
|
})
|
||||||
|
|
||||||
|
def list_user_pool_clients(self):
|
||||||
|
user_pool_id = self._get_param("UserPoolId")
|
||||||
|
user_pool_clients = cognitoidp_backends[self.region].list_user_pool_clients(user_pool_id)
|
||||||
|
return json.dumps({
|
||||||
|
"UserPoolClients": [user_pool_client.to_json() for user_pool_client in user_pool_clients]
|
||||||
|
})
|
||||||
|
|
||||||
|
def describe_user_pool_client(self):
|
||||||
|
user_pool_id = self._get_param("UserPoolId")
|
||||||
|
client_id = self._get_param("ClientId")
|
||||||
|
user_pool_client = cognitoidp_backends[self.region].describe_user_pool_client(user_pool_id, client_id)
|
||||||
|
return json.dumps({
|
||||||
|
"UserPoolClient": user_pool_client.to_json(extended=True)
|
||||||
|
})
|
||||||
|
|
||||||
|
def update_user_pool_client(self):
|
||||||
|
user_pool_id = self.parameters.pop("UserPoolId")
|
||||||
|
client_id = self.parameters.pop("ClientId")
|
||||||
|
user_pool_client = cognitoidp_backends[self.region].update_user_pool_client(user_pool_id, client_id, self.parameters)
|
||||||
|
return json.dumps({
|
||||||
|
"UserPoolClient": user_pool_client.to_json(extended=True)
|
||||||
|
})
|
||||||
|
|
||||||
|
def delete_user_pool_client(self):
|
||||||
|
user_pool_id = self._get_param("UserPoolId")
|
||||||
|
client_id = self._get_param("ClientId")
|
||||||
|
cognitoidp_backends[self.region].delete_user_pool_client(user_pool_id, client_id)
|
||||||
|
return ""
|
||||||
|
|
||||||
|
# Identity provider
|
||||||
|
def create_identity_provider(self):
|
||||||
|
user_pool_id = self._get_param("UserPoolId")
|
||||||
|
name = self.parameters.pop("ProviderName")
|
||||||
|
identity_provider = cognitoidp_backends[self.region].create_identity_provider(user_pool_id, name, self.parameters)
|
||||||
|
return json.dumps({
|
||||||
|
"IdentityProvider": identity_provider.to_json(extended=True)
|
||||||
|
})
|
||||||
|
|
||||||
|
def list_identity_providers(self):
|
||||||
|
user_pool_id = self._get_param("UserPoolId")
|
||||||
|
identity_providers = cognitoidp_backends[self.region].list_identity_providers(user_pool_id)
|
||||||
|
return json.dumps({
|
||||||
|
"Providers": [identity_provider.to_json() for identity_provider in identity_providers]
|
||||||
|
})
|
||||||
|
|
||||||
|
def describe_identity_provider(self):
|
||||||
|
user_pool_id = self._get_param("UserPoolId")
|
||||||
|
name = self._get_param("ProviderName")
|
||||||
|
identity_provider = cognitoidp_backends[self.region].describe_identity_provider(user_pool_id, name)
|
||||||
|
return json.dumps({
|
||||||
|
"IdentityProvider": identity_provider.to_json(extended=True)
|
||||||
|
})
|
||||||
|
|
||||||
|
def delete_identity_provider(self):
|
||||||
|
user_pool_id = self._get_param("UserPoolId")
|
||||||
|
name = self._get_param("ProviderName")
|
||||||
|
cognitoidp_backends[self.region].delete_identity_provider(user_pool_id, name)
|
||||||
|
return ""
|
||||||
|
|
||||||
|
# User
|
||||||
|
def admin_create_user(self):
|
||||||
|
user_pool_id = self._get_param("UserPoolId")
|
||||||
|
username = self._get_param("Username")
|
||||||
|
temporary_password = self._get_param("TemporaryPassword")
|
||||||
|
user = cognitoidp_backends[self.region].admin_create_user(
|
||||||
|
user_pool_id,
|
||||||
|
username,
|
||||||
|
temporary_password,
|
||||||
|
self._get_param("UserAttributes", [])
|
||||||
|
)
|
||||||
|
|
||||||
|
return json.dumps({
|
||||||
|
"User": user.to_json(extended=True)
|
||||||
|
})
|
||||||
|
|
||||||
|
def admin_get_user(self):
|
||||||
|
user_pool_id = self._get_param("UserPoolId")
|
||||||
|
username = self._get_param("Username")
|
||||||
|
user = cognitoidp_backends[self.region].admin_get_user(user_pool_id, username)
|
||||||
|
return json.dumps(
|
||||||
|
user.to_json(extended=True, attributes_key="UserAttributes")
|
||||||
|
)
|
||||||
|
|
||||||
|
def list_users(self):
|
||||||
|
user_pool_id = self._get_param("UserPoolId")
|
||||||
|
users = cognitoidp_backends[self.region].list_users(user_pool_id)
|
||||||
|
return json.dumps({
|
||||||
|
"Users": [user.to_json(extended=True) for user in users]
|
||||||
|
})
|
||||||
|
|
||||||
|
def admin_delete_user(self):
|
||||||
|
user_pool_id = self._get_param("UserPoolId")
|
||||||
|
username = self._get_param("Username")
|
||||||
|
cognitoidp_backends[self.region].admin_delete_user(user_pool_id, username)
|
||||||
|
return ""
|
||||||
|
|
||||||
|
def admin_initiate_auth(self):
|
||||||
|
user_pool_id = self._get_param("UserPoolId")
|
||||||
|
client_id = self._get_param("ClientId")
|
||||||
|
auth_flow = self._get_param("AuthFlow")
|
||||||
|
auth_parameters = self._get_param("AuthParameters")
|
||||||
|
|
||||||
|
auth_result = cognitoidp_backends[self.region].admin_initiate_auth(
|
||||||
|
user_pool_id,
|
||||||
|
client_id,
|
||||||
|
auth_flow,
|
||||||
|
auth_parameters,
|
||||||
|
)
|
||||||
|
|
||||||
|
return json.dumps(auth_result)
|
||||||
|
|
||||||
|
def respond_to_auth_challenge(self):
|
||||||
|
session = self._get_param("Session")
|
||||||
|
client_id = self._get_param("ClientId")
|
||||||
|
challenge_name = self._get_param("ChallengeName")
|
||||||
|
challenge_responses = self._get_param("ChallengeResponses")
|
||||||
|
auth_result = cognitoidp_backends[self.region].respond_to_auth_challenge(
|
||||||
|
session,
|
||||||
|
client_id,
|
||||||
|
challenge_name,
|
||||||
|
challenge_responses,
|
||||||
|
)
|
||||||
|
|
||||||
|
return json.dumps(auth_result)
|
||||||
|
|
||||||
|
def forgot_password(self):
|
||||||
|
return json.dumps({
|
||||||
|
"CodeDeliveryDetails": {
|
||||||
|
"DeliveryMedium": "EMAIL",
|
||||||
|
"Destination": "...",
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
# This endpoint receives no authorization header, so if moto-server is listening
|
||||||
|
# on localhost (doesn't get a region in the host header), it doesn't know what
|
||||||
|
# region's backend should handle the traffic, and we use `find_region_by_value` to
|
||||||
|
# solve that problem.
|
||||||
|
def confirm_forgot_password(self):
|
||||||
|
client_id = self._get_param("ClientId")
|
||||||
|
username = self._get_param("Username")
|
||||||
|
password = self._get_param("Password")
|
||||||
|
region = find_region_by_value("client_id", client_id)
|
||||||
|
cognitoidp_backends[region].confirm_forgot_password(client_id, username, password)
|
||||||
|
return ""
|
||||||
|
|
||||||
|
# Ditto the comment on confirm_forgot_password.
|
||||||
|
def change_password(self):
|
||||||
|
access_token = self._get_param("AccessToken")
|
||||||
|
previous_password = self._get_param("PreviousPassword")
|
||||||
|
proposed_password = self._get_param("ProposedPassword")
|
||||||
|
region = find_region_by_value("access_token", access_token)
|
||||||
|
cognitoidp_backends[region].change_password(access_token, previous_password, proposed_password)
|
||||||
|
return ""
|
||||||
|
|
||||||
|
|
||||||
|
class CognitoIdpJsonWebKeyResponse(BaseResponse):
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
with open(os.path.join(os.path.dirname(__file__), "resources/jwks-public.json")) as f:
|
||||||
|
self.json_web_key = f.read()
|
||||||
|
|
||||||
|
def serve_json_web_key(self, request, full_url, headers):
|
||||||
|
return 200, {"Content-Type": "application/json"}, self.json_web_key
|
11
moto/cognitoidp/urls.py
Normal file
11
moto/cognitoidp/urls.py
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
from __future__ import unicode_literals
|
||||||
|
from .responses import CognitoIdpResponse, CognitoIdpJsonWebKeyResponse
|
||||||
|
|
||||||
|
url_bases = [
|
||||||
|
"https?://cognito-idp.(.+).amazonaws.com",
|
||||||
|
]
|
||||||
|
|
||||||
|
url_paths = {
|
||||||
|
'{0}/$': CognitoIdpResponse.dispatch,
|
||||||
|
'{0}/<user_pool_id>/.well-known/jwks.json$': CognitoIdpJsonWebKeyResponse().serve_json_web_key,
|
||||||
|
}
|
@ -69,8 +69,13 @@ class DomainDispatcherApplication(object):
|
|||||||
_, _, region, service, _ = environ['HTTP_AUTHORIZATION'].split(",")[0].split()[
|
_, _, region, service, _ = environ['HTTP_AUTHORIZATION'].split(",")[0].split()[
|
||||||
1].split("/")
|
1].split("/")
|
||||||
except (KeyError, ValueError):
|
except (KeyError, ValueError):
|
||||||
|
# Some cognito-idp endpoints (e.g. change password) do not receive an auth header.
|
||||||
|
if environ.get('HTTP_X_AMZ_TARGET', '').startswith('AWSCognitoIdentityProviderService'):
|
||||||
|
service = 'cognito-idp'
|
||||||
|
else:
|
||||||
|
service = 's3'
|
||||||
|
|
||||||
region = 'us-east-1'
|
region = 'us-east-1'
|
||||||
service = 's3'
|
|
||||||
if service == 'dynamodb':
|
if service == 'dynamodb':
|
||||||
dynamo_api_version = environ['HTTP_X_AMZ_TARGET'].split("_")[1].split(".")[0]
|
dynamo_api_version = environ['HTTP_X_AMZ_TARGET'].split("_")[1].split(".")[0]
|
||||||
# If Newer API version, use dynamodb2
|
# If Newer API version, use dynamodb2
|
||||||
|
1
setup.py
1
setup.py
@ -19,6 +19,7 @@ install_requires = [
|
|||||||
"pyaml",
|
"pyaml",
|
||||||
"pytz",
|
"pytz",
|
||||||
"python-dateutil<3.0.0,>=2.1",
|
"python-dateutil<3.0.0,>=2.1",
|
||||||
|
"python-jose<3.0.0",
|
||||||
"mock",
|
"mock",
|
||||||
"docker>=2.5.1",
|
"docker>=2.5.1",
|
||||||
"jsondiff==1.1.1",
|
"jsondiff==1.1.1",
|
||||||
|
539
tests/test_cognitoidp/test_cognitoidp.py
Normal file
539
tests/test_cognitoidp/test_cognitoidp.py
Normal file
@ -0,0 +1,539 @@
|
|||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
import boto3
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
import uuid
|
||||||
|
|
||||||
|
from jose import jws
|
||||||
|
from moto import mock_cognitoidp
|
||||||
|
import sure # noqa
|
||||||
|
|
||||||
|
|
||||||
|
@mock_cognitoidp
|
||||||
|
def test_create_user_pool():
|
||||||
|
conn = boto3.client("cognito-idp", "us-west-2")
|
||||||
|
|
||||||
|
name = str(uuid.uuid4())
|
||||||
|
value = str(uuid.uuid4())
|
||||||
|
result = conn.create_user_pool(
|
||||||
|
PoolName=name,
|
||||||
|
LambdaConfig={
|
||||||
|
"PreSignUp": value
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
result["UserPool"]["Id"].should_not.be.none
|
||||||
|
result["UserPool"]["Name"].should.equal(name)
|
||||||
|
result["UserPool"]["LambdaConfig"]["PreSignUp"].should.equal(value)
|
||||||
|
|
||||||
|
|
||||||
|
@mock_cognitoidp
|
||||||
|
def test_list_user_pools():
|
||||||
|
conn = boto3.client("cognito-idp", "us-west-2")
|
||||||
|
|
||||||
|
name = str(uuid.uuid4())
|
||||||
|
conn.create_user_pool(PoolName=name)
|
||||||
|
result = conn.list_user_pools(MaxResults=10)
|
||||||
|
result["UserPools"].should.have.length_of(1)
|
||||||
|
result["UserPools"][0]["Name"].should.equal(name)
|
||||||
|
|
||||||
|
|
||||||
|
@mock_cognitoidp
|
||||||
|
def test_describe_user_pool():
|
||||||
|
conn = boto3.client("cognito-idp", "us-west-2")
|
||||||
|
|
||||||
|
name = str(uuid.uuid4())
|
||||||
|
value = str(uuid.uuid4())
|
||||||
|
user_pool_details = conn.create_user_pool(
|
||||||
|
PoolName=name,
|
||||||
|
LambdaConfig={
|
||||||
|
"PreSignUp": value
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
result = conn.describe_user_pool(UserPoolId=user_pool_details["UserPool"]["Id"])
|
||||||
|
result["UserPool"]["Name"].should.equal(name)
|
||||||
|
result["UserPool"]["LambdaConfig"]["PreSignUp"].should.equal(value)
|
||||||
|
|
||||||
|
|
||||||
|
@mock_cognitoidp
|
||||||
|
def test_delete_user_pool():
|
||||||
|
conn = boto3.client("cognito-idp", "us-west-2")
|
||||||
|
|
||||||
|
user_pool_id = conn.create_user_pool(PoolName=str(uuid.uuid4()))["UserPool"]["Id"]
|
||||||
|
conn.list_user_pools(MaxResults=10)["UserPools"].should.have.length_of(1)
|
||||||
|
conn.delete_user_pool(UserPoolId=user_pool_id)
|
||||||
|
conn.list_user_pools(MaxResults=10)["UserPools"].should.have.length_of(0)
|
||||||
|
|
||||||
|
|
||||||
|
@mock_cognitoidp
|
||||||
|
def test_create_user_pool_domain():
|
||||||
|
conn = boto3.client("cognito-idp", "us-west-2")
|
||||||
|
|
||||||
|
domain = str(uuid.uuid4())
|
||||||
|
user_pool_id = conn.create_user_pool(PoolName=str(uuid.uuid4()))["UserPool"]["Id"]
|
||||||
|
result = conn.create_user_pool_domain(UserPoolId=user_pool_id, Domain=domain)
|
||||||
|
result["ResponseMetadata"]["HTTPStatusCode"].should.equal(200)
|
||||||
|
|
||||||
|
|
||||||
|
@mock_cognitoidp
|
||||||
|
def test_describe_user_pool_domain():
|
||||||
|
conn = boto3.client("cognito-idp", "us-west-2")
|
||||||
|
|
||||||
|
domain = str(uuid.uuid4())
|
||||||
|
user_pool_id = conn.create_user_pool(PoolName=str(uuid.uuid4()))["UserPool"]["Id"]
|
||||||
|
conn.create_user_pool_domain(UserPoolId=user_pool_id, Domain=domain)
|
||||||
|
result = conn.describe_user_pool_domain(Domain=domain)
|
||||||
|
result["DomainDescription"]["Domain"].should.equal(domain)
|
||||||
|
result["DomainDescription"]["UserPoolId"].should.equal(user_pool_id)
|
||||||
|
result["DomainDescription"]["AWSAccountId"].should_not.be.none
|
||||||
|
|
||||||
|
|
||||||
|
@mock_cognitoidp
|
||||||
|
def test_delete_user_pool_domain():
|
||||||
|
conn = boto3.client("cognito-idp", "us-west-2")
|
||||||
|
|
||||||
|
domain = str(uuid.uuid4())
|
||||||
|
user_pool_id = conn.create_user_pool(PoolName=str(uuid.uuid4()))["UserPool"]["Id"]
|
||||||
|
conn.create_user_pool_domain(UserPoolId=user_pool_id, Domain=domain)
|
||||||
|
result = conn.delete_user_pool_domain(UserPoolId=user_pool_id, Domain=domain)
|
||||||
|
result["ResponseMetadata"]["HTTPStatusCode"].should.equal(200)
|
||||||
|
result = conn.describe_user_pool_domain(Domain=domain)
|
||||||
|
# This is a surprising behavior of the real service: describing a missing domain comes
|
||||||
|
# back with status 200 and a DomainDescription of {}
|
||||||
|
result["ResponseMetadata"]["HTTPStatusCode"].should.equal(200)
|
||||||
|
result["DomainDescription"].keys().should.have.length_of(0)
|
||||||
|
|
||||||
|
|
||||||
|
@mock_cognitoidp
|
||||||
|
def test_create_user_pool_client():
|
||||||
|
conn = boto3.client("cognito-idp", "us-west-2")
|
||||||
|
|
||||||
|
client_name = str(uuid.uuid4())
|
||||||
|
value = str(uuid.uuid4())
|
||||||
|
user_pool_id = conn.create_user_pool(PoolName=str(uuid.uuid4()))["UserPool"]["Id"]
|
||||||
|
result = conn.create_user_pool_client(
|
||||||
|
UserPoolId=user_pool_id,
|
||||||
|
ClientName=client_name,
|
||||||
|
CallbackURLs=[value],
|
||||||
|
)
|
||||||
|
|
||||||
|
result["UserPoolClient"]["UserPoolId"].should.equal(user_pool_id)
|
||||||
|
result["UserPoolClient"]["ClientId"].should_not.be.none
|
||||||
|
result["UserPoolClient"]["ClientName"].should.equal(client_name)
|
||||||
|
result["UserPoolClient"]["CallbackURLs"].should.have.length_of(1)
|
||||||
|
result["UserPoolClient"]["CallbackURLs"][0].should.equal(value)
|
||||||
|
|
||||||
|
|
||||||
|
@mock_cognitoidp
|
||||||
|
def test_list_user_pool_clients():
|
||||||
|
conn = boto3.client("cognito-idp", "us-west-2")
|
||||||
|
|
||||||
|
client_name = str(uuid.uuid4())
|
||||||
|
user_pool_id = conn.create_user_pool(PoolName=str(uuid.uuid4()))["UserPool"]["Id"]
|
||||||
|
conn.create_user_pool_client(UserPoolId=user_pool_id, ClientName=client_name)
|
||||||
|
result = conn.list_user_pool_clients(UserPoolId=user_pool_id, MaxResults=10)
|
||||||
|
result["UserPoolClients"].should.have.length_of(1)
|
||||||
|
result["UserPoolClients"][0]["ClientName"].should.equal(client_name)
|
||||||
|
|
||||||
|
|
||||||
|
@mock_cognitoidp
|
||||||
|
def test_describe_user_pool_client():
|
||||||
|
conn = boto3.client("cognito-idp", "us-west-2")
|
||||||
|
|
||||||
|
client_name = str(uuid.uuid4())
|
||||||
|
value = str(uuid.uuid4())
|
||||||
|
user_pool_id = conn.create_user_pool(PoolName=str(uuid.uuid4()))["UserPool"]["Id"]
|
||||||
|
client_details = conn.create_user_pool_client(
|
||||||
|
UserPoolId=user_pool_id,
|
||||||
|
ClientName=client_name,
|
||||||
|
CallbackURLs=[value],
|
||||||
|
)
|
||||||
|
|
||||||
|
result = conn.describe_user_pool_client(
|
||||||
|
UserPoolId=user_pool_id,
|
||||||
|
ClientId=client_details["UserPoolClient"]["ClientId"],
|
||||||
|
)
|
||||||
|
|
||||||
|
result["UserPoolClient"]["ClientName"].should.equal(client_name)
|
||||||
|
result["UserPoolClient"]["CallbackURLs"].should.have.length_of(1)
|
||||||
|
result["UserPoolClient"]["CallbackURLs"][0].should.equal(value)
|
||||||
|
|
||||||
|
|
||||||
|
@mock_cognitoidp
|
||||||
|
def test_update_user_pool_client():
|
||||||
|
conn = boto3.client("cognito-idp", "us-west-2")
|
||||||
|
|
||||||
|
old_client_name = str(uuid.uuid4())
|
||||||
|
new_client_name = str(uuid.uuid4())
|
||||||
|
old_value = str(uuid.uuid4())
|
||||||
|
new_value = str(uuid.uuid4())
|
||||||
|
user_pool_id = conn.create_user_pool(PoolName=str(uuid.uuid4()))["UserPool"]["Id"]
|
||||||
|
client_details = conn.create_user_pool_client(
|
||||||
|
UserPoolId=user_pool_id,
|
||||||
|
ClientName=old_client_name,
|
||||||
|
CallbackURLs=[old_value],
|
||||||
|
)
|
||||||
|
|
||||||
|
result = conn.update_user_pool_client(
|
||||||
|
UserPoolId=user_pool_id,
|
||||||
|
ClientId=client_details["UserPoolClient"]["ClientId"],
|
||||||
|
ClientName=new_client_name,
|
||||||
|
CallbackURLs=[new_value],
|
||||||
|
)
|
||||||
|
|
||||||
|
result["UserPoolClient"]["ClientName"].should.equal(new_client_name)
|
||||||
|
result["UserPoolClient"]["CallbackURLs"].should.have.length_of(1)
|
||||||
|
result["UserPoolClient"]["CallbackURLs"][0].should.equal(new_value)
|
||||||
|
|
||||||
|
|
||||||
|
@mock_cognitoidp
|
||||||
|
def test_delete_user_pool_client():
|
||||||
|
conn = boto3.client("cognito-idp", "us-west-2")
|
||||||
|
|
||||||
|
user_pool_id = conn.create_user_pool(PoolName=str(uuid.uuid4()))["UserPool"]["Id"]
|
||||||
|
client_details = conn.create_user_pool_client(
|
||||||
|
UserPoolId=user_pool_id,
|
||||||
|
ClientName=str(uuid.uuid4()),
|
||||||
|
)
|
||||||
|
|
||||||
|
conn.delete_user_pool_client(
|
||||||
|
UserPoolId=user_pool_id,
|
||||||
|
ClientId=client_details["UserPoolClient"]["ClientId"],
|
||||||
|
)
|
||||||
|
|
||||||
|
caught = False
|
||||||
|
try:
|
||||||
|
conn.describe_user_pool_client(
|
||||||
|
UserPoolId=user_pool_id,
|
||||||
|
ClientId=client_details["UserPoolClient"]["ClientId"],
|
||||||
|
)
|
||||||
|
except conn.exceptions.ResourceNotFoundException:
|
||||||
|
caught = True
|
||||||
|
|
||||||
|
caught.should.be.true
|
||||||
|
|
||||||
|
|
||||||
|
@mock_cognitoidp
|
||||||
|
def test_create_identity_provider():
|
||||||
|
conn = boto3.client("cognito-idp", "us-west-2")
|
||||||
|
|
||||||
|
provider_name = str(uuid.uuid4())
|
||||||
|
provider_type = "Facebook"
|
||||||
|
value = str(uuid.uuid4())
|
||||||
|
user_pool_id = conn.create_user_pool(PoolName=str(uuid.uuid4()))["UserPool"]["Id"]
|
||||||
|
result = conn.create_identity_provider(
|
||||||
|
UserPoolId=user_pool_id,
|
||||||
|
ProviderName=provider_name,
|
||||||
|
ProviderType=provider_type,
|
||||||
|
ProviderDetails={
|
||||||
|
"thing": value
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
result["IdentityProvider"]["UserPoolId"].should.equal(user_pool_id)
|
||||||
|
result["IdentityProvider"]["ProviderName"].should.equal(provider_name)
|
||||||
|
result["IdentityProvider"]["ProviderType"].should.equal(provider_type)
|
||||||
|
result["IdentityProvider"]["ProviderDetails"]["thing"].should.equal(value)
|
||||||
|
|
||||||
|
|
||||||
|
@mock_cognitoidp
|
||||||
|
def test_list_identity_providers():
|
||||||
|
conn = boto3.client("cognito-idp", "us-west-2")
|
||||||
|
|
||||||
|
provider_name = str(uuid.uuid4())
|
||||||
|
provider_type = "Facebook"
|
||||||
|
user_pool_id = conn.create_user_pool(PoolName=str(uuid.uuid4()))["UserPool"]["Id"]
|
||||||
|
conn.create_identity_provider(
|
||||||
|
UserPoolId=user_pool_id,
|
||||||
|
ProviderName=provider_name,
|
||||||
|
ProviderType=provider_type,
|
||||||
|
ProviderDetails={},
|
||||||
|
)
|
||||||
|
|
||||||
|
result = conn.list_identity_providers(
|
||||||
|
UserPoolId=user_pool_id,
|
||||||
|
MaxResults=10,
|
||||||
|
)
|
||||||
|
|
||||||
|
result["Providers"].should.have.length_of(1)
|
||||||
|
result["Providers"][0]["ProviderName"].should.equal(provider_name)
|
||||||
|
result["Providers"][0]["ProviderType"].should.equal(provider_type)
|
||||||
|
|
||||||
|
|
||||||
|
@mock_cognitoidp
|
||||||
|
def test_describe_identity_providers():
|
||||||
|
conn = boto3.client("cognito-idp", "us-west-2")
|
||||||
|
|
||||||
|
provider_name = str(uuid.uuid4())
|
||||||
|
provider_type = "Facebook"
|
||||||
|
value = str(uuid.uuid4())
|
||||||
|
user_pool_id = conn.create_user_pool(PoolName=str(uuid.uuid4()))["UserPool"]["Id"]
|
||||||
|
conn.create_identity_provider(
|
||||||
|
UserPoolId=user_pool_id,
|
||||||
|
ProviderName=provider_name,
|
||||||
|
ProviderType=provider_type,
|
||||||
|
ProviderDetails={
|
||||||
|
"thing": value
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
result = conn.describe_identity_provider(
|
||||||
|
UserPoolId=user_pool_id,
|
||||||
|
ProviderName=provider_name,
|
||||||
|
)
|
||||||
|
|
||||||
|
result["IdentityProvider"]["UserPoolId"].should.equal(user_pool_id)
|
||||||
|
result["IdentityProvider"]["ProviderName"].should.equal(provider_name)
|
||||||
|
result["IdentityProvider"]["ProviderType"].should.equal(provider_type)
|
||||||
|
result["IdentityProvider"]["ProviderDetails"]["thing"].should.equal(value)
|
||||||
|
|
||||||
|
|
||||||
|
@mock_cognitoidp
|
||||||
|
def test_delete_identity_providers():
|
||||||
|
conn = boto3.client("cognito-idp", "us-west-2")
|
||||||
|
|
||||||
|
provider_name = str(uuid.uuid4())
|
||||||
|
provider_type = "Facebook"
|
||||||
|
value = str(uuid.uuid4())
|
||||||
|
user_pool_id = conn.create_user_pool(PoolName=str(uuid.uuid4()))["UserPool"]["Id"]
|
||||||
|
conn.create_identity_provider(
|
||||||
|
UserPoolId=user_pool_id,
|
||||||
|
ProviderName=provider_name,
|
||||||
|
ProviderType=provider_type,
|
||||||
|
ProviderDetails={
|
||||||
|
"thing": value
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
conn.delete_identity_provider(UserPoolId=user_pool_id, ProviderName=provider_name)
|
||||||
|
|
||||||
|
caught = False
|
||||||
|
try:
|
||||||
|
conn.describe_identity_provider(
|
||||||
|
UserPoolId=user_pool_id,
|
||||||
|
ProviderName=provider_name,
|
||||||
|
)
|
||||||
|
except conn.exceptions.ResourceNotFoundException:
|
||||||
|
caught = True
|
||||||
|
|
||||||
|
caught.should.be.true
|
||||||
|
|
||||||
|
|
||||||
|
@mock_cognitoidp
|
||||||
|
def test_admin_create_user():
|
||||||
|
conn = boto3.client("cognito-idp", "us-west-2")
|
||||||
|
|
||||||
|
username = str(uuid.uuid4())
|
||||||
|
value = str(uuid.uuid4())
|
||||||
|
user_pool_id = conn.create_user_pool(PoolName=str(uuid.uuid4()))["UserPool"]["Id"]
|
||||||
|
result = conn.admin_create_user(
|
||||||
|
UserPoolId=user_pool_id,
|
||||||
|
Username=username,
|
||||||
|
UserAttributes=[
|
||||||
|
{"Name": "thing", "Value": value}
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
result["User"]["Username"].should.equal(username)
|
||||||
|
result["User"]["UserStatus"].should.equal("FORCE_CHANGE_PASSWORD")
|
||||||
|
result["User"]["Attributes"].should.have.length_of(1)
|
||||||
|
result["User"]["Attributes"][0]["Name"].should.equal("thing")
|
||||||
|
result["User"]["Attributes"][0]["Value"].should.equal(value)
|
||||||
|
|
||||||
|
|
||||||
|
@mock_cognitoidp
|
||||||
|
def test_admin_get_user():
|
||||||
|
conn = boto3.client("cognito-idp", "us-west-2")
|
||||||
|
|
||||||
|
username = str(uuid.uuid4())
|
||||||
|
value = str(uuid.uuid4())
|
||||||
|
user_pool_id = conn.create_user_pool(PoolName=str(uuid.uuid4()))["UserPool"]["Id"]
|
||||||
|
conn.admin_create_user(
|
||||||
|
UserPoolId=user_pool_id,
|
||||||
|
Username=username,
|
||||||
|
UserAttributes=[
|
||||||
|
{"Name": "thing", "Value": value}
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
result = conn.admin_get_user(UserPoolId=user_pool_id, Username=username)
|
||||||
|
result["Username"].should.equal(username)
|
||||||
|
result["UserAttributes"].should.have.length_of(1)
|
||||||
|
result["UserAttributes"][0]["Name"].should.equal("thing")
|
||||||
|
result["UserAttributes"][0]["Value"].should.equal(value)
|
||||||
|
|
||||||
|
|
||||||
|
@mock_cognitoidp
|
||||||
|
def test_list_users():
|
||||||
|
conn = boto3.client("cognito-idp", "us-west-2")
|
||||||
|
|
||||||
|
username = str(uuid.uuid4())
|
||||||
|
user_pool_id = conn.create_user_pool(PoolName=str(uuid.uuid4()))["UserPool"]["Id"]
|
||||||
|
conn.admin_create_user(UserPoolId=user_pool_id, Username=username)
|
||||||
|
result = conn.list_users(UserPoolId=user_pool_id)
|
||||||
|
result["Users"].should.have.length_of(1)
|
||||||
|
result["Users"][0]["Username"].should.equal(username)
|
||||||
|
|
||||||
|
|
||||||
|
@mock_cognitoidp
|
||||||
|
def test_admin_delete_user():
|
||||||
|
conn = boto3.client("cognito-idp", "us-west-2")
|
||||||
|
|
||||||
|
username = str(uuid.uuid4())
|
||||||
|
user_pool_id = conn.create_user_pool(PoolName=str(uuid.uuid4()))["UserPool"]["Id"]
|
||||||
|
conn.admin_create_user(UserPoolId=user_pool_id, Username=username)
|
||||||
|
conn.admin_delete_user(UserPoolId=user_pool_id, Username=username)
|
||||||
|
|
||||||
|
caught = False
|
||||||
|
try:
|
||||||
|
conn.admin_get_user(UserPoolId=user_pool_id, Username=username)
|
||||||
|
except conn.exceptions.ResourceNotFoundException:
|
||||||
|
caught = True
|
||||||
|
|
||||||
|
caught.should.be.true
|
||||||
|
|
||||||
|
|
||||||
|
def authentication_flow(conn):
|
||||||
|
username = str(uuid.uuid4())
|
||||||
|
temporary_password = str(uuid.uuid4())
|
||||||
|
user_pool_id = conn.create_user_pool(PoolName=str(uuid.uuid4()))["UserPool"]["Id"]
|
||||||
|
client_id = conn.create_user_pool_client(
|
||||||
|
UserPoolId=user_pool_id,
|
||||||
|
ClientName=str(uuid.uuid4()),
|
||||||
|
)["UserPoolClient"]["ClientId"]
|
||||||
|
|
||||||
|
conn.admin_create_user(
|
||||||
|
UserPoolId=user_pool_id,
|
||||||
|
Username=username,
|
||||||
|
TemporaryPassword=temporary_password,
|
||||||
|
)
|
||||||
|
|
||||||
|
result = conn.admin_initiate_auth(
|
||||||
|
UserPoolId=user_pool_id,
|
||||||
|
ClientId=client_id,
|
||||||
|
AuthFlow="ADMIN_NO_SRP_AUTH",
|
||||||
|
AuthParameters={
|
||||||
|
"USERNAME": username,
|
||||||
|
"PASSWORD": temporary_password
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
# A newly created user is forced to set a new password
|
||||||
|
result["ChallengeName"].should.equal("NEW_PASSWORD_REQUIRED")
|
||||||
|
result["Session"].should_not.be.none
|
||||||
|
|
||||||
|
# This sets a new password and logs the user in (creates tokens)
|
||||||
|
new_password = str(uuid.uuid4())
|
||||||
|
result = conn.respond_to_auth_challenge(
|
||||||
|
Session=result["Session"],
|
||||||
|
ClientId=client_id,
|
||||||
|
ChallengeName="NEW_PASSWORD_REQUIRED",
|
||||||
|
ChallengeResponses={
|
||||||
|
"USERNAME": username,
|
||||||
|
"NEW_PASSWORD": new_password
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
result["AuthenticationResult"]["IdToken"].should_not.be.none
|
||||||
|
result["AuthenticationResult"]["AccessToken"].should_not.be.none
|
||||||
|
|
||||||
|
return {
|
||||||
|
"user_pool_id": user_pool_id,
|
||||||
|
"client_id": client_id,
|
||||||
|
"id_token": result["AuthenticationResult"]["IdToken"],
|
||||||
|
"access_token": result["AuthenticationResult"]["AccessToken"],
|
||||||
|
"username": username,
|
||||||
|
"password": new_password,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@mock_cognitoidp
|
||||||
|
def test_authentication_flow():
|
||||||
|
conn = boto3.client("cognito-idp", "us-west-2")
|
||||||
|
|
||||||
|
authentication_flow(conn)
|
||||||
|
|
||||||
|
|
||||||
|
@mock_cognitoidp
|
||||||
|
def test_token_legitimacy():
|
||||||
|
conn = boto3.client("cognito-idp", "us-west-2")
|
||||||
|
|
||||||
|
path = "../../moto/cognitoidp/resources/jwks-public.json"
|
||||||
|
with open(os.path.join(os.path.dirname(__file__), path)) as f:
|
||||||
|
json_web_key = json.loads(f.read())["keys"][0]
|
||||||
|
|
||||||
|
outputs = authentication_flow(conn)
|
||||||
|
id_token = outputs["id_token"]
|
||||||
|
access_token = outputs["access_token"]
|
||||||
|
client_id = outputs["client_id"]
|
||||||
|
issuer = "https://cognito-idp.us-west-2.amazonaws.com/{}".format(outputs["user_pool_id"])
|
||||||
|
id_claims = json.loads(jws.verify(id_token, json_web_key, "RS256"))
|
||||||
|
id_claims["iss"].should.equal(issuer)
|
||||||
|
id_claims["aud"].should.equal(client_id)
|
||||||
|
access_claims = json.loads(jws.verify(access_token, json_web_key, "RS256"))
|
||||||
|
access_claims["iss"].should.equal(issuer)
|
||||||
|
access_claims["aud"].should.equal(client_id)
|
||||||
|
|
||||||
|
|
||||||
|
@mock_cognitoidp
|
||||||
|
def test_change_password():
|
||||||
|
conn = boto3.client("cognito-idp", "us-west-2")
|
||||||
|
|
||||||
|
outputs = authentication_flow(conn)
|
||||||
|
|
||||||
|
# Take this opportunity to test change_password, which requires an access token.
|
||||||
|
newer_password = str(uuid.uuid4())
|
||||||
|
conn.change_password(
|
||||||
|
AccessToken=outputs["access_token"],
|
||||||
|
PreviousPassword=outputs["password"],
|
||||||
|
ProposedPassword=newer_password,
|
||||||
|
)
|
||||||
|
|
||||||
|
# Log in again, which should succeed without a challenge because the user is no
|
||||||
|
# longer in the force-new-password state.
|
||||||
|
result = conn.admin_initiate_auth(
|
||||||
|
UserPoolId=outputs["user_pool_id"],
|
||||||
|
ClientId=outputs["client_id"],
|
||||||
|
AuthFlow="ADMIN_NO_SRP_AUTH",
|
||||||
|
AuthParameters={
|
||||||
|
"USERNAME": outputs["username"],
|
||||||
|
"PASSWORD": newer_password,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
result["AuthenticationResult"].should_not.be.none
|
||||||
|
|
||||||
|
|
||||||
|
@mock_cognitoidp
|
||||||
|
def test_forgot_password():
|
||||||
|
conn = boto3.client("cognito-idp", "us-west-2")
|
||||||
|
|
||||||
|
result = conn.forgot_password(ClientId=str(uuid.uuid4()), Username=str(uuid.uuid4()))
|
||||||
|
result["CodeDeliveryDetails"].should_not.be.none
|
||||||
|
|
||||||
|
|
||||||
|
@mock_cognitoidp
|
||||||
|
def test_confirm_forgot_password():
|
||||||
|
conn = boto3.client("cognito-idp", "us-west-2")
|
||||||
|
|
||||||
|
username = str(uuid.uuid4())
|
||||||
|
user_pool_id = conn.create_user_pool(PoolName=str(uuid.uuid4()))["UserPool"]["Id"]
|
||||||
|
client_id = conn.create_user_pool_client(
|
||||||
|
UserPoolId=user_pool_id,
|
||||||
|
ClientName=str(uuid.uuid4()),
|
||||||
|
)["UserPoolClient"]["ClientId"]
|
||||||
|
|
||||||
|
conn.admin_create_user(
|
||||||
|
UserPoolId=user_pool_id,
|
||||||
|
Username=username,
|
||||||
|
TemporaryPassword=str(uuid.uuid4()),
|
||||||
|
)
|
||||||
|
|
||||||
|
conn.confirm_forgot_password(
|
||||||
|
ClientId=client_id,
|
||||||
|
Username=username,
|
||||||
|
ConfirmationCode=str(uuid.uuid4()),
|
||||||
|
Password=str(uuid.uuid4()),
|
||||||
|
)
|
Loading…
Reference in New Issue
Block a user