Обновление предметных / главных ролей во время выполнения в JSF2 - PullRequest
0 голосов
/ 20 февраля 2020

TL; DR: Можно ли обновить роли аутентифицированного пользователя во время выполнения без необходимости выхода из системы и входа в систему с помощью подсистемы undertow и JSF2

Проблема : В настоящее время я обновляю устаревшее приложение с jboss eap 6.4 до 7.2.5, одновременно перемещая его в контейнер docker.

Приложение использует JSF 2 / RichFaces 4.5.17 и из-за Временные ограничения Переработка в другой каркас на данный момент нежизнеспособна.

В EAP 6.4 было возможно использовать обходной путь, используя отражение, для обновления ролей текущего субъекта во время выполнения, без необходимо выйти и снова. Это именно то, что мне нужно, поскольку пользователь получает указанные c роли во время выполнения только на время сеанса, если была выполнена дополнительная проверка безопасности.

До обновления следующий код предоставлял необходимый результат :

FacesContext context = FacesContext.getCurrentInstance();
HttpServletRequest request = (HttpServletRequest) context.getExternalContext().getRequest();
try {
    Field f = request.getClass().getDeclaredField("request");
    f.setAccessible(true);
    Request realRequest = (Request) f.get(request); //org.apache.catalina.connector.Request

    GenericPrincipal p = (GenericPrincipal) realRequest.getPrincipal();
    f = GenericPrincipal.class.getDeclaredField("roles");
    f.setAccessible(true);
    String newRoles[] = { "Role 1", "Role 2" };
    f.set(p, newRoles);

С обновленной версией и измененными подсистемами в EAP этот код больше не работает. Адаптированный код также может изменить тему, но изменения вносятся слишком поздно или игнорируются, поскольку аутентификация не видит вновь добавленную роль.

    FacesContext context = FacesContext.getCurrentInstance();
    HttpServletRequest request = (HttpServletRequest) context.getExternalContext().getRequest();
    try {
        Field f = request.getClass().getDeclaredField("exchange");
        f.setAccessible(true);

        final HttpServerExchange serverExchange = (HttpServerExchange) f.get(request);
        final AuthenticatedSessionManager sessionManager = serverExchange
                .getAttachment(AuthenticatedSessionManager.ATTACHMENT_KEY);

        AuthenticatedSession authSession = sessionManager.lookupSession(serverExchange);

        final Account principal = authSession.getAccount();
        // final Account principal = serverExchange.getSecurityContext().getAuthenticatedAccount()

        final Field accountRolesField = principal.getClass().getDeclaredField("roles");
        accountRolesField.setAccessible(true);

        final Set<String> newRoles = Stream.of("Role 1", "Role 2")
                .collect(Collectors.toCollection(HashSet::new));

        accountRolesField.set(principal, newRoles);

Подсистема теперь использует Undertow, которая изменила реализации интерфейсов соответственно от каталины до откатки.

Я также заглянул в класс io.undertow.security.impl.CachedAuthenticatedSessionMechanism, так как он вызывается программой undertow для выполнения аутентификации и увидел, что полученный AuthenticatedSession не обновляется с ролями, которые я добавил в показанном фрагменте кода.

Добавление точек останова в этом классе показало, что мой код работает слишком поздно.

Однако я не могу переместить этот код в пользовательский фильтр, поскольку этот код необходимо вызывать при вводе правильного пароля для уже вошедшего в систему пользователя, поэтому мне необходим пользовательский интерфейс для его запуска. В зависимости от того, какая проверка была выполнена, для сеанса должна быть добавлена ​​другая роль.

...