Configurar o servidor para notificações push

O Google Play gera notificações em resposta a eventos que ocorrem e podem afetar uma empresa. Os provedores de soluções de EMM podem receber essas notificações e agir de acordo com elas, fornecendo alertas ou outros mecanismos para os administradores do cliente, por exemplo.

Neste guia, você verá como configurar a infraestrutura do servidor necessária para receber e processar apenas notificações push de EMM. As notificações pull não exigem a configuração detalhada neste guia.

Além da configuração do servidor descrita neste guia, para notificações push você também precisa conceder os privilégios apropriados e executar outras tarefas de configuração no Console de APIs do Google. Consulte Ativar notificações push de EMM para mais detalhes.

Para mais informações sobre o Google Cloud Pub/Sub, incluindo exemplos, consulte a documentação do Cloud Pub/Sub.

É possível configurar seu sistema para que as notificações push sejam enviadas a um endpoint HTTPS especificado ou a um servidor que aguarde o envio das notificações.

Sobre a configuração de endpoints de push

Para configurar um endpoint de push, é preciso um servidor com um certificado SSL válido. Neste exemplo, você cria e faz upload de um certificado SSL para uma autoridade de certificação (CA, na sigla em inglês) e, em seguida, configura o servidor NGINX. Por fim, compile e execute o código de teste para confirmar se a configuração está correta.

Neste exemplo, mostramos como configurar um servidor NGINX no modo de proxy reverso para se conectar ao app do assinante (em PushSubscriber.java) em execução na porta 8093 usando o Ubuntu 14.04. Sua empresa pode usar um servidor diferente, mas a configuração de amostra funcionará, sem alterações, em todas as distribuições baseadas no Debian. Outras distribuições (como as baseadas no RedHat) são semelhantes, mas o local dos arquivos de configuração pode ser diferente.

Antes de receber notificações, configure um endpoint que atenda aos seguintes critérios:

  • Você precisa ser o proprietário do domínio e confirmar a propriedade no Console de APIs do Google.

  • É preciso ser capaz de executar um serviço na porta 443 (SSL).

  • Você precisa ter um certificado SSL assinado pela CA. Os certificados autoassinados não funcionam.

  • O servidor da Web que você está executando precisa ser compatível com webhooks.

Seu endpoint não precisa ser executado no Google App Engine (embora seja possível).

Criar e fazer upload de um certificado SSL

1. Produza um certificado Secure Sockets Layer (SSL):

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

Isso gera a seguinte resposta. Substitua os valores de amostra (como push.solarmora.com e myusername@myhost) pelo nome real do servidor, empresa, endereço e assim por diante no código a seguir. É possível usar qualquer subdomínio, desde que o registro A desse subdomínio aponte para seu 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. Verifique se um arquivo de certificado foi criado:

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

3. Para receber esse certificado assinado, produza uma solicitação de assinatura de certificado (CSR, na sigla em inglês) para fazer upload desse certificado ao signatário:

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. Certifique-se de que o conteúdo do arquivo CSR seja parecido com este:

    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. Faça o upload da parte do certificado entre as linhas BEGIN e END (inclusivas) para sua CA. O processo exato dependerá da sua CA, mas incluirá as seguintes etapas:

  1. Faça upload do arquivo de CSR no site da AC ou cole o conteúdo do arquivo no site da AC. Em seguida, a AC valida e processa esses dados.
  2. Faça o download do certificado assinado gerado pela CA.

6. A saída da CA precisa conter vários arquivos: o próprio certificado assinado e o certificado da CA confirmando que eles estão qualificados para assinar certificados. Concatene todos os arquivos de certificado *.crt no pacote salvo em um único arquivo, por exemplo, bundle.push.solarmora.com.crt:

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

Configurar seu servidor proxy

Nesta seção, você configurará o servidor da Web de código aberto NGINX e o servidor proxy reverso para exibir o endpoint e encaminhar todas as solicitações recebidas para o servidor assinante. O NGINX é usado como exemplo, mas é possível utilizar qualquer outro proxy HTTP.

1. Instale o NGINX no seu servidor:

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

2. Para garantir que os arquivos extras de configuração do servidor criados no diretório sites-enabled sejam processados pelo NGINX, edite /etc/nginx/nginx.conf e inclua o seguinte:

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

3. Copie os arquivos de certificado para um local seguro que possa ser lido pelo usuário www-data, mas preferencialmente não por outros usuários. Talvez seja necessário ajustar o nome do usuário se o servidor da Web estiver sendo executado como um usuário 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. Crie uma nova configuração server. Edite push.solarmora.com em /etc/nginx/sites-enabled e use o nome de domínio totalmente qualificado do seu servidor real como o nome do arquivo:

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. Reinicie o NGINX para implementar as alterações:

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

6. O servidor foi configurado. Para verificar a configuração, tente consultar seu servidor usando 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>

Essa é a resposta esperada, já que nenhum servidor downstream foi configurado (localhost:8093 no arquivo de configuração).

Compilar e executar exemplos

Para executar os exemplos nesta seção, você precisa de um projeto ativo do Console de APIs do Google. Recomendamos que você crie um especificamente para fins de teste e o mantenha separado do seu projeto de produção. Depois de criar um projeto de teste, você precisa criar uma conta de serviço. Anote o endereço de e-mail da conta de serviço e coloque o arquivo .p12 associado em algum lugar no seu servidor.

Configurar a árvore de código-fonte

1. Clone o repositório 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. Em sistemas baseados em Debian, instale o Maven e o compilador de buffers de protocolo do Google:
    $ sudo apt-get install maven protobuf-compiler

3. Verifique se o Maven e o compilador do Google Protocol Buffers estão instalados corretamente:

    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. O arquivo de configuração do Maven pom.xml pressupõe que o compilador de buffers de protocolo esteja instalado no diretório /usr/bin/protoc:

    myusername@myhost:~$ which protoc
    /usr/bin/protoc
Se esse não for o caso, modifique pom.xml ou o link simbólico protoc:
    $ sudo ln -s which protoc /usr/bin/protoc
5. Compile os exemplos. Verifique se é possível criar o código executando mvn clean compile assembly:single. Isso produz um arquivo chamado emm-notifications-[version-number]-jar-with-dependencies.jar, em que [version number] é a versão atual do exemplo, por exemplo, 1.0-SNAPSHOT:
    myusername@myhost:~/code/play-work/examples/emm-notifications$ ls target/*
    target/emm-notifications-1.0-SNAPSHOT-jar-with-dependencies.jar
6. Verifique se é possível executar o código TestPublisher compilado. Espera-se que o código falhe:

    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. É preciso substituir alguns valores no arquivo settings.properties. Para fazer isso, crie uma cópia do arquivo e modifique as propriedades na cópia da seguinte maneira:

    # 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. Execute o código TestPublisher novamente para garantir que ele não falhe mais. Talvez você veja um único erro na saída do registro.

Executar o código de teste do editor

Execute o exemplo de código para publicar notificações para que seu assinante tenha algumas mensagens para ler.

No exemplo abaixo, o código procura o tema especificado em my_settings.properties, mas não o encontra e, portanto, cria o tópico. Em seguida, publica uma mensagem no tópico. Este exemplo fornece uma ferramenta de teste valiosa que permite emular mensagens enviadas pela API Google Play EMM.

    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}]}

Executar o código de teste do assinante

O código de teste do assinante confirma que você pode receber as mensagens publicadas pelo código TestPublisher.

1. Verifique se o código está atualizado e compilado. Em seguida, execute o código de teste do assinante:

    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" }
O assinante está em execução e pronto para aceitar mensagens recebidas.

2. Execute o editor novamente, e novas mensagens serão adicionadas ao 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 }
Uma mensagem foi recebida e processada corretamente.