Ce petit article (qui sera aussi adapté en Anglais pour le blog international de Lunatech) vous propose de voir comment configurer Quarkus, Keycloak et notre ami Swagger, pour que tout fonctionne ensemble. Notre objectif est de configurer l’authentification du côté de l’API OpenAPI 3.0, afin d’utiliser le système d’authentification de Keycloak. Vous pourrez ainsi tester votre API REST directement via swagger, tout en étant authentifié correctement. Cela facilite les tests et les vérifications de votre API.

Quarkus est une solution Java open-source très puissante, que nous utilisons dans le cadre du développement d’une application en interne. Nous vous en parlerons prochainement, car nous participons au concours Quarkus Hackaton. Vous aurez accès au code source en juin. Cette application Quarkus est accompagné d’un frontend en React.

Du côté de notre application Quarkus, nous utilisons les modules suivants :

- quarkus-resteasy
- quarkus-junit5
- rest-assured
- quarkus-flyway
- quarkus-resteasy-jackson
- quarkus-hibernate-orm-panache
- quarkus-jdbc-postgresql
- quarkus-keycloak-authorization
- quarkus-oidc
- quarkus-test-h2
- keycloak-admin-client
- junit-jupiter
- quarkus-smallrye-openapi
- quarkus-smallrye-health
- jakarta.security.jacc-api
- jna
- vavr

A noter que nous sommes passés de JaxB à Jackson, cela méritera un article sur ce sujet…

Nous avons donc configuré le module quarkus-smallrye-openapi, documenté ici sur le site de Quarkus. Ce module permet alors d’obtenir automatiquement une intégration de Swagger, ce qui permet de “tester” votre API REST. Une fois le module installé, vous avez directement accès à une page servie par Quarkus, ce qui est pratique.

Dans le cas présent, les endpoints comme /api/clients ci-dessous, sont tous protegés par Keycloak. Il est donc nécessaire d’obtenir un jeton JWT pour pouvoir appeler chacun de ces endpoints.

Tout d’abord, voici ce que nous souhaitons obtenir :

Notez le bouton “Authorize” qui, lorsque l’on va cliquer dessus, nous permettra de s’authentifier en utilisant le point d’accès OAuth2 de notre serveur Keycloak. Il suffira simplement de spécifier un clientID dont nous allons parler plus loin dans cet article.

Dans notre exemple, Quarkus fonctionne sur le port 8081, et Keycloak sur le port 8082.

Nous allons étudier maintenant la configuration du côté de Keycloak. Un Realm a été déclaré à la racine, et nous avons configuré un Client spécifique pour cette partie swagger. Il n’est pas recommandé de ré-utiliser un client, pour des raisons évidentes de sécurité. Notre application utilise aussi un Client pour la partie Quarkus et un Client pour la partie React.

Le Client ID sera “timekeeper-swagger”. Il sera configuré en ‘implicit flow enabled’, avec les restrictions suivantes :

A noter qu’il existe un bug actuellement dans Quarkus, qui nous a forcé à recopier la page HTML oauth2-redirect.html dans notre projet. Il faudra donc créer un fichier dans le répertoire suivant de votre projet quarkus :

src/main/resources/META-INF/resources/oauth2-redirect.html

en prévision de la correction de ce bug, nous avons cependant déclaré 2 URLs de redirection. L’URL “correcte” est /swagger-ui/oauth2-redirect.html. L’autre URL est le fichier que vous allez placer à la racine du projet en attendant.

Une fois que votre Client est configuré, seul le ClientID sera donc important.

Il reste enfin à déclarer correctement tout ceci dans les annotations Microprofiles, utilisées par le module de quarkus pour “générer” notre page Swagger.

Voici comment cela se présente :

package fr.lunatech.timekeeper;


import org.eclipse.microprofile.openapi.annotations.ExternalDocumentation;
import org.eclipse.microprofile.openapi.annotations.OpenAPIDefinition;
import org.eclipse.microprofile.openapi.annotations.enums.SecuritySchemeType;
import org.eclipse.microprofile.openapi.annotations.info.Contact;
import org.eclipse.microprofile.openapi.annotations.info.Info;
import org.eclipse.microprofile.openapi.annotations.info.License;
import org.eclipse.microprofile.openapi.annotations.security.*;
import org.eclipse.microprofile.openapi.annotations.servers.Server;

import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;

@ApplicationPath("/api")
@OpenAPIDefinition(
        info = @Info(title = "TimeKeeper API",
                description = "This API allows CRUD operations and interaction with TimeKeeper",
                version = "1.0",
                contact = @Contact(name = "TimeKeeper GitHub", url = "https://github.com/lunatech-labs/lunatech-timekeeper"),
                license = @License(name = "Apache 2.0", url = "http://www.apache.org/licenses/LICENSE-2.0.html")
        ),
        servers = {
                @Server(
                        url = "http://localhost:8081",
                        description = "DEV Server"
                )
                // here you can add also other servers...
        }
        , security = {
        @SecurityRequirement( name = "dev_timekeeperOAuth2" ,scopes = { "profile"})
}

)
@SecurityScheme(
        securitySchemeName = "dev_timekeeperOAuth2",
        type = SecuritySchemeType.OAUTH2,
        description = "authentication for OAuth2 access",
        flows = @OAuthFlows(
                implicit = @OAuthFlow(authorizationUrl = "http://localhost:8082/auth/realms/Timekeeper/protocol/openid-connect/auth")
        )
)
public class TimeKeeperApplication extends Application {

}

Et voilà !

Vous pouvez maintenant tester en précisant clientId=timekeeper-swagger dans la page d’authentification de Swagger.

Il est assez difficile de trouver un exemple complet de configuration, lorsque l’on souhaite donc générer correctement le contrat OpenId (ici un exemple assez complet).

Quarkus est vraiment simple à utiliser, il offre une intégration propre et rapide, et il nous permet donc de tester ici les différentes ressources de notre API.

Si vous avez d’autres idées, n’hésitez pas à me contacter directement pour proposer d’autres idées (nicolas.martignole AT lunatech POINT fr)