В webapp, использующем зависимость pac4j для реализации поддержки единого входа, я столкнулся с проблемой.Проблема отмены авторизации аутентификации SSO с pac4j (несколько провайдеров)
Контекст:
- Java EE/JRE 1.7.0.79, Tomcat 7.0.70, org.springframework: весна: 3.2.16.RELEASE, org.springframework.security:spring-security-core:3.2 .9.RELEASE, org.pac4j: spring-security-pac4j: 1.4.1, org.pac4j: pac4j-oauth: 1.8.3, org.pac4j: pac4j-saml: 1.8.3
- Множественная сторонняя аутентификация провайдеры включены в конфигурацию webapp (например, Google OAuth и любой SAML), перенаправленные в UI в виде 2 кнопок на странице входа: «Войти в Google», «Войти с помощью my_SAML_provider_label»
Требования:
- Модернизация Java и/или Tomcat является опцией. Обновление весна и pac4j не
- Не следует использовать Spring аннотации инъекции, в любое время можно
выпуска конечного пользователя последовательность:
- 1/Нажмите "Вход с Google" (UserAgent перенаправляется аутентификации от Google страница)
- 2/Проверьте подлинность на странице Google с помощью внешнего пользователя, который будет или не будет соответствовать ни одному из ваших пользователей локального приложения после обратного вызова
- 3/Вернуться к локальной странице входа в систему webapp
- 4/Нажмите «Вход с my_SAML_provider_label» сейчас (UserAgent перенаправляются на страницу аутентификации провайдера)
- 5/Аутентифицировать правильно на странице третьей стороны, с внешним пользователем, который будет или не соответствует ни одному из ваших локальные пользователи приложения Upon обратного вызова
- 6/Утверждают следующее исключение в журналах: org.pac4j.oauth.profile.google2.Google2Profile не может быть приведен к org.pac4j.saml.profile.SAML2Profile
Выпуск StackTrace:
java.lang.ClassCastException: org.pac4j.oauth.profile.google2.Google2Profile cannot be cast to org.pac4j.saml.profile.SAML2Profile
at com.company.module.sso.SAMLAuthenticationService.retrieveAuthenticatedUser(SAMLAuthenticationService.java:59)
..
at org.apache.struts.action.RequestProcessor.processActionPerform(RequestProcessor.java:484)
at org.apache.struts.action.RequestProcessor.process(RequestProcessor.java:274)
at org.apache.struts.action.ActionServlet.process(ActionServlet.java:1482)
at org.apache.struts.action.ActionServlet.doGet(ActionServlet.java:507)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:624)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:731)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:303)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
at com.company.module.filters.ApplicationAvailabilityFilter.doFilter(ApplicationAvailabilityFilter.java:59)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
at com.company.module.filters.LogFilter.doFilter(LogFilter.java:57)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
at com.company.module.filters.ChronoFilter.doFilter(ChronoFilter.java:78)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
at com.company.module.filters.HibernateFilter.doFilter(HibernateFilter.java:53)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:118)
at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:84)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:113)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:103)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:113)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:154)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:45)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:199)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:110)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:50)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:106)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:87)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:192)
at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:160)
at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:343)
at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:260)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:218)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:122)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:505)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:169)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:103)
at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:956)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:116)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:442)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1082)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:623)
at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:318)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:745)
Связанные исходный код:
ApplicationContext-security.xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans
xmlns="http://www.springframework.org/schema/security"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-3.2.xsd">
..
<beans:bean id="clientFilter" class="org.pac4j.springframework.security.web.ClientAuthenticationFilter">
<beans:constructor-arg value="/outer-authentication"/>
<beans:property name="clients" ref="clients" />
<beans:property name="sessionAuthenticationStrategy" ref="sas" />
<beans:property name="authenticationManager" ref="authenticationManager" />
</beans:bean>
..
<beans:bean id="sas" class="org.springframework.security.web.authentication.session.SessionFixationProtectionStrategy" />
</beans:beans>
SAMLAuthenticationService.Java:
..
ClientAuthenticationToken token = null;
try {
token = (ClientAuthenticationToken) SecurityContextHolder.getContext().getAuthentication();
final SAML2Profile samlProfile = (SAML2Profile) token.getUserProfile(); // L59
..
} finally {
token.eraseCredentials(); // troubleshooting: not clearing credentials made no difference
}
..
Наблюдение:
- Тот же вопрос можно получить по первой попытке входа через провайдера SAML, а затем через один Google: порядка пользователя последовательности кажется неактуальной
- A Обходной путь - остановить Tomcat, очистить его рабочий каталог, а затем перезапустить его.
- В любом случае, нужно дождаться, когда начальный токен аутентификации (вызванный/полученный от провайдера 1) истечет (истечение срока задержки установлено на 1 час через конфигурацию ввода/вывода pac4j)
- выпуск будет ударяться снова, как только неисправное последовательность выполняется снова конечным пользователем
Guess:
- , связанные с ненадлежащей отзывом маркера аутентификации предыдущей аутентификации SSO (callbacked/получен от поставщика 1), прежде чем пытаться прочитать токен аутентификации текущего процесса аутентификации (обратный вызов/полученный от провайдера 2)
- Косвенно из-за неправильного использования org.springframework.security.web.authentication.session. SessionAuthenticationStr ategy (моя реализация в конфигурации XML Spring Security кажется стандартным/по умолчанию)
Благодаря