Uma política que permite uma sessão por conta parece resolvida até chegar o segundo login. São possíveis dois desfechos: o recém-chegado substitui a sessão em curso, ou a sessão em curso mantém a vaga e o recém-chegado é recusado. Só o segundo é uma política em que a primeira sessão vence. A opção de cliente a que a maioria recorre ativa a concorrência e, por isso, não a produz.

Dois contratos escondem-se atrás de uma só definição

Com a concorrência desativada, uma segunda ligação que apresente o mesmo nome de certificado pode desalojar a sessão já em execução. Ativar a concorrência permite várias sessões ao mesmo tempo, o que é o contrário de um limite. Nenhum dos estados é uma política de recusa, pelo que a decisão tem de ser tomada noutro lugar.

Escreva o contrato antes de implementar seja o que for: quem é recusado, que prova identifica a sessão em curso e o que acontece quando uma sessão morre sem um corte limpo. Uma política que ninguém formulou assim não pode ser testada mais tarde.

A expulsão ocorre antes do seu hook de ligação

No percurso de código do servidor 2.6, a preparação inicial de um novo cliente remove as instâncias existentes com o mesmo nome quando a concorrência está desativada. Essa remoção acontece antes de a cadeia de gestores de ligação correr. Um script que deteta o duplicado e devolve falha recusa, portanto, o recém-chegado depois de a sessão em curso já ter sido expulsa, exatamente o resultado que a política pretendia evitar. A ordem das chamadas de retorno na implementação upstream é a única resposta fiável para a sua compilação.

StageWho can still refuseEffect on the incumbent
Certificate checkServer trust configurationNone
Authentication decisionThe authentication controllerNone, because establishment has not run
Connect handlerA profile scriptAlready evicted in the same-name case
Post-establishmentStatus tooling, monitoringBoth sessions already exist or one is gone

Consultar o ficheiro de estado também não é uma porta. Duas tentativas que cheguem juntas podem ambas ver uma vaga vazia antes de qualquer uma a confirmar, e ambas prosseguem.

Mova a decisão para a autenticação

A interface de gestão pode assumir a decisão de autenticação depois da verificação do certificado. Nessa disposição, o controlador não é um monitor: recebe cada instância de cliente que se liga e responde se essa instância pode prosseguir. Como a resposta chega antes do estabelecimento, uma recusa deixa a sessão em curso intacta. O mesmo canal comunica os cortes, e é assim que o controlador sabe que uma vaga foi libertada legitimamente.

Cada nova instância tem de passar por essa porta, incluindo reconexões e qualquer percurso que se reautentique sem pedido. Uma porta a que algumas instâncias nunca chegam não protege nada, e a omissão permanece invisível até alguém experimentar o atalho.

Os tokens podem passar ao lado da porta

Depois de um token ser emitido, o servidor pode validá-lo internamente e dispensar a autenticação externa para essa ligação. A chamada de gestão nunca acontece, pelo que uma verificação de vaga implementada apenas ali nunca vê a nova instância. Esse comportamento é uma comodidade para os utilizadores e um buraco numa política de concorrência. Faça com que as ligações autenticadas por token passem por uma verificação autoritativa equivalente, ou desative o percurso do token quando a política exigir uma decisão em cada ligação.

Não compense isso aceitando todos os tokens sem condições. Um token expirado ou inválido tem de falhar na mesma, e tem de falhar pelo mesmo ponto de decisão que tudo o resto.

Ligue a reserva a uma instância, não a um endereço

Um endereço é uma identidade fraca: uma reconexão do mesmo portátil pode chegar de outro endereço, e uma credencial copiada pode chegar do mesmo. Ligue a reserva à instância de cliente que o servidor atribui, para que uma reautenticação da instância já admitida seja reconhecida como proprietária. Um novo identificador de instância tem de adquirir a sua própria vaga através da decisão do primeiro a chegar, mesmo quando apresenta o mesmo token.

Liberte apenas a reserva pertencente à tentativa que falhou. Um evento de corte atrasado de uma tentativa mais antiga não pode limpar a vaga de um proprietário mais recente, e é por isso que a libertação nomeia a instância e não a conta. Após o reinício do controlador, reconcilie as sessões ativas antes de admitir alguém, e aplique a mesma regra em cada gateway que sirva a conta.

Decida em separado como é recuperada uma vaga realmente obsoleta. O administrador precisa de uma forma documentada de a limpar, e esse caminho não deve estar acessível a um utilizador que apenas clica em restabelecer.

Teste os pares que importam: dois logins quase simultâneos, uma reconexão após um encerramento limpo, uma reautenticação da sessão em curso, um recém-chegado recusado e um reinício do controlador. Em todos os casos a sessão em curso tem de permanecer utilizável e o recém-chegado tem de ser recusado sem danos colaterais para outras contas.

Artigos relacionados