Como usar tmp com a biblioteca de cliente .NET

Jeff Fisher, equipe de APIs de dados do Google
agosto de 2007

Introdução: por que o tmp é importante?

O melhor das APIs de dados do Google ("GData", na sigla em inglês) é como elas permitem que os desenvolvedores criem aplicativos que interajam com os Serviços do Google. Mais especificamente, eles permitem acessar dados particulares do usuário para uso no aplicativo. Com as APIs, é possível criar aplicativos para sincronizar, importar, exportar e gerenciar esses dados. Embora as APIs concedam esses recursos avançados, você precisa se lembrar de usá-las com responsabilidade. Como os dados do usuário são informações particulares, é natural que você queira acessá-los de maneira segura. Uma parte fundamental disso é poder autenticar nos servidores do Google de maneira segura.

Digamos que você tenha um novo aplicativo da Web que precisa estar vinculado aos dados armazenados nos serviços da Web do Google. Agora você quer fazer a autenticação para acessar esses dados particulares. Por que não usar algo simples, como ClientLogin? Isso dá certo, mas você ainda está processando mais dados particulares: as credenciais de login do usuário. O ClientLogin exige que seu aplicativo solicite o nome de usuário e a senha do Google. Isso não é um problema em aplicativos para computadores executados na máquina pessoal do usuário, mas é ideal para aplicativos baseados na Web. Além da responsabilidade de lidar com essas credenciais no seu próprio servidor, talvez alguns dos seus usuários mais cautelosos tenham medo de armazenar essas informações. Outra preocupação comum dos usuários é quando eles querem conceder a um programa acesso apenas a um serviço específico (como os eventos no Google Agenda), mas não a outro serviço (como o Google Docs). O jpeg resolve esses dois problemas, permitindo que um usuário faça a autenticação por meio dos servidores do Google, permitindo que seu programa solicite apenas o acesso necessário.

Agora que você leu sobre a teoria por trás de XPN, é hora de aprender a programar. Para este artigo, optei por simplificar e fazer tudo dentro de uma única página ASP, mas você deve conseguir integrar facilmente as técnicas demonstradas aqui no seu próprio aplicativo.

Como processar a autenticação

Então o que é realmente necessário para usar o XPN em seu aplicativo da Web? Primeiro, há algumas importações padrão da biblioteca de cliente do GData:

<%@ Import Namespace="Google.GData.Client" %>
<%@ Import Namespace="Google.GData.Extensions" %>
<%@ Import Namespace="System.Net" %>

A primeira coisa que você precisa fazer é enviar o usuário para um URL especialmente criado. Isso é o que permite que os servidores do Google lidem com a autenticação e redirecionem o usuário de volta ao seu site. Felizmente, você não precisa gerar esse URL manualmente, já que existem métodos para fazer isso. Vejamos um exemplo:

authSubUrl = AuthSubUtil.getRequestUrl(target, scope, secure, session);
  • target: é uma string que contém o URL do seu aplicativo da Web. Este é o endereço para onde o usuário será redirecionado após a autenticação.
  • scope Essa string é determinada pela API que você está usando. Ele corresponde a um dos feeds em uma API GData. Por exemplo, o feed que contém todas as informações da agenda de um usuário é "http://www.google.com/calendar/feeds/default/private/full".
  • secure: esse é um booleano que informa ao servidor que você se registrou no Google e vai assinar criptograficamente as solicitações para o servidor. Esse argumento geralmente é falso por padrão, principalmente ao trabalhar em um ambiente de teste.
  • session Este é outro booleano que indica que você quer um "token de sessão" em vez de um "token de uso único". O papel desse argumento vai ficar mais claro em breve.

Depois de clicar no URL gerado, o usuário será direcionado para uma página de Contas do Google que permite fazer login. Em seguida, ele é redirecionado de volta à página da Web especificada na variável "target", mas com um parâmetro de consulta "token", que contém um token de uso único. Normalmente, esse token pode ser usado exatamente uma vez. Ou seja, ela pode ser usada para realizar uma ação em um determinado feed. No entanto, se você especificar o parâmetro "session" como true, ele poderá ser trocado por um "token de sessão" que poderá ser reutilizado até que o usuário encerre a sessão. Você pode fazer isso da seguinte maneira:

String token = Request.QueryString["token"];
Session["token"] = AuthSubUtil.exchangeForSessionToken(token, null).ToString();

Aqui, você extrai o token do parâmetro de consulta e o troca por um "token de sessão". Dessa forma, para que ela possa ser salva para uso posterior, é possível armazená-lo na matriz Session automática do .NET. Também é possível armazenar o token em um banco de dados. A próxima etapa é usar esse token para fazer uma solicitação autenticada:

GAuthSubRequestFactory authFactory = new GAuthSubRequestFactory("cl", "My-Cool-Application");
authFactory.Token = (String) Session["token"];
CalendarService service = new CalendarService(authFactory.ApplicationName);
service.RequestFactory = authFactory;

Aqui você configura um objeto CalendarService para interagir com a API Google Calendar usando o XPN para autenticação. O "cl" usado no construtor para GAuthSubRequestFactory é o nome do serviço do Agenda. Você pode consultar as perguntas frequentes sobre as APIs de dados do Google para ver outros nomes de serviço.

Seguro (registrado) seguro

Se você optar por registrar seu aplicativo da Web, poderá ativar um nível adicional de segurança enquanto estiver usando o tmp. Isso permite que você assine digitalmente todas as solicitações feitas pelo seu código. Assim, alguém não pode usar tokens de PersistentVolume emitidos para você, a menos que tenha sua chave privada. O primeiro passo é verificar se você está gerando o link IFRAME correto ao chamar AuthSubUtil.getRequestUrl, definindo o argumento "secure" como true. Há duas outras alterações de código que você precisará fazer:

String token = Request.QueryString["token"];
Session["token"] = AuthSubUtil.exchangeForSessionToken(token, rsaKey).ToString();

...

authFactory.PrivateKey = rsaKey;

Primeiro, em vez de null, transmita a variável "rsaKey" para o método exchangeForSessionToken. Essa mesma variável também é usada para definir uma propriedade do GAuthSubRequestFactory ao configurar a conexão com o serviço. A variável "rsaKey" é uma RSACryptoServiceProvider correspondente ao componente de chave privada do certificado x509 que você registrou no Google.

Gerar uma chave privada RSA e um certificado autoassinado pode ser um pouco confuso, especialmente porque o framework .NET não entende chaves ou certificados armazenados no formato PEM. Os comandos a seguir mostram como gerar uma chave privada e um certificado público usando o pacote de ferramentas do OpenSSL:

openssl req -x509 -nodes -days 365 -newkey rsa:1024 -sha1 -subj \
  '/C=US/ST=CA/L=Mountain View/CN=www.example.com' -keyout \
  test_key.pem -out test_cert.pem

openssl pkcs12 -export -in test_cert.pem -inkey test_key.pem \
  -out test_cert.pfx -name "Testing Certificate"

A primeira etapa gera uma chave privada e um certificado X509 público no formato PEM chamados "test_key.pem" e "test_cert.pem", respectivamente. O certificado está definido para ser registrado como "www.example.com" com base em Mountain View, CA, EUA. Substitua os valores adequados para sua empresa aqui. O arquivo "test_cert.pem" contém as informações necessárias para o envio na página de registro do ISBN.

A segunda etapa gera um arquivo PFX com base na chave privada e no certificado. Esse arquivo pode ser importado para a biblioteca de cliente .NET para assinar digitalmente solicitações feitas às APIs GData. O código a seguir mostra como importar a chave privada do arquivo PFX para um aplicativo da Web:

protected AsymmetricAlgorithm getRsaKey()
{

  X509Certificate2 cert = new X509Certificate2("C:/MyAspSite/test_cert.pfx","");
  RSACryptoServiceProvider privateKey = cert.PrivateKey as RSACryptoServiceProvider;

  return privateKey;
}

A função getRsaKey() definida por este snippet pode ser usada no lugar da variável "rsaKey" mostrada acima quando usada para autenticar as APIs. Naturalmente, o caminho do arquivo precisa ser substituído pelo local apropriado do arquivo PFX que você gerou.

Listagem de códigos completa

A maneira mais fácil de mostrar como usar os métodos demonstrados na seção anterior é com um exemplo ativo. A amostra de código a seguir é uma página ASP simples que usa o tmpt para autenticar o usuário e imprimir os eventos do Google Agenda.

<%@ Page Language="C#" AutoEventWireup="true"  CodeFile="Default.aspx.cs" Inherits="_Default" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<%@ Import Namespace="Google.GData.Client" %>
<%@ Import Namespace="Google.GData.Extensions" %>
<%@ Import Namespace="Google.GData.Calendar" %>
<%@ Import Namespace="System.Net" %>

<script runat="server">
    void PrintCalendar() {

        GAuthSubRequestFactory authFactory = new GAuthSubRequestFactory("cl", "TesterApp");
        authFactory.Token = (String) Session["token"];
        CalendarService service = new CalendarService(authFactory.ApplicationName);
        service.RequestFactory = authFactory;

        EventQuery query = new EventQuery();

        query.Uri = new Uri("http://www.google.com/calendar/feeds/default/private/full");

        try
        {
            EventFeed calFeed = service.Query(query);
            foreach (Google.GData.Calendar.EventEntry entry in calFeed.Entries)
            {
                Response.Write("Event: " + entry.Title.Text + "<br/>");
            }
        }
        catch (GDataRequestException gdre)
        {
            HttpWebResponse response = (HttpWebResponse)gdre.Response;
            
            //bad auth token, clear session and refresh the page
            if (response.StatusCode == HttpStatusCode.Unauthorized)
            {
                Session.Clear();
                Response.Redirect(Request.Url.AbsolutePath, true);
            }
            else
            {
                Response.Write("Error processing request: " + gdre.ToString());
            }
        }
    }

</script>


<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
    <title>Test Site</title>
</head>
<body>

    <form id="form1" runat="server">
    <h1>AuthSub Sample Page</h1>
    <div>
    <%
        GotoAuthSubLink.Visible = false;
        
        if (Session["token"] != null)
        {
            PrintCalendar();
        }
        else if (Request.QueryString["token"] != null)
        {
            String token = Request.QueryString["token"];
            Session["token"] = AuthSubUtil.exchangeForSessionToken(token, null).ToString();
            Response.Redirect(Request.Url.AbsolutePath, true);
        }
        else //no auth data, print link
        {
            GotoAuthSubLink.Text = "Login to your Google Account";
            GotoAuthSubLink.Visible = true;
            GotoAuthSubLink.NavigateUrl = AuthSubUtil.getRequestUrl(Request.Url.ToString(),
                "http://www.google.com/calendar/feeds/",false,true);
        }
        
     %>
    <asp:HyperLink ID="GotoAuthSubLink" runat="server"/>

    </div>
    </form>
</body>
</html>

Conclusão

O tmp permite que seu aplicativo da Web acesse dados armazenados na Conta do Google de um usuário de maneira segura e controlada. Usar a biblioteca de cliente .NET facilita a integração do seu site baseado em ASP aos serviços do Google. Este artigo tem o objetivo de ajudar você a começar, mas recomendamos consultar outros recursos: