Spring Безопасность и миграция Google OpenID Connect
Вопросы:
1) Какой лучший способ интегрировать аутентификацию OpenID Connect в веб-приложение, использующее Spring Безопасность для аутентификации?
2) Есть ли какой-либо способ - либо из MITREid стороны, либо из стороны в аккаунтах Google - получить фильтр проверки подлинности MITREid OpenID Connect работать с сервисом Google OpenID Connect?
Я уверен, что ответы на эти вопросы будут полезны для любого разработчика, который использует модуль OpenID модуля Spring для аутентификации с Google.
Деталь:
Мой webapp использует Spring модуль безопасности OpenID (<openid-login .../>
) для аутентификации с учетными записями Google в качестве поставщика удостоверений. т.е. пользователи аутентифицируются с использованием своего адреса Google Apps или GMail.
В последнее время, когда пользователи аутентифицируются, они получают это предупреждение от учетных записей Google:
Важное замечание: OpenID2 для аккаунтов Google уходит в апреле 20, 2015 г.
Таким образом, Google отказывается от поддержки OpenID, полностью отключит его в апреле 2015 года и заявляет, что вы должны перейти на протокол OpenID Connect, если хотите выполнить аутентификацию с помощью учетных записей Google.
Я надеялся, что Spring У безопасности будет встроенная поддержка OpenID Connect, так же как и встроенная поддержка OpenID. например что-то вроде элемента <openid-connect-login .../>
. Но мои поиски не получили такой поддержки.
Лучшим кандидатом, который я нашел до сих пор, является MITREid Connect. Он включает в себя Spring фильтр проверки подлинности безопасности с именем OIDCAuthenticationFilter
для OpenID Connect. Проблема в том, что она не взаимодействует с реализацией Google OpenID Connect.
Я попробовал клонирование простого веб-приложения MITREid и настроил его для аутентификации (с помощью OpenID Connect) с учетными записями Google. Но это не сработало, потому что это зависит от nonce, которую не поддерживает реализация Google OpenID Connect. Сообщение об ошибке из аккаунтов Google:
Параметр, не разрешенный для этого типа сообщения: nonce
Далее я попытался подключить собственную реализацию интерфейса MITREid AuthRequestUrlBuilder
в конфигурацию MITREid. Единственная разница между моей реализацией и реализацией MITREid заключалась в том, что я не отправил nonce.
Не отправляя незапланированную реализацию Google OpenID Connect счастливой, но MITREid выбрал исключение, если не смог найти nonce в ответе проверки подлинности Google. Сообщение об ошибке:
Ошибка аутентификации: токен идентификатора не содержит требования nonce
Я отслеживал исключение MITREid до этих строк в MITREID OIDCAuthenticationFilter
:
// compare the nonce to our stored claim
String nonce = idClaims.getStringClaim("nonce");
if (Strings.isNullOrEmpty(nonce)) {
logger.error("ID token did not contain a nonce claim.");
throw new AuthenticationServiceException("ID token did not contain a nonce claim.");
}
Но мне не удастся расширить реализацию MITREid, чтобы игнорировать nonce. Так близко, но пока! Если учетные записи Google согласятся с тем, что nonce или MITREid могут быть настроены на игнорирование nonce, тогда у нас будет решение.
В списке проблем MITREid Connect в github я обнаружил, что другие сталкиваются с подобными проблемами:
1) # 726 - Документация по использованию клиента с Google в качестве поставщика проверки подлинности
2) # 704 - добавьте атрибут useNonce в ServerConfiguration, чтобы указать, принимает ли IdP значение nonce в свои запросы.
Итак, я застрял. Приезжайте в апреле 2015 г. Google завершит проверку подлинности Open ID.
Некоторые релевантные ссылки:
1) https://support.google.com/accounts/answer/6135882
2) https://www.tbray.org/ongoing/When/201x/2014/03/01/OpenID-Connect
3) https://github.com/mitreid-connect
4) https://github.com/mitreid-connect/OpenID-Connect-Java-Spring-Server/blob/master/openid-connect-client/src/main/java/org/mitre/openid/connect/client/OIDCAuthenticationFilter.java
5) https://github.com/mitreid-connect/simple-web-app
6) https://github.com/mitreid-connect/OpenID-Connect-Java-Spring-Server/blob/master/openid-connect-client/src/main/java/org/mitre/openid/connect/client/service/impl/PlainAuthRequestUrlBuilder.java
7) https://github.com/mitreid-connect/OpenID-Connect-Java-Spring-Server/issues/726
8) https://github.com/mitreid-connect/OpenID-Connect-Java-Spring-Server/pull/704
2015-02-18 Обновление
Функциональность недавно была добавлена в ветку разработки mitreid-connect для отключения nonce - поэтому делает OIDC-сервер Google счастливым. К счастью, mitreid-connect также предоставил некоторые рекомендации по взаимодействию с Google.
К сожалению, изменение "nonceEnabled" пока недоступно в Maven, но, надеюсь, это скоро изменится.
Ответы
Ответ 1
AFAIK, нет чистой и легкой Spring миграции безопасности с OpenID на аутентификацию OpenID Connect. Внедрение аутентификации OpenID с помощью Spring Безопасность выполняется с использованием хорошо документированного <openid-login/>
, но для OpenID Connect не существует аналога.
альтернатива MITREid все еще находится на ветке разработки и недоступна в Maven Central и, следовательно, не является кандидатом.
В комментариях Чак Мах указывает на Как реализовать OpenID-соединение и Spring Безопасность, где Romain F. предоставляет пример кода.
Образец кода Romain указал мне в правильном направлении. Это время заканчивается, я пошел с романтическим подходом, который должен был написать пользовательский Spring Security AuthenticationFilter, который использует spring -security-oauth2 для запроса oauth2 api конечная точка userinfo (для Google это https://www.googleapis.com/oauth2/v2/userinfo). Предполагается, что если мы сможем успешно запросить конечную точку userinfo, пользователь успешно завершит аутентификацию, чтобы мы могли доверять возвращенной информации - например, адрес электронной почты пользователя.
Когда я впервые начал изучать OpenID Connect, "центральным понятием стала" . Однако, просматривая исходный код spring -security-oauth2, он, похоже, игнорируется. Это приводит к вопросу, какова точка маркера ID, если мы можем аутентифицироваться без него (просто запросив конечную точку oauth2 userinfo)?
Минималистское решение, которое я бы предпочел, просто вернет проверенный токен ID. Не было бы необходимости запрашивать конечную точку userinfo. Но такого решения не существует в виде фильтра проверки подлинности Spring.
Мой webapp не был spring -boot-приложением, таким как romain. spring -boot делает много конфигурации за кулисами. Вот некоторые из проблем/решений, с которыми я столкнулся на этом пути:
-
проблема: статус HTTP 403 - ожидаемый токен CSRF не найден. Срок действия вашего сеанса истек?
- Решение: java config: httpSecurity.csrf(). disable()
-
проблема: статус HTTP 500 - ошибка при создании bean с именем 'scopedTarget.googleOAuth2RestTemplate': Scope 'session' неактивен для текущего потока;
- Решение: java config: OAuth2RestTemplate не обязательно должен быть областью сеанса (OAuth2ClientContext уже имеет сеанс и что все, что необходимо)
-
Проблема: HTTP Status 500 - Ошибка при создании bean с именем 'scopedTarget.oauth2ClientContext': Scope 'session' неактивен для текущего потока;
- solution: web.xml: добавить RequestContextListener
- : потому что доступ к oauth2ClientContext с сеансом bean осуществляется за пределами области Spring MVC DispatcherServlet (к нему обращаются из OpenIdConnectAuthenticationFilter, который является частью цепочки фильтров Spring).
<listener>
<listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
</listener>
-
Проблема: org.springframework.security.oauth2.client.resource.UserRedirectRequiredException: для получения одобрения пользователей требуется перенаправление.
- solution: web.xml: добавьте определение фильтра сразу. PRECEEDING springSecurityFilterChain
<filter>
<filter-name>oauth2ClientContextFilter</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>oauth2ClientContextFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
К сожалению, OpenID Connect не позволяет нам запрашивать область email
.
Когда наши пользователи прошли аутентификацию с помощью OpenID, они увидели бы экран согласия, например "webapp хотел бы просмотреть ваш адрес электронной почты", с которым им было удобно. Теперь мы должны запросить области openid email
, в результате чего появится экран согласия с просьбой предоставить нам общий доступ к нашему общедоступному профилю... который нам действительно не нужен или хочет... и пользователи менее удобны с этим экраном согласия.