parent
0211e9d78d
commit
c9dd9cc7f9
5
Makefile
5
Makefile
@ -1,13 +1,10 @@
|
||||
SHELL := /bin/bash
|
||||
|
||||
ifeq ($(TEST_SERVER_MODE), true)
|
||||
# exclude test_iot and test_iotdata for now
|
||||
# because authentication of iot is very complicated
|
||||
|
||||
# exclude test_kinesisvideoarchivedmedia
|
||||
# because testing with moto_server is difficult with data-endpoint
|
||||
|
||||
TEST_EXCLUDE := -k 'not (test_iot or test_kinesisvideoarchivedmedia)'
|
||||
TEST_EXCLUDE := -k 'not test_kinesisvideoarchivedmedia'
|
||||
else
|
||||
TEST_EXCLUDE :=
|
||||
endif
|
||||
|
@ -425,8 +425,19 @@ class IoTResponse(BaseResponse):
|
||||
self.iot_backend.attach_policy(policy_name=policy_name, target=target)
|
||||
return json.dumps(dict())
|
||||
|
||||
def dispatch_attached_policies(self, request, full_url, headers):
|
||||
# This endpoint requires specialized handling because it has
|
||||
# a uri parameter containing forward slashes that is not
|
||||
# correctly url encoded when we're running in server mode.
|
||||
# https://github.com/pallets/flask/issues/900
|
||||
self.setup_class(request, full_url, headers)
|
||||
self.querystring["Action"] = ["ListAttachedPolicies"]
|
||||
target = self.path.partition("/attached-policies/")[-1]
|
||||
self.querystring["target"] = [unquote(target)] if "%" in target else [target]
|
||||
return self.call_action()
|
||||
|
||||
def list_attached_policies(self):
|
||||
principal = unquote(self._get_param("target"))
|
||||
principal = self._get_param("target")
|
||||
# marker = self._get_param("marker")
|
||||
# page_size = self._get_int_param("pageSize")
|
||||
policies = self.iot_backend.list_attached_policies(target=principal)
|
||||
|
@ -7,4 +7,19 @@ url_bases = ["https?://iot.(.+).amazonaws.com"]
|
||||
response = IoTResponse()
|
||||
|
||||
|
||||
url_paths = {"{0}/.*$": response.dispatch}
|
||||
url_paths = {
|
||||
#
|
||||
# Paths for :class:`moto.core.models.MockAWS`
|
||||
#
|
||||
# This route requires special handling.
|
||||
"{0}/attached-policies/(?P<target>.*)$": response.dispatch_attached_policies,
|
||||
# The remaining routes can be handled by the default dispatcher.
|
||||
"{0}/.*$": response.dispatch,
|
||||
#
|
||||
# (Flask) Paths for :class:`moto.core.models.ServerModeMockAWS`
|
||||
#
|
||||
# This route requires special handling.
|
||||
"{0}/attached-policies/<path:target>$": response.dispatch_attached_policies,
|
||||
# The remaining routes can be handled by the default dispatcher.
|
||||
"{0}/<path:route>$": response.dispatch,
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ from __future__ import unicode_literals
|
||||
from moto.core.responses import BaseResponse
|
||||
from .models import iotdata_backends
|
||||
import json
|
||||
from six.moves.urllib.parse import unquote
|
||||
|
||||
|
||||
class IoTDataPlaneResponse(BaseResponse):
|
||||
@ -29,6 +30,17 @@ class IoTDataPlaneResponse(BaseResponse):
|
||||
payload = self.iotdata_backend.delete_thing_shadow(thing_name=thing_name)
|
||||
return json.dumps(payload.to_dict())
|
||||
|
||||
def dispatch_publish(self, request, full_url, headers):
|
||||
# This endpoint requires specialized handling because it has
|
||||
# a uri parameter containing forward slashes that is not
|
||||
# correctly url encoded when we're running in server mode.
|
||||
# https://github.com/pallets/flask/issues/900
|
||||
self.setup_class(request, full_url, headers)
|
||||
self.querystring["Action"] = ["Publish"]
|
||||
topic = self.path.partition("/topics/")[-1]
|
||||
self.querystring["target"] = [unquote(topic)] if "%" in topic else [topic]
|
||||
return self.call_action()
|
||||
|
||||
def publish(self):
|
||||
topic = self._get_param("topic")
|
||||
qos = self._get_int_param("qos")
|
||||
|
@ -7,4 +7,19 @@ url_bases = ["https?://data.iot.(.+).amazonaws.com"]
|
||||
response = IoTDataPlaneResponse()
|
||||
|
||||
|
||||
url_paths = {"{0}/.*$": response.dispatch}
|
||||
url_paths = {
|
||||
#
|
||||
# Paths for :class:`moto.core.models.MockAWS`
|
||||
#
|
||||
# This route requires special handling.
|
||||
"{0}/topics/(?P<topic>.*)$": response.dispatch_publish,
|
||||
# The remaining routes can be handled by the default dispatcher.
|
||||
"{0}/.*$": response.dispatch,
|
||||
#
|
||||
# (Flask) Paths for :class:`moto.core.models.ServerModeMockAWS`
|
||||
#
|
||||
# This route requires special handling.
|
||||
"{0}/topics/<path:topic>$": response.dispatch_publish,
|
||||
# The remaining routes can be handled by the default dispatcher.
|
||||
"{0}/<path:route>$": response.dispatch,
|
||||
}
|
||||
|
@ -34,6 +34,13 @@ UNSIGNED_REQUESTS = {
|
||||
}
|
||||
UNSIGNED_ACTIONS = {"AssumeRoleWithSAML": ("sts", "us-east-1")}
|
||||
|
||||
# Some services have v4 signing names that differ from the backend service name/id.
|
||||
SIGNING_ALIASES = {
|
||||
"eventbridge": "events",
|
||||
"execute-api": "iot",
|
||||
"iotdata": "data.iot",
|
||||
}
|
||||
|
||||
|
||||
class DomainDispatcherApplication(object):
|
||||
"""
|
||||
@ -74,6 +81,7 @@ class DomainDispatcherApplication(object):
|
||||
try:
|
||||
credential_scope = auth.split(",")[0].split()[1]
|
||||
_, _, region, service, _ = credential_scope.split("/")
|
||||
service = SIGNING_ALIASES.get(service.lower(), service)
|
||||
except ValueError:
|
||||
# Signature format does not match, this is exceptional and we can't
|
||||
# infer a service-region. A reduced set of services still use
|
||||
@ -94,11 +102,6 @@ class DomainDispatcherApplication(object):
|
||||
# S3 is the last resort when the target is also unknown
|
||||
service, region = DEFAULT_SERVICE_REGION
|
||||
|
||||
if service == "EventBridge":
|
||||
# Go SDK uses 'EventBridge' in the SigV4 request instead of 'events'
|
||||
# see https://github.com/spulec/moto/issues/3494
|
||||
service = "events"
|
||||
|
||||
if service == "dynamodb":
|
||||
if environ["HTTP_X_AMZ_TARGET"].startswith("DynamoDBStreams"):
|
||||
host = "dynamodbstreams"
|
||||
|
@ -1,5 +1,9 @@
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import json
|
||||
from six.moves.urllib.parse import quote
|
||||
|
||||
import pytest
|
||||
import sure # noqa
|
||||
|
||||
import moto.server as server
|
||||
@ -17,4 +21,32 @@ def test_iot_list():
|
||||
|
||||
# just making sure that server is up
|
||||
res = test_client.get("/things")
|
||||
res.status_code.should.equal(404)
|
||||
res.status_code.should.equal(200)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"url_encode_arn",
|
||||
[
|
||||
pytest.param(True, id="Target Arn in Path is URL encoded"),
|
||||
pytest.param(False, id="Target Arn in Path is *not* URL encoded"),
|
||||
],
|
||||
)
|
||||
@mock_iot
|
||||
def test_list_attached_policies(url_encode_arn):
|
||||
backend = server.create_backend_app("iot")
|
||||
test_client = backend.test_client()
|
||||
|
||||
result = test_client.post("/keys-and-certificate?setAsActive=true")
|
||||
result_dict = json.loads(result.data.decode("utf-8"))
|
||||
certificate_arn = result_dict["certificateArn"]
|
||||
|
||||
test_client.post("/policies/my-policy", json={"policyDocument": {}})
|
||||
test_client.put("/target-policies/my-policy", json={"target": certificate_arn})
|
||||
|
||||
if url_encode_arn:
|
||||
certificate_arn = quote(certificate_arn, safe="")
|
||||
|
||||
result = test_client.post("/attached-policies/{}".format(certificate_arn))
|
||||
result.status_code.should.equal(200)
|
||||
result_dict = json.loads(result.data.decode("utf-8"))
|
||||
result_dict["policies"][0]["policyName"].should.equal("my-policy")
|
||||
|
@ -1,5 +1,8 @@
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from six.moves.urllib.parse import quote
|
||||
|
||||
import pytest
|
||||
import sure # noqa
|
||||
|
||||
import moto.server as server
|
||||
@ -19,3 +22,22 @@ def test_iotdata_list():
|
||||
thing_name = "nothing"
|
||||
res = test_client.get("/things/{}/shadow".format(thing_name))
|
||||
res.status_code.should.equal(404)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"url_encode_topic",
|
||||
[
|
||||
pytest.param(True, id="Topic in Path is URL encoded"),
|
||||
pytest.param(False, id="Topic in Path is *not* URL encoded"),
|
||||
],
|
||||
)
|
||||
@mock_iotdata
|
||||
def test_publish(url_encode_topic):
|
||||
backend = server.create_backend_app("iot-data")
|
||||
test_client = backend.test_client()
|
||||
|
||||
topic = "test/topic"
|
||||
topic_for_path = quote(topic, safe="") if url_encode_topic else topic
|
||||
|
||||
result = test_client.post("/topics/{}".format(topic_for_path))
|
||||
result.status_code.should.equal(200)
|
||||
|
Loading…
Reference in New Issue
Block a user