Custom Authorizer using QueryString - aws-lambda

I am trying to restrict user to just view its own data and not anyone else's. So, if a user (bob) tries to hit
/api/v1/get-device-info?username=jon
, I want API gateway to send 403, only allowing username=bob. On the Lambda side, I am getting data from RDS. To solve this, I was looking at Custom Authorizers and got blocked thinking how to establish the identity of the user making the query.

What do you mean "establish the identity of the user"? If you are using Custom Authorizers then the user should be sending a token in the request header that identifies them as your API's user.

Related

Okta bearer token - Service to service

We have a scenario where we have different apps in the backend that needs to do some operation between them. Those apps are registered in the Okta console and have their own workflow. They both allow access to users that authenticate through an access token that they will get through a process the widget on the web. The two services needs to perform operations between them. For example, on one service we need information about products on another service. But it's not a "user" request, it's a service to service.
As far as my understanding goes, we still need to send a request as it would a normal user, so we need a bearer token to authenticate the request.
I cannot find in the docs a way to request an access token on the backend. I only found some libraries that can help providing a callback uri and multiple step process where you need to have a window to pop up to interact to insert your Okta login.
Is there any way to request an access token as an API call? In the backend services we won't have windows to pop up and authenticate?
We tried to use Okta-auth-js but seems to be more "front-end" oriented as most of the methods are "browser-only".
Yes, you need to create OIDC application of type "OAuth service", which will created "client credential" flow app for you. It supports calls to /token endpoint using client_id and client_secret available after the creation of the app in Okta. As a result of your call to /token directly from the backend, you will obtain an access token for machine-to-machine communication (no user context)

Can a Lambda Authorizer function detect when an IAM user has been disabled?

How does a Lambda Authorizer detect if an IAM user has been Disable?
We have a two client servers of Iterable and Punchh. The first one uses a payload of just the base64 token of the username : password while the other server uses the username and password (password is masked).
These 2 servers are pushing (POST method) events down to our API Gateway. To avoid any ,malicious packets being sent down to the gateway, we use an IAM test user (dd_transfer in the example figures below) that can be disbaled once malicious packets are discovered. Thus the IAM test user should now be denied access to the API Gateways where both Punchh and Iterable are pushing their payloads.
When I have an active test user, they are allowed access to the API gateway whenever Punchh or Iterable webhooks push(Post) data. However when that same user is Disabled (password is null) in IAM, that user should not be allowed to access to the gateway. Unfortunately, the 2 external servers are still allowed access once the IAM test user has been deactivated/disabled. I don't want to program and search through a credentials report csv file using boto3 that's encoded to base64. This would expose too much account user info - very risky. Is there another way for the Lambda Authorizer function to determine when an IAM user has been deactivated?
Here are the screen shots below for code, gateway , and servers.
Note that the payloads for the two servers are represented differently. Punchh webhook admin page uses password and username while Iterable webhook admin page uses only the base64 encoded token.
Thanks
Lambda Authorizer Code
API Gateway Method (Note: Post and Get Method Requests are identical)
Lambda Authorizer configuration
Punchh Webhook page
Iterable Webhook Page
I found a safe way to determine whether the dd_transfer user is enabled or not and that is with using the GetLoginProfile API. https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/iam.html#IAM.Client.get_login_profile
If there is a valid password for dd_transfer, then a LoginProfile object will be displayed in the response message, a 200 response code is returned, and the access to the API Gateway will be given when the policy is generated (‘Allow’).
However if the password is null because the dd_transfer has been disabled, a NoSuchEntity exception will be returned indicating that the Login Profile for User dd_transfer cannot be found. It’s blunt but at least I don’t have to worry about access being given to allow malicious events to bypass our API Gateway and into S3 buckets.
I have added a try/catch block to gracefully handle the error by calling the generate Policy function passing the ‘Deny’ parameter in order to generate the Deny Access policy.
It’s a lot less work than using the Credential Report API and then BASE 64 decoding each record in the text/csv file to look for dd_transfer’s entry. The csv file doesn’t expose actual raw data like passwords etc but GetLoginProfile takes less to write up. Then in the exception handler, I would make a call to the generate the Deny Policy.

Elixir Phoenix Absinthe GraphQL API authentication in both web and mobile app's

I'm working on an Absinthe GraphQL API for my app. I'm still learning the procedure(so please go easy on me).
I've a Absinthe/GraphQL MyAppWeb.schema.ex file in which I use for my queries and mutations. My question is how do I use this API for authenticating the user on both Mobile and Web app?
How do set a cookie(httpOnly & secure) in my web app and access/refresh tokens in a single Absinthe API to serve my website and mobile app. Basically what I'm trying to learn is how do I authenticate the user based on specific platform.
If my question sounds bit confusing, I would be happy to provide more information related to my question. I would really be grateful if someone could explain the procedure, I've been very stuck on this for a while.
I would avoid using authentication mechanisms provided by absinthe(if there are any). Depending on what front-end you are using, I would go with JSON API authentication. The flow on server goes the following way:
Create a endpoint for login that will receive a user and password and will return a refresh token.
Create a endpoint for exchanging refresh token for access token.
Use a library like guardian to generate your refresh/access tokens.
Create a phoenix plug for authentication that will check your tokens, guardian has some built-in plugs for this.
Now on device you have to implement:
Ability to save refresh and access token on device.
Have a global handler for injecting access token on authorized requests.
Have a global handler for case when access token is expired. (you usually check if your request returns Unauthorized, then you should request a new access token from the server using your refresh token)
This seems like a crude implementation, however I would advise in implementing your system instead of using a black box library that you have no idea how it works under the hood.

Service to service workflow with AWS cognito and AWS Lambda

I'm rather new to AWS Cognito and AWS Lambda. So far I've played around with Serverless and deployed my REST API via AWS Lambda. However, I would like to make my API available for several external parties. As this is service to service, there is no end user directly calling my API. I make the API available for other businesses which use it in their applications. All functionalities exposed via the API are rather simple, meaning they are not invoking any other AWS services like a Dynamo DB etc.
I have several questions, some are rather high-level others are quite specific to the setup of AWS Cognito. I decided to put all in one post as it makes it much more self-contained and easier understandable.
1. Question, Cognito vs API key: What is the advantage of using AWS Cognito vs AWS Lambda in combination with restricting the access via an API key and IP-Whitelisting? Is one much more secure than other?
Let's assume I want to use AWS Cognito. As this is a service to service case, I've read that the standard is to use token endpoints where the grant_type is client_credential. I've found the following on medium. The first few steps consist of
Create a user pool in AWS Cognito.
Create an App client
Add Resource Servers
Enable the client credentials checkbox for Allower OAuth flows
2. Question, App client: Within the added App client I find the corresponding App client id and App client secret. If I expose my API to several different parties, do I need to add for each party another App client? Otherwise they use all the same credentials. Is this the right way to do it?
3. Question, Resource Server: Here I'm completely stuck. What exactly is the meaning for this? At then end, all I want is that my clients can do a post request against my API and access is granted through Cognito. Some clarification what this is for and how this applies in my case would be appreciated. More than happy to share more insights if needed.
The next part is to configure Cognito Authorizer for the API Gateway. This should be fine.
4. Question, client workflow Regarding my clients workflow. Am I correct that this consist of the following steps:
First, I provide to the client his client_id and client_secret.
then the client implements on his side the following workflow:
Whenever he wants to use my API exposed via API Gateway, he first uses his provided client_id and client_secret to retrieve his bearer token.
He uses this bearer token to make a request to API Gateway with the bearer token in the Authorization header.
If access granted, the client retrieves the output of my API.
Is this correct or am I missing anything?
1-Question, Cognito vs API key
Well as you can see here.
Amazon Cognito user pools let you create customizable authentication
and authorization solutions for your REST APIs.
Usage plans let you provide API keys to your customers — and then
track and limit usage of your API stages and methods for each API key
So the purpose is different, the API Key is used basically to count a customer usage while AWS Cognito is there to authenticate/authorize calls to your API.
Let us say, you have a requirement that a trail user can't call your API more than 100 times.
Then using AWS Cognito, you will allow a user to sign up, also you will provide the same user with an API Key, you will identify the source of the calls using Cognito and with each call API Gateway will decrease the limit assigned to user's API Key by 1.
And you will have the following cases:
When token (obtained through login using username and password), and
API Key are valid, then the call will be successful.
When token is wrong/missing, your caller will get 401 status code.
When API Key is wrong/missing, your caller will get 403 status code.
When API Key is correct but limit is exceeded, your caller will get
429 status code.
2. Question, App client:
Well, client id and client secrets are meant to identify a trusted client (app) rather than a user and each app should have its own client id, so if the caller is an application not a user so yes, create a client id for each separate app. Please be aware that client secrets must be kept confidential so if the caller app can't achieve that, such as single-page Javascript apps or native apps, then the secret shouldn't be issued.
3. Question, Resource Server:
It is your API server.
Check this page.
The resource server is the OAuth 2.0 term for your API server. The
resource server handles authenticated requests after the application
has obtained an access token.
Large scale deployments may have more than one resource server.
Google’s services, for example, have dozens of resource servers, such
as the Google Cloud platform, Google Maps, Google Drive, Youtube,
Google+, and many others. Each of these resource servers are
distinctly separate, but they all share the same authorization server.
4. Question, client workflow
Check Client credentials grant in here
The steps for the process are as follows:
An app makes a POST request to https://AUTH_DOMAIN/oauth2/token, and specifies the following parameters:
grant_type – Set to “client_credentials” for this grant type.
client_id – The ID for the desired user pool app client.
scope – A space-separated list of scopes to request for the generated access token.
In order to indicate that the app is authorized to make the request, the Authorization header for this request is set as “Basic
BASE64(CLIENT_ID:CLIENT_SECRET)“, where
BASE64(CLIENT_ID:CLIENT_SECRET) is the base64 representation of the
app client ID and app client secret, concatenated with a colon.
The Amazon Cognito authorization server returns a JSON object with the following keys:
access_token – A valid user pool access token.
expires_in – The length of time (in seconds) that the provided access token is valid for.
token_type – Set to ” Bearer“.
Note that, for this grant type, an ID token and a refresh token aren’t returned.
The app uses the access token to make requests to an associated resource server.
The resource server validates the received token and, if everything checks out, executes the request from the app.

Securing web app and api using OpenID Connect

I don't want to roll my own security anymore and am looking at using OpenID Connect with my c# API and AngularJS app. I can get all that to work just fine. However, my brain cannot seem to understand how to secure my API correctly for both use cases:
Use Case 1: AngularJS SPA
My AngularJS app connects to my API and sends a bearer token identifying the user and includes user claims. This one is easy and there is tons of documentation on it.
Use Case 2: API to API
Some customers want to access my API directly instead of going through my AngularJS app. In this case, I thought I could use a Client ID/Secret for toen-based authentication which is great except then I know nothing about the user that's using the client id/secret. There could be 10 users using the same custom API that is calling my API. How do I get user info via the API call? I've seen others use API keys that they then lookup the user and create a JWT but I thought there might be an easier way. Any ideas?
The whole point of API to API authentication is that there is no user context. Or well, the user in that case is the machine trying to access your API. You would then need to design your authorization logic around that and implement scope based permissions. Alternatively, your options are to use api keys as you mentioned or if you want OAuth protocol with user context in the api to api scenario - then ResourceOwnerCredentials flow is an option.
API to API communcation
You can use Client Credentials Grant defined through OAuth 2.0. This won't require you to have end user credentials. Now this won't be OpenID Connect. OpenID Connect require the involvement of an end user and bound to authentication. OAuth 2.0 on the other hand is about authorization, checking whether the entity can access the resource.
With Client Credential Grant, your identity server will issue tokens for a specific client. So one of your API becomes the client (resource consumer). From request handling API endpoint, you can accept valid tokens and respond back with resource.
If you require fine grained access control from request handling API, you will require to use token introspection to identify to whom this token was issued. In this case, it will be identification of specific client identity and execute a logic on top of it. You can check the token introspection response to identify such details.
Alternatively, access tokens can be come in form of a JWT. If this is the case, they can be considered as self contained tokens so validation is straightforward.

Resources