AWS API Gateway expects the request URL to be encoded twice - amazon-web-services

My API is a request that can potentially have spaces in the pathParameters.
/data/{id}/hello/{Some message with a space}.
A sample request would be /data/23/hello/Say%20Hi
My angular code from the frontend encodes the request URL that is sent out to the AWS API Gateway but I get the following error.
`The Canonical String for this request should have been
'GET
/data/23/hello/Sayr%2520Hi`
My API gateway has a velocity template the decodes the parameters using $util.urlDecode()

I'm facing the same problem.
I've been stuck for a day.
If you are using HttpApi it cannot be solved.
Nevertheless, if you use RestApi I managed to make this work.
Specifically, you should use the URL Path Parameters.
You should:
Add a resource containing the /{variable}
Add a Url Path Parameter in the Integration Request Configuration with name variable and mapped from method.request.path.variable
Notice that the solution may depend on the integration type that you are using.
In the screenshot below you can see how I'm redirecting all the received traffic to a NetworkLoadBalancer.
The resource has the variable /{proxy+}, the endpoint URL has the {proxy}, and, in the URL Path Parameters, I've configured the mapping method.request.path.proxy.

Related

API Gateway configuration returns 403

I have an API Gateway configured and deployed. If I make a GET request to one of its staged endpoints, for example https://1234567890.execute-api.us-east-1.amazonaws.com/dev/doc, I get a 200 OK response.
If I take a look at the Custom Domain Names section and supplant the URL found there into my request, for example abcdefghijkl-f4cwy0d1u5.execute-api.us-east-1.amazonaws.com to make https://abcdefghijkl-f4cwy0d1u5.execute-api.us-east-1.amazonaws.com/dev/doc, I get 403 Forbidden.
Am I wrong in thinking that I should be able to make a request to the domain name - and thus use the API's Custom domain name in a CNAME record - or does the 403 indicate that a specific configuration item is missing?
you can find some response headers that come together with your 403 error here: https://aws.amazon.com/premiumsupport/knowledge-center/api-gateway-troubleshoot-403-forbidden/
this might help you to find which error you are facing!
TL;DR: When getting 403 Forbidden with API Gateway and using the Custom domain name it's important to trim the stage name because API Gateway is routing the custom name to that stage.
Using the documentation provided by #leoandreotti I was able to identify the response header:
x-amzn-ErrorType: ForbiddenException
For this, the documentation states:
Invoking a REST API that has a custom domain name using the default
execute-api endpoint - The caller uses the default execute-api
endpoint to invoke a REST API after disabling the default endpoint.
This made me think back to a header I had been recommended to use by a colleague - the Host header.
So, I added the header back into the request and got this:
x-amzn-ErrorType: MissingAuthenticationTokenException
For which the docs state:
Resource path doesn't exist - A request with no "Authorization" header
is sent to an API resource path that doesn't exist.
But the path /dev/doc absolutely does exist. Then I realised that the /dev portion is actually the stage name.
So I trimmed the /dev portion from the path and got 200 OK - then I removed the Host header and also got 200 OK!
Thanks #leoandreotti

why does api gateway with http api using api mapping fail with 404?

I have a custom domain name in AWS API gateway. I am using the same domain for 2 separate API stages. One API stage is REST API, and the other HTTP API.
When I test out my setup, everything works for the REST API. However, the mapping path for HTTP API is not working and I get status-code = 404 Not Found, with 0kb body.
references used:
https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-mappings.html
https://docs.aws.amazon.com/apigateway/latest/developerguide/rest-api-mappings.html
From my testing in postman, i get the following result when calling the custom domain.
1. {{api.gateway.custom.domain.url}}/foobar - works
2. {{api.gateway.custom.domain.url}}/this-no-work/foobar - 404
3. {{api.gateway.custom.domain.url}}/this-works/foobar - works
does anyone know why (2) gives 404? api-gateway REST API with mapping works while api-gateway HTTP API will return 404 with 0kb body. Is there something I am missing?
note: the (none) path mapping has been added for a sanity check, and I was able to get the expected response.
I had the same problem.
The problem is in the configuration of routers of your application.
When you configure one API mapping in AWS API Gateway, the configured path (this-no-work) is passed to your web application as a prefix of routes.
SO ... if you have one route like this:
/api/foobar
you need configure one more route with the prefix point to the same action:
/this-no-work/api/foobar
A good one is to make one global configuration to your web app.
You can note it enabling the cloudwatch logs of your API Gateway stage and looking into the cloudwatch logs the path property passed from API Gateway to the Web application.
Thanks to answer from #gean-ribeiro, I was able to figure why my HTTP API was returning 404 Not Found.
Turns out it was not an issue with HTTP API. The error 404 Not Found with 0kb body was coming from the API integration sitting behind APIG. Specifically, it was a load balancer using rules based on HTTP path pattern.
By default, any unmatched path pattern will return 404 with text/plain body. this-no-work was a new HTTP API I added, and it did not have the necessary listener rules.
Once I added a new listener rule for HTTP Path pattern is /this-no-work/*, it worked as expected..
when default endpoin is created in my case it uses this pattern
https://{api_id}.execute-api.{region}.amazonaws.com/
an answer might be: Disable the default endpoint for an HTTP API
more details here
https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-disable-default-endpoint.html

AWS API Gateway: How to remove/replace query string parameter in HTTP Proxy Passthrough integration?

When I query my Invoke URL as https://xxx.execute-api.yyy.amazonaws.com/test/q?apiKey=AAA with my below setup my backend receives a call as https://api.mysite.com/q?apiKey=AAA&apiKey=111: one apiKey=AAA comes from the client, the second one - apiKey=111 comes from the Integration Request configuration.
Question:
What/How should I configure an integration that apiKey=AAA either removed from the client call or replaced on the integration step with 111 value so that only one apiKey comes to the backend?
Note:
with proxy passthrough integration the Mapping Templates are not available;
the reason for such configuration is that my legacy backend has a big amount of endpoints which is not possible to configure individually.
My setup:
I have created a new REST API.
Then I have created a new Configure as a Proxy resource named proxy with a Resource Path /{proxy+} with the following setup for ANY method as a proxy integration:
Integration type HTTP Proxy
Endpoint URL: https://api.mysite.com/{proxy}
Content Handling: Passthrough
As a next step, I have configured an Integration Request for my /{proxy+} - ANY by adding a new query string to the URL Query String Parameters section:
Name: myApiKey
Mapped from: '111'
Then I click Deploy API to test stage and getting Invoke URL, let's say: https://xxx.execute-api.yyy.amazonaws.com/test.
Even with Proxy Integration, we can still override Request & Response.
Here is the blog. Let me try to summarize.
Ensure that Use Proxy Integration is unchecked
Simple VTL template in Mapping Template to replace apiKey queryParameter.
#set($newApiKey = "abcd")
$input.json("$")
#set($context.requestOverride.querystring.apiKey = $newApiKey)
Add Method Responses example response codes 200, 400 and 500.
Add Integration Response for each status code for each response codes for example http status for 2xx 2\d{2} with pass through behaviour.
Lets say we have a proxy setup for path /someapi/sompath. Above template will replace /someapi/sompath?apiKey=100 to {proxy}?apiKey=abcd

Routing or redirecting partial path in API gateway proxy to Lambda

I have an implementation of API Gateway as proxy to a Lambda function (which is the one that returns the statusCode and payload)
The invokation url is something like:
https://5656tre23.execute-api.us-east-1.amazonaws.com/dev
I have the following path: /book/${some-uuid}
Full URL: https://5656tre23.execute-api.us-east-1.amazonaws.com/dev/book/${some-uuid}
I also created a custom domain: api.mydomain.com/ which resolves to https://5656tre23.execute-api.us-east-1.amazonaws.com/dev/
If I pass the full path, it works with both, regular Api Gateway URL and with the custom domain. Example:
api.mydomain.com/book/${some-uuid}
However, if the I enter:
https://5656tre23.execute-api.us-east-1.amazonaws.com/dev
https://5656tre23.execute-api.us-east-1.amazonaws.com/dev/book
I receive the following message
{"message":"Missing Authentication Token"}
What I want, if the I go to:
/dev
/dev/book
or anything else than https://5656tre23.execute-api.us-east-1.amazonaws.com/dev/book/${some-uuid} redirect to mydomain.com
I will appreciate help.
Do you have some sort of authentication setup? Like catapult?
If so, you will need to add all of your endpoints to that policy in order to access them.
Check out: https://aws.amazon.com/blogs/compute/control-access-to-your-apis-using-amazon-api-gateway-resource-policies/

Exclude headers from s3v4 signature calculation

We are using an onPrem S3 compatible storage server in an intranet network and we want to expose this intranet url to internet so we used a ReverseProxy with a mapping to the intranet url. When we test the intranet url it works perfectly but when we test the internet url we get the 403 error:
The request signature we calculated does not match the signature you provided. Check your Secret Access Key and signing method. For more information, see REST Authentication and SOAP Authentication for details. (Service: Amazon S3; Status Code: 403; Error Code: SignatureDoesNotMatch; Request ID: 0a440c7f:15cc604b1e2:12d3af:24d; S3 Extended Request ID: null), S3 Extended Request ID: null
After debugging, we found that the proxy modifies the host header used to calculate the signature in order to redirect the request to the intranet url...
So my question is how to supress some headers from the V4 signature calculation using AWS SDK or Boto3 client. or is there a better architecture to expose an onPrem S3 service.
Thanks in advance.
Amir.
There are essentially two solutions to this.
The first one is easier: sign the request for the internal URL, then just use simple string prefix replacement to rewrite the host part of the signed URL to point it to the hostname of the external proxy. When the proxy rewrites the Host header, it will end up rewriting it back to exactly what you signed.
It is, I assume, common knowledge that signed URLs are immune to tampering, for all practical purposes: you can't change anything about a signed URL without invalidating it... but that's not what this is. The change is temporary, and the proxy's net effect is to undo the change.
The alternate solution requires the proxy or another service in the chain (before the storage service) to know the signing keys and secrets, so that it can first validate the incoming request, and if valid, modify the request and then generate a new signature that the service will accept. I once wrote a service to do this so that when a request was for HEAD, the proxy would use the same key and secret (which it knew) to generate a signature for the same request, but with GET. If it matched the signature in the incoming request, the proxy would replace the existing signature with a signature for a HEAD request -- thus allowing the client to use a URL originally signed for a GET request, to make either a GET or a HEAD request -- something S3 does not natively support, since a GET and a HEAD for the same object require two different signed URLs. The concept is the same, though -- generate a signature in the proxy for what the client is requesting, to validate the incoming signature, and then re-sign the request as needed. The solution I built used HAProxy's Lua integration to examine and modify the request in flight.