Configura el servidor para las notificaciones push

Google Play genera notificaciones en respuesta a eventos que ocurren y pueden afectar a una empresa. Los proveedores de soluciones de EMM pueden recibir estas notificaciones y tomar medidas sobre ellas; por ejemplo, proporcionan alertas o, también, otros mecanismos para sus administradores de clientes.

En esta guía, se explica cómo configurar la infraestructura del servidor necesaria para recibir y procesar solo notificaciones push de EMM. Las notificaciones de extracción no requieren la configuración que se detalla en esta guía.

Además de la configuración del servidor descrita en esta guía, para las notificaciones push debes otorgar los privilegios adecuados y realizar otras tareas de configuración en la Consola de API de Google. Consulta Habilita notificaciones push de EMM para obtener más detalles.

Para obtener más información sobre Google Cloud Pub/Sub, incluidos ejemplos, consulta la documentación de Cloud Pub/Sub.

Puedes configurar el sistema para que las notificaciones push se envíen a un extremo HTTPS especificado o a un servidor que espere a que se envíen las notificaciones.

Acerca de la configuración de extremos de envío

Para configurar un extremo de envío, necesitas un servidor con un certificado SSL válido. En este ejemplo, crearás y subirás un certificado SSL a una autoridad certificadora (CA) y, luego, configurarás el servidor de NGINX. Por último, compilas y ejecutas el código de prueba para confirmar que tu configuración es correcta.

En este ejemplo, se muestra cómo configurar un servidor NGINX en modo proxy inverso para conectarse a la app de suscriptor (en PushSubscriber.java) que se ejecuta en el puerto 8093 mediante Ubuntu 14.04. Es posible que tu empresa use un servidor diferente, pero la configuración de muestra debería funcionar, sin cambios, en todas las distribuciones basadas en Debian. Otras distribuciones (como las basadas en Red Hat) son similares, pero la ubicación de los archivos de configuración puede ser diferente.

Antes de poder recibir notificaciones, debes configurar un extremo que cumpla con los siguientes criterios:

  • Debes ser propietario del dominio y verificar la propiedad en la Consola de API de Google.

  • Debes poder ejecutar un servicio en el puerto 443 (SSL).

  • Debes tener un certificado SSL firmado por una CA. Los certificados autofirmados no funcionan.

  • El servidor web que ejecutas debe admitir webhooks.

No es necesario que el extremo se ejecute en Google App Engine (aunque puede hacerlo).

Crea y sube un certificado SSL

1. Genera un certificado de capa de conexión segura (SSL):

    myusername@myhost:/tmp$ sudo openssl req -x509 -nodes -days 365 \
      -newkey rsa:2048 -keyout cert.key -out cert.crt

Esto genera la siguiente respuesta. Reemplaza los valores de muestra (como push.solarmora.com y myusername@myhost) por el nombre real del servidor, la empresa, la dirección, etc., en el siguiente código. Puedes usar cualquier subdominio, siempre y cuando el registro A de este subdominio apunte a tu servidor.

    Generating a 2048 bit RSA private key
    ...........................................................................
    .....+++
    writing new private key to 'cert.key'
    -----
    You are about to be asked to enter information that will be incorporated
    into your certificate request.
    What you are about to enter is what is called a Distinguished Name or a DN.
    There are quite a few fields but you can leave some blank
    For some fields there will be a default value,
    If you enter '.', the field will be left blank.
    -----
    Country Name (2 letter code) [AU]:GB
    State or Province Name (full name) [Some-State]:England
    Locality Name (eg, city) []:London
    Organization Name (eg, company) [Internet Widgits Pty Ltd]:Solarmora, Inc.
    Organizational Unit Name (eg, section) []:Creative Publications
    Common Name (e.g. server FQDN or YOUR name) []:push.solarmora.com
    Email Address []:admin@solarmora.com

2. Verifica que se haya creado un archivo de certificado:

$ myusername@myhost:/tmp$ ls cert*
cert.crt  cert.key

3. Para obtener este certificado firmado, produce una solicitud de firma de certificado (CSR) para subir a tu firmante:

myusername@myhost:/tmp$ sudo openssl x509 -x509toreq -in cert.crt \
  -out cert.csr -signkey cert.key
Getting request Private Key
Generating certificate request
myusername@myhost:/tmp$ ls cert.*
cert.crt  cert.csr  cert.key

4. Asegúrate de que el contenido del archivo CSR tenga el siguiente aspecto:

    Certificate Request:
    Data:
        Version: 0 (0x0)
        Subject: C=GB, ST=England, L=London, O=Solarmora, Inc.,
        OU=Creative Publications,
        CN=push.solarmora.com/emailAddress=admin@solarmora.com
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                Public-Key: (2048 bit)
                Modulus:
                    00:cc:0f:54:26:3d:d9:17:eb:8f:6c:f7:27:5e:77:
                    64:65:00:db:fe:2a:1f:fa:ea:de:21:7a:c5:5d:87:
                    ...
                    ...
                Exponent: 65537 (0x10001)
        Attributes:
            a0:00
    Signature Algorithm: sha256WithRSAEncryption
         1d:ea:12:b8:c2:6a:d6:f4:6e:92:2f:b9:12:5e:e3:91:15:a0:
         06:b5:81:ce:c5:cf:b7:d2:a7:dd:f2:78:ca:28:8e:21:cd:6d:
         ...
         ...
    -----BEGIN CERTIFICATE REQUEST-----
    MIIC6zCCAdMCAQAwgaUxCzAJBgNVBAYTAkdCMRAwDgYDVQQIDAdFbmdsYW5kMQ8w
    DQYDVQQHDAZMb25kb24xGDAWBgNVBAoMD0FDTUUgQ29ycCwgSW5jLjEYMBYGA1UE
    CwwPQ3JlYXRpdmUgQW52aWxzMRswGQYDVQQDDBJwdXNoLmFjbWUtY29ycC5jb20x
    IjAgBgkqhkiG9w0BCQEWE2FkbWluQGFjbWUtY29ycC5jb20wggEiMA0GCSqGSIb3
    ...
    ...
    -----END CERTIFICATE REQUEST-----

5. Sube la parte del certificado entre las líneas BEGIN y END (inclusive) a tu CA. El proceso exacto dependerá de tu AC, pero incluirá los siguientes pasos:

  1. Sube el archivo CSR a tu sitio de CA o pega el contenido del archivo en el sitio de CA. Luego, la AC valida y procesa estos datos.
  2. Descarga el certificado firmado que generó tu AC.

6. El resultado de la AC debe contener varios archivos: el certificado firmado y el certificado de la AC que confirma que son aptos para firmar certificados. Concatena todos los archivos de certificados *.crt en el paquete descargado en un solo archivo de paquete, por ejemplo, bundle.push.solarmora.com.crt:

$ cat *.crt > bundle.push.solarmora.com.crt

Configura tu servidor proxy

En esta sección, configurarás el servidor web de código abierto de NGINX y el servidor proxy inverso para entregar al extremo y reenviar todas las solicitudes entrantes al servidor suscriptor. NGINX se usa como ejemplo, pero puedes usar cualquier otro proxy HTTP en su lugar.

1. Instala NGINX en tu servidor:

    $ sudo apt-get update
    $ sudo apt-get install nginx
    $ nginx -v
    $ nginx version: nginx/1.4.6 (Ubuntu)

2. Para asegurarte de que NGINX procese los archivos de configuración adicionales del servidor que creas en el directorio sites-enabled, edita /etc/nginx/nginx.conf y, luego, incluye lo siguiente:

    $ include /etc/nginx/conf.d/*.conf;
    $ include /etc/nginx/sites-enabled/*;

3. Copia los archivos de certificado en una ubicación segura que el usuario www-data pueda leer, pero preferentemente que no lo pueda leer ningún otro usuario (es posible que debas ajustar el nombre de usuario si tu servidor web se ejecuta como un usuario diferente):

    $ sudo mkdir -p /var/openssl/push.solarmora.com
    $ sudo mv /tmp/cert.key 
/var/openssl/push.solarmora.com/push.solarmora.com.key $ sudo mv /tmp/bundle.push.solarmora.com.crt
/var/openssl/push.solarmora.com/bundle.push.solarmora.com.crt

4. Crea una nueva configuración de server. Edita push.solarmora.com en /etc/nginx/sites-enabled y usa el nombre de dominio completamente calificado de tu servidor real como nombre de archivo:

server {
   listen 443;
   server_name push.solarmora.com;

   ssl on;
   ssl_certificate
     /var/openssl/push.solarmora.com/bundle.push.solarmora.com.crt;
   ssl_certificate_key
     /var/openssl/push.solarmora.com/push.solarmora.com.key;

   # it is usually very convenient to have separate files for your
   # access and error log to analyze for possible problems
   access_log /var/log/nginx/nginx.push.solarmora.com.log;
   error_log /var/log/nginx/nginx.push.solarmora.com.log;

   location / {
            # assuming the subscriber will run on the same machine
            # on port 8093
            proxy_pass http://localhost:8093;
   }
}

5. Reinicia NGINX para implementar los cambios:

    myusername@myhost:/etc/nginx$ sudo service nginx restart
    * Restarting nginx nginx
    ...done.

6. Tu servidor ya está configurado. Para verificar la configuración, intenta consultar tu servidor mediante curl:

    [myusername@myhost:~]$ curl push.solarmora.com
    <html>
    <head><title>502 Bad Gateway</title></head>
    <body bgcolor="white">
    <center><h1>502 Bad Gateway</h1></center>
    <hr><center>nginx/1.4.6 (Ubuntu)</center>
    </body>
    </html>

Esta es la respuesta esperada, ya que no se configuró ningún servidor descendente (localhost:8093 en nuestro archivo de configuración).

Ejemplos de compilación y ejecución

Para ejecutar los ejemplos de esta sección, necesitas un proyecto activo de la Consola de API de Google. Te recomendamos que crees una específicamente para realizar pruebas y la mantengas separado de tu proyecto de producción. Después de crear un proyecto de prueba, debes crear una cuenta de servicio. Toma nota de la dirección de correo electrónico de la cuenta de servicio y coloca el archivo .p12 asociado en alguna parte de tu servidor.

Cómo configurar el árbol del código fuente

1. Clona el repositorio play-work.git:

    myusername@myhost:~/code$ git clone
    https://github.com/google/play-work.git
    Cloning into 'play-work'...
    Username for 'https://github.com': username
    Password for 'https://username@github.com':
    remote: Counting objects: 110, done.
    remote: Compressing objects: 100% (60/60), done.
    remote: Total 110 (delta 24), reused 95 (delta 9), pack-reused 0
    Receiving objects: 100% (110/110), 23.88 KiB | 0 bytes/s, done.
    Resolving deltas: 100% (24/24), done.
    Checking connectivity... done.
2. En los sistemas basados en Debian, instala Maven y el compilador de búferes de protocolo de Google:
    $ sudo apt-get install maven protobuf-compiler

3. Verifica que Maven y el compilador de búferes de protocolo de Google estén instalados correctamente:

    myusername@myhost:~$ mvn -v
    Apache Maven 3.0.5
    Maven home: /usr/share/maven
    Java version: 1.7.0_75, vendor: Oracle Corporation
    Java home: /usr/lib/jvm/java-7-openjdk-amd64/jre
    Default locale: en_US, platform encoding: UTF-8
    OS name: "linux", version: "3.16.0-30-generic", arch: "amd64", family: "unix"
    myusername@myhost:~$ protoc --version
    libprotoc 2.5.0

4. En el archivo de configuración de Maven pom.xml, se supone que el compilador de búferes de protocolo está instalado en el directorio /usr/bin/protoc:

    myusername@myhost:~$ which protoc
    /usr/bin/protoc
Si este no es el caso, puedes modificar pom.xml o symlink protoc:
    $ sudo ln -s which protoc /usr/bin/protoc
5. Compila los ejemplos. Ejecuta mvn clean compile assembly:single para verificar que puedes compilar el código. Esto debería producir un archivo llamado emm-notifications-[version-number]-jar-with-dependencies.jar, en el que [version number] es la versión actual del ejemplo, por ejemplo, 1.0-SNAPSHOT:
    myusername@myhost:~/code/play-work/examples/emm-notifications$ ls target/*
    target/emm-notifications-1.0-SNAPSHOT-jar-with-dependencies.jar
.6. Verifica que puedas ejecutar el código TestPublisher compilado. Se espera que el código falle:

    myusername@myhost:~/code/play-work/examples/emm-notifications$ java -cp \
      target/emm-notifications-1.0-SNAPSHOT-jar-with-dependencies.jar \
      com.google.android.work.emmnotifications.TestPublisher
    Exception in thread "main" java.lang.IllegalArgumentException:
    You must specify non-default ServiceAccountEmail in
    settings.properties
        at com.google.api.client.repackaged.com.google.common.base.Preconditions.checkArgument(Preconditions.java:119)
        at com.google.api.client.util.Preconditions.checkArgument(Preconditions.java:69)
        at com.google.android.work.emmnotifications.Settings.verifyVariable(Settings.java:129)
        at com.google.android.work.emmnotifications.Settings.getSettings(Settings.java:103)
        at com.google.android.work.emmnotifications.TestPublisher.main(TestPublisher.java:39)

7. Debes anular algunos valores en el archivo settings.properties. Para ello, crea una copia del archivo y modifica las propiedades en ella de la siguiente manera:

    # This should be your own service account's email address
    ServiceAccountEmail=368628613713-t4hfexampledn5lhpdcu1qqfgio01626@developer.gserviceaccount.com
    ServiceAccountP12KeyFile=/opt/secret/secret.p12
    # This will be the name of the service account
    ProjectName=enterprise-cloud-pub-sub
    SubscriptionName=projects/enterprise-cloud-pub-sub/subscriptions/default
    TopicName=projects/enterprise-cloud-pub-sub/topics/default
    # The push endpoint in your API Console project
    PushEndpoint=https://push.solarmora.com

8. Vuelve a ejecutar el código TestPublisher para asegurarte de que ya no falle. (es posible que veas un solo error en el resultado del registro).

Ejecuta el código de prueba del publicador

Debes ejecutar el código de muestra para publicar notificaciones de modo que tu suscriptor tenga algunos mensajes que leer.

En el siguiente ejemplo, el código busca el tema especificado en my_settings.properties, pero no lo encuentra y, por lo tanto, crea el tema. Luego, publica un mensaje en el tema. En este ejemplo, se proporciona una herramienta de pruebas valiosa que te permite emular los mensajes que envía la API de EMM de Google Play.

    myusername@myhost:~/code/play-work/examples/emm-notifications$ DEVELOPER_CONSOLE_SETTINGS=./my_settings.properties java -cp \
      target/emm-notifications-1.0-SNAPSHOT-jar-with-dependencies.jar com.google.android.work.emmnotifications.TestPublisher
    Feb 27, 2015 1:39:59 PM com.google.android.work.emmnotifications.RetryHttpInitializerWrapper$1 handleResponse
    INFO: RetryHandler: {
      "error": {
        "code": 404,
        "message": "Resource not found (resource=default).",
        "errors": [
          {
            "message": "Resource not found (resource=default).",
            "domain": "global",
            "reason": "notFound"
          }
        ],
        "status": "NOT_FOUND"
      }
    }

    Feb 27, 2015 1:39:59 PM com.google.android.work.emmnotifications.TestPublisher main
    INFO: Topic projects/enterprise-cloud-pub-sub/topics/default doesn't exists, creating it
    Feb 27, 2015 1:40:02 PM com.google.android.work.emmnotifications.TestPublisher main
    INFO: Topic projects/enterprise-cloud-pub-sub/topics/default created
    Feb 27, 2015 1:40:02 PM com.google.android.work.emmnotifications.TestPublisher main
    INFO: Publishing a request: {messages=[{data=CjEKFQoIMTIzMjEzMjESCXJpZ2h0IG5vdxIWY29tLmdvb2dsZS5hbmRyb2lkLmdtcxgA}]}

Ejecuta el código de prueba del suscriptor

El código de prueba del suscriptor confirma que puedes recibir los mensajes publicados por el código TestPublisher.

1. Asegúrate de que tu código esté actualizado y compilado. Luego, ejecuta el código de prueba del suscriptor:

    myusername@myhost:~/code/play-work/examples/emm-notifications$ DEVELOPER_CONSOLE_SETTINGS=./my_settings.properties 
java -cp target/emm-notifications-1.0-SNAPSHOT-jar-with-dependencies.jar
com.google.android.work.emmnotifications.PushSubscriber Feb 27, 2015 1:46:37 PM com.google.android.work.emmnotifications.PushSubscriber main INFO: Will be using topic name: projects/enterprise-cloud-pub-sub/topics/default, subscription name:
projects/enterprise-cloud-pub-sub/subscriptions/default Feb 27, 2015 1:46:38 PM com.google.android.work.emmnotifications.PushSubscriber main INFO: Trying to get subscription named projects/enterprise-cloud-pub-sub/subscriptions/default Feb 27, 2015 1:46:38 PM com.google.android.work.emmnotifications.RetryHttpInitializerWrapper$1 handleResponse INFO: RetryHandler: { "error": { "code": 404, "message": "Resource not found (resource=default).", "errors": [ { "message": "Resource not found (resource=default).", "domain": "global", "reason": "notFound" } ], "status": "NOT_FOUND" } } Feb 27, 2015 1:46:38 PM com.google.android.work.emmnotifications.PushSubscriber main INFO: Subscription doesn't exist, will try to create projects/enterprise-cloud-pub-sub/subscriptions/default Feb 27, 2015 1:46:43 PM com.google.android.work.emmnotifications.PushSubscriber main INFO: Created: { "ackDeadlineSeconds" : 600, "name" : "projects/enterprise-cloud-pub-sub/subscriptions/default", "pushConfig" : { "pushEndpoint" : "https://push.solarmora.com" }, "topic" : "projects/enterprise-cloud-pub-sub/topics/default" }
El suscriptor ya se está ejecutando y está listo para aceptar mensajes entrantes.

2. Vuelve a ejecutar el publicador y se agregarán los mensajes nuevos al registro:

    Feb 27, 2015 1:47:24 PM com.google.android.work.emmnotifications.PushSubscriber$1 handle
    INFO: Raw request: {"message":{"data":"CjEKFQoIMTIzMjEzMjESCXJpZ2h0IG5vdxIWY29tLmdvb2dsZS5hbmRyb2lkLmdtcxgA",
"attributes":{},"message_id":"71571141246"},"subscription":"/subscriptions/enterprise-cloud-pub-sub/default"} Feb 27, 2015 1:47:24 PM com.google.android.work.emmnotifications.PushSubscriber$1 handle INFO: Pubsub message received: { "attributes" : { }, "data" : "CjEKFQoIMTIzMjEzMjESCXJpZ2h0IG5vdxIWY29tLmdvb2dsZS5hbmRyb2lkLmdtcxgA", "message_id" : "71571141246" } Feb 27, 2015 1:47:24 PM com.google.android.work.emmnotifications.PushSubscriber$1 handle INFO: Message received: product_approval_event { common_event_information { enterprise_id: "12321321" event_notification_sent_timestamp: "right now" } product_id: "com.google.android.gms" approved: false }
Se recibió y procesó un mensaje de forma correcta.