2017-07-06 1 views
0

J'essaie d'activer le contrôle d'accès basé sur les rôles sur un point de repos que j'ai configuré en utilisant undertow, jersey et CDI. J'initialiser le déploiement de servlet comme suit:Le gestionnaire de servlet Undertow perd SecurityContext déjà authentifié et valide géré par keycloak

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

J'activé l'authentification basée sur kecloak this example code.

Alors, mon serveur est démarré comme:

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(); 

Lorsque les deux méthodes sessionHandling() et addSecurity() sont soulevés de l'exemple que j'ai lié ci-dessus.

L'authentification fonctionne, je suis obligé de me connecter et la ligne de consignation est imprimée avec les détails corrects. Mais, une fois qu'il a atteint la gestion de la servlet, le contexte de sécurité (et le compte) est perdu. J'ai suivi cet appel et je peux voir qu'à un certain moment le long du chemin, il est remplacé par le tout nouveau SecurityContext qui a un compte nul. Maintenant ma question - existe-t-il un mécanisme d'authentification qui me manque qui propagerait l'état après l'authentification keycloak ou puis-je juste corriger le code de sous-courant et dans le SecurityContext, si le contexte passé est déjà correctement authentifié, accepter cet état et passer à autre chose? (ce dernier ne semble pas correct, je suppose que c'est parce que l'authentification pourrait être différente pour le déploiement de servlet?) Si oui, est-il possible de connecter le déploiement de servlet pour voir que l'authentification keycloak a déjà eu lieu?

Répondre

1

Incase quelqu'un vient chercher ici sur la façon d'authentifier servlets correctement avec l'authentification basée sur les rôles de keycloak et d'utilisation, cela a fonctionné pour moi (note, cela a fonctionné pour moi sans l'exigence de tous les fichiers xml, purement avec annotations.

Tout d'abord dans l'application de servlet (où vous avez étendu ResourceConfig) register() le RolesAllowedDynamicFeature.class.

permettent également "use-resource-role-mappings": true en keycloak.json.

Ensuite, instancier le déploiement de servlet avec un s initial wrapper écurité:

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)) est essentiellement le code du repo github lié.

Maintenant authentification via keycloak fonctionne, ainsi que l'authentification basée sur les rôles fonctionnera, donc par exemple, si vous avez un CDI injecté point final reste, comme:

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

Tant que les rôles sont configurés en keycloak, ça devrait marcher.