How to validate or filter a wildcard in path for http endpoints in Serverless and AWS API gateway before the process triggs the lambda function? - api

I have the following http path devices/{sn} in a Serverless-AWS APIgateway API. The wildcard sn is a 15 digits [A-Z0-9] pattern.
In the API today any string that is not recognized as a valid path is redirected to this end-point. Ex: devices/test goes to devices/{sn}, devices/bla goes to devices/{sn} and so on. All those strings will query the database and return null because there is no such sn in the table. I could create a validation process inside the lambda to avoid the unnecessary database query. But I want to save lambda resource and I would like to validate before call the lambda.
This is what I have today for this endpoint:
- http:
path: devices/{sn}
method: GET
private: false
cors: true
authorizer: ${file(env.yml):${self:provider.stage}.authorizer}
request:
parameters:
paths:
sn: true
How can I setup this validation or filter in Serverless.yml?
In fact it should be a very straight-forward functionality of AWS/Serverless.
Let's say we have the following scenario: myPath/{id}. In this case id is a integer (a pk in a table). If I type myPath/blabla it will trigg the lambda. The system will spend resource. It shoul have a kind of previous validation - trig the endpoint only if the {id} === integer.

Your issue is very similar to this issue
According to the post and from my experience, No, I don't think you can perform validation in api-gateway level.

Related

Conditional OpenAPI request body when query param provided

I have the following endpoints configured for managing types of food
POST ~ /food/types
GET ~ /food/types
GET ~ /food/types/{id}
PUT ~ /food/types/{id}
Delete ~ /food/types/{id}
I'm trying to represent a clone operation in my REST API and wanted to avoid the use of Verbs in my endpoints.
After some research I've come up with the following as it conforms the most out of other solutions i could think of to basic REST principles:
POST ~ /food/types?sourceId={id}
This would mean that the method for this endpoint (in a typical MVC framework) would need to conditionally handle both the creation when a JSON payload is sent, and the duplication of a resource when a query parameter is provided.
I'm trying to think how i can express that in my OpenAPI specification document (v3.0.2)
Here is what i've got so far:
/api/food/types:
post:
summary: Create a new type of food
responses:
'201':
description: Created
content:
application/json:
schema:
$ref: ./response/food-type.yaml
'400':
description: Bad Request
requestBody:
content:
application/json:
schema:
$ref: ./request/food-type.yaml
description: Create a new type of food
tags:
- Food Type
parameters: []
The request/food-type.yaml contains an object with two required parameters:
Name,
Category
When my framework validates the request against the OpenAPI specification, i want it to sometimes ignore the request body if and only if, a request parameter has been provided with a 'sourceId' parameter.
Is this type of thing even possible to express in OpenAPI 3+, or am i going about this the wrong way?
Simply put, is it possible to ignore the request body when a specific query parameter has been provided in a post request using OpenAPI 3.
And following that question, is my approach to REST lacking, and is there a better way i could represent the cloning of a resource in my API?
Use the body of the message instead to describe the source:
POST /food/types {"clone": "{id}"}
You can even use verb if you convert them into nouns:
POST /food/type-cloning {"source": "{id}"}

JMeter - RegEx Extractor seems correct but request header has ${token} instead of value

Set-up
Request #1
POST https://url/
RegEx Extractor
Response #1
{
"Token":"WkQTxNnZRR0nofyJzb-kioALlXgwc7cN9rokXrKzWmtB2BDedUXeQnd94S5KWvaz0",
"ExpirationUTC":"2121-09-17T14:39:57.504Z",
"TokenId":"string"
}
Request #2
GET https://some-other-url
Header Manager
As shown:
Result
Instead of
Authorization: Bearer WkQTxNnZRR0nofyJzb-kioALlXgwc7cN9rokXrKzWmtB2BDedUXeQnd94S5KWvaz0
we have
Authorization: Bearer ${token}
Debug Component Results - Starting to Look Like a Variable Scope Issue
... but:
Result of RegExp Tester
Here, I used the same reg-ex as I used in the Reg Ex Extractor, and it finds the desired string.
JSON Extractor Attempt
Still says Bearer ${token}
As per JMeter Documentation Variables are local to a thread hence you cannot refer the variables which are set in one Thread Group in another Thread Group.
You either need to convert the variable into a JMeter Property using __setProperty() function in 1st thread group and load it using __P() function in 2nd thread group or go for Inter-Thread Communication Plugin
Also be informed that JSON is not a regular language hence using regular expressions is not the best choice for extracting the token from the response

Receiving "Invalid policy document or request headers!"

I am attempting to upload a file to S3 following the examples provided in your documentation and source files. Unfortunately, I'm receiving the following errors when attempting an upload:
[Fine Uploader 5.3.2] Invalid policy document or request headers!
[Fine Uploader 5.3.2] Policy signing failed. Invalid policy document
or request headers!
I found a few posts on here with similar errors, but those solutions didn't help me.
Here is my jQuery:
<script>
$('#fine-uploader').fineUploaderS3({
request: {
endpoint: "http://mybucket.s3.amazonaws.com",
accessKey: "changeme"
},
signature: {
endpoint: "endpoint.php"
},
uploadSuccess: {
endpoint: "success.html"
},
template: 'qq-template'
});
</script>
(Please note that I changed the keys/bucket names for security sake.)
I used your endpoint-cors.php as a model and have included the portions that I modified here:
require 'assets/aws/aws-autoloader.php';
use Aws\S3\S3Client;
// These assume you have the associated AWS keys stored in
// the associated system environment variables
$clientPrivateKey = $_ENV['changeme'];
// These two keys are only needed if the delete file feature is enabled
// or if you are, for example, confirming the file size in a successEndpoint
// handler via S3's SDK, as we are doing in this example.
$serverPublicKey = $_ENV['AWS_SERVER_PUBLIC_KEY'];
$serverPrivateKey = $_ENV['AWS_SERVER_PRIVATE_KEY'];
// The following variables are used when validating the policy document
// sent by the uploader.
$expectedBucketName = $_ENV['mybucket'];
// $expectedMaxSize is the value you set the sizeLimit property of the
// validation option. We assume it is `null` here. If you are performing
// validation, then change this to match the integer value you specified
// otherwise your policy document will be invalid.
// http://docs.fineuploader.com/branch/develop/api/options.html#validation-option
$expectedMaxSize = (isset($_ENV['S3_MAX_FILE_SIZE']) ? $_ENV['S3_MAX_FILE_SIZE'] : null);
I also changed this:
// Only needed in cross-origin setups
function handleCorsRequest() {
// If you are relying on CORS, you will need to adjust the allowed domain here.
header('Access-Control-Allow-Origin: http://test.mydomain.com');
}
The POST seems to work:
POST http://test.mydomain.com/somepath/endpoint.php 200 OK
318ms
...but that's where the success ends.
I think part of the problem is that I'm not sure what to enter for "clientPrivateKey". Is that my "Secret Access Key" I set up with IAM?
And I'm definitely unclear on where I get the serverPublicKey and serverPrivateKey. Where am I generating a key-pair on the S3? I've combed through the docs, and perhaps I missed it.
Thank you in advance for your assistance!
First off, you are using endpoint-cors.php in a non-CORS environment. Communication between the browser and your endpoint appears to be same-origin, based on the URL of your signature endpoint. Switch to the endpoint.php example.
Regarding your questions about the keys, you should have create two distinct IAM users: one for client-side operations (heavily restricted) and one for server-side operations (an admin user). For each user, you'll have an access key (public) and a secret key (private). You always supply Fine Uploader with your client-side public key, and use your client-side private key to sign requests server-side. To perform other, more restricted operations (such as deleting files), you should use your server user keys.

WSO2 api manager always expect query parameter issue in case query and path parameter?

Does anyone know how to use WSO2 api manager to specify all query parameters as optional through URL pattern specification in WSO2 API Manager UI(Paath Params also present in the same URI)? for example, I have a API which will be registered in WSO2 api manager , and its uri is 'search//?type="xx"&status="yy"', currently both of these 2 query parameters (type & status) are optional and is pathparam.
I specified URL Pattern "search/{stationcode}*". Now I am calling with path param only, it gives Error "No matching resource found in the API for the given request".
I call "search/TAMK", it is not working. But if I use "search/TAMK?" or "search/TAMK*" or "search/TAMK*", it works just fine.
I tried to use "search/{stationcode}/*", but still it did not solve the issue. It is always expecting one character for queryparam. Can any one please help me to solve this. Without query parameter it should work, right?
I would suggest you to use the new API Manager (1.9) and try the following.
Create an API with the backend URL of
http://...../search
when you define the URL patterns you can define the following pattern
/{stationcode}*
and you can add 'type' and 'status' as optional parameters in the design view of the API creation page. You can choose the parameter type as 'query' and Required as 'False'

How do you use Snap's authentication mechanisms during a single POST request?

I'm working on a Haskell Snap-based web app, and I want to expose an API endpoint that will be invoked by a remote service without establishing an authenticated session a-priori; however, I do want that request to be authenticated, so the credentials should be provided at the time of the request.
You could imagine the request containing four fields:
username
password
payload id
payload file
The payload id and file might be irrelevant for this question, but I include them because I (a) need to support file uploads in this request (which, as I understand it, restricts the encoding used to send fields) and (b) need to retrieve at least one non-file field. The combination of those things posed some difficulty when I set this up without authentication, so perhaps it is relevant.
In Snap parlance, let's call this handler uploadHandler.
As indicated above, I have this working fine without authentication, with a setup like this:
uploadHandler :: Handler App App ()
uploadHandler = do
-- collect files / form fields and process as needed.
-- and using the routes:
routes :: [(ByteString, Handler App App ())]
routes = [ ("/login", with auth handleLoginSubmit)
, ("/logout", with auth handleLogout)
, ("/new_user", with auth handleNewUser)
-- handle the upload:
, ("/upload", handleUpload)
]
The naive solution is to simply add 'with auth' and change the type of handleUpload:
uploadHandler :: Handler App (AuthManager App) ()
uploadHandler = do
-- collect files / form fields and process as needed.
-- and using the routes:
routes :: [(ByteString, Handler App App ())]
routes = [ ("/login", with auth handleLoginSubmit)
, ("/logout", with auth handleLogout)
, ("/new_user", with auth handleNewUser)
-- handle the upload, with auth:
, ("/upload", with auth handleUpload)
]
However, this seems to require two requests: (i) authenticate and establish a session, (ii) send the POST request containing the actual payload.
I found a way to do this in one request, but it seems like there should be a more elegant means. Here's the example restricted POST handler I've hacked together:
restrictedPOST :: Handler App (AuthManager App) ()
restrictedPOST = do
mName <- getPostParam "username"
mPass <- getPostParam "password"
let uName = C8.unpack $ fromMaybe "" mName
pass = ClearText $ fromMaybe "" mPass
authResult <- loginByUsername (T.pack uName) pass False
case authResult of
Left authFail -> writeText "Could not log in"
Right user -> writeText (T.append "Hello " (userLogin user))
Is there something like 'with auth' that I can use instead of turning this example (restrictedPOST) into a combinator? I realize it may need to know which fields to get credentials out of, but I also know very little about web services (maybe there is another means? Maybe this is a total non-issue, and I just don't know how to check auth for POST requests. I'm open to any suggestions!)
I don't think you understand what with auth is doing. It has nothing to do with whether authentication is required. All it does is convert a Handler b (AuthManager b) into a Handler b v. No permissions checks are performed. Your restrictedPOST function has the right idea.