AWS APIGateway lambda authorizer caching policy even after setting ttl to zero - node.js

I am using an APIGateway lambda Authorizer with the following policy generation code but seems like even after setting the time to live on the authorizer lambda to zero still the policy is getting cached for some reason.
The caching behavior is random.
I have set the time to leave to zero because I want the authorizer to be called for each and every request.
This is my code:
var generatePolicy = function(principalId, effect, resource) {
var authResponse = {};
authResponse.principalId = principalId;
if (effect && resource) {
var policyDocument = {};
policyDocument.Version = '2012-10-17';
policyDocument.Statement = [];
var statementOne = {};
statementOne.Action = 'execute-api:Invoke';
statementOne.Effect = effect;
statementOne.Resource = resource.replace(/:function:.+$/, ':function:*');
policyDocument.Statement[0] = statementOne;
authResponse.policyDocument = policyDocument;
}
authResponse.context = {
"stringKey": "stringval",
"numberKey": 123,
"booleanKey": true
};
return authResponse;
}
}

Try changing the statementOne.Resource = '*'; this will work.
For a valid policy, API Gateway caches the returned policy, associated with the incoming token or identity source request parameters.

Related

Access Azure Data Explorer with Kusto.Data in Azure Function -- Kusto failed to send request -- local debugging works

I am having the following problem and an extensive search online didn't provide any good results.
When trying to access my Azure Data Explorer Database and querying using the Kusto.Data SDK in an Azure Function, it yields the following error:
Kusto client failed to send a request to the service: 'An unknown, invalid, or unsupported option or level was specified in a getsockopt or setsockopt call.'
However, running the Function on my local machine, everything works fine.
Edit: The function excepts at using (var reader = await queryProvider.ExecuteQueryAsync(Database, query, clientRequestProperties))
EDIT2 - SOLUTION:
You can downgrade the NuGet Kusto.Data Package to Version 9.4.1, this solves the problem and doesn't throw any error anymore. If you still encounter difficulties, you can try to directly access the ADX database via http requests:
const string tenantId = "<tenantId>";
const string client_id = "<clientId>";
const string client_secret = "<client_secret>";
const string Cluster = "<cluster_adress";
const string Database = "<database_name>";
var authUrl = "https://login.microsoftonline.com/<tenantId>/oauth2/token";
var param = new Dictionary<string, string>
{
{"client_id",client_id},
{"grant_type","client_credentials"},
{"client_secret",client_secret},
{"resource","https://help.kusto.windows.net"}
};
var data = new FormUrlEncodedContent(param);
using var authClient = new HttpClient();
var response = await authClient.PostAsync(authUrl, data);
string result = response.Content.ReadAsStringAsync().Result;
//parse result
var resultJson = System.Text.Json.JsonDocument.Parse(result);
//retrieve access token
var accessToken = resultJson.RootElement.GetProperty("access_token");
//-----------------------------------------------------------------------------------------------
var dataXUrl = Cluster + "/v1/rest/query";
var database = Database;
var dataXQuery = "sample_table| where Time > ago(2min)";
var body = new Dictionary<string, string>
{
{"db",database},
{"csl",dataXQuery}
};
using var dataXClient = new HttpClient();
dataXClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken.ToString());
dataXClient.DefaultRequestHeaders.Add("Accept", "application/json");
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, dataXUrl);
request.Content = new StringContent(JsonConvert.SerializeObject(body), Encoding.UTF8, "application/json");
var table = await dataXClient.SendAsync(request);
//pretty print
var obj = JsonConvert.DeserializeObject(table.Content.ReadAsStringAsync());
var tableJSON = JsonConvert.SerializeObject(obj, Formatting.Indented);
log.LogInformation("\n\n" + tableJSON);
I am having the same issue on a continuous webjob on an Azure App Service. The Kusto nuget version I am using is 10.1.0
Downgrading to nuget 9.4.1 solved the problem immediately.
FYI - This only seems to affect 10.1.0. The earlier 10.x.x versions should work.
The ADX team believes they will have this fixed in the next nuget version.

I'm receiving a Stripe exception "No such payout: 'po_1KJ6pFQ**********YsFVzT4'" when fetching balance transactions

I'd like to fetch all the Stripe Transfers that make up a Payout. I'm following this Stackoverflow post here that says fetch the balance transactions and pass in a payout ID and set the type to "transfer".
In my Stripe dashboard I can see multiple payouts and I'm just copying/pasting different ID's to test this call.
Problem - I keep getting the same error message from Stripe saying "No such payout: 'po_1KJ6pFQ**********YsFVzT4'"
Here's how I'm calling the balance transactions.
var options = new BalanceTransactionListOptions
{
Payout = "po_1KJ6pFQ**********YsFVzT4",
// Type = "transfer",
// Limit = 100,
};
var service = new BalanceTransactionService();
try {
StripeList<BalanceTransaction> balanceTransactions = service.List(options);
foreach(BalanceTransaction balTransaction in balanceTransactions) { // do something }
}
} catch(StripeException ex) {
var e = ex;
}
No such (object) error messages occurs when the object you're attempting to access does not exist on the Stripe account.
By default, the request would be made on the Stripe account whose API key you're using. If you're using Connect and you need to access an object on a connected account, you should use your platform's API key and the Stripe-Account header.
var requestOptions = new RequestOptions();
requestOptions.StripeAccount = "{{CONNECTED_ACCOUNT_ID}}";
var options = new BalanceTransactionListOptions
{
Payout = "po_1KJ6pFQ**********YsFVzT4",
// Type = "transfer",
// Limit = 100,
};
var service = new BalanceTransactionService();
try {
StripeList<BalanceTransaction> balanceTransactions = service.List(options, requestOptions);
foreach(BalanceTransaction balTransaction in balanceTransactions) { // do something }
}
} catch(StripeException ex) {
var e = ex;
}

Setting CORS rules using Azure.Storage.Blobs

I'm trying to migrate from the deprecated Microsoft.WindowsAzure.Storage to Azure.Storage. In my API app, I have a method that I call occasionally to programmatically set the CORS rules in my Azure Storage account.
How do I add CORS rules to the properties using the new Azure.Storage.Blobs?
My original code that worked under Microsoft.WindowsAzure.Storage is as follows. In the following code, the _client is an instance of CloudBlobClient. I understand that in Azure.Storage.Blobs, I need to use BlobServiceClient which I now do but as I said, some parts of the following code are not working because some methods/properties are no longer there. I'm sure they're moved somewhere else but I haven't been able to figure out where.
public async Task ConfigureCors()
{
var ALLOWED_CORS_ORIGINS = new List<String> { "http://localhost:49065", "https://myappdomain.com", "https://www.myappdomain", "https://login.microsoftonline.com" };
var ALLOWED_CORS_HEADERS = new List<String> { "x-ms-meta-qqfilename", "Content-Type", "x-ms-blob-type", "x-ms-blob-content-type" };
const CorsHttpMethods ALLOWED_CORS_METHODS = CorsHttpMethods.Get | CorsHttpMethods.Delete | CorsHttpMethods.Put | CorsHttpMethods.Options;
const int ALLOWED_CORS_AGE_DAYS = 5;
var properties = await _client.GetServicePropertiesAsync();
properties.DefaultServiceVersion = "2013-08-15";
await _client.SetServicePropertiesAsync(properties);
var addRule = true;
if (addRule)
{
var ruleWideOpenWriter = new CorsRule()
{
AllowedHeaders = ALLOWED_CORS_HEADERS,
AllowedOrigins = ALLOWED_CORS_ORIGINS,
AllowedMethods = ALLOWED_CORS_METHODS,
MaxAgeInSeconds = (int)TimeSpan.FromDays(ALLOWED_CORS_AGE_DAYS).TotalSeconds
};
properties.Cors.CorsRules.Clear();
properties.Cors.CorsRules.Add(ruleWideOpenWriter);
await _client.SetServicePropertiesAsync(properties);
}
}
Looks like I can get and set properties by changing _client.GetServicePropertiesAsync() to _client.GetPropertiesAsync() but DefaultServiceVersion is no longer there. Also I can't seem to find the right way to set CORS rules.
I'd appreciate your suggestions. Thanks!
You can use the code below when using Azure.Storage.Blobs(I'm using sync method, please change it to async method if you need that):
var properties = blobServiceClient.GetProperties().Value;
properties.DefaultServiceVersion = "xxx";
BlobCorsRule rule = new BlobCorsRule();
rule.AllowedHeaders= "x-ms-meta-qqfilename,Content-Type,x-ms-blob-type,x-ms-blob-content-type";
rule.AllowedMethods = "GET,DELETE,PUT,OPTIONS";
rule.AllowedOrigins = "http://localhost:49065,https://myappdomain.com,https://www.myappdomain,https://login.microsoftonline.com";
rule.MaxAgeInSeconds = 3600; // in seconds
properties.Cors.Add(rule);
blobServiceClient.SetProperties(properties);

Lambda Authorizer not returning proper error message with callback() in node.js

I have created a Lambda Authorizer on a AWS API Gateway, which calls a Lambda Function. Following is the code in the Lambda Function written in Node.js 8.0 code.
exports.handler = function(event, context, callback) {
var token = event.authorizationToken;
switch (token.toLowerCase()) {
case 'allow':
callback(null, generatePolicy('user', 'Allow', event.methodArn));
break;
case 'deny':
callback(null, generatePolicy('user', 'Deny', event.methodArn));
break;
case 'unauthorized':
callback("Unauthorized"); // Return a 401 Unauthorized response
break;
default:
callback("Error: Invalid token");
}
};
// Help function to generate an IAM policy
var generatePolicy = function(principalId, effect, resource) {
var authResponse = {};
authResponse.principalId = principalId;
if (effect && resource) {
var policyDocument = {};
policyDocument.Version = '2012-10-17';
policyDocument.Statement = [];
var statementOne = {};
statementOne.Action = 'execute-api:Invoke';
statementOne.Effect = effect;
statementOne.Resource = resource;
policyDocument.Statement[0] = statementOne;
authResponse.policyDocument = policyDocument;
}
// Optional output with custom properties of the String, Number or Boolean type.
authResponse.context = {
"stringKey": "stringval",
"numberKey": 123,
"booleanKey": true
};
return authResponse;
}
(The above sample code if from the web site https://markpollmann.com/lambda-authorizer/)
If I save and Test this function by passing an invalid value for authorizationToken, I get expected result which is below.
Response:
{
"errorMessage": "Error: Invalid token"
}
Request ID:
"e93567c0-fcbb-4cb1-b0b3-28e9c1b30162"
But If I call this API from Postman, by passing the value in the header, I get the following response. I am getting this error for any value in the header i.e, deny, allow, unauthorized, wrong etc.
{
"message": null
}
The status message in postman shows "500 Internal Server Error". Following is the detail from header section in postman.
content-length →16
content-type →application/json
date →Fri, 08 Mar 2019 14:07:57 GMT
status →500
x-amz-apigw-id →W89kFDRDoEFxYg=
x-amzn-errortype →AuthorizerConfigurationException
x-amzn-requestid →92f31d11-41ab-11e9-9c36-97d38d96f31b
I do not understand why the API is returning the above response and error message, while the Lambda test is working fine.
I have already gone through the following two threads in SO, but the answers/comments couldn't help in my case.
AWS API Gateway with custom authorizer returns AuthorizerConfigurationException
AWS API Gateway Custom Authorizer AuthorizerConfigurationException
I have understood the reason why I was getting message = null for the invalid input. The default block in the switch case was using parameter "Error: Invalid token" in the callback() method. API Gateway only identifies "Allow", "Deny" and "Unauthorized" as valid values. These values are also case sensitive. If any string values other than these values are passed to the callback() method, then API Gateway will return message=null to the client.

How to get root path "/" Resource from AWS Api Gateway?

I've been trying to retrieve the Resource with the path "/" (the root) from AWS Api Gateway using the Nodejs AWS SDK. I know the naïve solution would be to do it this way:
var AWS = require('aws-sdk');
var __ = require('lodash');
var Promise = require('bluebird');
var resources = [];
var apiGateway = Promise.promisifyAll(new AWS.APIGateway({apiVersion: '2015-07-09', region: 'us-west-2'}));
var _finishRetrievingResources = function (resources) {
var orderedResources = __.sortBy(resources, function (res) {
return res.path.split('/').length;
});
var firstResource = orderedResources[0];
};
var _retrieveNextPage = function (resp) {
resources = resources.concat(resp.data.items);
if (resp.hasNextPage()) {
resp.nextPage().on('success', _retrieveNextPage).send();
} else {
_finishRetrievingResources(resources);
}
};
var foo = apiGateway.getResources({restApiId: 'mah_rest_api_id'}).on('success', _retrieveNextPage).send();
However, does anybody know of an alternate method? I'd prefer to know that I'll alway have to do at most one call than having to do multiple.
PS: I know there are several optimizations that could be made (e.g. check for root path on every response), I really want to know if there's a single SDK Call that could fix this.
There is not a single call, though it can be if you have less than 500 resources. As a consolation prize, this is the best-practice, using position to prevent accidental misses if there are over 500 resources. If there are less than 500 resources, this will work with one call:
https://github.com/andrew-templeton/cfn-api-gateway-restapi/blob/bd964408bcb4bc6fc8ec91b5e1f0387c8f11691a/index.js#L77-L102

Resources