Как получить доступ к зарегистрированному принципалу из HttpSessionListener с Java EE Security? - PullRequest
0 голосов
/ 02 июля 2019

У меня есть приложение с @CustomFormAuthenticationMechanismDefinition, и я хотел бы регистрировать имя пользователя, идентификатор сеанса, IP-адрес и т. Д. Как при входе, так и при выходе. HttpAuthMechanism, который применяется с этой аннотацией, связывает данный сеанс с принципалом, к которому я могу получить доступ через SecurityContext. С прямым выходом из системы у меня нет проблем с журналированием, но я также хотел бы войти, когда время сеанса истекло. Поэтому я создал HttpSessionListener и в его методе sessionDestroyed() я пытаюсь получить доступ к вошедшему в систему пользователю через SecurityContext, но он возвращает пустой набор, возможно, из-за того, что securityContext уже признан недействительным.

Одно из решений, которое я имею в виду, - сохранить принципала пользователя в параметре сеанса (что, вероятно, происходит в реализации HttpAuthMechanism) и получить к нему доступ от объекта HttpSessionEvent, но это не похоже на самое чистое решение. Есть ли другой слушатель, который я могу использовать, или какое-то другое решение?

1 Ответ

0 голосов
/ 04 июля 2019

Я пошел с пользовательским механизмом HttpAuthenticationMechanism, вот он, если кому-то понадобится (хотя я был бы более чем рад получить некоторые отзывы о том, есть ли у него недостатки безопасности или улучшения) .

В классе @ApplicationScoped, реализующем HttpAuthenticationMechanism:

@Override
public AuthenticationStatus validateRequest(HttpServletRequest request, HttpServletResponse response, HttpMessageContext httpMessageContext) throws AuthenticationException {
    if (!httpMessageContext.isProtected()) {
        return httpMessageContext.doNothing();
    }
    HttpSession session = request.getSession(false);

    Credential credential = httpMessageContext.getAuthParameters().getCredential();

    // If we already have a session, we get the user from it, unless it's a new login
    if (session != null && !(credential instanceof UsernamePasswordCredential)) {  
        User user = (User) session.getAttribute("user");
        if (user != null) {
            return httpMessageContext.notifyContainerAboutLogin(user, user.getRoles());
        }
    }

    // If we either don't have a session or it has no user attribute, we redirect/forward to login page
    if (!(credential instanceof UsernamePasswordCredential)) {
        return redirect(request, response, httpMessageContext);
    }

    // Here we have a Credential, so we validate it with the registered IdentityStoreHandler (injected as idStoreHandler)
    CredentialValidationResult validate = idStoreHandler.validate(credential);

    Context context = new Context();
    context.setIp(request.getRemoteAddr());

    if (validate.getStatus() == CredentialValidationResult.Status.VALID) {
        session = request.getSession(true);
        CallerPrincipal callerPrincipal = validate.getCallerPrincipal();
        session.setAttribute("user", callerPrincipal);


        context.setUser(callerPrincipal);
        context.setSessionId(session.getId());

        Logger log = new Logger(logger, "validateRequest", context);

        log.debug("Logged in user: " + callerPrincipal.getName());

        String redirectPage = "whatYouWant.xhtml";

        redirect(request, response, httpMessageContext, redirectPage);

        return httpMessageContext.notifyContainerAboutLogin(validate);
    } else if (validate.getStatus() == CredentialValidationResult.Status.NOT_VALIDATED) {
        return redirect(request, response, httpMessageContext);
    } else {
        // Logging
        return httpMessageContext.responseUnauthorized();
    }
}

И в реализованном HttpSessionListener:

 @Override
public void sessionDestroyed(HttpSessionEvent se) {
    User user = (User) se.getSession().getAttribute("user");

    if (user != null) {
        // logging
    }
}
...