Spring Security OAuth 2 — Обновление сервера авторизации с 0.1.0 до 0.1.1 / 0.1.2 приводит к тому, что примеры проектов не работают

#spring-boot #spring-security #spring-security-oauth2

Вопрос:

Я хочу использовать новое Spring Security Authorization Server для реализации OAuth2 для моего веб-сервиса.

В https://www.baeldung.com/spring-security-oauth-auth-server приведен пример, разделение

  • Авторизовать Сервер
  • Сервер ресурсов
  • Клиент

Код можно найти по адресу https://github.com/Baeldung/spring-security-oauth/tree/master/oauth-authorization-server

Эти три проекта Maven функционируют в данной версии, когда клиент в веб-браузере получает доступ http://localhost:8080/articles вывод выполнен правильно

 ["Article 1","Article 2","Article 3"]
 

Я попытался обновить Authorization Server проект до 0.1.1 , но, хотя он компилируется и запускается, когда клиент получает доступ http://localhost:8080/articles Я получаю

 Whitelabel Error Page

This application has no explicit mapping for /error, so you are seeing this as a fallback.
Sat Aug 07 15:57:26 CEST 2021
There was an unexpected error (type=None, status=999).
 

Я подумал, что это потому , что мне нужно обновить также другие версии во всех трех проектах, до Spring Boot 2.5.3 и также OpenJDK 16 , но та же ошибка.

Я обновил 0.1.2 и изменил уровень журнала на DEBUG , это отображается при запуске проекта сервера авторизации:

     ...
2021-08-09 17:54:45.876 DEBUG 16256 --- [           main] o.s.b.f.s.DefaultListableBeanFactory     : Creating shared instance of singleton bean 'org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryConfiguration$EmbeddedTomcat'
    2021-08-09 17:54:46.015 DEBUG 16256 --- [           main] o.a.catalina.core.AprLifecycleListener   : The Apache Tomcat Native library could not be found using names [tcnative-1, libtcnative-1] on the java.library.path [/usr/java/packages/lib:/usr/lib64:/lib64:/lib:/usr/lib]. The errors reported were [Can't load library: /home/myself/PROJECTs/SPRING/spring-authorization-server/bin/libtcnative-1.so, Can't load library: /home/myself/PROJECTs/SPRING/spring-authorization-server/bin/liblibtcnative-1.so, no tcnative-1 in java.library.path: /usr/java/packages/lib:/usr/lib64:/lib64:/lib:/usr/lib, no libtcnative-1 in java.library.path: /usr/java/packages/lib:/usr/lib64:/lib64:/lib:/usr/lib]
    
    org.apache.tomcat.jni.LibraryNotFoundError: Can't load library: /home/myself/PROJECTs/SPRING/spring-authorization-server/bin/libtcnative-1.so, Can't load library: /home/myself/PROJECTs/SPRING/spring-authorization-server/bin/liblibtcnative-1.so, no tcnative-1 in java.library.path: /usr/java/packages/lib:/usr/lib64:/lib64:/lib:/usr/lib, no libtcnative-1 in java.library.path: /usr/java/packages/lib:/usr/lib64:/lib64:/lib:/usr/lib
        at org.apache.tomcat.jni.Library.<init>(Library.java:101) ~[tomcat-embed-core-9.0.50.jar:9.0.50]
        at org.apache.tomcat.jni.Library.initialize(Library.java:211) ~[tomcat-embed-core-9.0.50.jar:9.0.50]
        at org.apache.catalina.core.AprLifecycleListener.init(AprLifecycleListener.java:192) ~[tomcat-embed-core-9.0.50.jar:9.0.50]
        at org.apache.catalina.core.AprLifecycleListener.isAprAvailable(AprLifecycleListener.java:101) ~[tomcat-embed-core-9.0.50.jar:9.0.50]
        at org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory.getDefaultLifecycleListeners(TomcatServletWebServerFactory.java:173) ~[spring-boot-2.5.3.jar:2.5.3]
        at org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory.<init>(TomcatServletWebServerFactory.java:120) ~[spring-boot-2.5.3.jar:2.5.3]
        at org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryConfiguration$EmbeddedTomcat.tomcatServletWebServerFactory(ServletWebServerFactoryConfiguration.java:76) ~[spring-boot-autoconfigure-2.5.3.jar:2.5.3]
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:78) ~[na:na]
        at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
        at java.base/java.lang.reflect.Method.invoke(Method.java:567) ~[na:na]
        at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:154) ~[spring-beans-5.3.9.jar:5.3.9]
        at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:653) ~[spring-beans-5.3.9.jar:5.3.9]
        at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:638) ~[spring-beans-5.3.9.jar:5.3.9]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1334) ~[spring-beans-5.3.9.jar:5.3.9]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1177) ~[spring-beans-5.3.9.jar:5.3.9]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:564) ~[spring-beans-5.3.9.jar:5.3.9]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:524) ~[spring-beans-5.3.9.jar:5.3.9]
        at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:335) ~[spring-beans-5.3.9.jar:5.3.9]
        at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) ~[spring-beans-5.3.9.jar:5.3.9]
        at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:333) ~[spring-beans-5.3.9.jar:5.3.9]
        at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:213) ~[spring-beans-5.3.9.jar:5.3.9]
        at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.getWebServerFactory(ServletWebServerApplicationContext.java:217) ~[spring-boot-2.5.3.jar:2.5.3]
        at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.createWebServer(ServletWebServerApplicationContext.java:180) ~[spring-boot-2.5.3.jar:2.5.3]
        at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.onRefresh(ServletWebServerApplicationContext.java:160) ~[spring-boot-2.5.3.jar:2.5.3]
        at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:577) ~[spring-context-5.3.9.jar:5.3.9]
        at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:145) ~[spring-boot-2.5.3.jar:2.5.3]
        at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:754) ~[spring-boot-2.5.3.jar:2.5.3]
        at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:434) ~[spring-boot-2.5.3.jar:2.5.3]
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:338) ~[spring-boot-2.5.3.jar:2.5.3]
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:1343) ~[spring-boot-2.5.3.jar:2.5.3]
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:1332) ~[spring-boot-2.5.3.jar:2.5.3]
        at com.baeldung.OAuth2AuthorizationServerApplication.main(OAuth2AuthorizationServerApplication.java:10) ~[classes/:na]
...
 

Похоже, то же самое происходит и с 0.1.1

Мой pom.xml

 <project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.baeldung</groupId>
    <artifactId>spring-authorization-server</artifactId>
    <version>0.1.0-SNAPSHOT</version>
    <packaging>jar</packaging>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.5.3</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.security.experimental</groupId>
            <artifactId>spring-security-oauth2-authorization-server</artifactId>
            <version>0.1.2</version>
        </dependency>
    </dependencies>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <java.version>16</java.version>
    </properties>
</project>
 

Изменение только версии сервера авторизации в pom.xml, 0.1.0 или 0.1.1 или 0.1.2 предоставляют все одно и то же исключение.

Пример проекта из Baeldung запускается только (доставляет статьи с локального хоста:8080/статьи) с 0.1.0, но с 0.1.1 и 0.1.2 я получаю описанную страницу с белой ошибкой.

Комментарии:

1. 0.1.2 доступен, но та же ошибка.

Ответ №1:

Во-первых, я бы рекомендовал вам ознакомиться с образцами в самом проекте spring-authorization-server (см., например, Эту строку), что позволит вам быть в курсе быстрых изменений, происходящих в проекте, поскольку эти учебные пособия в Интернете будут быстро устаревать.

Во-вторых, я считаю, что 2-я ошибка в отладке не связана с этой проблемой, так что это похоже на проблему локальной установки, но я не уверен на 100%.

В-третьих, первая ошибка происходит в более новых версиях SAS из-за #243. Изменение включало включение рекомендаций OAuth 2.1, раздел 9.7.1, в котором говорится:

При перенаправлении URI с помощью localhost (т. е. «http://localhost:{порт}/{путь}») функция аналогично перенаправлениям IP-адресов с обратной связью, описанным в разделе 10.3.3, использование «локального хоста» НЕ РЕКОМЕНДУЕТСЯ. Указание URI перенаправления с помощью литерала IP-адреса обратной связи, а не «localhost», позволяет избежать непреднамеренного прослушивания сетевых интерфейсов, отличных от интерфейса обратной связи. Он также менее восприимчив к брандмауэрам на стороне клиента и неправильному разрешению имен хостов на устройстве пользователя.

Эта ошибка появляется только при перенаправлении обратно в клиентское приложение, когда URI перенаправления содержит множество localhost . Если вы включите ведение журнала трассировки на сервере авторизации (например logging.level.org.springframework.security=trace ), вы увидите успешную аутентификацию, за которой последует перенаправление на страницу с ошибкой, что-то вроде:

 ...
2021-08-10 11:10:41.596 DEBUG 90071 --- [io-9000-exec-10] w.a.UsernamePasswordAuthenticationFilter : Set SecurityContextHolder to UsernamePasswordAuthenticationToken [Principal=org.springframework.security.core.userdetails.User [Username=user, Password=[PROTECTED], Enabled=true, AccountNonExpired=true, credentialsNonExpired=true, AccountNonLocked=true, Granted Authorities=[ROLE_PILOT]], Credentials=[PROTECTED], Authenticated=true, Details=WebAuthenticationDetails [RemoteIpAddress=127.0.0.1, SessionId=3786957448CCBB82DAE6AB29DBCA5D2C], Granted Authorities=[ROLE_USER]]
2021-08-10 11:10:41.596 DEBUG 90071 --- [io-9000-exec-10] o.s.s.web.DefaultRedirectStrategy        : Redirecting to http://auth-server:9000/error?response_type=codeamp;client_id=messaging-clientamp;scope=openidamp;state=Vg-fUjLSdOjAG_4Y9LcjcxxYTGhd33Trbaclp92XoDQ=amp;redirect_uri=http://localhost:8080/login/oauth2/code/messaging-clientamp;nonce=s8hJD_zDopreLImNeRwQ3fslL4yFNySjbt6MiYK1mPw
...
 

Это говорит мне о том, что что-то произошло раньше в потоке, и мы только сейчас испытываем симптом. Если вы посмотрите выше в журналах, перед входом в систему, вы увидите что-то вроде этого:

 ...
2021-08-10 11:10:37.444 TRACE 90071 --- [nio-9000-exec-8] o.s.security.web.FilterChainProxy        : Invoking OAuth2AuthorizationEndpointFilter (6/24)
2021-08-10 11:10:37.444 TRACE 90071 --- [nio-9000-exec-8] o.s.s.authentication.ProviderManager     : Authenticating request with OAuth2AuthorizationCodeRequestAuthenticationProvider (1/10)
2021-08-10 11:10:37.445 TRACE 90071 --- [nio-9000-exec-8] o.s.s.w.header.writers.HstsHeaderWriter  : Not injecting HSTS header since it did not match request to [Is Secure]
2021-08-10 11:10:37.445 DEBUG 90071 --- [nio-9000-exec-8] w.c.HttpSessionSecurityContextRepository : Did not store empty SecurityContext
2021-08-10 11:10:37.445 DEBUG 90071 --- [nio-9000-exec-8] w.c.HttpSessionSecurityContextRepository : Did not store empty SecurityContext
2021-08-10 11:10:37.445 DEBUG 90071 --- [nio-9000-exec-8] s.s.w.c.SecurityContextPersistenceFilter : Cleared SecurityContextHolder to complete request
2021-08-10 11:10:37.447 TRACE 90071 --- [nio-9000-exec-8] o.s.security.web.FilterChainProxy        : Trying to match request against DefaultSecurityFilterChain [RequestMatcher=org.springframework.security.config.annotation.web.configurers.oauth2.server.authorization.OAuth2AuthorizationServerConfigurer$Lambda$603/0x000000080041a040@4dd90166, Filters=[org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter@52227eb2, org.springframework.security.web.context.SecurityContextPersistenceFilter@21263314, org.springframework.security.web.header.HeaderWriterFilter@4d84049a, org.springframework.security.web.csrf.CsrfFilter@1d8b0500, org.springframework.security.web.authentication.logout.LogoutFilter@6413d7e7, org.springframework.security.oauth2.server.authorization.web.OAuth2AuthorizationEndpointFilter@32d5279, org.springframework.security.oauth2.server.authorization.oidc.web.OidcProviderConfigurationEndpointFilter@fe87ddd, org.springframework.security.oauth2.server.authorization.web.OAuth2AuthorizationServerMetadataEndpointFilter@448b808a, org.springframework.security.oauth2.server.authorization.web.NimbusJwkSetEndpointFilter@ebda593, org.springframework.security.oauth2.server.authorization.web.OAuth2ClientAuthenticationFilter@22d322f5, org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter@4337afd, org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter@d16be4f, org.springframework.security.web.authentication.ui.DefaultLogoutPageGeneratingFilter@5ad1904f, org.springframework.security.oauth2.server.resource.web.BearerTokenAuthenticationFilter@60e06f7d, org.springframework.security.web.savedrequest.RequestCacheAwareFilter@4a92c6a9, org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter@64c781a9, org.springframework.security.web.authentication.AnonymousAuthenticationFilter@a146b11, org.springframework.security.web.session.SessionManagementFilter@642857e0, org.springframework.security.web.access.ExceptionTranslationFilter@30c3ae63, org.springframework.security.web.access.intercept.FilterSecurityInterceptor@550e9be6, org.springframework.security.oauth2.server.authorization.web.OAuth2TokenEndpointFilter@32ec9c90, org.springframework.security.oauth2.server.authorization.web.OAuth2TokenIntrospectionEndpointFilter@456bcb74, org.springframework.security.oauth2.server.authorization.web.OAuth2TokenRevocationEndpointFilter@3b332962, org.springframework.security.oauth2.server.authorization.oidc.web.OidcClientRegistrationEndpointFilter@58a2d9f9]] (1/2)
2021-08-10 11:10:37.447 TRACE 90071 --- [nio-9000-exec-8] o.s.security.web.FilterChainProxy        : Trying to match request against DefaultSecurityFilterChain [RequestMatcher=any request, Filters=[org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter@1b01a0d, org.springframework.security.web.context.SecurityContextPersistenceFilter@91f565d, org.springframework.security.web.header.HeaderWriterFilter@67b355c8, org.springframework.security.web.csrf.CsrfFilter@79f90a3a, org.springframework.security.web.authentication.logout.LogoutFilter@414f87a9, org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter@6e31d989, org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter@1ddc6db2, org.springframework.security.web.authentication.ui.DefaultLogoutPageGeneratingFilter@2ed71727, org.springframework.security.web.savedrequest.RequestCacheAwareFilter@46e3559f, org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter@3b83459e, org.springframework.security.web.authentication.AnonymousAuthenticationFilter@5261ec9, org.springframework.security.web.session.SessionManagementFilter@388623ad, org.springframework.security.web.access.ExceptionTranslationFilter@22bdb1d0, org.springframework.security.web.access.intercept.FilterSecurityInterceptor@416d56f2]] (2/2)
2021-08-10 11:10:37.447 DEBUG 90071 --- [nio-9000-exec-8] o.s.security.web.FilterChainProxy        : Securing GET /error?response_type=codeamp;client_id=messaging-clientamp;scope=openidamp;state=Vg-fUjLSdOjAG_4Y9LcjcxxYTGhd33Trbaclp92XoDQ=amp;redirect_uri=http://localhost:8080/login/oauth2/code/messaging-clientamp;nonce=s8hJD_zDopreLImNeRwQ3fslL4yFNySjbt6MiYK1mPw
...
 

Таким образом, ошибка действительно происходит , OAuth2AuthorizationEndpointFilter и перенаправление ошибки сохраняется в качестве целевого URL-адреса после аутентификации , затем мы перенаправляемся на /login , а после аутентификации перенаправляемся обратно /error , что создает страницу с ошибкой с белой меткой.

Краткосрочное исправление состояло бы в том, чтобы убедиться , что вы используете 127.0.0.1 для своего клиентского приложения, вместо localhost того, чтобы, в том числе, изменять URI перенаправления на сервере авторизации (см. Пример). Но если вы забудете и запустите свой браузер по адресу http://localhost:8080 , вы все равно получите эту ошибку. Пока вы можете обойти это с помощью фильтра в своем клиентском приложении, подобного этому:

 /**
 * This filter ensures that the loopback IP <code>127.0.0.1</code> is used to access the
 * application so that the sample works correctly, due to the fact that redirect URIs with
 * "localhost" are rejected by the Spring Authorization Server, because the OAuth 2.1
 * draft specification states:
 *
 * <pre>
 *     While redirect URIs using localhost (i.e.,
 *     "http://localhost:{port}/{path}") function similarly to loopback IP
 *     redirects described in Section 10.3.3, the use of "localhost" is NOT
 *     RECOMMENDED.
 * </pre>
 *
 * @see <a href=
 * "https://datatracker.ietf.org/doc/html/draft-ietf-oauth-v2-1-01#section-9.7.1">Loopback Redirect
 * Considerations in Native Apps</a>
 */
@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
public class LoopbackIpRedirectFilter extends OncePerRequestFilter {

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
            throws ServletException, IOException {
        if (request.getServerName().equals("localhost")) {
            UriComponents uri = UriComponentsBuilder.fromHttpRequest(new ServletServerHttpRequest(request))
                    .host("127.0.0.1").build();
            response.sendRedirect(uri.toUriString());
            return;
        }
        filterChain.doFilter(request, response);
    }

}
 

Я бы посоветовал вам открыть проблему, чтобы запросить улучшение способа обработки этой ошибки. И если вам интересно, мы хотели бы обсудить это с вами и привлечь вас к участию в проекте, чтобы помочь решить эту проблему.

Комментарии:

1. Стив, спасибо за усилия. Я не понял всего, что вы сказали, но я заменил «localhost» на «127.0.0.1» везде в 3 проектах Baeldung, и это повело себя еще хуже. Я больше не получал страницу входа в систему.

2. Я надеюсь, что команда Белдунга проверит и обновит свои образцы. Тем временем я пробую официальные образцы.

3. Примите этот ответ, если вы почувствовали, что он вам помог

4. @Toerktumlare разве ты не читал мой комментарий? Это не помогло. И я не буду продолжать попытки с проектами Баельдунга, пока они сами не проверят, что не так.

5. Я не могу отдать должное ответу, который в моем случае не решил проблему. Как принять ответ, который я не мог одобрить? Я последовал его рекомендации попробовать официальные образцы.

Ответ №2:

Я тоже столкнулся с той же проблемой. после четырех-пяти дней борьбы я нашел решение. Во всех примерах uri эмитента является http://auth-server:9000

я только что добавил в файл etc/hosts следующую запись

127.0.0.1 аутентификационный сервер

это решило проблему

Комментарии:

1. Я хочу использовать IP-адрес, а не что-то вроде «auth-сервера», так что я не хочу изменять файл хоста. Я не могу следить за этим прямо сейчас, так как мне пришлось принять решение о рабочем промежуточном решении с Keycloak, но позже я могу вернуться к использованию сервера аутентификации Spring Security.