Skip to content

Gerenciamento de Senhas

Configure no Potato o hash de senhas PBKDF2-SHA256, redefinições via CLI e API de administrador, links de redefinição self-service por token e armazenamento de credenciais em SQLite ou PostgreSQL.

Novo na v2.4.0

O sistema de autenticação do Potato usa PBKDF2-SHA256 com 100.000 iterações e salts por usuário, a mesma abordagem recomendada pelo NIST para armazenamento seguro de senhas. Esta página aborda como as senhas são armazenadas, como redefini-las e como manter as credenciais entre reinicializações do servidor.

Ela se aplica aos métodos in_memory e database. Com OAuth, quem gerencia a senha é o provedor de identidade, então nada disto se aplica, exceto às contas locais no modo misto.

Implementação de segurança

As senhas são armazenadas no formato salt$hash:

  • Salt hexadecimal de 32 caracteres, único por usuário
  • Digest hexadecimal de 64 caracteres, derivado por PBKDF2-HMAC-SHA256 a partir da senha, com esse salt e 100.000 iterações
  • Comparação em tempo constante via hmac.compare_digest para evitar ataques de temporização

Uma única passada de SHA-256 sobre uma senha com salt é rápida o bastante para permitir força bruta em larga escala. São as 100.000 iterações que tornam cada tentativa cara.

Senhas em texto simples existentes em arquivos user_config.json são automaticamente re-hasheadas com salts únicos quando o Potato as carrega, sem necessidade de migração manual.

Configuração padrão

Por padrão, o Potato usa autenticação em memória. require_password é uma chave de nível superior e não faz parte do bloco authentication:

yaml
require_password: true
 
authentication:
  method: in_memory
 
user_config:
  users:
    - username: "annotator1"
      password: "initial-password"   # will be hashed on first load
    - username: "annotator2"
      password: "initial-password"

Credenciais persistentes

Contas criadas pelo formulário de cadastro são gravadas em um arquivo JSONL e lidas de volta na próxima inicialização. Com in_memory, esse arquivo é user_config.json, ao lado do diretório de saída, a menos que você indique outro.

Persistência baseada em arquivo

yaml
authentication:
  method: in_memory
  user_config_path: /shared/path/to/user_config.jsonl

Indique um caminho quando várias instâncias do servidor compartilham uma mesma lista de usuários, ou quando você quiser a lista em outro lugar que não ao lado das anotações. Novos cadastros e alterações de senha são gravados no momento em que acontecem.

Mantenha a lista de usuários junto com a saída das anotações. O diretório de um anotador recebe o nome do seu nome de usuário. Se a lista de usuários sumir enquanto o diretório de saída continua existindo, a próxima pessoa que digitasse esse nome de usuário herdaria o trabalho de outra pessoa. Por isso o Potato recusa o cadastro, o que significa que o anotador não consegue voltar até que você restaure o arquivo.

Antes da v2.8.3, in_memory não gravava nada se user_config_path não estivesse definido explicitamente, então as contas não sobreviviam a uma reinicialização. Se você conduziu um estudo em uma versão anterior, essas contas se perderam; as anotações, não.

Backend de banco de dados

SQLite (sem dependências adicionais):

yaml
authentication:
  method: database
  database_url: "sqlite:///auth/users.db"

PostgreSQL (requer psycopg2-binary):

yaml
authentication:
  method: database
  database_url: "postgresql://user:password@localhost:5432/potato_auth"

O Potato cria a tabela users na primeira inicialização e roda o SQLite em modo WAL para melhorar as leituras concorrentes. database_url deve começar com sqlite:/// ou postgresql://. Você também pode definir POTATO_DB_CONNECTION no ambiente; quando os dois estão presentes, database_url prevalece.

Nota: method: database e user_config_path são mutuamente exclusivos. Escolha uma única estratégia de persistência. O Potato gera um erro se os dois estiverem configurados.

Redefinindo senhas

CLI de administrador

Redefina uma senha pela linha de comando:

bash
# Prompts for username and password
potato reset-password config.yaml
 
# Prompts for the password only
potato reset-password config.yaml --username annotator1

API de administrador

Redefina programaticamente com a chave de API de administrador:

bash
curl -X POST http://localhost:8000/admin/reset_password \
  -H "X-API-Key: $ADMIN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"username": "annotator1", "new_password": "new-secure-password"}'

A chave vem, nesta ordem, da configuração de nível superior admin_api_key, da variável de ambiente POTATO_ADMIN_API_KEY ou de um arquivo admin_api_key.txt gerado no diretório da tarefa.

Redefinição self-service por token

Anotadores que esquecem a senha podem redefini-la por conta própria. Eles acessam /forgot-password e informam o nome de usuário, e o Potato gera um token de uso único válido por 24 horas. O link de redefinição aparece na tela para que um administrador o repasse; o Potato não envia e-mails. O anotador abre /reset/<token> e define uma nova senha, o que consome o token.

O fluxo não exige configuração. Quando require_password: true está definido, um link "Forgot Password?" aparece na página de login.

Administradores também podem gerar um token diretamente:

bash
curl -X POST http://localhost:8000/admin/create_reset_token \
  -H "X-API-Key: $ADMIN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"username": "annotator1"}'
 
# {"reset_link": "http://localhost:8000/reset/abc123...",
#  "token": "abc123...", "expires_in_hours": 24}

Passe "ttl_hours": 48 no corpo da requisição para outro prazo de validade.

Modo sem senha

Para demonstrações em sala de aula, estudos rápidos ou tarefas que usam autenticação externa (MTurk, Prolific), você pode desabilitar as senhas por completo:

yaml
require_password: false
 
authentication:
  method: in_memory

Os anotadores informam qualquer nome de usuário para entrar, sem nenhuma solicitação de senha. Não recomendado para dados sensíveis ou tarefas que exijam identidade verificada.

Consulte Login sem Senha para mais detalhes.

Referência completa

yaml
# Top-level: require a password at login (default: true)
require_password: true
 
# Top-level: key for the admin endpoints
admin_api_key: ${POTATO_ADMIN_API_KEY}
 
authentication:
  # in_memory (default) | database | clerk | oauth
  method: in_memory
 
  # in_memory only, mutually exclusive with method: database
  user_config_path: users.jsonl
 
  # database only; sqlite:/// or postgresql://
  # database_url: "sqlite:///auth.db"
 
user_config:
  users:
    - username: "researcher"
      password: "secure-passphrase"
    - username: "annotator1"
      password: "initial-pass"
EndpointMétodoAutenticaçãoDescrição
/forgot-passwordGET, POSTnenhumaSolicitar um token de redefinição
/reset/<token>GET, POSTnenhumaDefinir uma nova senha
/admin/reset_passwordPOSTchave de APIRedefinição de senha pelo administrador
/admin/create_reset_tokenPOSTchave de APIGerar um token de redefinição

Leitura adicional

Para detalhes de implementação, consulte a documentação de origem.