Trabaja con alcances de OAuth2

Estás consultando la documentación de Apigee Edge.
Consulta la documentación de Apigee X.
Información

En este tema, se analiza cómo usar los permisos de OAuth 2.0 en Apigee Edge.

¿Qué es un permiso de OAuth2?

Los permisos de OAuth 2.0 proporcionan una forma de limitar la cantidad de acceso que se otorga a un token de acceso. Por ejemplo, un token de acceso emitido para una app cliente puede recibir acceso de LECTURA y ESCRITURA a recursos protegidos o solo acceso de LECTURA. Puedes implementar tus API para aplicar cualquier permiso o combinación de permisos que desees. Por lo tanto, si un cliente recibe un token con permiso de LECTURA, y trata de llamar a un extremo de API que requiere acceso de ESCRITURA, la llamada fallará.

En este tema, analizaremos cómo se asignan los permisos a los tokens de acceso y cómo Apigee Edge aplica los permisos de OAuth 2.0. Después de leer este tema, podrás usar permisos de confianza.

¿Cómo se asignan los permisos a los tokens de acceso?

Cuando Edge genera un token de acceso, puede asignarle un alcance. Para comprender cómo sucede esto, primero debes familiarizarte con estas entidades de Apigee Edge: productos de API, desarrolladores y apps para desarrolladores. Para ver una introducción, consulta Introducción a la publicación. Te recomendamos que revises este material si necesitas continuar.

Un token de acceso es una string larga de caracteres aleatorios que permite que Edge verifique las solicitudes a la API entrantes (considéralo un reemplazo de las credenciales típicas de nombre de usuario y contraseña). Técnicamente, el token es una clave que hace referencia a una colección de metadatos que se ve de la siguiente manera:

{
  "issued_at" : "1416962591727",
  "application_name" : "0d3e1d41-a59f-4d74-957e-d4e3275d4781",
  "scope" : "A",
  "status" : "approved",
  "api_product_list" : "[scopecheck1-bs0cSuqS9y]",
  "expires_in" : "1799", //--in seconds
  "developer.email" : "scopecheck1-AdBmANhsag@apigee.com",
  "organization_id" : "0",
  "token_type" : "BearerToken",
  "client_id" : "eTtB7w5lvk3DnOZNGReBlvGvIAeAywun",
  "access_token" : "ODm47ris5AlEty8TDc1itwYPe5MW",
  "organization_name" : "wwitman",
  "refresh_token_expires_in" : "0", //--in seconds
  "refresh_count" : "0"
}

Los metadatos del token incluyen la string del token de acceso, la información de vencimiento, la identificación de la app para desarrolladores, el desarrollador y los productos asociados con el token. También notarás que los metadatos incluyen "permiso".

¿Cómo obtiene su permiso el token?

La primera clave para comprender el permiso es recordar que cada producto en una app de desarrollador puede tener cero o más permisos asignados. Estos permisos se pueden asignar cuando se crea el producto o se pueden agregar más adelante. Existen como una lista de nombres y se incluyen en los "metadatos" asociados con cada producto.

Cuando creas una app de desarrollador y le agregas productos, Edge busca todos los productos de la app del desarrollador y crea una lista de todos los alcances de esos productos (la lista principal o de alcance global de la app, es decir, una unión de todos los alcances reconocidos).

Cuando una app cliente solicita un token de acceso de Apigee Edge, puede especificar de forma opcional qué alcances desea tener asociado con ese token. Por ejemplo, la siguiente solicitud solicita el permiso “A”. Es decir, el cliente solicita que el servidor de autorización (Edge) genere un token de acceso con alcance "A" (lo que le otorga a la app autorización para llamar a las APIs que tienen el alcance "A"). La aplicación envía una solicitud POST como la siguiente:

curl -i -X POST -H Authorization: Basic Mg12YTk2UkEIyIBCrtro1QpIG -H content-type:application/x-www-form-urlencoded http://myorg-test.apigee.net/oauth/token?grant_type=client_credentials&scope=A

¿Qué ocurre entonces?

Cuando Edge recibe esta solicitud, sabe qué app realiza la solicitud y sabe qué app para desarrollador se registró (el ID de cliente y las claves secretas del cliente están codificadas en el encabezado de autenticación básico). Debido a que se incluye el parámetro de búsqueda scope, Edge debe decidir si alguno de los productos de API asociados con la app para desarrolladores tiene el permiso “A”. Si los tiene, se genera un token de acceso con el permiso “A”. Otra forma de ver esto es que el parámetro de consulta de permisos es un tipo de filtro. Si la app para desarrolladores reconoce los permisos “A, B, X”, y el parámetro de consulta especifica “scope=X Y Z”, entonces solo se asignará el permiso “X” al token.

¿Qué sucede si el cliente no adjunta un parámetro de permiso? En este caso, Edge genera un token que incluye todos los permisos reconocidos por la app para desarrolladores. Es importante comprender que el comportamiento predeterminado es mostrar un token de acceso que contenga la unión de todos los permisos de todos los productos incluidos en la app para desarrolladores.

Si ninguno de los productos asociados a una app de desarrollador especifica permisos, y un token tiene permiso, las llamadas realizadas con ese token fallarán.

Supongamos que una app para desarrolladores reconoce estos permisos: A B C D. Esta es la lista principal de permisos de la app. Puede ser que un producto en la app tenga los permisos A y B, y otro tenga los permisos C y D, o cualquier combinación. Si el cliente no especifica un parámetro de scope (o si especifica un parámetro de permiso sin valor), se le otorgará el token a los cuatro permisos: A, B, C y D. Nuevamente, el token recibe un conjunto de permisos que es la unión de todos los permisos que reconoce la aplicación para desarrolladores.

Hay otro caso en el que el comportamiento predeterminado es mostrar un token de acceso con todos los permisos reconocidos, y es cuando la política GenerateAccessToken (la política de Apigee Edge que genera tokens de acceso) no especifica un elemento <Scope>. Por ejemplo, esta es una política de GenerateAccessToken en la que se especifica <Scope>. Si falta ese elemento <Scope> (o si está presente, pero vacío), se ejecuta el comportamiento predeterminado.

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<OAuthV2 async="false" continueOnError="false" enabled="true" name="OAuthV2-GenerateAccessToken">
    <DisplayName>OAuthV2 - Generate Access Token</DisplayName>
    <Attributes>
      <Attribute name='hello' ref='system.time' display='false'>value1</Attribute>
    </Attributes>
    <Scope>request.queryparam.scope</Scope> 
    <GrantType>request.formparam.grant_type</GrantType>
    <ExternalAuthorization>false</ExternalAuthorization>
    <Operation>GenerateAccessToken</Operation>
    <SupportedGrantTypes>
      <GrantType>client_credentials</GrantType>
    </SupportedGrantTypes>
  <GenerateResponse enabled="true"/>
</OAuthV2>

¿Cómo se aplican los permisos?

Primero, recuerda que, en Apigee Edge, los tokens de acceso se validan con la política OAuthV2 (por lo general, se coloca al comienzo de un flujo de proxy). La política debe tener especificada la operación VerifyAccessToken. Veamos esta política:

<OAuthV2 async="false" continueOnError="false" enabled="true" name="OAuthV2-VerifyAccessTokenA">
    <DisplayName>Verify OAuth v2.0 Access Token</DisplayName>
    <ExternalAuthorization>false</ExternalAuthorization>
    <Operation>VerifyAccessToken</Operation>
    <Scope>A</Scope> <!-- Optional: space-separated list of scope names. -->
    <GenerateResponse enabled="true"/>
</OAuthV2>

Observa el elemento <Scope>. Se usa para especificar qué permisos acepta la política.

En este ejemplo, la política tendrá éxito solo si el token de acceso incluye el permiso "A". Si se omite este elemento <Scope> o si el elemento no tiene valor, la política ignora el permiso del token de acceso.

Ahora, con la capacidad de validar tokens de acceso basados en los permisos, puedes diseñar tus API para aplicar permisos específicos. Para ello, diseña flujos personalizados con políticas VerifyAccessToken adaptadas a los permisos y asociadas a esos flujos.

Supongamos que tu API tiene un flujo definido para el extremo /resourceA:

<Flow name="resourceA">
            <Condition>(proxy.pathsuffix MatchesPath "/resourceA") and (request.verb = "GET")</Condition>
            <Description>Get a resource A</Description>
            <Request>
                <Step>
                    <Name>OAuthV2-VerifyAccessTokenA</Name>
                </Step>
            </Request>
            <Response>
                <Step>
                    <Name>AssignMessage-CreateResponse</Name>
                </Step>
            </Response>
        </Flow>

Cuando se activa este flujo (ingresa una solicitud con /resourceA en el sufijo de la ruta), se llama de inmediato a la política OAuthV2-VerifyAccessTokenA. Esta política verifica que el token de acceso sea válido y verifica qué permisos admite el token. Si se configura la política como en el ejemplo que aparece a continuación, con <Scope>A</Scope>, la política solo tendrá éxito si el token de acceso tiene el permiso “A”. De lo contrario, se mostrará un error.

<OAuthV2 async="false" continueOnError="false" enabled="true" name="OAuthV2-VerifyAccessTokenA">
    <DisplayName>Verify OAuth v2.0 Access Token</DisplayName>
    <ExternalAuthorization>false</ExternalAuthorization>
    <Operation>VerifyAccessToken</Operation>
    <Scope>A</Scope>
    <GenerateResponse enabled="true"/>
</OAuthV2>

En resumen, los desarrolladores de API son responsables de diseñar la aplicación de permisos en sus API. Para ello, crean flujos personalizados a fin de controlar permisos específicos y vinculan políticas VerifyAccessToken para aplicar esos permisos.

Ejemplos de código

Finalmente, veamos algunas llamadas a la API de ejemplo para ayudar a ilustrar cómo los tokens reciben permisos y cómo se aplican los permisos.

Caso predeterminado

Supongamos que tienes una app de desarrollador con productos y que la unión de los permisos de esos productos es A, B y C. Esta llamada a la API solicita un token de acceso, pero no especifica un parámetro de consulta de permiso.

curl -X POST -H content-type:application/x-www-form-urlencoded http://wwitman-test.apigee.net/scopecheck1/token?grant_type=client_credentials

En este caso, el token generado recibirá los permisos A, B y C (el comportamiento predeterminado). Los metadatos del token se verán de la siguiente manera:

{
  "issued_at" : "1417016208588",
  "application_name" : "eb1a0333-5775-4116-9eb2-c36075ddc360",
  "scope" : "A B C",
  "status" : "approved",
  "api_product_list" : "[scopecheck1-yEgQbQqjRR]",
  "expires_in" : "1799", //--in seconds
  "developer.email" : "scopecheck1-yxiuHuZcDW@apigee.com",
  "organization_id" : "0",
  "token_type" : "BearerToken",
  "client_id" : "atGFvl3jgA0pJd05rXKHeNAC69naDmpW",
  "access_token" : "MveXpj4UYXol38thNoJYIa8fBGlI",
  "organization_name" : "wwitman",
  "refresh_token_expires_in" : "0", //--in seconds
  "refresh_count" : "0"
}

Ahora, supongamos que tienes un extremo de API con permiso “A” (es decir, es VerifyAccessToken requiere el permiso “A”). Esta es la política de VerifyAccessToken:

<OAuthV2 async="false" continueOnError="false" enabled="true" name="OAuthV2-VerifyAccessTokenA">
    <DisplayName>Verify OAuth v2.0 Access Token</DisplayName>
    <ExternalAuthorization>false</ExternalAuthorization>
    <Operation>VerifyAccessToken</Operation>
    <Scope>A</Scope>
    <GenerateResponse enabled="true"/>
</OAuthV2>

Esta es una llamada de muestra a un extremo que aplica el permiso A:

curl -X GET -H Authorization: Bearer MveXpj4UYXol38thNoJYIa8fBGlI http://wwitman-test.apigee.net/scopecheck1/resourceA 

Esta llamada GET se realiza correctamente:

 {
   "hello" : "Tue, 25 Nov 2014 01:35:53 UTC"
 }

La operación se ejecuta de forma correcta porque la política VerifyAccessToken que se activa cuando se llama al extremo requiere el permiso A, y al token de acceso se le otorgaron los permisos A, B y C (el comportamiento predeterminado).

Caso de filtrado

Supongamos que tienes una app para desarrolladores con productos que tienen los permisos A, B, C y X. Solicita un token de acceso y, además, incluye el parámetro de búsqueda scope, de la siguiente manera:

curl -i -X POST -H content-type:application/x-www-form-urlencoded 'http://myorg-test.apigee.net/oauth/token?grant_type=client_credentials&scope=A X'

En este caso, al token generado se le asignarán los permisos A y X, porque A y X son permisos válidos. Recuerda que la app para desarrolladores reconoce los permisos A, B, C y X. En este caso, filtras la lista de productos de API según estos permisos. Si un producto tiene un permiso A o X, puedes configurar los extremos de API que aplicarán estos permisos. Si un producto no tiene permiso A o X (supongamos que tiene B, C y Z), no se puede llamar a las API que aplican los permisos A o X con el token.

Cuando llamas a la API con el token nuevo, sucede lo siguiente:

curl -X GET -H Authorization: Bearer Rkmqo2UkEIyIBCrtro1QpIG http://wwitman-test.apigee.net/scopecheck1/resourceX

El proxy de API valida el token de acceso. Por ejemplo:

<OAuthV2 async="false" continueOnError="false" enabled="true" name="OAuthV2-VerifyAccessTokenX">
    <DisplayName>Verify OAuth v2.0 Access Token</DisplayName>
    <ExternalAuthorization>false</ExternalAuthorization>
    <Operation>VerifyAccessToken</Operation>
    <Scope>A X</Scope>
    <GenerateResponse enabled="true"/>
</OAuthV2>

Los activadores de llamadas GET tienen éxito y se muestra una respuesta. Por ejemplo:

 {
   "hello" : "Tue, 25 Nov 2014 01:35:53 UTC"
 }
 

La operación se ejecuta con éxito porque la política VerifyAccessToken requiere los permisos A o X, y el token de acceso incluye los permisos A y X. Por supuesto, si el elemento <Scope> se hubiera configurado como “B”, esta llamada fallaría.

Resumen

Es importante comprender cómo Apigee Edge maneja los permisosde OAuth 2.0. A continuación, se presentan los puntos principales:

  • Una app de desarrollador “reconoce” la unión de todos los permisos definidos para todos sus productos.
  • Cuando una app solicita un token de acceso, tiene la oportunidad de especificar qué permisos desea tener. Le corresponde a Apigee Edge (el servidor de autorización) determinar los permisos que realmente asignará al token de acceso según (a) los permisos que se solicitan y (b) los que se reconoce la app de desarrollador.
  • Si Apigee Edge no está configurado para verificar el permiso (falta el elemento <Scope> en la política VerifyAccessToken o el elemento está vacío), la llamada a la API se realizará correctamente siempre que el permiso que está incorporado en el token de acceso coincida con uno de los permisos que reconoce la app para desarrolladores registrada (uno de los permisos de la lista "principal" de permisos de la app).
  • Si un token de acceso no tiene ningún permiso asociado, solo funcionará en casos en los que Edge no tenga en cuenta el permiso (falta el elemento <Scope> en la política VerifyAccessToken o el elemento está vacío).