Compatibilidad con CWT para CloudFront Functions
En esta sección, se proporcionan detalles sobre la compatibilidad con los tókenes web CBOR (CWT) en las CloudFront Functions, lo que permite la autenticación y la autorización seguras basadas en tókenes en las ubicaciones periféricas de CloudFront. Esta compatibilidad se proporciona como un módulo, al que se puede acceder desde CloudFront Functions.
Para usar este módulo, cree una función de CloudFront con tiempo de ejecución 2.0 de JavaScript e incluya la siguiente instrucción en la primera línea del código de la función:
import cf from 'cloudfront';
Los métodos asociados a este módulo son accesibles mediante (donde * es un comodín que representa las diferentes funciones presentes en el módulo):
cf.cwt.*
Para obtener más información, consulte Características del tiempo de ejecución 2.0 de JavaScript para CloudFront Functions.
Actualmente, el módulo solo admite la estructura MAC0 con el algoritmo HS256 (HMAC-SHA256) con un límite de 1 KB para el tamaño máximo del token.
Estructura de token
En esta sección se describe la estructura de token que espera el módulo de CWT. El módulo espera que el token esté correctamente etiquetado y sea identificable (por ejemplo, COSE MAC0). Además, en cuanto a la estructura del token, el módulo sigue los estándares establecidos por Firma y cifrado de objetos CBOR (COSE) [RFC 8152]
( // CWT Tag (Tag value: 61) --- optional ( // COSE MAC0 Structure Tag (Tag value: 17) --- required [ protectedHeaders, unprotectedHeaders, payload, tag, ] ) )
ejemplo : CWT utiliza la estructura COSE MAC0
61( // CWT tag 17( // COSE_MAC0 tag [ { // Protected Headers 1: 4 // algorithm : HMAC-256-64 }, { // Unprotected Headers 4: h'53796d6d6574726963323536' // kid : Symmetric key id }, { // Payload 1: "https://iss.example.com", // iss 2: "exampleUser", // sub 3: "https://aud.example.com", // aud 4: 1444064944, // exp 5: 1443944944, // nbf 6: 1443944944, // iat }, h'093101ef6d789200' // tag ] ) )
nota
La etiqueta de CWT es opcional a la hora de generar los tókenes. Sin embargo, se requiere la etiqueta de estructura COSE.
método validateToken()
La función decodifica y valida un token de CWT con la clave especificada. Si la validación es exitosa, devuelve el token de CWT decodificado. De lo contrario, emite un error. Tenga en cuenta que esta función no valida el conjunto de reclamaciones.
Solicitud
cf.cwt.validateToken(token, handlerContext{key})
Parameters
- token (obligatorio)
-
Token codificado para la validación. Debe ser un búfer de JavaScript.
- handlerContext (obligatorio)
-
Un objeto de JavaScript que almacena el contexto de la llamada a validateToken. Por el momento, solo se admite la propiedad de la clave.
- clave (obligatorio)
-
Clave secreta para el cálculo del resumen del mensaje. Se puede proporcionar como cadena o búfer de JavaScript.
Respuesta
Cuando el método validateToken() devuelve un token validado correctamente, la respuesta de la función es un CWTObject en el siguiente formato. Una vez decodificadas, todas las claves de reclamación se representan como cadenas.
CWTObject { protectedHeaders, unprotectedHeaders, payload }
Ejemplo: Validación del token con el identificador enviado como parte del token
En este ejemplo, se muestra la validación del token de CWT, en la que se extrae el identificador del encabezado. A continuación, el identificador pasa a KeyValueStore de CloudFront Functions para obtener la clave secreta utilizada para validar el token.
import cf from 'cloudfront' const CwtClaims = { iss: 1, aud: 3, exp: 4 } async function handler(event) { try { let request = event.request; let encodedToken = request.headers['x-cwt-token'].value; let kid = request.headers['x-cwt-kid'].value; // Retrieve the secret key from the kvs let secretKey = await cf.kvs().get(kid); // Now you can use the secretKey to decode & validate the token. let tokenBuffer = Buffer.from(encodedToken, 'base64url'); let handlerContext = { key: secretKey, } try { let cwtObj = cf.cwt.validateToken(tokenBuffer, handlerContext); // Check if token is expired const currentTime = Math.floor(Date.now() / 1000); // Current time in seconds if (cwtObj[CwtClaims.exp] && cwtObj[CwtClaims.exp] < currentTime) { return { statusCode: 401, statusDescription: 'Token expired' }; } } catch (error) { return { statusCode: 401, statusDescription: 'Invalid token' }; } } catch (error) { return { statusCode: 402, statusDescription: 'Token processing failed' }; } return request; }
método generateToken()
Esta función genera un nuevo token de CWT mediante la carga útil y la configuración de contexto proporcionados.
Solicitud
cf.cwt.generateToken(generatorContext, payload)
Parameters
- generatorContext (obligatorio)
-
Se trata de un objeto de JavaScript que se utiliza como contexto para generar el token y contiene los siguientes pares de valores clave:
- cwTag (opcional)
-
Este valor es un booleano que, si
truelo especifica,cwtTagse debe agregar. - coseTag (obligatorio)
-
Especifica el tipo de etiqueta de COSE. Actualmente, solo admite
MAC0. - clave (obligatorio)
-
Clave secreta para el cálculo del resumen del mensaje. Este valor puede ser una cadena o JavaScript
Buffer.
- carga útil (obligatorio)
-
Carga útil del token para la codificación. La carga útil debe estar en formato
CWTObject.
Respuesta
Devuelve un búfer de JavaScript que contiene el token codificado.
ejemplo : genera un token de CWT
import cf from 'cloudfront'; const CwtClaims = { iss: 1, sub: 2, exp: 4 }; const CatClaims = { catu: 401, catnip: 402, catm: 403, catr: 404 }; const Catu = { host: 1, path: 2, ext: 3 }; const CatuMatchTypes = { prefix_match: 1, suffix_match: 2, exact_match: 3 }; const Catr = { renewal_method: 1, next_renewal_time: 2, max_uses: 3 }; async function handler(event) { try { const response = { statusCode: 200, statusDescription: 'OK', headers: {} }; const commonAccessToken = { protected: { 1: "5", }, unprotected: {}, payload: { [CwtClaims.iss]: "cloudfront-documentation", [CwtClaims.sub]: "cwt-support-on-cloudfront-functions", [CwtClaims.exp]: 1740000000, [CatClaims.catu]: { [Catu.host]: { [CatuMatchTypes.suffix_match]: ".cloudfront.net" }, [Catu.path]: { [CatuMatchTypes.prefix_match]: "/media/live-stream/cf-4k/" }, [Catu.ext]: { [CatuMatchTypes.exact_match]: [ ".m3u8", ".ts", ".mpd" ] } }, [CatClaims.catnip]: [ "[IP_ADDRESS]", "[IP_ADDRESS]" ], [CatClaims.catm]: [ "GET", "HEAD" ], [CatClaims.catr]: { [Catr.renewal_method]: "header_renewal", [Catr.next_renewal_time]: 1750000000, [Catr.max_uses]: 5 } } }; if (!request.headers['x-cwt-kid']) { throw new Error('Missing x-cwt-kid header'); } const kid = request.headers['x-cwt-kid'].value; const secretKey = await cf.kvs().get(kid); if (!secretKey) { throw new Error('Secret key not found for provided kid'); } try { const genContext = { cwtTag: true, coseTag: "MAC0", key: secretKey }; const tokenBuffer = cf.cwt.generateToken(commonAccessToken, genContext); response.headers['x-generated-cwt-token'] = { value: tokenBuffer.toString('base64url') }; return response; } catch (tokenError) { return { statusCode: 401, statusDescription: 'Could not generate the token' }; } } catch (error) { return { statusCode: 402, statusDescription: 'Token processing failed' }; } }
ejemplo : actualice el token según alguna lógica
import cf from 'cloudfront' const CwtClaims = { iss: 1, aud: 3, exp: 4 } async function handler(event) { try { let request = event.request; let encodedToken = request.headers['x-cwt-token'].value; let kid = request.headers['x-cwt-kid'].value; let secretKey = await cf.kvs().get(kid); // Retrieve the secret key from the kvs // Now you can use the secretKey to decode & validate the token. let tokenBuffer = Buffer.from(encodedToken, 'base64url'); let handlerContext = { key: secretKey, } try { let cwtJSON = cf.cwt.validateToken(tokenBuffer, handlerContext); // Check if token is expired const currentTime = Math.floor(Date.now() / 1000); // Current time in seconds if (cwtJSON[CwtClaims.exp] && cwtJSON[CwtClaims.exp] < currentTime) { // We can regnerate the token and add 8 hours to the expiry time cwtJSON[CwtClaims.exp] = Math.floor(Date.now() / 1000) + (8 * 60 * 60); let genContext = { coseTag: "MAC0", key: secretKey } let newTokenBuffer = cf.cwt.generateToken(cwtJSON, genContext); request.headers['x-cwt-regenerated-token'] = newTokenBuffer.toString('base64url'); } } catch (error) { return { statusCode: 401, statusDescription: 'Invalid token' }; } } catch (error) { return { statusCode: 402, statusDescription: 'Token processing failed' }; } return request; }