Обработка перенаправлений SAML в запросах AJAX

У меня есть несколько приложений AngularJS, использующих Spring/Java и SAML 2.0 для единого входа (с использованием расширения Spring Security SAML). Мой поставщик идентификаторов SSO — OpenAM, и все работает очень хорошо. Однако я сталкиваюсь с ситуацией, когда пользователь выполняет глобальный выход из одного приложения, но у него открыты другие вкладки. Поскольку это одностраничные веб-приложения, многие функции могут по-прежнему использоваться на потерянных вкладках, ДО ТОГО, как пользователь не сделает что-то для вызова ajax-запроса. Конечно, эти запросы AJAX перехватываются фильтрами Spring Security SAML и запускают попытку аутентификации через ПЕРЕНАПРАВЛЕНИЕ на URL-адрес входа OpenAM. Конечно, это вызывает хаос в браузере, поскольку перенаправления на другой домен не разрешены для запросов AJAX. Кроме того, я ничего не могу сделать с перехватчиками Angular $http, поскольку запросы «отменяются», а в функции обратного вызова ошибки $http нет информации о качестве (например, удобный код состояния 401/403). Все, что я знаю, это то, что запрос не выполнен.

Я не хочу предполагать, что все плохие запросы $http связаны с проблемами аутентификации (и выполнить $window.location.reload()), поскольку могут быть законные причины сбоя. Я предпочитаю подавлять перенаправление Spring Security (на страницу входа в систему OpenAM) для запросов ajax и вместо этого отправлять обратно код состояния 401/403. Это позволило бы мне обработать ошибку в перехватчике $http и выполнить полную загрузку страницы, если это ошибка аутентификации, таким образом элегантно перенаправляя на страницу входа, как если бы они заходили на сайт в первый раз.

Любые идеи о том, как это сделать?


person Dan Hayes    schedule 25.09.2014    source источник


Ответы (2)


Компонент, отвечающий за инициализацию аутентификации и решение вернуть ошибку HTTP, выполнить перенаправление, ... является экземпляром AuthenticationEntryPoint. Чтобы изменить его поведение, вы можете:

  • настроить текущий SAMLEntryPoint (расширить метод commence) и переопределить поведение по умолчанию в случае, если запрос является вызовом AJAX из Angular, поэтому он возвращает ошибку HTTP вместо выполнения перенаправления на IDP
  • или определите другой элемент security:http в вашем контексте Spring (перед текущим), который охватывает только ваши запросы AJAX (например, с атрибутом pattern="/api/**") и использует точку входа, которая ведет себя так, как вы хотите (см. Http403ForbiddenEntryPoint)
person Vladimír Schäfer    schedule 26.09.2014
comment
Владимир...спасибо за ответ. Я обнаружил то же самое решение примерно в то время, когда вы ответили. Потребовалось немного покопаться, так как Spring Security настолько абстрактен (и я давно не копался в этом), но я, наконец, понял, что мне нужно было расширить SAMLEntryPoint. Теперь мой угловой перехватчик $http может правильно обрабатывать ответы 403 в браузере. Спасибо еще раз! - person Dan Hayes; 26.09.2014
comment
Ребята, спасибо за направление, для многих было бы очень полезно, если бы один из вас мог придумать образец учебника по github. Ваше здоровье. - person Himalay Majumdar; 21.11.2014
comment
@HimalayMajumdar и другие, пожалуйста, посмотрите решение, которое я нашел в блоге о том, что Владимир говорит в своей первой пуле. - person Michail Michailidis; 20.06.2019

Ссылаясь на возможную реализацию первой пули Владимира — взято из 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-вызова.

person Michail Michailidis    schedule 19.06.2019