cambiatus / backend

Cambiatus GraphQL API
GNU Affero General Public License v3.0
21 stars 18 forks source link

Improve Authentication #141

Closed lucca65 closed 2 years ago

lucca65 commented 3 years ago

Authentication Phase 2

Now with the basic security implemented, we now need to improve the next phase of our authentication update, this next batch should allow us to have signature verification as a password.

New features

We still need some steps to allow greater security and flexibility!

  1. Create the idea of a session, to allow us to store different devices the user is using and have control on their data access. Sessions should allow us to drop anyone sessions at anytime and require them to signIn again, to be used as needed by security reasons.
  2. Require a signature verification that the user really has the private key. We can to leverage eosjs to do so
  3. Make sure the backend has a way to inform which API version on every response it sends, or at least on the signIn. The final objetive is to have a way for the frontend to know if it needs to reload itself. In the cases of breaking and obligatory full loads, we can simply drop everyone's session after a deploy.

I feel like the 3 feature still needs more maturation and discussions on how the general idea works

Story Update

Eu como usuário Quero me autenticar no sistema Para utilizar partes não públicas (offchain) da aplicação

Telas

N/A

Casos de uso

Dado um usuário fazendo login Quando colocou sua chave privada/12 palavras Então o frontend guarda essas chave privada/12 palavras na Wallet do browser

Dada um usuário ainda não autenticado Quando já tem a chave privada/12 palavras salvas na Wallet Então o frontend solicita uma nova sessão

Dada uma nova solicitação de sessão, gerada pelo backend Quando o frontend a solicitar Então é criado no banco uma nova sessão ainda não autenticada, com um Time to Live de 30 segundos (análogo a tabela veil_requests do Natus

Dado que o frontend recebeu a nova sessão Quando o front assinar e mandar um signIn contendo a assinatura da frase Então o backend verifica se a frase foi assinada usando a chave pública do dono da conta que fez a solicitação

Dado uma sessão já logada Quando o plug (CambiatusWeb.Plugs.SetCurrentUser) for verificar se o usuário já está logado e constatar que o token foi atualizado faz mais tempo do que está parametrizado Então dá erro de token expirado

venomnert commented 3 years ago
venomnert commented 3 years ago

Hey @lucca65 regarding the decoupling of eosjs wrapper. I would like to suggest that we incorporate the decoupling refactor within the same PR as the session table.

Mainly due to the fact that the decoupling wasn't a major refactor as anticipated.

lucca65 commented 3 years ago

we can create new contexts by adding the device as a suffix

Hmm, maybe we can simply store their user-agent information, or other stuff we found on the headers, and filter from there. I think it would only be useful to have something like this if we need to treat them differently... any ideas?

venomnert commented 3 years ago

@lucca65 I need your advise with this edge case here, when the client doesn't save their session token after sign in.

One solutions is to allow phrase creation even if a session already exists.

image

lucca65 commented 3 years ago

This prevents the client from creating a new phrase because the session stills exists from sign in.

Hmm, why not? We can have several sessions on the same user, that's the case when they have multiple devices

venomnert commented 3 years ago

As discussed on the call I will address in my second PR to improve-auth. Which will solve the above case and allow a single user to create sessions across multiple devices.

lucca65 commented 3 years ago

https://hex.pm/packages/eosjs_auth_wrapper

lucca65 commented 3 years ago

Autenticação

Dentro da função Accounts.verify_pass/2

  1. Fazer requisição para o EOS perguntando qual é a chave pública da conta fornecida como argumento para a função
  2. Extrair chave pública da assinatura
  3. Verificar se a chave da assinatura da frase é a mesma da conta consultada no EOS
  4. Se sim, autentica, se não falha

Sessão

É criada para solicitar um login novo e expira automaticamente.

> ecc.sign(frase, '5JZAmtKZ9fwgFHfnCKKxdamV8dwUdoixNAPsLNedQdeteWoga7y')
< "SIG_K1_K21huz3XyG3Z1pJ1731ieEaPyWUGDDuoxNAxd9imxcnEYpDd6EVH23aPj7x5GYAFVSrohzR6KQyMfEEnm8x77Toxy1CS25"
> sig = ecc.sign(frase, '5JZAmtKZ9fwgFHfnCKKxdamV8dwUdoixNAPsLNedQdeteWoga7y')
< "SIG_K1_K21huz3XyG3Z1pJ1731ieEaPyWUGDDuoxNAxd9imxcnEYpDd6EVH23aPj7x5GYAFVSrohzR6KQyMfEEnm8x77Toxy1CS25"
> ecc.verify(sig, frase, '')
< AssertionError: Invalid public key
> ecc.verify(sig, frase, 'EOS54m7kANU7F635hGqjfaiCbkB2JviXH55UfSeGajQmgdWvC5S16')
< true
> ecc.verify(sig, frase, 'EOS5xMPivcfHXCUQoYhMvExMZcMxESHsiZf57Rt6wyEm71uJEE7mm')
< false