Integrating the Media Token Verifier
About the Media Token Verifier about-media-token-verifier
When authorization succeeds, Adobe Pass Authentication creates a long-lived authorization (AuthZ) token. The AuthZ token is either passed to the client-side or stored on the server-side, depending upon the client’s platform. (See Understanding Tokens for how tokens are stored on different client systems, along with other details.)
An AuthZ token authorizes the user of the site to view a given resource. It has a typical time-to-live (TTL) of 6 to 24 hours, after which the token expires. For actual viewing access, the Adobe Pass Authentication uses the AuthZ token to generate a short-lived media token that you obtain and pass to your media server. These short-lived media tokens have a very brief TTL (typically, a few minutes).
In AccessEnabler integrations, you obtain the short-lived media token via the setToken()
callback. For Clientless API integrations, you obtain the short-lived Media token with the <SP_FQDN>/api/v1/tokens/media
API call. The token is a string sent in clear text, signed by Adobe, using token protection based on PKI (Public Key Infrastructure). With this PKI-based protection, the token is signed using an asymmetric key, issued to Adobe by a certification authority.
Because there is no validation on the client side for the token, a malicious user could use tools to inject fake setToken()
calls. Therefore you cannot rely simply on the fact that setToken()
was triggered, when considering whether a user is authorized or not. You must validate that the short-lived token itself is legitimate. The tool to perform the validation is the Media Token Verifier Library.
Validating Short-lived Tokens with the Media Token Verifier validate-short-livedttokens
We recommend that Programmers send the token to a web service that uses the Media Token Verifier Library, in order to validate the token before actually starting the video stream. The very short TTL of the short-lived media tokens is defined to be sufficiently long to allow for clock-synchronization issues between the server generating the token and the server validating the token, but no longer.
The Media Token Verifier Library is available for Adobe Pass Authentication partners.
The Media Token Verifier library is contained in the Java archive mediatoken-verifier-VERSION.jar
. The library defines:
- A token-verification API (
ITokenVerifier
interface), with JavaDoc documentation - The Adobe public key used to verify that the token does indeed come from Adobe
- A reference implementation (
com.adobe.entitlement.test.EntitlementVerifierTest.java
) that shows how to use the Verifier API and how to use the Adobe public key contained in the library to verify its origin
The archive contains all dependencies and certificate keystores. The default password for the included certificate keystore is “123456”.
- The verification library requires JDK version 1.5 or higher.
- Use your preferred JCE provider for the signature algorithm, “SHA256WithRSA”.
The Verifier Library must be the only means used to analyze the token content. Programmers should not parse the token and extract the data themselves, because the token format is not guaranteed and is subject to future change. Only the Verifier API is guaranteed to function correctly. Parsing the string directly might work temporarily, but cause problems in the future when the format might change. The Verifier API retrieves information from the token, such as:
- Is the token valid (the
isValid()
method)? - The resource ID tied to the token (the
getResourceID()
method); this can be compared to (and it should match) the other parameter of thesetToken()
function callback. If it doesn’t match, this might indicate fraudulent behavior. - The time the token was issued (
getTimeIssued()
method). - The TTL (
getTimeToLive()
method). - An anonymized authentication GUID received from the MVPD (
getUserSessionGUID()
method). - The distributor’s ID that authenticated the user and if it is the case - the proxy-MVPD that provided the authentication for the distributor.
Using the Verifier API using-verifier-api
The ITokenVerifier
class defines methods you use to validate token authenticity for a given resource. Use the ITokenVerifier
methods to analyze a token received in response to a setToken()
request.
The isValid()
method is the primary means of validating a token. It takes one argument, a resource ID. If you pass a null resource ID, the method validates only the token authenticity and validity period.
The isValid()
method returns one of these status values:
Additional methods provide specific access to the resource ID, the time issued, and the time-to-live for a given token.
- Use
getResourceID()
to retrieve the resource ID associated with the token and compare it to the ID returned from the setToken() request. - Use
getTimeIssued()
to retrieve the time the token was issued. - Use
getTimeToLive()
to retrieve the TTL. - Use
getUserSessionGUID()
to retrieve an anonymized GUID set by the MVPD. - Use
getMvpdId()
to retrieve the ID of the MVPD which authenticated the user. - Use
getProxyMvpdId()
to retrieve the ID of the Proxy MVPD which authenticated the user.
Sample Code sample-code
The Media Token Verifier archive contains a reference implementation (com.adobe.entitlement.test.EntitlementVerifierTest.java
) and an example of invoking the API with the test class. This sample (com.adobe.entitlement.text.EntitlementVerifierTest.java
) illustrates the integration of the token verification library into a media server.
package com.adobe.entitlement.test;
import com.adobe.entitlement.verifier.CryptoDataHolder;
import com.adobe.entitlement.verifier.ITokenVerifier;
import com.adobe.entitlement.verifier.ITokenVerifierFactory;
import com.adobe.entitlement.verifier.SimpleTokenPKISignatureVerifierFactory;
import com.adobe.tve.crypto.SignatureVerificationCredential;
import java.io.InputStream;
public class EntitlementVerifierTest {
String mRequestorID = null;
String mTokenToVerify = null;
String mPathToCertificate = null;
String mKeystoreType = null;
String mKeystorePasswd = null;
String mResourceID = null;
public static void main(String[] args) {
if (args == null || args.length < 2 ) {
System.out.println("Incorrect args: Usage: EntitlementVerifierTest requestorID tokenToVerify [resourceID]");
return;
}
String requestorID = args[0];
String tokenToVerify = args[1];
String pathToCertificate = "media_token_keystore.jks"; // the default keystore provided in the entitlement jar
String keystoreType = "jks";
String keystorePasswd = "123456"; // password for the default keystore
if (requestorID == null || tokenToVerify == null) {
System.out.println("One or more arguments is null");
return;
}
System.out.println("RequestorID: " + requestorID);
System.out.println("token: " + tokenToVerify);
System.out.println("cert: " + pathToCertificate);
System.out.println("keystoretype: " + keystoreType);
System.out.println("keystore passwd: " + keystorePasswd);
String resourceID = null;
if (args.length > 2) {
resourceID = args[2];
}
System.out.println("Resource ID: " + resourceID);
EntitlementVerifierTest verifier = new EntitlementVerifierTest(requestorID,
tokenToVerify, pathToCertificate, keystoreType, keystorePasswd, resourceID);
verifier.verifyToken();
}
protected EntitlementVerifierTest(String inRequestorID,
String inTokenToVerify,
String inPathToCertificate,
String inKeystoreType,
String inKeystorePasswd, String inResourceID) {
mRequestorID = inRequestorID;
mTokenToVerify = inTokenToVerify;
mPathToCertificate = inPathToCertificate;
mKeystoreType = inKeystoreType;
mKeystorePasswd = inKeystorePasswd;
mResourceID = inResourceID;
}
protected void verifyToken() {
// It is expected that the SignatureVerificationCredential and
// CryptoDataHolder could be created at Init time in a web application
// and be reused for all token verifications.
CryptoDataHolder cryptoData = createCryptoDataHolder(mPathToCertificate, mKeystoreType, mKeystorePasswd);
ITokenVerifierFactory tokenVerifierFactory = new SimpleTokenPKISignatureVerifierFactory();
ITokenVerifier tokenVerifier = tokenVerifierFactory.getInstance(mRequestorID, mTokenToVerify, cryptoData);
ITokenVerifier.eReturnValue status = tokenVerifier.isValid(mResourceID);
System.out.println("Is token Valid? : " + status.toString());
System.out.println("Token User ID: " + tokenVerifier.getUserSessionGUID());
System.out.println("Token was generated at: " + tokenVerifier.getTimeIssued());
System.out.println("Token Mvpd ID: " + tokenVerifier.getMvpdId());
System.out.println("Token Proxy Mvpd ID: " + tokenVerifier.getProxyMvpdId());
}
protected CryptoDataHolder createCryptoDataHolder(String pathToCertificate,
String keystoreType, String keystorePasswd) {
SignatureVerificationCredential verificationCredential =
readShortTokenVerificationCredential(pathToCertificate, keystoreType, keystorePasswd);
CryptoDataHolder cryptoData = new CryptoDataHolder();
cryptoData.setCertificateInfo(verificationCredential);
return cryptoData;
}
protected SignatureVerificationCredential readShortTokenVerificationCredential(String keystoreFile,
String keystoreType,
String keystorePasswd) {
SignatureVerificationCredential cred = null;
if (keystoreFile != null){
try {
// load the keystore file
ClassLoader loader = EntitlementVerifierTest.class.getClassLoader();
InputStream certInputStream = loader.getResourceAsStream(keystoreFile);
if (certInputStream != null) {
cred = new SignatureVerificationCredential(certInputStream, keystorePasswd, keystoreType);
}
}
catch (Exception e) {
System.out.println("Error creating short token server credentials: " + e.getMessage());
}
}
if (cred == null) {
System.out.println("Error creating short token server credentials");
}
return cred;
}
}