Esse tutorial the guiará no processo de criação de um user impersonation a partir de super / admin usuários com spring security.

Introdução

É um caso de uso comum para aplicações seguras que um admin / super usuário seja capaz de fazer login como qualquer outro usuário. Isso pode ser muito útil em casos como análise de suporte ao cliente onde o analista pode acessar o sistema como o usuário real.

Uma possível solução para isso seria pedir a senha para o cliente ou então procurar por isso no banco de dados. Essa solução não é nada além de uma falha de segurança. Se o armazenamento de senhas é implementado correntamente deveria ser impossível recuperar a senha de um cliente.

Para resolver esse problema deveria ser possível para um super / admin usuário personificar qualquer outro usuário específico sem a necessidade da senha do usuário final. Com uma implementação de personificação de usuário o sistema sabe quem estava realmente autenticado e isso pode ser usado para rastrear as ações do super usuário se houver um log de auditoria.

Implementar uma funcionalidade de personificação de usuário é muito trabalhoso, por sorte essa funcionalidade está presente no spring security.

Conheça o SwitchUserFilter

SwitchUserFilter é um filtro responsável por fazer a troca de contexto dos usuários.

Do javadoc:

Esse filtro é similar ao Unix ‘su’ entretanto para aplicações web gerenciadas pelo Spring Security Um caso de uso comum para essa funcionalidade é a habilidade de permitir usuários com autoridades altas (ex: ROLE_ADMIN) trocar para um usuário comum (ex: ROLE_USER).

Esse filtro requer as seguintes propriedades:

Propriedade Descrição
switchUserUrl A URL de processamento para a personificação do usuário
switchFailureUrl A URL de redirecionamento caso a personificação falhe
targetUrl A URL de redirecionamento caso a personificação tenha sucesso
userDetailsService Uma referencia para o @Bean userDetailsService


@Bean
public SwitchUserFilter switchUserFilter() {
    SwitchUserFilter filter = new SwitchUserFilter();
    filter.setUserDetailsService(userDetailsService());
    filter.setSwitchUserUrl("/impersonate");
    filter.setSwitchFailureUrl("/switchUser");
    filter.setTargetUrl("/hello");
    return filter;
}

SwitchUserFilter Form

Agora nós precisamos definir um formulário HTML que será usado para fazer a troca dos usuários.

<form method="GET" th:action="@{/impersonate}" class="form">
    <label for="usernameField">User name:</label>
    <input type="text" name="username" id="usernameField" />
    <input type="submit" value="Switch User" />
</form>

Algumas observações:

  • O valor definido na action do formulário precisa ser o mesmo definido na propriedade SwitchUserFilter#switchUserUrl.
  • Isso pode ser um request do tipo GET.
  • O request é interceptado pelo filtro SwitchUserFilter.

Aplicando segurança ao formulário

É necessário fazer com que somente usuários ADMIN sejam capazes de acessar o formulário de personificação, caso contrário, qualquer usuário será capaz de personificar outro usuário sem a necessidade de uma senha.

Adicione o seguinte código na configuração do spring security.

http.authorizeRequests()
        .antMatchers("/switchUser").access("hasRole('ADMIN')");

Agora, se qualquer outro usuário tentar acessar o endpoint /switchUser, eles receberão uma resposta HTTP 403 Forbidden.

Quem realmente está logado?

Esse mecanismo troca totalmente o objecto Authentication no SecurityContext, isso quer dizer que se você olhar para as permissões e roles do usuário atual, você recebrá os valores do usuário personificado, não o usuário ADMIN.

Spring Security por padrão adiciona uma nova role ROLE_PREVIOUS_ADMINISTRATOR para o usuário personificado. Para facilitar a volta para o usuário ADMIN nós precisamos adicionar essa role para a configuração.

http.authorizeRequests()
        .antMatchers("/switchUser").access("hasAnyRole('ADMIN', 'ROLE_PREVIOUS_ADMINISTRATOR')");

Sumário

Parabéns! Você acabou de criar uma personificação de usuário usando spring security.

Nota de rodapé

  • O código utilizado nesse tutorial pode ser encontrado no GitHub