Adding custom authorization gives error : The request signature we calculated does not match the signature you provided - aws-lambda

I am facing this error sometimes (not always). I create a resource and a method in an API Gateway function. Then I map it to a Lambda function. On testing it there itself, everything works fine.
Now I add a custom authorization function to the method. Now, if I test it there,
If I do not provide the Authorization header, it works (since it is not deployed yet. After deployment, it would require the Auth header)
If I, however, provide the Authorization token, I get the error:
The request signature we calculated does not match the signature you
provided. Check your AWS Secret Access Key and signing method. Consult
the service documentation for details.\n\nThe Canonical String for
this request should have
been\n'POST\n/2015-03-31/functions/arn%3Aaws%3Alambda%3Aus-eas
More details: The lambda function belonging to this method was deleted. Then I re-created the function with the same name. And noticed that the method was deleted when the API was deployed. So I re-created the mapping and mapped it to the Lambda function. Since, then I am facing this issue. I am sure if I change the name of the Lambda, it might fix the issue. But I think it's a bug with AWS and not at my end. Need to clarify if there is anything I am doing wrong ?

It looks like the currently deployed version of the API is forwarding the Authorization header from the method request to the integration request (Lambda). If you are trying to fix the current state of your API, then I suggest removing the Authorization header from the method request, which will also remove it from the integration request. This should fix the Lambda signature errors.
If you're trying to use the custom authorizer on a method, you don't need to set up the Authorization header in the method request. You just need to set the authorizer identity source as 'method.request.header.Authorization'

Related

Springboot authentication for a webhook post

I need to authenticate a webhook post from a third party integration on my backend api server. The only thing I can define is the endpoint url they will call. It can't be dynamic once they have to register and the process takes 3 days. And we use a multi-tenant solution, so we have to authenticate with different schema on every call.
So the problem is that I have to create a filter for this webhook, so I can authenticate it through a value contained in the json of a post body.
So I defined a WebSecurityConfigurerAdapter and added a AbstractPreAuthenticatedProcessingFilter so I can intercept the request, read the value in the json body authenticated with the appropriate credentials.
I follow this tutorial Reading HttpServletRequest Multiple Times in Spring so I could be able to read InputStream from the request without erase it.
So my question about it are two.
1: Is there a better/easy approach so I can archive this result?
2: I guess this tutorial are missing something, because I'm getting null pointer at servlet when try to read the request (again, after I have already read at the filter).
Any guess would be appreciated, thanks in advance.
Are we allowed to know which 3rd party service?
PayPal/Stripe for example have docs already to explain how to verify the data.
If you can add metadata/custom fields to the webhook, you could sign it for example.
As far as checking the signature/verifying it, why not do this in the #Contoller=>#Service?

Calling AWS API Gateway from AWS Lambda

The scenario is :
I have a Rest api gateway which when triggered invokes a lambda which processes the request and returns the repsonse.
This api endpoint is public.
I have another lambda which will call this API gateway/endpoint and obtain response from it.
Now the queries :
I am directly calling the invoke url of api just like any other api. So is this the right way to do so?
When I put the invoke url in browser address bar, it is giving missing authentication token.
How to actually call the url in calling lambda, i mean how to pass tokens; in Node.js ?
Thanks 😊
Well, the questions are quite wide enough. I'm trying to answer as much as possible.
First, the design you are following of Rest API -> Lambda, it is called 'Integration Type' is 'Lambda function' and use 'Use Lambda Proxy integration'.
Please take a look on the documentation here and an example here
Go through the document I believe you will understand in-out of this model. At high level, this model API Gateway is passing through request and response and you (Lambda) will handle everything.
Question 1:
I am directly calling the invoke url of api just like any other api. So is this the right way to do so?
[Answer] There is nothing wrong with this model. And yes, you can call this API (Lambda proxy) as any Rest API.
Question 2:
When I put the invoke url in browser address bar, it is giving missing authentication token
[Answer] Please check the setting of your API. As the below screen-shot, my api is using Cognito as Authorizer. It means consumers need to provide 'Token' (oAuth2 for example) when calling the API. You can use either Lambda authorizer or Cognito authroizer. It's up to you.
And if you are not requiring any authorizer, you can set it as NONE so there is no authentication token require for your API.
In short, the message you are getting now it means your API is having an 'Authorizer' and you are not sending token along with request.
Question 3:
How to actually call the url in calling lambda, i mean how to pass tokens; in Node.js ?
It is pretty common. You can google it like 'oAuth2 in Node.js', it will give you tons of examples
https://resources.infosecinstitute.com/securing-web-apis-part-ii-creating-an-api-authenticated-with-oauth-2-in-node-js/
https://stormpath.com/blog/talking-to-oauth2-services-with-nodejs
I hope it helps. Otherwise, leave your comments and questions.
Thanks,

Cloud function authorization vs validationHandler

Found myself opening a couple of functions for access to users with invalid session tokens. The only way I could find to do that is to intercept the request using a bodyParser before Parse gets the request and removing sessionToken from the request.
Now trying to do a better job managing authorization to all functions - My question are:
can I relax the requirement that if a sessionToken is included it must be valid in any other way? Is session token validation done using a default validationHandler that can be replaced or is that done elsewhere?
to control access to cloud functions, is there anything like ACL roles? does cloud function's "validationHandler" accept only param? or can I inspect the user object as well?
Yes. In parse-server you can make sure that the sessions are valid because if you will try to run any CRUD operation with invalid session you will get http 403 error that your session is not valid or expired. You can control on the "Length" of your session by changing the sessionLength property in your parse-server app. The default is 1 year
There is no control access to cloud functions but you can check if a logged in user trigger this function by checking if the request.user is not undefined. Cloud functions can get only params in key-value pairs and those params cannot be Parse Objects. if you want to send ParseObject you can send the objectId of the parse object and then query for it in cloud code to get the full object. You can always access the user context in request.user (only if cloud code was triggered by the user). If you still want to "protect" your cloud code you can check if the calling user have a Role by query the Role DB and check if the user is contained there.

IdentityServer3 Token Validation - Exception in EmitCorsResponseHeaders after insufficient scope in access token

I've set up a basic WebApi project according to the guide here https://identityserver.github.io/Documentation/docsv2/overview/jsGettingStarted.html
Token validation works just fine if I pass the correct api scope in the token, but if it is not included (if the user denies access) then it proceeds to add a 403 to the response as expected.
In EmitCorsResponseHeaders (ScopeRequirementMiddleware.cs) it goes to add CORS headers but throws an exception -
[ArgumentException: The key 'Access-Control-Allow-Origin' is already present in the dictionary.]
Microsoft.Owin.Host.SystemWeb.CallHeaders.AspNetResponseHeaders.Add(String key, String[] value) +178
IdentityServer3.AccessTokenValidation.ScopeRequirementMiddleware.EmitCorsResponseHeaders(IDictionary`2 env) in c:\local\identity\server3\AccessTokenValidation\source\AccessTokenValidation\Plumbing\ScopeRequirementMiddleware.cs:97
Should this be happening or is there something I have missed? app.UseCors(CorsOptions.AllowAll) is set in the startup.cs as specified in the getting started guide.
Thanks
There's indeed an issue here, but I'm not totally sure how to resolve it.
The ScopeRequirementMiddleware tries to set the Allow-Access-Control-Origin header on the response, but it does so only if the scope requirement set in the middleware is not met.
This obviously conflicts with the fact that we already have the CORS middleware earlier in the OWIN pipeline which has already set this specific header.
I'm not sure why the scope requirement middleware sets these headers in this specific case, I'll create an issue on GitHub and link it back here for visibility.

Azure B2C Access Token NULL Spring OAuth 2.0

I am trying to get a custom web application to work with Azure B2C OAuth and the Spring OAuth2.0 framework.
The authentication leg comes back fine and I receive a JWT token. When the request for a token occurs afterwards I get the following error:
java.lang.IllegalStateException: Access token provider returned a null access token, which is illegal according to the contract.
at org.springframework.security.oauth2.client.OAuth2RestTemplate.acquireAccessToken(OAuth2RestTemplate.java:223) ~[spring-security-oauth2-2.0.8.RELEASE.jar:na]
at org.springframework.security.oauth2.client.OAuth2RestTemplate.getAccessToken(OAuth2RestTemplate.java:173) ~[spring-security-oauth2-2.0.8.RELEASE.jar:na]
...
From some debugging of the spring code I can see the token is expected to be called access_token as seen in the OAuth2AccessToken class. From looking at the B2C tutorials their token is called token_id. Furthermore the applications.yml config I have for my spring application has a field called tokenName. Surely this should be used to pick up the token name field instead of the hardcoded static variable as above.
Am I missing something and is there a solution to my problem. Can I override the token name field used by the spring OAuth framework?
I'm going to go ahead and post this as the answer.
I started with the Spring tutorial, and made some modifications to it. For a working example, see the public github repo: https://github.com/Pytry/azure-b2c-oauth2.git
To properly parse the token received you will need:
A custom implementation of an AccessToken that will parse the JWT, pulling and setting variables as required by spring security. I extended DefaultOAuth2AccessToken and added this parsing to a private method called by the constructor.
If you are going to verify the RSA signature using the public keys, you will need a custom JWT object so you can access the header information. I chose to extend springs JWT, and add some parsing on creation to access the header. It may also be useful to have some custom Pojos for parsing the returned meta data and rsakey information into.
An extension of the JwtAccessTokenConverter, with an overridden "decode" method. Azure does not give a "user_name" nor a "client_id" in the returned id_token, so you need to add those. I also included some logic in the super class that I found suefull (such as converting strings to int/long when appropriate).
A custom UserDetailsManger to override the default in memory one. This can either retrioeve user information from the GraphAPI, or it can load it from your user repository. I actually did not create either of these, and instead used the default in memory service, but injected it into the token converter; then whenever a user was properly authenticated, I would add them to the managers store, or update them if they already existed.
There are a few things I have not done yet.
RSA verification is not being done. Any help on this is appreciated.

Resources