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 не обновляется с ролями, которые я добавил в показанном фрагменте кода.
Добавление точек останова в этом классе показало, что мой код работает слишком поздно.
Однако я не могу переместить этот код в пользовательский фильтр, поскольку этот код необходимо вызывать при вводе правильного пароля для уже вошедшего в систему пользователя, поэтому мне необходим пользовательский интерфейс для его запуска. В зависимости от того, какая проверка была выполнена, для сеанса должна быть добавлена другая роль.