Quarkus a un module pour faire de l’authentification. La documentation explique comment l’utiliser avec Keycloak. J’ai du l’utiliser avec Strava.
Extension
Extension quarkus-oidc
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-oidc</artifactId>
</dependency>
Keycloak
Configuration
quarkus:
oidc:
auth-server-url: http://localhost:8180/realms/quarkus
client-id: frontend
application-type: web-app
authentication:
redirect-path: /tokens
http:
auth:
permission:
authenticated:
paths: /*
policy: authenticated
Avec cette configuration, une authentification est demandée pour n’importe quelle requête. Pour ça, la requête est redirigée vers Keycloak.
Keycloak doit être démarré au préalable et le realm fourni dans l’exemple doit être importé.
docker run --name keycloak -e KC_BOOTSTRAP_ADMIN_USERNAME=admin -e KC_BOOTSTRAP_ADMIN_PASSWORD=admin -p 8180:8080 quay.io/keycloak/keycloak:26.0.7 start-dev
Sans la propriété quarkus.oidc.auth-server-url
, en dev, Quarkus démarre une instance de Keycloak, sous forme de Dev Service.
Transport par le cookie q_session.
Code
Il y a plusieurs possibilités d’injection.
@Inject
SecurityIdentity securityIdentity;
-
io.quarkus.security.identity.SecurityIdentity
-
isAnonymous(): boolean
-
getRoles(): Set<String>
-
getPrincipal(): Principal
-
getCredentials(): Set<Credential>
-
getCredential(Class<T> credentialType): T
-
getAttributes(): Map<String, Object>
-
getAttribute(String name): T
-
C’est assez générique, mais pas très lisible.
@Inject
IdTokenCredential idToken;
@Inject
AccessTokenCredential accessToken;
@Inject
RefreshToken refreshToken;
-
io.quarkus.oidc.SecurityIdentity
-
getToken(): String
-
getType(): String
-
isInternal(): boolean
-
-
io.quarkus.oidc.AccessTokenCredential
-
getToken(): String
-
getType(): String
-
isOpaque(): boolean
-
-
io.quarkus.oidc.RefreshToken
-
getToken(): String
-
getType(): String
-
Ça manque d’informations utilisables.
@Inject @IdToken
JsonWebToken idToken;
@Inject
JsonWebToken accessToken;
@Inject
JsonWebToken refreshToken;
Là on a le détail des tokens JWT. Ça marche parce que Keycloak fournit des tokens JWT.
Strava
Strava fait partie des fournisseurs prédéfinis, comme Google, Microsoft, Facebook,…
quarkus:
oidc:
provider: strava
client-id: 45678
credentials:
secret: 0123456789abcdef0123456789abcdef01234567
application-type: web-app
authentication:
redirect-path: /tokens
http:
auth:
permission:
authenticated:
paths: /*
policy: authenticated
Pour les injections, on a des différences car les tokens fournis par Strava sont opaques. Et aucun id token n’est fourni. A la place, Quarkus en construit un en interne à partir des user info.
Si on injecte des JsonWebToken, une OIDCException est lancée, expliquant qu’un token opaque ne peut pas être converti en JWT.
io.quarkus.oidc.OIDCException: Opaque access token can not be converted to JsonWebToken
at io.quarkus.oidc.runtime.OidcJsonWebTokenProducer.getTokenCredential(OidcJsonWebTokenProducer.java:67)
at io.quarkus.oidc.runtime.OidcJsonWebTokenProducer.currentAccessToken(OidcJsonWebTokenProducer.java:41)
Pas de problème pour l’id token, qui est généré en interne, en JWT.
Personnalisation
Pour stocker les tokens en base de données: DatabaseTokenStateManager (extends TokenStateManager).
Pour personnaliser les rôles (par exemple avec les clubs): RolesAugmentor (extends SecurityIdentityAugmentor).
Pour les deux, on a la même impossibilité d’injecter des beans de scope request ou session. C’est dû au fait que le contexte de RequestScoped n’est pas encore actif.