Undertow servlet处理程序丢失已经通过keycloak管理的身份验证和有效的SecurityContext

问题描述:

我试图启用基于角色的访问控制,我已设置使用底池,球衣和CDI的休息终点。我初始化servlet部署如下:Undertow servlet处理程序丢失已经通过keycloak管理的身份验证和有效的SecurityContext

DeploymentInfo servletBuilder = Servlets.deployment() 
    .setClassLoader(Main.class.getClassLoader()) 
    .setContextPath("/rest") 
    .setDeploymentName("sv.war") 
    .addListeners(listener(Listener.class)) 
    .setLoginConfig(new LoginConfig("KEYCLOAK", "some-realm")) 
    .setAuthorizationManager(auth) // my dummy for testing 
    .addServlets(servlet("jerseyServlet", ServletContainer.class) 
     .setLoadOnStartup(1) 
     .addInitParam("javax.ws.rs.Application", SystemViewApplication.class.getName()) 
     .addMapping("/api/*")); 

我启用kecloak认证基于this example code

所以,我的服务器启动为:

DeploymentManager manager = Servlets.defaultContainer().addDeployment(servletBuilder); 
manager.deploy(); 

PathHandler path = Handlers.path(Handlers.resource(staticResources).setDirectoryListingEnabled(false).setWelcomeFiles("index.html")) 
    .addPrefixPath("/rest", manager.start()); 
Undertow server = Undertow.builder() 
    .addHttpListener(8087, "localhost") 
    .setHandler(sessionHandling(addSecurity(exchange -> { 
     final SecurityContext context = exchange.getSecurityContext(); 
     if (!context.isAuthenticated()) { 
     exchange.endExchange(); 
     return; 
     } 
     log.info("Authenticated: {} {} {}", context.getMechanismName(), context.getAuthenticatedAccount().getPrincipal().getName(), context.getAuthenticatedAccount().getRoles()); 
     // propagate the request 
     path.handleRequest(exchange); 
    }))) 
    .build(); 
server.start(); 

如果这两种方法sessionHandling()addSecurity()从例如举起我上面链接。

验证有效,我强制登录,并且Authenticated: ..记录行用正确的详细信息打印出来。但是,一旦它遇到了servlet处理,安全上下文(和帐户)就会丢失。我跟踪了这​​个电话,我可以看到在路上的某个时刻,它被替换为全新的SecurityContext,它有一个空账户。

现在我的问题 - 是否有一些身份验证机制,我错过了将在keycloak身份验证之后传播状态,或者我可以只修复上游代码,并且在SecurityContext中,如果传入的上下文已经正确验证,该状态并继续前进? (后者看起来不正确,我猜这是因为这可能是servlet部署的不同身份验证?)如果是这样,是否有任何方法连接servlet部署以查看keycloak身份验证已经发生?

柜面有人来就如何servlet的基于keycloak和使用角色的身份验证正确验证这里寻找,这个工作对我来说(注意,这个工作对我来说没有任何XML文件的要求,纯粹与注解。

首先在servlet的应用程序(无论你扩展ResourceConfigregister()RolesAllowedDynamicFeature.class

而且在keycloak.json使"use-resource-role-mappings": true

接下来,最初的小号实例化servlet部署ecurity包装:

DeploymentInfo servletBuilder = Servlets.deployment() 
    .setClassLoader(Main.class.getClassLoader()) 
    .setContextPath("/") 
    .setDeploymentName("sv.war") 
    .addListeners(listener(Listener.class)) 
    .setIdentityManager(idm) 
    .setSessionManagerFactory(new InMemorySessionManagerFactory()) 
    .setInitialSecurityWrapper(handler -> sessionHandling(addSecurity(handler))) 
    .setResourceManager(staticResources) 
    .addWelcomePage("index.html") 
    .addServlets(servlet("jerseyServlet", ServletContainer.class) 
     .setLoadOnStartup(1) 
     .addInitParam("javax.ws.rs.Application", SystemViewApplication.class.getName()) 
     .addMapping("/api/*")); 


DeploymentManager manager = Servlets.defaultContainer().addDeployment(servletBuilder); 
manager.deploy(); 

Undertow server = Undertow.builder() 
    .addHttpListener(8087, "localhost") 
    .setHandler(Handlers.path(manager.start())) 
    .build(); 
server.start(); 

哪里sessionHandling(addSecurity(handler))基本上是从链接GitHub库的代码。

现在认证通过keycloak会工作,也是基于角色的身份验证将正常工作,因此,例如,如果你有一个CDI注入休息终点,如:

@RolesAllowed({"admin", "guest"}) 
@GET 
@Path("/{id}") 
public Response findById(@PathParam("id") @NotNull Integer id){ 
    // some method 
} 

只要角色配置在keyclak中,它应该起作用。