Обработка перенаправлений SAML в запросах AJAX
У меня есть несколько приложений AngularJS, использующих Spring/Java и SAML 2.0 для единого входа (используя расширение Spring Security SAML). Мой поставщик SSO-идентификаторов - OpenAM, и все работает довольно хорошо. Однако я сталкиваюсь с ситуацией, когда пользователь выполняет глобальный выход из одного приложения, но открывает другие вкладки. Так как это одностраничные веб-приложения, многие функции по-прежнему могут быть использованы на потерянных вкладках до тех пор, пока пользователь не сделает что-то для вызова ajax-запроса. Конечно, эти AJAX-запросы перехватываются фильтрами SAML Spring Security и запускают попытку аутентификации через REDIRECT на URL-адрес входа OpenAM. Конечно, это приводит к хаосу в браузере, так как перенаправления на другой домен не разрешены по запросам AJAX. Более того, я ничего не могу поделать с $http-перехватчиками Angular, так как запросы "отменены" и информация о качестве недоступна в функции обратного вызова $http (например, удобный код состояния 401/403). Все, что я знаю, это то, что запрос не прошел.
Я не хочу предполагать, что все плохие запросы $http происходят из-за проблем с аутентификацией (и делают $window.location.reload()), так как могут быть законные причины сбоя. Я предпочитаю подавлять перенаправление Spring Security (на страницу входа в OpenAM) для запросов ajax и вместо этого отправлять обратно код состояния 401/403. Это позволило бы мне обработать ошибку в перехватчике $http и выполнить полную загрузку страницы, если это ошибка аутентификации, таким образом, элегантно перенаправляя на страницу входа, как если бы они впервые заходили на сайт.
Есть идеи, как этого добиться?
1 ответ
Компонент, ответственный за инициализацию аутентификации и решение возвратить ошибку HTTP, выполнить перенаправление,... является экземпляром AuthenticationEntryPoint
, Чтобы изменить его поведение, вы можете:
- настроить текущий
SAMLEntryPoint
(расширитьcommence
метод) и переопределить поведение по умолчанию в случае, если запрос является вызовом AJAX из Angular, поэтому он возвращает ошибку HTTP вместо выполнения перенаправления в IDP - или определить другой
security:http
элемент в контексте Spring (до текущего), который охватывает только ваши запросы AJAX (например, с атрибутомpattern="/api/**"
) и использует точку входа, которая ведет себя так, как вы хотите (см.Http403ForbiddenEntryPoint
)
Относительно возможной реализации первой пули Владимира - взято из https://www.jasha.eu/blogposts/2015/10/saml-authentication-angularjs-spring-security.html
public class XhrSamlEntryPoint extends SAMLEntryPoint {
@Override
public void commence(HttpServletRequest request, HttpServletResponse response,
AuthenticationException e) throws IOException, ServletException {
if (isXmlHttpRequest(request) && e instanceof InsufficientAuthenticationException) {
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, e.getMessage());
return;
}
super.commence(request, response, e);
}
private boolean isXmlHttpRequest(HttpServletRequest request) {
return "XMLHttpRequest".equalsIgnoreCase(request.getHeader("X-Requested-With"));
}
}
Имейте в виду, что X-Requested-With не является обязательным заголовком, поэтому в соответствии с этим ответом обнаружение не является пуленепробиваемым. В моем случае, поскольку серверная часть использовалась с интерфейсом SPA, я полностью удалил проверку вызова ajax.