Lorawan-stack: Introduzir um novo aplicativo de conta (para substituir o aplicativo oauth)

Criado em 4 out. 2019  ·  32Comentários  ·  Fonte: TheThingsNetwork/lorawan-stack

Resumo

No momento, temos muitos problemas relacionados ao nosso fluxo OAuth, troca de contas, gerenciamento de tokens, marca respectiva etc. Esta é uma tentativa de tornar tudo isso mais acionável em um novo aplicativo account que cuidará de todas essas preocupações.

Por que nós precisamos disso?

  • Falta a funcionalidade de troca de conta ⟶ #488
  • Falta de branding e contexto para o usuário ⟶ #730
  • Gerenciamento de sessão ausente ⟶ #1217
  • Confusão do usuário em torno do fluxo de autenticação OAuth ⟶ #265

O que já existe? O que você vê agora?

  • Aplicativo OAuth com IU limitada

O que está faltando? O que você quer ver?

Um aplicativo que atua como provedor OAuth e IU de configuração de marca e recursos completos em torno de todas as questões de conta e autenticação

Ambiente

Rede

Como você se propõe a implementar isso?

Eu acho que um grande problema com a implementação atual é a falta de clareza e contexto para o usuário. É difícil reconhecer o aplicativo OAuth como uma entidade de autenticação independente. Os motivos são:

  • falta de branding e contexto
  • UI muito reduzida e pouco informativa
  • console agindo como se ele próprio tratasse da autenticação (mensagem "Login" em vez de "Login com sua conta {OAuth provider service name}", ignorando a autorização)
    Para melhorar a clareza, precisamos tornar o aplicativo mais visível, distinguível e objetivo:
  • Adicionar branding configurável
  • Funcionalidade de destaque

    • Troca de conta

    • Gerenciamento de sessão

    • Gerenciamento de autorizações

    • Configurações do perfil (alterar/esquecer a senha, e-mail, foto do perfil)

Criei três wireframes que dão uma ideia de como imagino o aplicativo de contas:

Ver wireframes

account_login
account_overview
account_profile_settings
(observe o alternador de contas integrado no menu suspenso de usuários no canto superior direito)

Você pode fazer isso sozinho e enviar um Pull Request?

sim. @johanstokking @htdvisser , por favor, deixe-me saber se você acha que é bom continuar.

identity server uweb umbrella

Todos 32 comentários

Em relação a todo o problema de confusão de login/logout entre console e provedor oauth, aqui está meu plano:

  • Usamos um logotipo Account separado para o aplicativo da conta (em vez do logotipo TTS) e usamos o mesmo componente de cabeçalho que também usamos para o console (cc @pierreph)
  • Em vez de ter duas telas de login separadas para console e aplicativo de conta, devemos unir a experiência mais próxima, o que significa

    • Vamos remover a tela de login do console /console/login

    • O console redirecionará automaticamente para a página de login do aplicativo da conta /account/login , quando não tiver token de acesso (válido)

    • Como já fazemos com o botão de login do console, usaremos um parâmetro de consulta de redirecionamento para enviar o usuário de volta ao console após o login bem-sucedido

    • O logout da interface do usuário do console resultará na remoção do token de acesso armazenado, bem como no logout do aplicativo da conta. Dessa forma, os usuários sempre terão que inserir novamente suas credenciais para fazer login novamente no console.



      • Para poder fazer isso, precisamos de uma maneira de acionar logouts de solicitações de origem cruzada (já que o console e o aplicativo de conta não são garantidos na mesma origem)


      • Na v2, estamos usando uma rota simples /users/logout que acionará um logout que pode ser consultado de qualquer lugar


      • Seria bom procurar maneiras de alcançar a mesma coisa, mantendo o CSRF seguro



    • O novo fluxo será muito parecido com o fluxo do console v2; basicamente sacrificaremos a separação do cliente do console e do servidor de autorização para melhorar o UX, o que é bom, já que o console é uma espécie de cliente de caso especial

    • Talvez seja necessário revisar esse fluxo se permitirmos procedimentos de login diferentes no futuro

Se eu não ouvir nenhuma reclamação sobre esse plano, começarei a implementá-lo.

Soa como um grande plano. Concordo que não precisamos de logout explícito do Console e permanecemos logados via OAuth no UX, embora funcione dessa maneira por baixo.

O que você precisa para o logout entre origens? Não seria uma abordagem simples em duas etapas; sair da "página" para remover o token de acesso armazenado no console e redirecionar para a página de logout genérica onde o aplicativo Conta faz logout? Ou você quer isso sem redirecionamento, mas poste em um ponto de extremidade de logout?

Para o logout, podemos nos inspirar no logout do OpenID Connect. Um bom resumo pode ser encontrado aqui: https://medium.com/@robert.broeckelmann/openid -connect-logout-eccc73df758f

Soa como um grande plano. Concordo que não precisamos de logout explícito do Console e permanecemos logados via OAuth no UX, embora funcione dessa maneira por baixo.

O que você precisa para o logout entre origens? Não seria uma abordagem simples em duas etapas; sair da "página" para remover o token de acesso armazenado no console e redirecionar para a página de logout genérica onde o aplicativo Conta faz logout? Ou você quer isso sem redirecionamento, mas poste em um ponto de extremidade de logout?

A abordagem em duas etapas está correta. Minha preocupação era que o logout do aplicativo da conta precisasse ser desativado por CSRF, o que significa que qualquer pessoa com um link de logout poderia atrair alguém para sair de sua conta. No momento, isso também é possível com a pilha v2 ( clicando aqui você será desconectado ).
Eu acho que por enquanto isso é aceitável, mas não exatamente a melhor prática.

Eu fiz um bom trabalho agora para o novo aplicativo de conta:

  • Componentes e contêineres refatorados que podem ser usados ​​pelo console e pelo aplicativo de conta
  • Implementou novos designs (incluindo capacidade de resposta)
  • Configurações de perfil implementadas, incluindo foto de perfil
  • Gerenciamento de autorizações implementado (visualizar e revogar)
  • Gerenciamento de sessão implementado (visualizar e revogar)
  • Resolvendo um problema que resultava em renderizações em branco ao usar dependências compartilhadas do módulo css

Fiz isso codificando um token de acesso para poder usar a API de pilha. No momento, não consigo avançar com uma implementação adequada, pois não sei qual seria a melhor maneira de obter um token de acesso para o aplicativo da conta.
No momento, o "aplicativo oauth" é apenas um SPA que se conecta aos endpoints de autenticação do servidor oauth (login, logout e outros endpoints relacionados à conta que não precisam de um token de acesso).
@htdvisser me mencionou que nossa ideia inicial era ter o aplicativo de conta como cliente oauth separado, usando o tipo de concessão de senha. Acho que devemos abrir uma discussão sobre isso, já que:

  • dependendo da fonte, o tipo de concessão de senha é desencorajado, mesmo para clientes "oficiais" e confiáveis
  • isso exigiria outra tela de login (ao lado da tela de login do provedor oauth)
  • Gostaria de saber se existe uma forma de obter um token de acesso direto do provedor oauth, sem precisar usar outro cliente separado, pois já estamos fazendo autenticação dentro do app oauth
  • se usarmos a concessão de senha para o aplicativo da conta, devemos usá-la também para o console

Eu já disse ao @htdvisser que todo o aspecto de autenticação/autorização delegada disso é um pouco esmagador para mim e não me sinto conhecedor o suficiente para ser responsável por um assunto tão sensível à segurança.

O que devemos buscar é um fluxo que faça com que o fluxo de autenticação de nossos clientes oficiais pareça uma autenticação nativa (veja também meu outro comentário ), o que significa que logins e logouts são globais e não deve haver distinção entre o estado autenticado dos clientes e o provedor de autorização.

Então, eu precisaria de ajuda e informações para continuar com o aplicativo da conta. Como podemos coordenar isso?

dependendo da fonte, o tipo de concessão de senha é desencorajado, mesmo para clientes "oficiais" e confiáveis

Sim, a concessão de senha não deve ser usada, veja a especificação e o raciocínio aqui: https://tools.ietf.org/html/draft-ietf-oauth-security-topics-13#section -3.4

Atualmente bloqueado por #2148

Então, depois de estar envolvido com isso por um tempo, acho que preciso de alguma contribuição.

A ideia original do aplicativo de conta era substituir o aplicativo oauth atual e estender a funcionalidade para o gerenciamento de perfis e sessões (consulte OP). O problema com isso é que, para implementar essa funcionalidade, o aplicativo precisaria de um token de acesso, o que significa essencialmente que o aplicativo da conta seria um provedor e cliente OAuth.

Minha ideia era apresentar um novo cliente OAuth ( account ) e em termos de frontend, para combinar a funcionalidade com o aplicativo OAuth atual. Para o usuário, parece que tanto o provedor OAuth (login, registro, validação de conta etc.) é uma separação técnica entre o provedor OAuth e o cliente. No back-end, o cliente da conta se tornaria parte do pacote oauth . Em termos de frontend, também poderíamos tratar as duas coisas como o mesmo aplicativo, usando o mesmo ponto de entrada ( account.js ).
Da mesma forma, o roteamento refletiria essa combinação, por exemplo:

  • /account/login para o login oauth [camada do provedor OAuth]
  • /account/register para registro do usuário [camada do provedor OAuth]
  • /account/forgot-password para registro de usuário [camada de provedor OAuth]
  • /account/client/login/ttn-stack para o login do cliente (autorização) [camada do cliente OAuth]
  • /account/client/oauth/callback para trocar o código de autenticação [camada do cliente OAuth]
  • /account página de visão geral do cliente oauth [camada do cliente OAuth]

Como alternativa, poderíamos manter as duas preocupações separadas, deixando o provedor OAuth ( /oauth via pkg/oauth ) como está e tratando o aplicativo da conta ( /account via pkg/account ) como uma coisa completamente separada, como fazemos com o console. O provedor OAuth seria responsável apenas por questões de autenticação, incluindo autorização e registro de conta de usuário, mas não teria uma visão autenticada própria como tem atualmente. Em vez disso, após o login, ele redirecionaria para o aplicativo da conta por padrão, que recuperaria um token automaticamente.

Sinto que a primeira solução pode evitar parte da confusão que temos atualmente em torno da autenticação e do gerenciamento de contas, mas não posso prever se isso pode introduzir outras complicações. A segunda solução parece mais limpa, mas a questão é como comunicar/marcar a separação. Por exemplo, ambos devem ser comunicados como "aplicativo de conta" ainda? Ou deveria ser The Things Stack Single Sign On e The Things Stack Account Application ?

Por favor, deixe-me saber suas opiniões.

Hmm, dando um passo para trás, qual é o propósito de tornar o aplicativo de conta um cliente OAuth? Qual funcionalidade via OAuth queremos lá?

  • Configurações de perfil (nome, e-mail, foto do perfil)
  • Gerenciamento de sessão (revisar, revogar)
  • Gerenciamento de autorização (revisar, revogar)
  • (Potencialmente outras meta-configurações relacionadas ao TTES no futuro)

Todos eles exigem um token de acesso, pois essa é a única maneira de autorizar os respectivos RPCs.

Precisamos de uma separação entre o provedor OAuth - que pode ser externo, por exemplo, "The Things Network Community" - e o gerenciamento de usuários - que trata do gerenciamento de campos da entidade User armazenados com The Things Stack, incluindo os pontos @kschiffer escreveu no comentário acima.

Nossos pontos de extremidade /api/v3/* não aceitam autenticação de cookie porque são habilitados para CORS. Eles só funcionam com chaves de API e tokens de acesso.

  • Configurações de perfil (nome, e-mail, foto do perfil)
  • Gerenciamento de sessão (revisar, revogar)
  • Gerenciamento de autorização (revisar, revogar)
  • (Potencialmente outras meta-configurações relacionadas ao TTES no futuro)

Todos eles exigem um token de acesso, pois essa é a única maneira de autorizar os respectivos RPCs.

Também poderíamos fazer isso parte do console, mas isso significaria que o console misturaria preocupações até certo ponto. Eu pude ver situações em que seria melhor executar o gerenciamento de contas sem a sobrecarga de todas as outras funcionalidades do console, mas talvez seja eu fazendo engenharia excessiva 🤷‍♂️.

Geralmente, a questão seria se queremos ver o console apenas como uma ferramenta para gerenciar assuntos relacionados à rede. Podemos abri-lo para ser uma plataforma de gerenciamento de propósito geral para todos os assuntos relacionados ao TTS ou podemos ser mais atômicos e manter a separação e usar aplicativos/clientes diferentes para diferentes preocupações. É uma questão estratégica. Eu vejo casos para ambos.

Eu não acho que o console (todos os consoles, porque há um console em cada cluster) deve ter direitos totais sobre o usuário. Os consoles não devem ser usados ​​para gerenciar clientes OAuth autorizados, sessões, endereço de e-mail principal, informações de contato. Ter um aplicativo de gerenciamento de usuários dedicado (o aplicativo de contas) é muito melhor.

De fato, bom ponto. Então voltamos à pergunta inicial .

Minha tomada é:

Abordagem mista:

  • De um ponto de vista do usuário menos confuso (um local para todos os assuntos relacionados à conta)
  • Marca/comunicação mais fácil
  • Em conformidade com o plano original do aplicativo da conta
  • Em termos de front-end, não precisamos de um novo ponto de entrada e, portanto, de padronização separada
  • A implementação se torna mais complexa/confusa (aplicativo de conta sendo provedor e cliente oauth)

Abordagem separada:

  • Implementação mais limpa e convencional
  • Configuração mais flexível e clara
  • Apresenta um novo aplicativo ao lado do aplicativo oauth, que precisa de branding e comunicação sensatos
  • Compilações mais longas (podem ser marginais, não testadas) e mais ativos

Eu me inclino para a abordagem combinada.

  • Configurações de perfil (nome, e-mail, foto do perfil)
  • Gerenciamento de sessão (revisar, revogar)
  • Gerenciamento de autorização (revisar, revogar)
  • (Potencialmente outras meta-configurações relacionadas ao TTES no futuro)

Este é um aplicativo de conta, certo? Não é OAuth?

  • Apresenta um novo aplicativo ao lado do aplicativo oauth, que precisa de branding e comunicação sensatos

Para que serve o aplicativo OAuth então ainda?

Você pode listar os recursos para o usuário do que o cliente OAuth adiciona ao aplicativo da conta, que não podemos criar no aplicativo da conta, possivelmente por meio de novos endpoints?

Este é um aplicativo de conta, certo? Não é OAuth?

Sim, este é um aplicativo de conta. Mas o plano era que o que temos atualmente como aplicativo OAuth se torne parte do aplicativo da conta.

Para que serve o aplicativo OAuth então ainda?

Para autenticação (como parte do fluxo OAuth), registro do usuário, autorização do cliente, redefinição de senha. Basicamente tudo que tem a ver com autenticação de usuários e autorização de clientes.

Você pode listar os recursos para o usuário do que o cliente OAuth adiciona ao aplicativo da conta, que não podemos criar no aplicativo da conta, possivelmente por meio de novos endpoints?

O problema é mais o contrário, não podemos simplesmente estender nosso aplicativo OAuth atual com as funcionalidades que queremos para o aplicativo da conta, pois precisaríamos obter um token de acesso. É um pouco de um problema de galinha e ovo. Se houvesse um meio diferente de autorização para as funcionalidades do aplicativo de conta (sessões, autorizações, etc), por exemplo, através do cookie de sessão que o aplicativo OAuth possui, então seria diferente. Mas pelo que vejo isso é inviável.

O aplicativo OAuth é autônomo? Ele está implementando os fluxos de redirecionamento para clientes OAuth? Ou é um cliente OAuth em si?


Destaque meu:

Minha ideia era apresentar um novo cliente OAuth ( account ) e em termos de frontend, para combinar a funcionalidade com o aplicativo OAuth atual . Para o usuário, afigura-se como se ambos provedor de OAuth (login, registo, conta validar, etc) eo cliente conta aplicativo (configurações de perfil, gerenciamento de sessão, gestão de autorização) são uma ea mesma aplicação, enquanto no fundo, há é uma separação técnica entre o provedor OAuth e o cliente . No backend , o cliente da conta se tornaria parte do pacote oauth .

eu vejo aqui;

  • Cliente OAuth
  • aplicativo OAuth atual
  • Provedor OAuth
  • o cliente do aplicativo de conta
  • o provedor OAuth
  • o cliente
  • o back-end
  • o cliente da conta
  • o pacote oauth

Estou tentando entender a proposta, mas ainda não entendo completamente o que é o que é.

Então, quais são os recursos que queremos?

  1. Criar Conta
  2. Esqueceu a senha
  3. Conecte-se
  4. Alterar a senha
  5. Visualizar e editar perfil
  6. Gerenciar sessões
  7. Coisas do OAuth

    1. Tela de consentimento (fluxo de código de autorização OAuth)

    2. Gerenciar autorizações OAuth

Eu acho que 1-6 pode ser implementado sem tocar em OAuth, se formos com autenticação de sessão. Isso é possível, certo?

Sim, desculpe-me. Temos vários termos não fixos aqui que tornam bastante difícil explicar as coisas. Pelo menos dá uma boa visão da complexidade da questão 😅.

Vamos então ao status quo:

Provedor OAuth
A entidade que fornece autorização (e no nosso caso também autenticação) de acordo com a especificação OAuth 2.0. No nosso caso é o pacote pkg/oauth , que por sua vez usa o aplicativo OAuth (veja abaixo) para implementar a interface de usuário necessária para obter informações do usuário (login de renderização, registro, visualizações de autorização, etc.).

Aplicativo OAuth
Este é o aplicativo web de reação no frontend. Nosso código frontend consiste em diferentes aplicativos (com diferentes pontos de entrada oauth.js / console.js ) que compartilham partes comuns, como componentes de reação e utilitários

Cliente OAuth
Um cliente registrado que usa OAuth para autenticação e autorização, como o console ou CLI.

pacote oauth
O pacote Go responsável pela implementação do provedor OAuth. Isso é pkg/oauth .

Então você vê, há três ou quatro camadas diferentes em jogo aqui. O problema é que, se mantivermos a forma como fazemos a autorização no momento, precisaríamos ter algo que desempenhasse todos os papéis descritos acima ao mesmo tempo.

Eu acho que 1-6 pode ser implementado sem tocar em OAuth, se formos com autenticação de sessão. Isso é possível, certo?

sim. 1-4 já são possíveis sem oauth/token de acesso. 5 e 6 atualmente precisam de um token de acesso. 7. ii ainda não está implementado. Se 5 e 6 fossem possíveis sem token de acesso, não precisaríamos de outro cliente oauth para fazer isso. Ainda assim, precisamos considerar que todas as funcionalidades que desejamos adicionar ao aplicativo de conta no futuro não devem usar o token de acesso como único meio de autorização.

Se 5 e 6 fossem possíveis sem token de acesso, não precisaríamos de outro cliente oauth para fazer isso. Ainda assim, precisamos considerar que todas as funcionalidades que desejamos adicionar ao aplicativo de conta no futuro não devem usar o token de acesso como único meio de autorização.

Direito. Isso faz muito sentido para mim. Isso também é uma base melhor para o "modo sudo", onde os usuários podem fazer coisas _somente_ no aplicativo da conta, depois de inserir novamente sua senha, por exemplo. Então, sim, pode haver alguma sobreposição entre o que os clientes OAuth e o aplicativo de conta podem fazer, mas essa sobreposição não parece grande para mim. Vejo valor em manter as coisas dedicadas ao aplicativo de contas.

Tudo certo, combinado.
@htdvisser Você tem alguma objeção? E se não, você pode me indicar os arquivos/pacotes relativos para autorização, porque suponho que você não terá tempo para trabalhar nisso tão cedo (?).

Como comentei antes, nossos endpoints /api/v3/* não aceitam autenticação de cookie, porque são habilitados para CORS. Se você quiser começar a aceitar a autenticação de cookie, precisará dar uma boa olhada em nossos cabeçalhos CORS, porque realmente não queremos que um invasor faça solicitações de origem cruzada autenticadas por cookie para esses endpoints.


Nossa API é toda gRPC, e a autenticação é feita com o cabeçalho Authorization , que é propagado para gRPC como metadados de solicitação. A implementação da autenticação de sessão pode ser assim:

  • Adicione um tipo SessionToken a pkg/auth/auth.go
  • Adicione uma parte secreta ao modelo Session , semelhante ao que fazemos com chaves de API e tokens de acesso.
  • Adicione um middleware que extraia o ID da sessão e o segredo da sessão do cookie e os encaminhe para o cabeçalho Authorization como um SessionToken
  • Adicione SessionToken como case ao switch tokenType { em pkg/identityserver/entity_access.go

Uma coisa a considerar aqui é que isso também significa que o aplicativo da conta e a API v3 precisam ser servidos da mesma origem. Caso contrário, a autenticação de cookie não funcionaria, pois o contexto de autenticação compreende origens diferentes.
Não tenho certeza de como isso é aceitável. Pelo menos na prática, parece que estamos usando as mesmas origens em nossas implantações.

Sim, serão da mesma origem.

@kschiffer, por favor, deixe-nos saber como podemos desbloquear o progresso aqui.

OK, vamos continuar essa conversa aqui.

@kschiffer Depois de trabalhar um pouco nisso:

  • A parte de front-end do aplicativo oauth consistiria basicamente apenas na tela de autorização

sim

  • Eu acho muito chato ter que manter as configurações is.oauth.ui.* só para isso
    [...]
  • Também estou um pouco inseguro sobre as restrições exatas de como podemos alterar a configuração da pilha sem quebrar o CC
  • Estou um pouco sem sorte em encontrar uma solução viável aqui e realmente preciso de alguma contribuição

Não podemos interromper a configuração na V3, mas podemos introduzir uma nova configuração, descontinuar a configuração antiga, usar a configuração antiga como fallback e arquivar um problema TODO rotulado bump/major para remover a configuração antiga.

Portanto, minha sugestão seria introduzir uma nova configuração que fosse uma substituição completa e habilitasse o novo aplicativo de conta. Para compatibilidade com versões anteriores, ele deve funcionar sem que o usuário especifique essa nova configuração, ou seja, confie em valores padrão sãos e na configuração antiga via is.oauth.ui.* .

@kschiffer qual é o status aqui?

Atualmente rebase meu trabalho no novo andaime, que está em andamento aqui: #3453

O próximo passo é rebasear, corrigir e fazer PR das visualizações autenticadas e ajustar os designs atuais para a nova marca.

@kschiffer qual é o status aqui?

O App Conta foi introduzido na versão 3.11. Atualmente ainda faltam:

  • Troca de conta #488
  • Gerenciamento de sessão
  • Gerenciamento de autorizações (iirc isso também inclui a adição de endpoints de API)

OK. https://github.com/TheThingsNetwork/lorawan-stack/issues/488 já está fechado, parece.

Este tem sido um grande problema. Você pode registrar um ou dois novos problemas para o acima para substituir este, para que possa ser fechado?

Esta página foi útil?
0 / 5 - 0 avaliações

Questões relacionadas

adriansmares picture adriansmares  ·  8Comentários

kschiffer picture kschiffer  ·  6Comentários

thinkOfaNumber picture thinkOfaNumber  ·  4Comentários

johanstokking picture johanstokking  ·  8Comentários

adriansmares picture adriansmares  ·  9Comentários