How can i limit access to the aws-cognito service? - amazon-cognito

I would like to limit the access to my cognito service.
My scope is to filter all the calls to cognito adding a server layer that allow me to do specific actions when the user uses the service.
I know that triggering events is the right way to do this but the events in cognito are very limited and a lot of stuff can not be done. For example if the Authentication fails for some reason the postAuthentication event is not triggered.
Another use case can be the validation of the attribute, or limit the reading of some attribute.
The only idea I've is to hide the IdentityPoolId or the UserPoolClientId but seems pretty unsafe.

There are two approaches in using AWS Cognito UserPools.
Using Hosted UI.
Using the SDKs/RESTAPI and Implement Your Own API and UI interface.
Using Hosted UI
If you go with the first option, pretty much of the things are handled by AWS and the control you have is limited. However, you can do certain configuration using triggers. On the other hand, you have lesser risks from your side since you are maintaining a limited code.
Using the SDKs/RESTAPI
If you go with the second option, you can limit Cognito UserPools as required putting the logic inside your own code. This allows limiting access as you desire. However, you have to write custom code to authenticate and signup users.
Mix of Both
It is also possible to use a mix of these approaches. For example, you can write custom code for signup but for sign in use hosted UI.
Custom Attributes and Claims
Also if you plan to return attributes based on your custom rules, use the trigger Pre token generation. Amazon Cognito invokes this trigger before token generation allowing you to customize identity token claims.
Note: A similar approach can be done for the Cognito Identity Pools.

Related

Handling authorization with IdentityServer4

I'm extremely confused on how to use a centralized IDP with both authentication and authorization. The architecture for my project was to be a single web API and one React client. I wanted to keep things structured out into microservices just to try something more modern, but I'm having major issues with the centralized identity, as many others have.
My goal is fairly simple. User logs in, selects a tenant from a list of tenants that they have access to, and then they are redirected to the client with roles and a "tid" or tenant id claim which is just the GUID of the selected company.
The Microsoft prescribed way to add identity in my scenario is IdentityServer, so I started with that. Everything was smooth sailing until I discovered the inner workings of the tokens. While some others have issues adding permissions, the authorization logic in my application is very simple and roles would suffice. While I would initially be fine with roles refreshing naturally via expiration, they must immediately update whenever my users select a different tenant to "log in" to. However, the problem is that I cannot refresh these claims when the user changes tenants without logging out. Essentially, I tried mixing authorization with authentication and hit a wall.
It seems like I have two options:
Obtain the authorization information from a separate provider, or even an endpoint on the identity server itself, like /user-info but for authorization information. This ends up adding a huge overhead, but the actual boilerplate for the server and for the client is minimal. This is similar to how the OSS version of PolicyServer does it, although I do not know how their paid implementation is. My main problem here is that both the client and resource (API) will need this information. How could I avoid N requests per interaction (where N is the number of resources/clients)?
Implement some sort of custom state and keep a store of users who need their JWTs refreshed. Check these and return some custom response to the caller, which then uses custom js client code to refresh the token on this response. This is a huge theory and, even if it is plausible, still introduces state and kind of invalidates the point of JWTs while requiring a large amount of custom code.
So, I apologize for the long post but this is really irking me. I do not NEED to use IdentityServer or JWTs, but I would like to at least have a React front-end. What options do I have for up-to-date tenancy selection and roles? Right when I was willing to give in and implement an authorization endpoint that returns fresh data, I realized I'd be calling it both at the API and client every request. Even with cached data, that's a lot of overhead just in pure http calls. Is there some alternative solution that would work here? Could I honestly just use a cookie with authorization information that is secure and updated only when necessary?
It becomes confusing when you want to use IdentityServer as-is for user authorization. Keep concerns seperated.
As commented by Dominick Baier:
Yes – we recommend to use IdentityServer for end-user authentication,
federation and API access control.
PolicyServer is our recommendation for user authorization.
Option 1 seems the recommended option. So if you decide to go for option 1:
The OSS version of the PolicyServer will suffice for handling the requests. But instead of using a json config file:
// this sets up the PolicyServer client library and policy provider
// - configuration is loaded from appsettings.json
services.AddPolicyServerClient(Configuration.GetSection("Policy"))
.AddAuthorizationPermissionPolicies();
get the information from an endpoint. Add caching to improve performance.
In order to allow centralized access, you can either create a seperate policy server or extend IdentityServer with user authorization endpoints. Use extension grants to access the user authorization endpoints, because you may want to distinguish between client and api.
The json configuration is local. The new endpoint will need it's own data store where it can read the user claims. In order to allow centralized information, add information about where the permissions can be used. Personally I use the scope to model the permissions, because both client and api know the scope.
Final step is to add admin UI or endpoints to maintain the user authorization.
I ended up using remote gRPC calls for the authorization. You can see more at https://github.com/Perustaja/PermissionServerDemo
I don't like to accept my own answer here but I think my solution and thoughts on it in the repository will be good for anyone thinking about possible solutions to handing stale JWT authorization information.

Restricting user authentication with Firebase

I'm using Firebase to authenticate the users on my application but, since the app is very early stage, I would like to restrict the login (or registration) to only users that have a specific code.
It looks like there's no option like this and I was wondering if there's any solution that doesn't involve a back-end.
Right now I'm using a specific code in the database that the user has to enter while logging in. If that code is not correct you can't login. The problem is the function (obviously) is executed on the front-end so a person with the right knowledge could easily modify the code and still access without token.
Is there a more robust solution?
if you truly want no back end, you can see my answer at the bottom here How to protect firebase Cloud Function HTTP endpoint to allow only Firebase authenticated users? , which involves taking advantage of the fact that every firebase project is also a Google cloud platform project and GCP allows for private functions.
however, there is an easier way: just wrap your cloud function logic with an if clause that checks for any of a number of things before actually executing the function
assuming, for instance, you're on the web platform, when someone invokes an HTTPS callable function from the front, it will be sent with data and context objects.
you could check for context.auth.email to restrict to specific users. or you could check for data.mySecretKey and since the check is occurring in your cloud function, no one could inspect your code to find the key.

How can I define policies for my API for two types of access tokens, one with an identity (sub) and one without?

I am using IdentityServer4 via ASPNET Core, and I want users to access my API both by the web browser via their identity (Implicit and Hybrid), and by clients programatically (Client Credentials). I realize all I have to do is add AddIdentityServerAuthentication and I am done. However, that only solves the authentication aspect of this problem, not the authorization.
Authorization:
With ASPNET Core, you can just use Role based auth (or PolicyServer permissions which is similar) but only if you have an identity with role claims, that does not work for client credentials. So that brings us to needing to secure by role, or policies AND by scopes. How can I do this?
You cant have multiple policies, if you do, they both must pass.
You can't have multiple auth schemes, because my call to AddIdentityServerAuthentication will have to use the same authority, so how would IdentityServer4.AccessTokenValidation/JwtBearer know which you scheme challenge you are trying to pass?
Multiple requirements could work, but you need to add extra requirements on the condition that you are dealing with a non-identity access token. How can you detect what type of token you are dealing with? Is it safe to just say "If no sub, this is client creds."
Should I scrap this design and force device code flow on my users? Look at az cli it magically opens a browser, and then you can start scripting away to your hearts content. IS4 supports this with ease, especially with verficationUrlComplete
I think I have a working POC, but I am far from happy with it. https://gist.github.com/VictorioBerra/8c333a228c55d86a7c15f7f300284634
It involves basically re-implementing the default scope claim requirement handler and policyservers permission requirement handler. But thats the only way to conditionally apply the requirement handlers based on the token type.
There are at least a couple of ways of how to go around your problem of implementing role based authentication:
You might have misunderstood the fact that a client can have role claims in the client_credentials flow.
You could even have sub claim if you implemented client_credentials_custom flow and essentially bind a client to a particular user account (think of this as a service account)

Is AWS API Gateway custom authorizer useful?

I am looking to use some "serverless api server" for AWS Lambda /zappa that uses a custom API Gateway authorizer for user authentification. In serverless AWS lambda service is there a considerable security or cost benefit in using custom authorizer rather than checking the issued JWT token directly in your code controller? For me checking with the code could be more convenient.
UPDATE
I went for pre request hooks, however there is header level authorizer, it is easier to use for CORS, yet it is not supported by zappa I believe. Also setting mock API for Options might be possible via swagger upload, will update if succeed.
I don't think there is strictly speaking a security or cost benefit. The benefit is that it is a single place, a single piece of code, that handles your authorization. It prevents you from having to duplicate that authorization code in every single Lambda function you deploy behind your API. And it allows you to update a single function to make any changes to your authorization logic.
From the perspective that it provides a single source of truth for your authorization logic, and it allows you to implement separation of concerns, it could be said to enhance your application's security.
That being said, if your entire API consists of a single Lambda function, then the benefit is somewhat dubious. I think API Gateway Custom Authorizers really become beneficial when your API has many Lambda functions or when your API Gateway is sitting in front of traditional HTTP servers.
#Mark B makes excellent points I certainly don't dispute anything in his answer. I'd like to contribute to the conversation nevertheless.
An answer tailored more specifically to you might depend on where the JWTs come from, and how they're being acquired, used, and refreshed. Using a custom authorizer may make sense in these scenarios:
Use Case 1
Custom authorizers can be useful if you want to secure a single Lambda behind several different flavors of authorization. For example, you can create three different API Gateway endpoints that each invoke the same Lambda, but use distinct authorizers. This ties into Mark's point about the DRY benefits.
Use Case 2
Custom authorizers afford you the ability to build IAM permissions inline in your authorizer code. Rather than assigning a pre-existing IAM role to a caller, you can build any arbitrary set of permissions you like. Note that this can easily become a nasty attack vector if you're somehow using (untrusted) user input to assign IAM permissions.
Use Case 3
Lambdas are great for hiding secrets. For example, you have a front-end JS app and you need to participate in OAuth 2.0 flows that require client id and client secret. Or you need to call endpoints that require API keys of some sort.
Clearly, you can't expose these secrets to the browser.
These values can be encrypted and stored in environment variables specific to the Lambda function. While you could certainly take this approach with your back-end lambda, using an authorizer instead has the following benefit:
I like being able to restrict the scope of these secrets as tightly as possible. By using an authorizer, my application can remain blissfully unaware of these secrets. This ties into Mark's point about separation of concerns.
IAM and Least Privilege
I prefer that my back end code never gets invoked by unauthorized parties. For this reason, I use an authorizer of some type on virtually every API Gateway resource I create. I have used custom authorizers, but they're kind of my last resort. I lean on IAM authorization most of the time, using Cognito to trade tokens for temporary IAM credentials.
If you perform authorization in your back-end lambda, rather than in an authorizer, you can't be as restrictive when defining the IAM contols around your back-end lambda. This is a violation of the principle of least privilege. This isn't just a matter of code organization and application architecture; it's a legitimate security concern. You're essentially exposing more attack surface than you have to.
Furthermore, the real power of IAM shines when your back end grows. Your back-end lambda may need to write to S3, invoke other Lambdas, publish to SNS or SQS, interact with RDS or DynamoDB, etc. I'd suggest that "best practice" dictates that all of this access is governed by strict IAM policies. In my experience, using an API Gateway authorizer (of any type, not necessarily custom) to assign a role is the most straightforward way to accomplish this.
To the cost part of the question.
Authorizer will be a separate charge for one additional lambda call, and new cpu time with its own 100ms minimum charge.
This may be significant costs if there are many short lambdas in backend, could be doubling cost of each of them.

How to get OAuth 2.0 right for consuming external APIs in my Custom API .net core

I want to create a custom API that behind the scenes, call number of other APIs which use OAuth 2.0 for authentication. I want to manage this internally so that my custom endpoint somewhat abstract this.
Or to begin with I want to do what app like buffer (https://buffer.com) do - where you connect to different social services and than post your status.
How can I achieve this in .NetCore ?? I don't want to login with these (a lot of samples are catering this scenario), user login is different than this. I just want to establish these connections (like API Connections if you look at Azure API Management) and then perform some operations against those endpoints.
I hope i convey my point. please let me know if this isn't clear.
Thanks
Sanjay
OAuth2 systems are all based on the same workflow.
here's an authorization url, you pass some ids in an authorization header, if everything is correct you get a token, you then use the token to do whatever you are allowed to do. What changes are the credentials you use for authentication and the urls you hit for the various parts of this workflow.
You could write your own OAuth2 library which deals with all this, that's pretty much what I did and simply changed the details for every specific system I had to interact with.
This being said you can always use one of the existing implementations to connect to the various systems you care about, they all have an API you could use, all you have to do is make sure you follow the OAuth2 flow correctly.