Authorizing asset on a user by user basis - azure-media-services

Documentation is quite vague and everything related to this subject mostly points towards AAD.
The requirement I have is to be able to show a video only to users who have a specific permission. This can be as simple as having a claim in their JWT. Using AAD isn't an option so I was wondering if there is any other way I can achieve this.
The way I could imagine this work is that you can specify a claim that you want Azure Media Services to check that the incoming JWT has and then specify the token's AES key or provide a certificate if you choose to go with RS token encryption.

It is NOT required to use any specific token provider (such as Azure AD). You can definitely create your own JWT provider (so-called STS, Secure Token Service), using asymmetric key encryption. In your STS, you can add custom claims as desired based on your business logic.
Make sure the issuer, audience and claims all match up exactly between what is in JWT and the ContentKeyPolicyRestriction used in ContentKeyPolicy in Azure Media Services.

Related

Create my own AccessTokens with MS Identity Platform

I am in the process of expanding our login options on our product to support MS Identity Platform, to be able to use Azure AD login (and gain SSO/MFA with that)
Currently we are using .Net Core + JWT (JwtBearerDefaults.AuthenticationScheme)
The environment is angular clients, .Net Core APA, and a back-end database.
I have the setup working.
My challenge is that in our business model and backend database we have ~2.000 userrights and our own User/Role model granting access.
I am currently getting the IdToken from MSAL and in my proof of concept using the oid to couple the Azure ID with our User model.
But, in our existing JWT solution, our access token holds claims about the User Id, but also the role, and another property (Unit/Vessel) determining access. From these three properties we can verify against the 2.000 userights on API side whether or not a request is allowed or not.
I would like to keep this information (User, Role, Unit) in the token - but have doubts on how.
Constraints:
We cant create/use Azure claims. We have too many, and customers will manage the Azure application - while we create, add, remove rights for each version of our software.
Azure don't know about role/unit data - and these are different for each customer - so that information can't be in Azure either.
My best idea is outlined below - would this approach be correct, and live up to the way ID/Access is separated?
I hope someone can give me some feedback on this.
My idea is, that the Angular client gets the Azure IDToken. I then use the Azure IDToken, call our API, which on server side, validates ID Token, and then grants me an access token, which contains the user, role and unit. This token is not Azure'd at all, just a token generated by our API - which again will be the only one validating it). Pro's on this approach is also I can keep one type of Access Token, no matter which IDToken is supplied by Azure or our own API.
Tried to outline the flow below in this DrawIO diagram.
I hope someone with more experience in the Token field can validate if this would be a viable approach?
Best regards
/Anders
This is a viable approach except for one thing.
Do not use Id token for authorization.
Your front-end should acquire an access token from AAD for your back-end.
This access token contains the user objectId, allowing you to map the user to a user in your database.
An Id token is only meant for the application that requested authentication and tells it metadata on the user like their display name etc., but it is not meant for authorizing anything.

OpenIdConnect: how to add additional claims in the token?

I'm quite new to OpenIdConnect so excuse me if i still miss some basic concept.
I have a SPA-style web application I'm developing for my company (AspNet Core + Aurelia).
I want to use AzureAD via OpenIdConnect for authentication and authorization, everything works very well so far i'm able to obrain a token and sign in.
the problem is that my application needs to provide to the client's browser some app-specific claims like: can read X, can edit Y...
if i add these claims to the JWT token provided by AzureAD obviously it will became invalid, as the signature will not match the content.
if i generate a new token with the new claims, but signed with the app key, obviously it will be a different token valid only in the context of my app (what if I'll later need to access some other resource using the AzureAD token?, is it a good idea to insert the AzureID token as claim of the newly issued token?)
Are there something I'm missing in the OpenConnectId? or is there a way to add claims to a token issued by a 3rd-party provider like AzureAD while keeping the token valid? Maybe a way to ask AzureAd to add claims to the token and re-sign it?
I think a good way to solve this situation may be to obtain an access_token for my own application's api (from my app backend) in exchange of the id_token provided by azure (after its validation)
so the application frontend in the browser will own two tokens and it will be able to use the correct one for each type of request.
there are some standardized flow that are quite similar to this but not exactly the same.
You could try to use a custom claim mapping policy. This is documented here.
This feature is used by tenant admins to customize the claims emitted in tokens for a specific application in their tenant.
As far as I can understand, this is still in preview stage. So it may require some trial and error verification.
Alternatively, you can define some policy in your application itself. Given that you know client IDs from your application (hence you require to use them for OpenID Connect requests), you may create a simple policy to check tokens and perform verifications.

Using Cognito for REST API authentication

I'm looking to use API Gateway + Lambda + Cognito User Pools to build a simple REST API.
The API will be used in two ways. The first is to support a basic web app (hosted on CloudFront + S3). Authentication for the web application uses the hosted Cognito sign in / sign up flow and is working fine (with API Gateway setup to use the user pool authenticator).
The second method will be for customers to use the REST API to communicate with the system.
As an example, the client might use the web app to configure a workflow and then use an API to invoke that workflow.
What is the recommended method of authenticating the API for use with backend services?
Traditionally, I'd expect to use an API key + secret token for this purpose. I have no issue creating API keys in the API Gateway interface however I can't see anyway to link that to a specific user, nor can I see any method of specifying a secret token alongside the API key.
And assuming the above is possible, how would I set it up in such a way that I could use the JWT-based approach for the web application and the API key + secret token for customers to use.
EDIT: Additionally, I notice that app clients have an ID and a secret. Are they intended to be used for 3rd API-based-authentication (similar to how other systems make you create an app for API access)? I'm a bit skeptical because there's a limit of 25 per user pool, although it is a soft limit...
I have been searching for an answer to this myself and my searching led me to your question. I will give you my best answer from my research, assuming you want to utilize the well-known key/secret approach. Maybe others can provide a better approach.
Basically, the approach is:
Your REST API accounts are just Cognito users in a (possibly separate) user pool
The management of API accounts is done from the back end
The username and password will be the API key and secret, are administratively created (see the Admin* operations), and can be whatever format you want (within Cognito limits)
The REST API is authorized via Cognito JWT tokens
API account key and secret are only used to retrieve or refresh tokens
This requires the REST API to have a set of endpoints to support token retrieval and refresh using account keys and secrets
Based upon how long you set up the Cognito refresh interval, you can require API accounts to submit their key/secret credentials from very often to almost never
Structuring the authorization of your REST API to use Cognito tokens will allow you to integrate the REST API directly with API Gateway's support for Cognito.
I think the biggest headache of this whole thing is that you will have to create the supporting pieces for, e.g., registered users to request API accounts and for the administration of those accounts, as well as some extra helper REST endpoints for token exchange. Additionally, clients will have to keep track of keys/secrets AND token(s) as well as add client-side logic to know when to supply tokens or credentials.
When i was starting out using API gateway and Congito, i referenced https://github.com/awslabs/aws-serverless-auth-reference-app a lot and found it very helpful in demonstrating the integration between the different AWS components.
If I understand you correctly, you want to create a "long-lived API key + secret" for programmatic access to your API?
I have exactly this need, and am sadly finding that it appears to not be possible. The longest a key can be valid for is 1 hour. You can have a refresh token that's valid for 10 years. https://docs.aws.amazon.com/cognito/latest/developerguide/limits.html
I'm currently looking for an elegant solution to this. I'd be interested to hear if you ever found a solution, or if you rolled your own.
Did anyone ever find a more elegant solution to this problem?
The first answer seems like pushing too much work into the hands of my customers. I don't know the skill level of the developers calling my API, and I wouldn't wish becoming a Cognito developer on anyone lol. More seriously, I don't want them to have to store multiple pieces of information and then have to deal with refreshing tokens.
I might be Ok with giving them a refresh token. Then I could do one of two things:
Give them a refresh method. I'd figure out all the weird Cognito kinks and keep their method to a simple payload of just the refresh token. I'd give them back the access token to use on subsequent calls.
Let them pass me the refresh token as if it was an access token. I would use it on each call to get an access token and then use that to call the interior APIs.

Authentication without user credentials

I'm putting together a personal React site and want to send requests to an AWS API Gateway. However, I just want my site to be able to pull data. There will be no user model and every auth model I've ever used requires the user to do something with sign-in, be it user/pwd or AD. Can someone guide me to a model that covers this scenario?
One common approach is to use a Cognito Identity Pool with "Unauthenticated Identities" enabled. You can secure your API gateway endpoints using IAM, and require requests to be sig4 signed.
With this approach, Cognito is used only in a kind identity broker capacity, not as an actual identity provider. You do not need to create a User Pool or use any other identity management features of Cognito. In this capacity, Cognito is essentially just a thin layer between your code and the underlying STS APIs that produce the IAM keys your application needs.
Using the Cognito SDK, you request temporary IAM credentials (access key, secret key, session token) that can be used to sign the requests.
This answer outlines one way to accomplish this. When the protected AWS resource you want to access is API Gateway, your code may look something like the example near the end of this post.
I typically either use aws-api-gateway-client, as the example does, or aws4 with axios to sign requests.
As noted in the linked to answer above, I normally use AWS.config.credentials.get(), rather than AWS.CognitoIdentity.getCredentialsForIdentity() to actually get the IAM keys (as in this doc).
The signed requests then include an Authorization header that is very difficult to counterfeit. I don't want to suggest that this approach is bulletproof, but it does at least give you a reasonable level of confidence that your API Gateway endpoints are only being successfully invoked by your application.

Multitenant token Validation using OpenidConnect

I have a multitenant aad app for which token validation needs to be done. I have access to the token in 'TokenValidated' event handler. For now, I have the property 'ValidateIssuer' set to true. Looking online, I noticed a lot of places this property is set to false for multitenant applications and there is a mention of custom validation. Can someone tell me what extra token validation needs to be done for multitenant applications? Examples will be helpful.
I have read about ValidatingIssuerNameRegistry, but don't know if that applies in my scenario since we do not restrict any specific tenants.
Thanks
-Ravi
Here's a great article on token validation you may find helpful. The Azure AD Token Claims Article is also extremely useful.
Issuer validation is used to indicate the sts that issued the token and the tenant for which it was issued. So in the case of a multi-tenant app, you may choose to turn off issuer validation as to not limit any tenants from signing in. In the single tenant or n tenant case, you can use this to only allow tokens from specific tenants.
The other validation necessary is signature validation. Doing this ensures the token was actually minted from Azure AD (issuing authority) and not fabricated from some nefarious source.