Saltar para o conteúdo

Início de sessão único

O início de sessão único permite que um fornecedor de identidade (IdP) externo decida quem pode iniciar sessão no seu servidor do Control Center. São suportados dois protocolos — SAML 2.0 e OpenID Connect — e ambos acabam no mesmo sítio: uma credencial de dispositivo acabada de emitir, indistinguível de um convite ou de um emparelhamento por QR em todo o percurso a jusante.

Os inícios de sessão SAML são intermediados pelo navegador. O IdP nunca abre uma ligação ao seu servidor; é o navegador do utilizador que transporta tudo:

browser ──> /saml/login ──> IdP ──POST SAMLResponse──> /saml/acs
│ verify
▼
provision user (maybe)
│
▼
browser handoff: device PSK in the URL
fragment (never a query parameter)

Como é o navegador que faz de mensageiro, um servidor atrás de NAT funciona bem para inícios de sessão: localhost, LAN, Tailscale, VPN ou um túnel servem todos — só o navegador do utilizador tem de alcançar o URL ACS. O retransmissor WebSocket usado pelo controlo remoto do telemóvel não consegue transportar a ida e volta HTTP, e é por isso que os pontos de entrada de SSO apontam sempre para a origem HTTP do servidor.

O OpenID Connect segue a mesma forma, com uma ida e volta de código de autorização + PKCE; as afirmações são lidas no endpoint de tokens do emissor por TLS, pelo que o navegador nunca fornece dados de identidade.

O Control Center divide a responsabilidade de forma deliberada:

Componente Onde Responsabilidade
cc_saml nativo packages/cc_natives/native/saml/ verificação de XML-DSig, canonicalização e validação do perfil SAML — delegadas na crate saml em Rust puro e com versão fixada, atrás de uma ABI C sem estado
SamlService / OidcService cc_server_core estado de início de sessão (registadores de pedidos pendentes, deduplicação de repetições), parâmetros da política de validação, a chamada de provisionamento partilhada
SsoProvisioner cc_server_core localizar ou criar o utilizador, fixar o sujeito do fornecedor, conceder pertenças segundo a política de membro automático
ScimService cc_server_core a superfície de envio do SCIM 2.0 (ciclo de vida de provisionamento/desprovisionamento)
SsoSettingsService cc_server_core as linhas de ligação guardadas, reaplicação em tempo real, o token SCIM

Não existe deliberadamente qualquer alternativa de criptografia SAML em Dart puro: a XML-DSig/canonicalização feitas à mão são exatamente o sítio onde vivem as vulnerabilidades de encapsulamento de assinatura, pelo que a ausência da biblioteca cc_saml recusa tanto o início de sessão SAML como o arranque do servidor. O nativo é, por conceção, sem estado — o estado entre pedidos vive nos serviços Dart, é de utilização única e de curta duração.

Dentro do nativo verificado e do serviço, pela ordem seguinte:

  1. a assinatura da asserção (sempre obrigatória; a do envelope de resposta é opcional conforme a configuração) — estruturalmente resistente ao encapsulamento de assinatura, porque o payload validado está vinculado ao elemento verificado,
  2. o emissor coincide com o IdP configurado,
  3. a audiência nomeia este fornecedor de serviço,
  4. o destino é o nosso URL ACS,
  5. InResponseTo coincide com um AuthnRequest pendente que emitimos (as respostas não solicitadas, iniciadas pelo IdP, estão desativadas por predefinição),
  6. as janelas de tempo de vida mantêm-se dentro do desvio de relógio (predefinição 90s) e
  7. o id da asserção nunca foi visto antes (cache de repetições).

As falhas regressam como códigos tipados — signature, expired, audience, destination, issuer, request-match — e os endpoints respondem com erros genéricos, para que um atacante não fique a saber por que razão uma falsificação falhou.

O primeiro início de sessão por SSO fixa o sujeito imutável do fornecedor (issuer e o NameID SAML / sub OIDC, ou o externalId SCIM) na conta. A partir daí, é o sujeito — e não o email — que identifica o início de sessão. Se outra pessoa apresentar mais tarde o mesmo email a partir do mesmo IdP ou de outro, a conta fixada recusa essa pessoa. É isto que impede que um email reciclado num fornecedor se transforme num apoderamento de conta.

O provisionamento JIT acontece no início de sessão (SsoProvisioner). O SCIM é uma superfície de envio separada (ScimService) que fixa o mesmo sujeito na linha do utilizador; não concede pertenças a espaços de trabalho. O desprovisionamento — SCIM active: false ou DELETE — é recusado se a conta for proprietária de um espaço de trabalho (transfira primeiro). Caso contrário, revoga primeiro todas as credenciais dos dispositivos (as sessões terminam em segundos através da vigilância dos dispositivos), remove todas as pertenças a espaços de trabalho e marca a conta como desativada. A linha do utilizador sobrevive: a atribuição é permanente. A reativação restaura o início de sessão, mas nunca volta a conceder pertenças.

  • O mapeamento grupo→função acontece no início de sessão, a partir dos atributos SAML / das afirmações OIDC — os grupos enviados por SCIM não são armazenados.
  • A função de proprietário é inalcançável a partir do SSO — nem como função predefinida nem através de um mapeamento de grupos.
  • O retransmissor WebSocket nunca é um canal de SSO; os telemóveis que só alcançam o servidor através do retransmissor não conseguem concluir uma ida e volta pelo navegador contra ele.