Nesta postagem, vou escrever sobre um novo recurso importante no Couchbase Mobile versão 1.3, Conexão OpenID (OIDC).

Introdução
O Couchbase Mobile tem vários recursos de segurança importantes. O Sync Gateway atua como o intermediário que permite que o Couchbase Lite replique os dados para o Couchbase Server. Naturalmente, muitos aplicativos desejam autenticar os usuários e controlar o que eles podem fazer por meio do Sync Gateway. O OpenID Connect oferece uma opção que, ao mesmo tempo, simplifica a adição de autenticação, oferece aos desenvolvedores um grande avanço nas opções de integração e elimina a dor de cabeça de suportar a infraestrutura necessária.
O objetivo
Deixe-me esclarecer um pouco. Em um cenário típico, um aplicativo usa o Couchbase Lite como seu principal armazenamento de dados. As informações são lidas e gravadas no banco de dados local. O aplicativo configura a replicação para um servidor de back-end por meio de uma instância do Sync Gateway em execução na nuvem.
Muitas vezes, como desenvolvedor de aplicativos, você deseja vincular os dados a uma identidade exclusiva e verificável. Os detalhes da identidade não são realmente importantes. O gerenciamento da infraestrutura torna-se uma sobrecarga desnecessária. O OpenID Connect oferece a maneira de transferir isso para outras fontes confiáveis.
Vamos explicar todos os atores. Temos o usuário, o aplicativo, o Couchbase Lite (integrado ao aplicativo), nossa instância do Sync Gateway e o provedor OpendID (OP).
O Sync Gateway controla a autorização de quaisquer alterações durante a replicação. O objetivo, portanto, é fazer com que o usuário faça login no aplicativo, autenticando-se no OP. O OP fornece informações que o aplicativo pode usar para fornecer ao Sync Gateway uma prova da identidade do usuário. Vamos examinar todas as etapas para isso.
OpendID Connect
Já existem muitos serviços que exigem que os usuários criem uma conta e assim por diante. Os Fundação OpenID formada para criar padrões para abrir as partes de autenticação desses sistemas para uso externo. Esse esforço produziu a especificação OpenID Connect. Nas palavras da OpenID Foundation:
Conexão OpenID é um protocolo de autenticação interoperável baseado na família de especificações OAuth 2.0. Ele usa fluxos de mensagens REST/JSON diretos com o objetivo de "tornar simples as coisas simples e possíveis as coisas complicadas". É excepcionalmente fácil de integrar para os desenvolvedores, em comparação com qualquer protocolo de identidade anterior.
Para saber mais sobre o OpenID Connect, dê uma olhada nos links acima. Também encontrei este artigo valioso.
Fluxos
O OpenID Connect segue três "fluxos" possíveis. Um fluxo especifica os estágios de ida e volta do protocolo e todos os detalhes de quais parâmetros são necessários e o que eles significam. Falaremos sobre o fluxo do código de autorização (fluxo auth) aqui. O fluxo auth define os recursos de atualização, portanto, se você não quiser incomodar um usuário para que ele faça login com muita frequência, esse é o fluxo a ser usado.
O Couchbase implementou classes para abstrair grande parte da complexidade do OpendID Connect. Como outras partes do Couchbase Lite, as classes de autenticação lidam com muitas coisas nos bastidores, especialmente as chamadas de rede.
Ainda assim, um exemplo de código completo é demais para uma publicação de blog. Fornecerei exemplos simplificados. Para ver um aplicativo completo, dê uma olhada nos projetos GrocerySync em couchbaselabs no Github. Aqui estão os links para Android e iOS. (Observe que, no momento da redação deste texto, você precisa mudar para o ramo openid).
Vamos examinar as principais etapas da implementação da autenticação em um aplicativo Android. Usaremos o Google como nosso provedor de OpenID (OP).
No Android, você pode implementar algo diretamente, usar o Login do Google ou usar os wrappers incorporados ao Couchbase Lite. Usaremos os wrappers do Couchbase Lite. Para entender melhor o código subjacente, talvez você queira consultar a documentação do Google sobre a implementação do OpenID Connect. Você pode encontrá-la aqui.
Replicação
No Couchbase, nós nos referimos à sincronização das alterações no banco de dados como replicação. Não é de surpreender, portanto, que a autenticação esteja profundamente ligada à replicação. Resumidamente, para sincronizar, você cria objetos de replicação, define algumas opções e, em seguida, aciona-os, seja no modo one-shot ou contínuo.
Normalmente, você faz a autenticação criando um arquivo Autenticador e atribuindo-o a um objeto Replication. O Couchbase Lite tem fábricas para criar diferentes tipos de autenticadores. Você pode ler mais sobre replicações, Replicação objetos e autenticadores aqui.
Código
Em meu aplicativo de exemplo simples, o primeiro Atividade na inicialização apresenta dois botões, um para entrar e outro para sair. Vou me referir a isso como a atividade principal. Se o usuário não estiver conectado, clicar no botão de conexão inicia uma atividade com uma visualização da Web para lidar com o processo de conexão. Chamarei isso de atividade de login. O armazenamento das credenciais ocorre após o retorno à atividade principal.
O código compreende três seções principais, distribuídas entre essas duas atividades.
Preparar uma replicação
As réplicas têm uma "direção". Uma replicação pull transfere dados de um Sync Gateway, enquanto uma push envia dados para um. Aqui eu apenas configurei uma replicação pull para destacar a parte de autenticação. O código está separado, mas é chamado durante onCreate na atividade principal.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
privado Replicação puxar; privado vazio prepareToReplicate() { Banco de dados db = Tempo de execução.getDb(); tentar { puxar = db.createPullReplication(novo URL(Tempo de execução.getSyncUrl())); } captura (ExceçãoURLE malformada ex) { ex.printStackTrace(); } puxar.setContinuous(verdadeiro); Autenticador autenticador = OpenIDConnectAuthenticatorFactory .createOpenIDConnectAuthenticator(novo OIDCLoginCallback() { @Override público vazio retorno de chamada(URL loginURL, URL redirectURL, OIDCLoginContinuation loginContinuação) { Atividade principal.este.loginContinuação = loginContinuação; Intenção loginIntent = novo Intenção(getApplicationContext(), Login.classe); loginIntent.putExtra(Login.LOGIN_URL_KEY, loginURL); loginIntent.putExtra(Login.REDIRECT_URL_KEY, redirectURL); startActivityForResult(loginIntent, LOGIN_REQUEST); } }, novo AndroidContext(getApplicationContext())); puxar.setAuthenticator(autenticador); } |
A parte crítica, para nossos propósitos, está na criação do autenticador. Não deixe que o tamanho das linhas de código o engane. É tudo muito simples. Pode ser útil examinar o código de dentro para fora.
Dê uma olhada no corpo do retorno de chamada método. Ele recebe três parâmetros de entrada. Um ele salva para depois. Dois ele coloca em um Intenção. Essa intenção dá início à atividade de login e solicita o recebimento de um resultado.
Toda a formulação das URLs da maneira que o OpenID precisa foi feita para você. Por exemplo, quando verifiquei o loginURL, ele tinha bem mais de 400 caracteres com o que parecia ser mais de 15 parâmetros! Como eu mesmo implementei um fluxo OAuth 2, gerenciando as chamadas de rede e tudo o mais, posso dizer que isso é muito mais agradável.
Veremos mais tarde como a configuração do Sync Gateway se alimenta desse fluxo. Por enquanto, se você examinar os URLs, saiba que o Sync Gateway fornece partes em resposta ao início inicial não autenticado de uma replicação.
O terceiro parâmetro do método de retorno de chamada (o OIDCLoginContinuation (implementação da interface) é fornecida pelo Couchbase Lite. Esse é o gancho que você usa para passar de volta os resultados do logon. Vamos explorá-lo em mais detalhes daqui a pouco.
Atividade de login
Como você deve imaginar, muitos provedores de OpenID funcionam com páginas da Web. A atividade de login consiste em uma visualização padrão da Web. (O uso de uma visualização da Web tem implicações de segurança significativas. Consulte a nota especial no final sobre segurança para obter detalhes). Você precisa configurar a navegação e ativar o JavaScript. Você pode ler tudo sobre isso na seção Guia do Android para criar aplicativos da Web. Só precisamos examinar detalhadamente a interceptação do carregamento de URL. Aqui está o código.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
privado classe LoginWebClient se estende Cliente WebView { @Override público booleano shouldOverrideUrlLoading(WebView visualização, Cordas url) { Uri uri = Uri.analisar(url); se (uri.getHost().contentEquals(redirectURL.getHost())) { Intenção resposta = novo Intenção(); resposta.setData(uri); setResult(RESULT_OK, resposta); acabamento(); retorno(verdadeiro); // true => o aplicativo cuidará disso } retorno(falso); // A visualização da Web carregará a url } } |
(Observação: o Android Studio pode emitir um aviso sobre shouldOverrideUrlLoading sendo preterido. No momento em que escrevo, essa versão ainda é a mais amplamente suportada).
Quando você fornece um Cliente WebViewO Android o utiliza para conectar todos os novos carregamentos de página. O OpenID codifica o resultado de uma tentativa de autenticação na forma de um URL com, mais uma vez, vários parâmetros incorporados. Nosso Cliente WebView aguarda para localizar o URL de redirecionamento, empacota-o e encerra a atividade de login, retornando à nossa atividade principal. Talvez você queira analisar a possibilidade de lidar com isso com uma AsyncTask para adicionar extras, como uma barra de progresso.
Finalização
A atividade de login passa o URL de resposta de volta para a atividade principal. Para concluir o processo de autenticação (incluindo o armazenamento de credenciais), o Couchbase Lite fornece seu próprio retorno de chamada, um que implementa a função OIDCLoginContinuation interface. A interface recebe dois argumentos, o url de resultado e uma exceção. Os comentários no trecho de código explicam a semântica dos argumentos, incluindo como as combinações de valores nulos e não nulos indicam sucesso ou outros resultados.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
@Override protegida vazio onActivityResult(int requestCode, int resultCode, Intenção dados) { se (LOGIN_REQUEST == requestCode) { URL url = nulo; Exceção erro = nulo; se (RESULT_OK == resultCode) { tentar { Cordas resposta = dados.getData().toString(); url = novo URL(resposta); } captura (ExceçãoURLE malformada ex) { ex.printStackTrace(); } } mais se (RESULT_CANCELED != resultCode) { erro = novo Exceção("Falha no login".); } // url = auth redirect => success // url = null, ex = error => error // url = null, ex = null => cancelado loginContinuação.retorno de chamada(url, erro); } } |
Trato os erros de forma simplista para fins de ilustração. Você provavelmente desejará fazer algo mais sofisticado. A url de resposta pode conter informações de erro se algo der errado. Você pode usar isso para fornecer ao usuário uma visão mais detalhada do que falhou.
Resumo do código do aplicativo
Usando as classes do Couchbase Lite, temos um fluxo muito simples. Configuramos um autenticador e o anexamos a uma replicação. Iniciamos a replicação, possivelmente em resposta a uma ação do usuário (ou seja, clicar no botão de login).
O autenticador nos devolve o controle junto com três elementos pré-formados, dois URLs e um retorno de chamada fornecido pelo Couchbase Lite. Prosseguimos com a autenticação da maneira que escolhermos. E, finalmente, precisamos terminar chamando o retorno de chamada que recebemos.
Dicas e truques
ID do usuário
Não mostramos isso no código, mas muitas vezes você desejará atribuir algum tipo de ID de usuário com base nas informações da resposta do OpenID. Você pode usar o ID para criar um canal Sync Gateway para filtrar documentos, por exemplo.
Sair do sistema
Você pode limpar as credenciais de uma replicação chamando o comandoclearAuthenticationStores método. Se você usou uma visualização da Web, talvez também queira se livrar de todos os cookies de sessão. Este trecho de código mostra como fazer isso com a API 21 do Android ou posterior.
|
1 2 3 |
puxar.clearAuthenticationStores(); Gerenciador de cookies.getInstance().removeAllCookies(nulo); Gerenciador de cookies.getInstance().descarga(); |
Testes
Você pode testar seu código usando um emulador e uma instância do Sync Gateway em execução no mesmo computador. Emuladores comuns, como o fornecido com o Android ou o da Genymotion, permitirão que você se conecte a um serviço em seu computador usando um endereço IP especial. No entanto, o OP do Google geralmente rejeita esses URLs. Usei um truque em que o Sync Gateway especifica localhost como seu endereço. Em seguida, no campo onActivityResult substituo o endereço IP exigido pelo emulador por esta linha:
|
1 |
resposta = resposta.replaceFirst(Tempo de execução.EMULADOR_HOST, Tempo de execução.EMULADOR_IP); |
Configuração do Sync Gateway
Concluímos o código do aplicativo. Vamos dar uma breve olhada na configuração do Sync Gateway para usar o OIDC. Este exemplo de configuração mostra como configurar o GoogleAuthFlow como um provedor. Você precisará gerar seu próprio client_id e validation_key para produção. Consulte a seção Documentação e links do Google para obter detalhes. Saiba mais sobre o Sync Gateway e como configurá-lo na documentação do Couchbase aqui.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
{ "log": ["*"], "bancos de dados": { "grocery-sync": { "servidor": "walrus:.", "usuários": { "CONVIDADO": {"desativado": verdadeiro} }, "sem suporte": { "oidc_test_provider": { "habilitado": verdadeiro } }, "oidc": { "provedores": { "GoogleAuthFlow": { "emissor":"https://accounts.google.com", "client_id":"31919031332-8ea1795ckkphb7hmg6i4ul0blcpq8oq5.apps.googleusercontent.com", "validation_key":"OCIbokd6-SE8LMZE_vQsq8F5", "callback_url":"https://localhost:4984/grocery-sync/_oidc_callback", "registrar":verdadeiro } }, "default_provider": "GoogleAuthFlow" }, "sync": ` função(doc, oldDoc) { var nome de usuário = doc.proprietário; se (!nome de usuário) nome de usuário = oldDoc.proprietário; se (!nome de usuário) lançar({proibido : "O item deve ter um proprietário"}); var channelName = "ch-" + nome de usuário; acesso(nome de usuário, channelName); canal(channelName); } ` } } } |
Nota especial - Segurança
Em parte, este blog descreve o uso de uma visualização da Web como parte do processo de autenticação. Essa abordagem tem desvantagens, incluindo a possibilidade de que o aplicativo possa espionar o processo de autenticação. Para aumentar a segurança, talvez você queira considerar o uso do navegador do sistema. Para obter mais detalhes, recomendo a leitura da versão mais recente deste artigo Rascunho da Internet da IETF. A segurança tende a ser um alvo móvel. Se estiver lidando com informações altamente confidenciais, reserve um tempo para ler sobre as práticas recomendadas atuais.
Pós-escrito
Confira mais recursos em nosso portal do desenvolvedor e nos siga no Twitter @CouchbaseDev.
Você pode postar perguntas em nosso fóruns. E participamos ativamente de Estouro de pilha.
Você pode me seguir pessoalmente em @HodGreeley