Dans ce post, je donne les étapes de mise en place d’une authentification OpenID Connect (OIDC). OIDC est une couche d’identification basée sur OAuth 2.0; OIDC permet à des clients d’identifier des utilisateurs et récupérer des informations sur l’utilisateur.
OAuth2 définit plusieurs types d’authorisation; les modes sont appelés des Grant Types.
Le Grant Type utilisé dans ce post est le grant “Implicit”.
Composants Techniques
- Le serveur d’authentification utilisé est Keycloak
- Le Front est une SPA implémentée avec Vue.js
- Le Back est une application java Spring
- Utilisation du module Spring Security OAuth2
Authentification
Dans le grant Type “Implicit”, l’authentification se fait côté Front.
-
L’utilisateur ouvre le Front dans un navigateur
- Comme l’utilisateur n’est pas authentifié, l’application le redirige vers la mire d’authentification de Keycloak
- L’utilisateur s’authentifie en saisissant son login et mot de passe;
- L’utilisateur est redirigé vers le Front par Keycloak (en intégrant dans l’URL un access token)
-
Toutes les requêtes Ajax du Front au Back doivent intégrer l’access token. En effet, ce token porte les informations de connexion de l’utilisateur
Configuration Keycloak
Créer un Realm
- Créer un Realm dans Keycloak
- Saisir le nom du Realm
Créer un Client
- Cliquer sur Clients dans la barre de menu à gauche
- Cliquer sur le bouton Create
Configurer le Client
- Cliquer sur l’onglet Settings du Client
-
Configurer le Client
-
Définir le Client ID (exemple : meltingpoc)
-
Définir le protocole (openid-connect)
-
Définir le type d’accès (confidential)
-
Activer le Implicit Flow
-
Préciser la liste des URL de redirection valide
-
Configuration côté Front
Le Front comporte deux routes :
- une route d’authentification qui redirige l’utilisateur vers Keycloak
- une route de post authentification qui récupère les informations de connexion à partir de l’URL
Route d’authentification
La route redirige vers l’URL d’authentification de keycloak en passant :
- l’id du client
- le secret du client (onglet Credentials du Client dans Keycloak)
- le bon type de réponse attenu (id_token token)
- l’URL de redirection après authentification
export default {
name: 'Login',
created() {
window.location = 'http://keycloak.k8.wildwidewest.xyz/auth/realms/meltingpoc/protocol/openid-connect/auth?'
+ querystring.stringify({
scope: 'read',
client_id: 'meltingpoc',
client_secret: '4a5bac8a-87e2-4ce1-a417-75f9f70bebef',
response_type: "id_token token",
redirect_uri: 'http://localhost:8080',
grant_type: 'implicit',
nonce: 1
});
}
}
querystring transforme un objet javascript en paramètres
Route Post-Authentification
Après authentification dans Keycloak, l’utilisateur est redirigé vers le Front.
La route de Post-Authentification récupère les informations de connexion de l’URL (notamment le paramètre access_token).
Appel des services Back
L’authentification des appels au Back se fait par ajout d’un header d’authorisation.
- Le header d’authorization’ contient le mot clef ‘Bearer ‘ suivi de l’access_token (stocké ici dans le sessionStorage)
let config = {
headers:
{
'Access-Control-Allow-Origin': '*',
'Authorization': 'Bearer ' + sessionStorage.getItem("access_token"),
'Accept': 'application/json'
}
};
axios.get(eventURL, config)
.then(response => {
this.items = response.data;
})
.catch(e => {
//this.errors.push(e)
});
Configuration côté Back
Le Back développé est une application spring-boot.
Dépendance OAuth
Ajouter les dépendances suivantes au projet
compile('org.springframework.boot:spring-boot-starter')
compile('org.springframework.boot:spring-boot-starter-web')
compile('org.springframework.boot:spring-boot-starter-security')
compile('org.springframework.security.oauth:spring-security-oauth2')
Configurer OAuth
package com.meltingpoc.events.config;
@Configuration
@EnableResourceServer
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
public class OAuth2AuthenticationConfiguration extends ResourceServerConfigurerAdapter {
@Bean
public RequestMatcher resources() {
return new RequestHeaderRequestMatcher("Authorization");
}
@Override
public void configure(HttpSecurity http) throws Exception {
http.requestMatcher(resources())
.authorizeRequests()
.anyRequest().authenticated();
}
}
Configurer CORS
Comme le Front et le Back sont deux applications différentes, il faut activer CORS au niveau du Backend.
@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
public class AjaxCorsFilter extends CorsFilter {
public AjaxCorsFilter() {
super(configurationSource());
}
private static UrlBasedCorsConfigurationSource configurationSource() {
CorsConfiguration config = new CorsConfiguration();
// origins
config.addAllowedOrigin("*");
// headers à autoriser
config.addAllowedHeader("access-control-allow-origin");
config.addAllowedHeader("authorization");
// methods à autoriser
config.addAllowedMethod(HttpMethod.OPTIONS);
config.addAllowedMethod(HttpMethod.GET);
config.addAllowedMethod(HttpMethod.POST);
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
// liste des ressources à protéger
source.registerCorsConfiguration("/events", config);
return source;
}
}
Paramétrage de l’application
Il faut paramétrer les URL OIDC dans le backend. Les URL sont décrites dans la documentation de Keycloak.
security:
basic:
enabled: false
oauth2:
resource:
userInfoUri: http://keycloak.k8.wildwidewest.xyz/auth/realms/meltingpoc/protocol/openid-connect/userinfo
token-info-uri: http://keycloak.k8.wildwidewest.xyz/auth/realms/meltingpoc/protocol/openid-connect/token/introspect
prefer-token-info: false
client:
clientId: meltingpoc
accessTokenUri: http://keycloak.k8.wildwidewest.xyz/auth/realms/meltingpoc/protocol/openid-connect/token
userAuthorizationUri: http://keycloak.k8.wildwidewest.xyz/auth/realms/meltingpoc/protocol/openid-connect/auth
scope: openid