[英]Error 500 while using bearer token with Spring boot + Keycloak
This is my first Keycloack integration with a SpringBoot + Spring Security app, and i found myself in a problem.这是我第一次与 SpringBoot + Spring 安全应用程序集成 Keycloack,我发现自己遇到了问题。 I am using the Keycloak Spring Security Adapter, but something is missing since an error 500 is shown instead of authorizing the request by bearer_token.
我正在使用 Keycloak Spring 安全适配器,但由于显示错误 500 而不是通过 bearer_token 授权请求,因此缺少某些内容。 When i don't send the token, an authorization problem presents which makes sense (401 Unauthorized), but when i do insert a token an error 500 is presented.
当我不发送令牌时,会出现授权问题,这是有意义的(401 Unauthorized),但是当我插入令牌时,会出现错误 500。 This happens however with endpoint that specify @RolesAllowed(), since those that doesn't have it can be fetch just fine.
然而,这发生在指定 @RolesAllowed() 的端点上,因为那些没有它的端点可以很好地获取。
Something you might notice is that for this kind of services is that usually the Access Type would be bearer-only , but for this instance is public .您可能会注意到,对于这种服务,访问类型通常是bearer-only ,但对于这种情况是public 。 For this project is necessary unless there's no other choice to this and bearer-only is the only way.
因为这个项目是必要的,除非没有其他选择,并且仅承载是唯一的方法。
General information一般信息
Keycloak:
- Running at port 3000
- Version 18.0.0
Springboot:
- Running at port 8080
- Version 2.7.1
Realm:
- Name:
* TRP (all uppercase)
Client:
- Client ID: <clientName>
- Access type: Public
- Standard Flow Enabled and Direct Access Grants Enabled enabled
- Valid Redirect URIs: http://localhost:8080/*
- Base URL: http://localhost:3000/
- Admin URL: http://localhost:3000/
- Web Origins: *
- Roles:
* extern-user(Users in role: *<user001>*)
Roles:
- app-user
* Composite Roles enabled
* Client Roles (Associated Roles:extern-user)
application.properties应用程序属性
server.port=8080
keycloak.auth-server-url = http://localhost:3000/
keycloak.realm = <realmName>
keycloak.resource = <clientName>
keycloak.ssl-required = external
keycloak.use-resource-role-mappings = true
keycloak.bearer-only = true
keycloak.public-client = true
pom.xml pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.1</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.package</groupId>
<artifactId>TRP</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>name</name>
<properties>
<java.version>17</java.version>
<keycloak.version>18.0.0</keycloak.version>
</properties>
<dependencies>
<!-- Agregado con Springboot Initializr -->
<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.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- Agregado para este proyecto -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-spring-boot-starter</artifactId>
<version>${keycloak.version}</version>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-spring-security-adapter</artifactId>
<version>${keycloak.version}</version>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.keycloak.bom</groupId>
<artifactId>keycloak-adapter-bom</artifactId>
<version>${keycloak.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
KeycloakSecurityConfig.java KeycloakSecurityConfig.java
package com.package.realm.config;
import org.keycloak.adapters.KeycloakConfigResolver;
import org.keycloak.adapters.springboot.KeycloakSpringBootProperties;
import org.keycloak.adapters.springsecurity.KeycloakConfiguration;
import org.keycloak.adapters.springsecurity.authentication.KeycloakAuthenticationProvider;
import org.keycloak.adapters.springsecurity.config.KeycloakWebSecurityConfigurerAdapter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.web.servlet.ServletListenerRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Primary;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.core.authority.mapping.SimpleAuthorityMapper;
import org.springframework.security.web.authentication.session.RegisterSessionAuthenticationStrategy;
import org.springframework.security.core.session.SessionRegistryImpl;
import org.springframework.security.web.authentication.session.SessionAuthenticationStrategy;
import org.springframework.security.web.session.HttpSessionEventPublisher;
@KeycloakConfiguration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true, jsr250Enabled = true)
public class KeycloakSecurityConfig extends KeycloakWebSecurityConfigurerAdapter {
// Registra el keycloakAuthenticationProvider con el administrador de autenticación
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception{
KeycloakAuthenticationProvider provider = new KeycloakAuthenticationProvider();
provider.setGrantedAuthoritiesMapper(new SimpleAuthorityMapper());
auth.authenticationProvider(provider);
}
// Define la estrategia de autenticación
@Bean
@Override
protected SessionAuthenticationStrategy sessionAuthenticationStrategy(){
return new RegisterSessionAuthenticationStrategy(new SessionRegistryImpl());
}
// Define desde donde se integran las propiedades de Keycloak
@Bean
@Primary
public KeycloakConfigResolver keycloakConfigResolver(KeycloakSpringBootProperties properties) {
System.out.println("\n"
+ "\nAuthentication server:" + properties.getAuthServerUrl()
+ "\nRealm:" + properties.getRealm()
+ "\nClient: " + properties.getResource()
+ "\n");
return new MyKeycloakSpringBootConfigResolver(properties);
}
@Bean
public ServletListenerRegistrationBean<HttpSessionEventPublisher> httpSessionEventPublisher() {
return new ServletListenerRegistrationBean<HttpSessionEventPublisher>(new HttpSessionEventPublisher());
}
@Override
protected void configure(HttpSecurity http) throws Exception
{
super.configure(http);
http.authorizeRequests()
.anyRequest().permitAll();
http.csrf().disable(); //Con tokens no hay problemas de ataques de Cross Reference
}
}
MyKeycloakSpringBootConfigResolver (class to resolve bean circular reference) MyKeycloakSpringBootConfigResolver (解析bean循环引用的类)
package com.package.realm.config;
import org.keycloak.adapters.KeycloakDeployment;
import org.keycloak.adapters.KeycloakDeploymentBuilder;
import org.keycloak.adapters.spi.HttpFacade;
import org.keycloak.adapters.springboot.KeycloakSpringBootConfigResolver;
import org.keycloak.adapters.springboot.KeycloakSpringBootProperties;
import org.springframework.context.annotation.Configuration;
/*
* Por defecto, el adaptador Spring Security busca por un archivo de configuración keycloak.json.
Podemos asegurarnos que busque por la configuración otorgada por el adaptador para Spring boot
al agregar este bean indicando que aca se encuentran las variables de configuración para acceder
a KeyCloak
*/
@Configuration
public class MyKeycloakSpringBootConfigResolver extends KeycloakSpringBootConfigResolver {
private final KeycloakDeployment keycloakDeployment;
public MyKeycloakSpringBootConfigResolver(KeycloakSpringBootProperties properties) {
keycloakDeployment = KeycloakDeploymentBuilder.build(properties);
}
@Override
public KeycloakDeployment resolve(HttpFacade.Request facade) {
return keycloakDeployment;
}
}
TestController.java测试控制器.java
package com.package.realm.controller;
import javax.annotation.security.RolesAllowed;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/test")
public class TestController {
@RolesAllowed("extern-user") //This creates problem
@RequestMapping(value = "/user", method = RequestMethod.GET)
public ResponseEntity<String> getUser() {
return ResponseEntity.ok("Hola usuario");
}
@RequestMapping(value = "/admin", method = RequestMethod.GET)
public ResponseEntity<String> getAdmin() {
return ResponseEntity.ok("Hola administrador");
}
}
Here's an image with every outcome.这是每个结果的图像。 Text
文本
The error stack错误堆栈
2022-07-07 17:56:42.297 ERROR 4292 --- [nio-8080-exec-2] o.a.c.c.C.[Tomcat].[localhost] : Exception Processing ErrorPage[errorCode=0, location=/error]
java.lang.NullPointerException: Cannot invoke "String.length()" because "this.input" is null
at java.base/java.net.URI$Parser.parse(URI.java:3164) ~[na:na]
at java.base/java.net.URI.<init>(URI.java:623) ~[na:na]
at java.base/java.net.URI.create(URI.java:904) ~[na:na]
at org.apache.http.client.methods.HttpGet.<init>(HttpGet.java:66) ~[httpclient-4.5.13.jar:4.5.13]
at org.keycloak.adapters.rotation.JWKPublicKeyLocator.sendRequest(JWKPublicKeyLocator.java:98) ~[keycloak-adapter-core-18.0.0.jar:18.0.0]
at org.keycloak.adapters.rotation.JWKPublicKeyLocator.getPublicKey(JWKPublicKeyLocator.java:63) ~[keycloak-adapter-core-18.0.0.jar:18.0.0]
at org.keycloak.adapters.rotation.AdapterTokenVerifier.getPublicKey(AdapterTokenVerifier.java:121) ~[keycloak-adapter-core-18.0.0.jar:18.0.0]
at org.keycloak.adapters.rotation.AdapterTokenVerifier.createVerifier(AdapterTokenVerifier.java:111) ~[keycloak-adapter-core-18.0.0.jar:18.0.0]
at org.keycloak.adapters.rotation.AdapterTokenVerifier.verifyToken(AdapterTokenVerifier.java:47) ~[keycloak-adapter-core-18.0.0.jar:18.0.0]
at org.keycloak.adapters.BearerTokenRequestAuthenticator.authenticateToken(BearerTokenRequestAuthenticator.java:103) ~[keycloak-adapter-core-18.0.0.jar:18.0.0]
at org.keycloak.adapters.BearerTokenRequestAuthenticator.authenticate(BearerTokenRequestAuthenticator.java:88) ~[keycloak-adapter-core-18.0.0.jar:18.0.0]
at org.keycloak.adapters.RequestAuthenticator.authenticate(RequestAuthenticator.java:67) ~[keycloak-adapter-core-18.0.0.jar:18.0.0]
at org.keycloak.adapters.springsecurity.filter.KeycloakAuthenticationProcessingFilter.attemptAuthentication(KeycloakAuthenticationProcessingFilter.java:154) ~[keycloak-spring-security-adapter-18.0.0.jar:18.0.0]
at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:227) ~[spring-security-web-5.7.2.jar:5.7.2]
at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:217) ~[spring-security-web-5.7.2.jar:5.7.2]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) ~[spring-security-web-5.7.2.jar:5.7.2]
at org.keycloak.adapters.springsecurity.filter.KeycloakPreAuthActionsFilter.doFilter(KeycloakPreAuthActionsFilter.java:96) ~[keycloak-spring-security-adapter-18.0.0.jar:18.0.0]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) ~[spring-security-web-5.7.2.jar:5.7.2]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:102) ~[spring-web-5.3.21.jar:5.3.21]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) ~[spring-security-web-5.7.2.jar:5.7.2]
at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:112) ~[spring-security-web-5.7.2.jar:5.7.2]
at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:82) ~[spring-security-web-5.7.2.jar:5.7.2]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) ~[spring-security-web-5.7.2.jar:5.7.2]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:102) ~[spring-web-5.3.21.jar:5.3.21]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) ~[spring-security-web-5.7.2.jar:5.7.2]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:102) ~[spring-web-5.3.21.jar:5.3.21]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) ~[spring-security-web-5.7.2.jar:5.7.2]
at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:211) ~[spring-security-web-5.7.2.jar:5.7.2]
at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:183) ~[spring-security-web-5.7.2.jar:5.7.2]
at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:354) ~[spring-web-5.3.21.jar:5.3.21]
at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:267) ~[spring-web-5.3.21.jar:5.3.21]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) ~[tomcat-embed-core-9.0.64.jar:9.0.64]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) ~[tomcat-embed-core-9.0.64.jar:9.0.64]
at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) ~[spring-web-5.3.21.jar:5.3.21]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) ~[spring-web-5.3.21.jar:5.3.21]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) ~[tomcat-embed-core-9.0.64.jar:9.0.64]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) ~[tomcat-embed-core-9.0.64.jar:9.0.64]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:102) ~[spring-web-5.3.21.jar:5.3.21]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) ~[tomcat-embed-core-9.0.64.jar:9.0.64]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) ~[tomcat-embed-core-9.0.64.jar:9.0.64]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:102) ~[spring-web-5.3.21.jar:5.3.21]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) ~[tomcat-embed-core-9.0.64.jar:9.0.64]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) ~[tomcat-embed-core-9.0.64.jar:9.0.64]
at org.apache.catalina.core.ApplicationDispatcher.invoke(ApplicationDispatcher.java:711) ~[tomcat-embed-core-9.0.64.jar:9.0.64]
at org.apache.catalina.core.ApplicationDispatcher.processRequest(ApplicationDispatcher.java:461) ~[tomcat-embed-core-9.0.64.jar:9.0.64]
at org.apache.catalina.core.ApplicationDispatcher.doForward(ApplicationDispatcher.java:385) ~[tomcat-embed-core-9.0.64.jar:9.0.64]
at org.apache.catalina.core.ApplicationDispatcher.forward(ApplicationDispatcher.java:313) ~[tomcat-embed-core-9.0.64.jar:9.0.64]
at org.apache.catalina.core.StandardHostValve.custom(StandardHostValve.java:403) ~[tomcat-embed-core-9.0.64.jar:9.0.64] at org.apache.catalina.core.StandardHostValve.status(StandardHostValve.java:249) ~[tomcat-embed-core-9.0.64.jar:9.0.64] at org.apache.catalina.core.StandardHostValve.throwable(StandardHostValve.java:344) ~[tomcat-embed-core-9.0.64.jar:9.0.64]
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:169) ~[tomcat-embed-core-9.0.64.jar:9.0.64] at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92) ~[tomcat-embed-core-9.0.64.jar:9.0.64]
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78) ~[tomcat-embed-core-9.0.64.jar:9.0.64]
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:360) ~[tomcat-embed-core-9.0.64.jar:9.0.64]
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:399) ~[tomcat-embed-core-9.0.64.jar:9.0.64]
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65) ~[tomcat-embed-core-9.0.64.jar:9.0.64]
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:890) ~[tomcat-embed-core-9.0.64.jar:9.0.64]
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1787) ~[tomcat-embed-core-9.0.64.jar:9.0.64]
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) ~[tomcat-embed-core-9.0.64.jar:9.0.64]
at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191) ~[tomcat-embed-core-9.0.64.jar:9.0.64]
at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659) ~[tomcat-embed-core-9.0.64.jar:9.0.64]
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) ~[tomcat-embed-core-9.0.64.jar:9.0.64]
at java.base/java.lang.Thread.run(Thread.java:833) ~[na:na]
So, at this point i tried a couple of changes on application.properties, change and test different options on the config file, putting and taking out dependencies, etc. but everything leads to the same 500 error.因此,此时我尝试了对 application.properties 的一些更改,更改和测试配置文件上的不同选项,放置和取出依赖项等,但一切都会导致相同的 500 错误。 I don't know what else configure, and the stack doesn't really show something that i can work on.
我不知道还有什么配置,而且堆栈并没有真正显示出我可以处理的东西。 Did anyone had a similar error?
有没有人有类似的错误? Does anyone have an idea what could i do?
有谁知道我能做什么?
Keycloak adapters are note quite ready for spring-boot 2.7 and later (still extens WebSecurityConfigurerAdapter). Keycloak 适配器已经为 spring-boot 2.7 及更高版本做好了准备(仍然扩展了 WebSecurityConfigurerAdapter)。
Get a look at https://github.com/ch4mpy/spring-addons .看看https://github.com/ch4mpy/spring-addons 。 It is ready for latest boot versions and much more portable to other OIDC servers.
它已为最新的引导版本做好准备,并且更易于移植到其他 OIDC 服务器。
So apparently, the server url wasn't properly configured.显然,服务器 url 配置不正确。 Taking out the /auth in the path helped solving it.
取出路径中的 /auth 有助于解决它。 The localhost:8000/auth was deprecated since KC 17, and from now on, it's just the server url.
localhost:8000/auth 自 KC 17 以来已被弃用,从现在开始,它只是服务器 url。
https://www.keycloak.org/migration/migrating-to-quarkus https://www.keycloak.org/migration/migrating-to-quarkus
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.