Fix: IoT does not work in server mode (#3644)

Closes #1631
This commit is contained in:
Brian Pandola 2021-02-01 05:15:57 -08:00 committed by GitHub
commit c9dd9cc7f9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 120 additions and 13 deletions

View file

@ -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)

View file

@ -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,
}

View file

@ -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")

View file

@ -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,
}

View file

@ -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"