Descripción general de la API de App Identity para Python

La API de App Identity permite que una aplicación descubra su ID (también llamado ID del proyecto). Con este ID, una aplicación de App Engine puede confirmar su identidad a otras aplicaciones de App Engine, API de Google y aplicaciones y servicios de terceros. El ID de aplicación también se puede usar a fin de generar una URL o dirección de correo electrónico, o bien para tomar una decisión en tiempo de ejecución.

Cómo obtener el ID de aplicación

El ID de aplicación se puede encontrar con el método app_identity.get_application_id(). El entorno WSGI o CGI expone algunos detalles de implementación que maneja la API.

Cómo obtener el nombre de host de la aplicación

De forma predeterminada, las apps de App Engine se entregan desde las URL en el formato http://<your_app_id>.appspot.com cuando el ID de aplicación es parte del nombre de host. Si una app se entrega desde un dominio personalizado, es posible que sea necesario recuperar todo el componente del nombre de host. Para ello, puedes usar el método app_identity.get_default_version_hostname().

Cómo confirmar la identidad a otras aplicaciones de App Engine

Si deseas determinar la identidad de la aplicación de App Engine que está realizando una solicitud a tu aplicación, puedes usar el encabezado de solicitud X-Appengine-Inbound-Appid. El servicio URLFetch agrega este encabezado a la solicitud y el usuario no puede modificarlo, por lo que indica de manera segura el ID de aplicación solicitante, si está presente.

Para que este encabezado se agregue a la solicitud, la aplicación que realiza la solicitud debe indicar al servicio URLFetch que no siga los redireccionamientos. Es decir, debe establecer el parámetro fetch follow_redirects en False. Luego, App Engine agregará automáticamente el encabezado a la respuesta HTTP.

En el controlador de la aplicación, puedes verificar el ID entrante si lees el encabezado X-Appengine-Inbound-Appid y lo comparas con una lista de ID permitidos para realizar solicitudes.

El siguiente fragmento de código muestra un controlador que verifica un ID de aplicación entrante contra una lista de ID de aplicaciones permitidos:

import webapp2

class MainPage(webapp2.RequestHandler):
    allowed_app_ids = [
        'other-app-id',
        'other-app-id-2'
    ]

    def get(self):
        incoming_app_id = self.request.headers.get(
            'X-Appengine-Inbound-Appid', None)

        if incoming_app_id not in self.allowed_app_ids:
            self.abort(403)

        self.response.write('This is a protected page.')

app = webapp2.WSGIApplication([
    ('/', MainPage)
], debug=True)

Cómo confirmar la identidad a las API de Google

Las API de Google usan el protocolo OAuth 2.0 para la autenticación y autorización. La API de App Identity puede crear tokens de OAuth que se pueden usar para confirmar que el origen de una solicitud es la misma aplicación. El método get_access_token() muestra un token de acceso para un alcance o una lista de alcances. Este token se puede configurar en los encabezados HTTP de una llamada para identificar la aplicación que realiza la llamada.

En el siguiente ejemplo, se muestra cómo usar la API de App Identity para autenticar en la API de Cloud Storage y recuperar y enumerar todos los depósitos del proyecto.
import json
import logging

from google.appengine.api import app_identity
from google.appengine.api import urlfetch
import webapp2

class MainPage(webapp2.RequestHandler):
    def get(self):
        auth_token, _ = app_identity.get_access_token(
            'https://www.googleapis.com/auth/cloud-platform')
        logging.info(
            'Using token {} to represent identity {}'.format(
                auth_token, app_identity.get_service_account_name()))

        response = urlfetch.fetch(
            'https://www.googleapis.com/storage/v1/b?project={}'.format(
                app_identity.get_application_id()),
            method=urlfetch.GET,
            headers={
                'Authorization': 'Bearer {}'.format(auth_token)
            }
        )

        if response.status_code != 200:
            raise Exception(
                'Call failed. Status code {}. Body {}'.format(
                    response.status_code, response.content))

        result = json.loads(response.content)
        self.response.headers['Content-Type'] = 'application/json'
        self.response.write(json.dumps(result, indent=2))

app = webapp2.WSGIApplication([
    ('/', MainPage)
], debug=True)

Ten en cuenta que la identidad de la aplicación se representa por el nombre de la cuenta de servicio, que suele ser applicationid@appspot.gserviceaccount.com. Puedes obtener el valor exacto con el método get_service_account_name(). Para los servicios que ofrecen LCA, puedes otorgar acceso a la aplicación si otorgas acceso a esta cuenta.

Cómo confirmar la identidad a servicios de terceros

El token que genera get_access_token() solo funciona en los servicios de Google. Sin embargo, puedes usar la tecnología de firma subyacente para confirmar la identidad de tu aplicación a otros servicios. El método sign_blob() firmará bytes a través de una clave privada única para tu aplicación, y el método get_public_certificates() mostrará los certificados que se pueden usar con el fin de validar la firma.

En el siguiente ejemplo, se muestra cómo firmar un BLOB y validar su firma:
import base64

from Crypto.Hash import SHA256
from Crypto.PublicKey import RSA
from Crypto.Signature import PKCS1_v1_5
from Crypto.Util.asn1 import DerSequence
from google.appengine.api import app_identity
import webapp2

def verify_signature(data, signature, x509_certificate):
    """Verifies a signature using the given x.509 public key certificate."""

    # PyCrypto 2.6 doesn't support x.509 certificates directly, so we'll need
    # to extract the public key from it manually.
    # This code is based on https://github.com/google/oauth2client/blob/master
    # /oauth2client/_pycrypto_crypt.py
    pem_lines = x509_certificate.replace(b' ', b'').split()
    cert_der = base64.urlsafe_b64decode(b''.join(pem_lines[1:-1]))
    cert_seq = DerSequence()
    cert_seq.decode(cert_der)
    tbs_seq = DerSequence()
    tbs_seq.decode(cert_seq[0])
    public_key = RSA.importKey(tbs_seq[6])

    signer = PKCS1_v1_5.new(public_key)
    digest = SHA256.new(data)

    return signer.verify(digest, signature)

def verify_signed_by_app(data, signature):
    """Checks the signature and data against all currently valid certificates
    for the application."""
    public_certificates = app_identity.get_public_certificates()

    for cert in public_certificates:
        if verify_signature(data, signature, cert.x509_certificate_pem):
            return True

    return False

class MainPage(webapp2.RequestHandler):
    def get(self):
        message = 'Hello, world!'
        signing_key_name, signature = app_identity.sign_blob(message)
        verified = verify_signed_by_app(message, signature)

        self.response.content_type = 'text/plain'
        self.response.write('Message: {}\n'.format(message))
        self.response.write(
            'Signature: {}\n'.format(base64.b64encode(signature)))
        self.response.write('Verified: {}\n'.format(verified))

app = webapp2.WSGIApplication([
    ('/', MainPage)
], debug=True)

Cómo obtener el nombre predeterminado del depósito de Cloud Storage

Cada aplicación puede tener un depósito de Cloud Storage predeterminado, que incluye 5 GB de almacenamiento gratuito y una cuota gratuita para operaciones de E/S. El almacenamiento máximo de este depósito es de 5 GB, el cual puedes aumentar con habilitar la facturación para tu aplicación. Esto dará como resultado un depósito de pago.

Para obtener el nombre del depósito predeterminado puedes usar la API de App Identity. Llama a google.appengine.api.app_identity.app_identity.get_default_gcs_bucket_name.

¿Te ha resultado útil esta página? Enviar comentarios:

Enviar comentarios sobre...

Entorno estándar de App Engine para Python