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

问题描述 投票:0回答:1

我正在尝试在我使用underow,jersey和CDI设置的休息终点上启用基于角色的访问控制。我按如下方式初始化servlet部署:

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/*"));

我启用了基于this example code的kecloak身份验证。

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

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身份验证已经发生?

java authentication servlets keycloak undertow
1个回答
1
投票

任何人都来这里看看如何使用keycloak正确验证servlet并使用基于角色的身份验证,这对我有用(注意,这对我有用,不需要任何xml文件,纯粹带有注释。

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

同时在"use-resource-role-mappings": true启用keycloak.json

接下来,使用初始安全包装器实例化servlet部署:

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 repo的代码。

现在通过keycloak进行身份验证将起作用,并且基于角色的身份验证也可以正常工作,例如,如果您有一个CDI注入的休息终点,例如:

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

只要角色在keycloak中配置,它就应该有效。

© www.soinside.com 2019 - 2024. All rights reserved.