Subdomínios compartilhados, duas entradas: quem vê quais registros?
O subdomínio escolhe a marca, a associação verificada escolhe os dados. Execute as mesmas verificações de inquilino quer a solicitação chegue de um endereço de escritório ou de uma VPN.
A Clínica A e a Clínica B compartilham uma base de código, dois subdomínios e uma mistura de visitantes do escritório e via VPN. As equipes de rede costumam configurar as duas entradas separadamente, e isso está bem, desde que a aplicação não o faça. As verificações abaixo pertencem à aplicação e devem se comportar de forma idêntica, independentemente da porta usada pela solicitação.
Primeiro: o nome do host apenas nomeia um inquilino
Resolva o nome do host solicitado contra um mapeamento mantido pelo administrador e rejeite qualquer coisa desconhecida. Use o valor de host validado pelo framework em vez do cabeçalho bruto, para que um Host forjado não possa injetar uma chave de consulta. Uma correspondência bem-sucedida diz ao código qual configuração de inquilino e qual marca carregar. Ela não diz nada sobre se o chamador pode ver os dados desse inquilino. Mantenha essa segunda pergunta em uma função separada com uma entrada separada.
Uma função auxiliar compartilhada que retorna tanto o contexto quanto a permissão a partir de uma única consulta de nome de host é o começo do defeito.
Segundo: a associação vem da sessão
Procure as associações ativas do usuário autenticado e compare-as com o inquilino da primeira verificação. Um usuário que pertence às duas clínicas pode alternar, mas a alternância deve ser uma ação explícita registrada no contexto da solicitação, não uma inferência da URL. Um usuário que pertence a uma clínica e solicita a outra é negado, inclusive para downloads e chamadas de API.
Teste o caso negativo editando um identificador de registro e um parâmetro de inquilino. Se qualquer uma das mudanças retornar dados, o escopo está sendo lido da solicitação e não da associação verificada.
O escopo dos cookies e o login único decidem onde uma conta pode ser apresentada. Eles não decidem o que essa conta pode ler.
Terceiro: a rede não prova nada sobre a pessoa
Um gateway VPN autentica um túnel, e uma lista de permissões pública autentica uma faixa de endereços. Nenhum dos dois identifica uma pessoa. O NAT agrupa muitos usuários em um único endereço de origem, e uma faixa de escritório faz o mesmo com todos no prédio. Trate ambos como fatos de transporte e mantenha a autorização na aplicação, ou em uma integração que afirme a identidade explicitamente e seja revisada como tal.
DNS é um terceiro fato de transporte. Uma resposta privada exige uma rota privada, e um front-end público exige um caminho de origem suportado. Nenhum deles carrega uma permissão.
Uma frase para a parede: a rede decide como uma solicitação chega, e a aplicação decide o que ela pode ler.
Quarto: execute a matriz nas duas entradas
Use contas controladas para exercitar A em A, B em B, A em B, um nome de host desconhecido e uma conta autenticada sem associações. A quarta e a quinta devem falhar fechadas e nunca recorrer a um inquilino padrão. Execute a mesma matriz também pela entrada VPN, com um pote de sessão por conta:
curl -s -o /dev/null -w '%{http_code}' -b jar.txt https://clinic-b.example.com/records/42
curl -s -o /dev/null -w '%{http_code}' -b jar.txt https://clinic-a.example.com/records/42
Depois altere uma entrada da lista de permissões e execute novamente. Um resultado que se move significa que um controle de rede está tomando uma decisão de autorização.
Repita a matriz após qualquer mudança no front-end, porque um segundo caminho de código que ignora a verificação é a forma mais comum de essa fronteira se erodir. O resultado esperado é entediante: cada entrada produz as mesmas respostas.