Azure media services: Customize ContentKey authorization policy based on backend data - azure-media-services

I've not been able to find decent information in the docs for this. Here's to the internet :)
This is my current understanding:
The documented approach is to create a ContentKeyPolicy with JWT restriction and Media Services will expect the claim added to the token of urn:microsoft:azure:mediaservices:contentkeyidentifier=INJECTED CONTENT KEY ID HERE based on what content the locator URL is serving up.
This means I'd need a new content key for every SKU sold to secure access to the media. Is there a way to hook into this authorization logic to say "I want you to call this API to run my custom validation" where I could check the JWT user's purchased content? This way only one content policy is really needed and becomes manageable.

The custom scenario you described is exactly the reason for using unique content key identifiers.
The way the key delivery server works with JWT tokens is that the key delivery server first checks to see which content key ID is being used. It then checks to see if the token is properly signed with the primary verification key that was used for that locator. Then it validates any claims that were applied when the encryption policies were set.
I'd recommend tracking the primary verification key (if unique per locator), the locator itself, the content key ID, and any claims in your own database so that all of those values are readily accessible for any of your content.

Related

JWT architecture for multiple users?

Most examples always take into consideration only one users using the system in the JWT/Flask tutorials. I want to understand this at a multi-user level but cannot find the correct resources.
Lets say we have the following secret key:
app.config['SECRET_KEY'] = 'randomkey'
Two Questions:
Would this key be the same for every user? if so, wouldn't this provide a security risk because if the key was stolen, anyone would have access to do whatever they want?
If it is not the same, how is the key stored on the server-side so it could be authenticated when requesting information? Would it be stored within the user's table under current token or something?
In this case, that key is the JWT signing key It could also be different from flask's secret key setting (see flask docs). It's not used for encryption so it's not intended to be a shared secret between server and users. Its role is to provide the server with a proof that the JWT content was generated by the server itself: it's a proof of integrity.
Having knowledge of that key means having the right to issue JWTs on behalf of the application, attackers could impersonate servers or make requests with some modified claims, eg pretending to be other users. This means that these keys are quite sensible from security perspective
Turns out that 1 app : 1 key, with some remarks
This key should theorically never change: if at time T1 KEY=x, a user could login in and receive a JWT signed with KEY=x. at T2 KEY=y, the user will invoke some API using the previous JWT and the server will try to verify(signature(payload , x) , y). So every user will be logged out automatically
Despite 1. It would be good to rotate the key. In this case the authentication system should save a buffer of old keys and use them to validate oldest JWT. Since a JWT should be short-lived, it could be useful set a rotation time grater than JWT expire time and just keep the last used key along with the current
This key is a secret and should be managed exactly as other secrets. Aside from terrible approaches like leaving it plaintext in the code/config, there are secret managers from cloud providers, or kubernetes secrets if you use the latter, as well as secret managers from configuration management tools (salt, ansible) or Hashicorp's Vault that is a specialized storage engine for sensible data. Anyway, it's more infra/security team concern if you are in a structured organization

Authorizing asset on a user by user basis

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.

How can I add claims to the context for GetProfileDataAsync & IsActiveAsync for a custom user service?

I am implementing a user service that is storing user info in Azure Table storage. I would like to use a value for tenant ID as part of my partition key, but, the claims available in GetProfileDataAsync and IsActiveAsync are just 5 built in claims (sub, name, amr, idp, auth_time).
I get tenant ID from my identity provider and it's included as a claim in both my access token & identity token. How can I make it available to those methods?
When the AuthenticateLocal is invoke, you return an AuthenticateResult to indicate the authentication outcome. If it's successful you use the ctor overload that accepts the subject and name values. There's also an optional claims collection. If you pass values for claims then you are adding your own custom claims to the authentication cookie at IdentityServer. Those claims are then part of the Subject for the GetProfile API (assuming the requests into those APIs are being done via the browser such as from the authorization request). You can then inspect those claims and use them in any way you want.
If the request is not via the browser, then the only claim you have on the Subject is the user's unique id (which is the sub claims).

REST - What verb to use to check for authorization

I'm designing an authorization service that will be queried internally by other public-services that are receving an Authorization header within a request.
This service handles the authorization (a pair of public key (user_id) and private key) and its task is to regenerate the signature (HMAC) -its the only service to know the private key-, so it seemed right to me to identify this as the server resource. Then I considered that there is no authorization resource without a user, so I ended up with this base URI:
/user/:user_id/authorization
I've then designed CRUD operations to handle the authorization, create when a new user is created, update whenever requested, read and delete when the user is deleted.
Note: the User entity is handled by another service, i'm only using this URI to pass in a logical way the public key (since it's strictly related to a user).
I'm not sure how should I query this service from other services to say: "Hey, is this key right?" passing alongside this request all data it needs to regenerate the signature.
So what I need is a way to CHECK the Authorization in a restful way
I've tought something like:
GET /user/:user_id/authorization?signature=SOMETHING&data=JSON-DATA-TO-REGENERATE-KEY
But maybe, we could also see it to be creating a new Authorization resource (also if nothing is returned, it's not a token system) thus making PUT or POST more right for this purpose.
What's your point of view? What is the right approach to handle this kind of situation?
GET /user/:user_id/authorization?signature=SOMETHING&data=JSON-DATA-TO-REGENERATE-KEY
Never forget that a GET method should be 'safe'. It should not "have the significance of taking an action other than retrieval". In other words, the client "should not request side-effects".
Personally I think that the obtaining initial authorization (the login) for a session/user/whatever should be a POST as it (presumeably) does create something new: some authorization token.
Subsequent authorization validation requests should be GET. They don't create anything new and basically return a boolean (albeit through response codes) to indicate whether the authorization headers are valid or not.
This service handles the authorization (a pair of public key (user_id) and private key)
Are you storing the private key server-side? And are you handling authorization and authentication on the same service?
I would personally prefer an architecture like WebID. See:
http://webid.info
http://www.w3.org/wiki/WebID

Good approach for a web API token scheme?

I am working on a REST API for a web application that up until now we have developed internally for a couple of companion applications. Now that we are looking at opening up to outside developers we want to add tokens to the API in order to help identify who is making requests and in general to help manage it's use. At this point we are using https and basic authentication for user authentication on the API.
The token scheme we've been discussing would be very simple where each developer would be assigned 1 or more tokens and these tokens would be passed as a parameter with each request.
My question is if you've done something similar before how did you do it (did you do more or less, how did you handle security, etc) and do you have any recommendations?
First, you might want look at http://OAuth.net. Depending on your usecases, it might provide the security you need.
As to the token, it's a BLOB to most protocols, including OAuth. You can put any information you need in it in any format.
Here is what we do,
First we assign each developer a key with associated secret.
The token itself is an encrypted name-value pairs. We put things like username, expiry, session id, roles etc in there. It's encrypted with our own secret so no one else can make it.
For easy of use with web API, we use the URL-safe version of Base64 so the token is always URL-safe.
Hope that helps!
You might also want to think about maybe adding a time based token that would allow you to limit the amount of time a request is valid. this will help with someone trying to do a replay attack.
You would have a handshake call to get/assign a time valid token based off the above developerKey. This token would be stored locally and passed back to the caller.
The developer would then use this key in a request to validate the request and the developer.
For example that key can then be used for 5 mins or for 10 requests or whatever you define. after that point the generated time based token is removed from the valid list and can no longer be used. the developer will then have to ask for a new token.
UUID is very good for any temporary random key you fancy dishing out. Unpredictable and fast to generate, with collisions so unlikely they are effectively unique. Make nice session keys also.